2014-06-12 15 views
7

Ich frage mich nur, ob es Tricks/Möglichkeiten gibt, wie ich die Plots, die durch unsere glänzende App generiert werden, zwischenspeichern kann.caching plots in R/Shiny

Hintergrund:

Wir tun etwas intensive Berechnungen berechnen, die schließlich in einem Plan zur Folge hat. Ich bin bereits im Caching (mit Memoise) die Berechnungen durchgeführt, global in glänzend, aber es dauert immer noch ca. 0,75 Sekunden, um eine Handlung zu rendern. Ich habe mich nur gefragt, ob wir diese Zeit reduzieren können, indem wir die Zeit, die es braucht, um ein Bild zu rendern, entfernen und ob es bereits raffinierte Möglichkeiten gibt, es zu tun.

Weitere Informationen:.

ich Gitter bin mit dem Grundstück (Heatmap in diesem Fall erstellen möchten in idealer Weise die Caching Platte als Speicherung Plots im Speicher basiert gewohnt Maßstabsvergrößerung

Dank. ! -Abhi

+0

Siehe das Beispiel unter '? RenderImage', es könnte Ihnen einige Ideen geben. Grundsätzlich möchten Sie eine Memo-Plot-Funktion, die eine PNG-Datei zurückgibt, denke ich; und benutze renderImage, um diese Memo-Funktion aufzurufen. –

+0

Danke Joe. Irgendwelche Ideen, wie wir glänzen können, um statische Bilder automatisch zu skalieren, die wir mit renderImage rendern. – Abhi

Antwort

4

Angenommen, Sie ggplot verwenden (die mit glänzenden, würde ich eine faire Annahme wette).

  1. Erstellen Sie eine leere Liste, um Ihren Grob zu speichern, sagen Sie Plist.
  2. Wenn eine Benutzeranfrage ein Graph, einen String-Hash erstellen die auf der Basis der glänzenden Eingänge
  3. Überprüfen Sie, ob der Graph bereits gespeichert, zB hash %in% names(Plist)
  4. Wenn ja servieren, dass Graph
  5. Wenn nein, erzeugen graph, speichern Sie die grob in die Liste, benennen Sie das Element durch den Hash, zB Plist[hash] <- new_graph
+0

danke für schnelle antwort. Ich benutze Grid für diese .. nur fragen, was meinst du mit Grob und auch mehrere Plots im Speicher speichern könnte teuer sein und auch ich möchte das Caching persistent über Server Neustarts. Irgendwelche Pakete, die die Plots auf Festplatte zwischenspeichern und von dort rendern? – Abhi

+0

auch wundernd wissen Sie von jedem Paket, das einen String-Hash basierend auf der Eingabe einer Funktion erstellen könnte..dies wäre für meinen Fall nützlich. – Abhi

+0

'grob' ist nur ein' graphisches Objekt'. Sie können sie wie jedes andere R-Objekt auf der Festplatte speichern. (siehe '? saveRDS'). Das Laden von der Festplatte dauert jedoch genauso lange wie die Neuberechnung. –

2

die Antwort von Ricardo Saporta sehr gut ist und was habe ich ein ähnliches Problem zu lösen, aber ich wollte einen Code hinzufügen Lösung auch.

Zum Caching habe ich digest::digest() verwendet, wo ich gerade eine Liste der Parameter für das bestimmte Diagramm an diese Funktion verfügte, um eine Hash-Zeichenfolge zu erstellen. Ich dachte zuerst, dass ich die Hash-Zeichenfolge von observe() extrahieren und dann eine if/else Anweisung verwenden müsste, um zu bestimmen, ob ich es an renderImage() oder renderPlot() senden sollte basierend darauf, ob das Bild zuvor erstellt wurde. Ich habe mit diesem eine Weile herumgewirbelt und dann zufällig über renderImage() gestolpert. Es ist keine perfekte Bildsubstitution, aber für die Zwecke dieser Demo mehr als nah genug.

ui.R

library(shiny) 

fluidPage(
    sidebarLayout(
    sidebarPanel(
     sliderInput("bins", 
        "Number of bins:", 
        min = 1, 
        max = 50, 
        value = 25), 
     selectInput("plot_color", "Barplot color", 
        c("green"="green", 
         "blue"="blue")) 
    ), 
    mainPanel(
     plotOutput("distPlot", width='100%', height='480px') 
    ) 
) 
) 

und server.R

library(shiny) 

function(input, output) { 

base <- reactive({ 
    fn <- digest::digest(c(input$bins, input$plot_color)) 
    fn}) 

output$distPlot <- renderImage({ 
    filename <- paste0(base(), ".png") 
    if(filename %in% list.files()){ 
     list(src=filename) 
    } else { 
    x <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1) 
    png(filename) 
    hist(x, breaks = bins, col = input$plot_color, border = 'white') 
    dev.off() 
list(src=filename) 
    } 

    }, deleteFile = FALSE) 
} 
0

Obwohl beide Antworten auf diese Frage sind sehr gut, ich wollte ein anderes füge mit shiny modules. Das folgende Modul verwendet eine Plotfunktion und eine reaktive Version seiner Argumente als Eingaben. Am Ende wird do.call(plotfun, args()) verwendet, um das Diagramm zu erstellen.

library(shiny) 

cachePlot <- function(input, output, session, plotfun, args, width = 480, height = 480, 
         dir = tempdir(), prefix = "cachedplot", deleteonexit = TRUE){ 
    hash <- function(args) digest::digest(args) 

    output$plot <- renderImage({ 
    args <- args() 
    if (!is.list(args)) args <- list(args) 
    imgpath <- file.path(dir, paste0(prefix, "-", hash(args), ".png")) 

    if(!file.exists(imgpath)){ 
     png(imgpath, width = width, height = height) 
     do.call(plotfun, args) 
     dev.off() 
    } 
    list(src = imgpath) 
    }, deleteFile = FALSE) 

    if (deleteonexit) session$onSessionEnded(function(){ 
    imgfiles <- list.files(tempdir(), pattern = prefix, full.names = TRUE) 
    file.remove(imgfiles) 
    }) 
} 

cachePlotUI <- function(id){ 
    ns <- NS(id) 
    imageOutput(ns("plot")) 
} 

Wie wir sehen können, löscht das Modul das Bild erstellt Dateien, wenn die Option benötigt und gibt einen benutzerdefinierten Cache-Verzeichnis, falls persistenten Cache benötigt wird, verwendet werden (wie es in meinem eigentlichen usecase ist).

Für ein Anwendungsbeispiel werde ich das hist(faithful[, 2]) Beispiel wie Stedy verwenden.

histfaithful <- function(bins, col){ 
    message("calling histfaithful with args ", bins, " and ", col) 
    x <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = bins + 1) 
    hist(x, breaks = bins, col = col, border = 'white') 
} 

shinyApp(
    ui = fluidPage(
    inputPanel(
     sliderInput("bins", "bins", 5, 30, 10, 1), 
     selectInput("col", "color", c("blue", "red")) 
    ), 
    cachePlotUI("cachedPlot") 
), 
    server = function(input, output, session){ 
    callModule(
     cachePlot, "cachedPlot", histfaithful, 
     args = reactive(list(bins = input$bins, col = input$col)) 
    ) 
    } 
)