2014-01-22 16 views
8

Ich habe eine Simulation in R geschrieben, die ich jetzt mit glänzend visualisieren möchte. Ich habe den Hauptteil der Simulation in einen Block setzen, um ausgewertet zu werden. Während dieses Evaluierungsprozesses, d. H. Für jede Iteration, möchte ich den aktuellen Status darstellen. Die Frage ist, wie kann ich dies erreichen, da in meinem tatsächlichen Code das Rendern des Plots nur ausgeführt wird, nachdem der Hauptbeobachter evaluiert wurde. Gibt es eine Möglichkeit, zum Beispiel die Ausführung des Beobachtungsblocks zu unterbrechen und nach der Aktualisierung des Diagramms fortzusetzen?Update-Plot innerhalb der Beobachterschleife in glänzender Anwendung

Sollte es nicht noch mehr Funktionalität von shiny geben, um einen solchen Fall anzugehen, da ich mir vorstellen kann, dass ich nicht der Einzige bin, der so etwas machen möchte ?!

Es wäre schön, wenn Sie mir helfen können mit dieser :) ist

Im Folgenden einig Skeleton-Code für den Server und ui.

ui.R:

library(shiny) 

shinyUI(pageWithSidebar(

    headerPanel("... Simulation"), 

    sidebarPanel(
    sliderInput("epochs", 
       "Number of Epochs:", 
       min = 1, 
       max = 100, 
       value = 10), 
    verbatimTextOutput("curr.iter"), 
    actionButton("actionB", "Action!") 
), 

    mainPanel(
    plotOutput("distPlot") 
) 
)) 

server.R:

library(shiny) 

sinus <- data.frame() 

shinyServer(function(input, output) { 

    dummy <- reactiveValues(iter=0) 

    obsMain <- observe({ 
    for (i in 1:input$epochs) { 
     cat(i, " ") 
     x <- seq(1:input$epochs) 
     y <- sin(x) 
     sinus <<- data.frame(x, y) 
     dummy$iter <- i 
     # 
     # At this time I want distPlot & curr.iter to be evaluated/updated! 
     # 
     Sys.sleep(1) 

    } 

    }, suspended=TRUE) 


    obsAction <- observe({ if(input$actionB > 0) obsMain$resume() }) # Helps to avoid initial evaluation of obsMain... 

    output$curr.iter <- renderText({ as.numeric(dummy$iter) }) 

    output$distPlot <- renderPlot({ if (dummy$iter > 1) plot(sinus, type="l") }) 

}) 

Antwort

0

Da Sie ein Sys.sleep() Anruf in Ihrem Code haben, ich nehme an, Sie nur durch eine Iteration pro Sekunde ausgeführt werden soll . Wenn dies der Fall ist, können Sie eine reactiveTimer setzen, die den Code jede Sekunde auswertet. Innerhalb dieses Timers würden Sie den Code für die aktuelle Iteration ausführen und dann die dummy$iter Variable erhöhen.

+0

Danke für Ihre Antwort. Ich habe bereits die Möglichkeit eines reaktiven Timers gesehen, aber ich habe einfach das Sys gesetzt.sleep() -Befehl, um etwas Zeit für das Erscheinen des Plots zu reservieren (in RStudio zum Beispiel muss ich es meistens auf die gleiche Weise tun, sonst wird das Plot nicht angezeigt). In meiner Simulation wird die Rechenaufgabe die notwendige Verzögerung erzeugen. Ich frage mich nur, ob es eine Möglichkeit gibt, das Rendern des Plots (wann immer ich will) auszulösen und daher die Simulation Engine so zu belassen, wie es ist, ohne die Schleife der Simulation rekonstruieren zu müssen. – user3220352

+0

Sie können das Diagramm jederzeit rendern. Das Problem ist, dass R single-threaded ist. Wenn es also mit der Verarbeitung Ihrer Simulation beschäftigt ist, werden andere reaktive Abhängigkeiten nicht ausgewertet. Dies ist noch kein gut durchdachter Teil von Shiny, aber momentan denke ich, dass Sie die "große" Verarbeitung (Simulation) so planen müssen, dass sie in kleinen Blöcken (1 oder nur wenige Iterationen) stattfindet treten alle paar Millisekunden auf - die Idee ist, dass die CPU nicht zu 100% mit dem Ausführen der Simulation beschäftigt ist, was Zeit gibt, andere reaktive Kontexte (wie Ihre Handlung) auszuwerten. –

+0

Ich würde empfehlen, es mit einem reaktiven Timer geplant 1/Sekunde. Sehen Sie, dass Sie die Architektur zum Laufen bringen können, und revidieren Sie von dort aus, um den Timer entweder auf ein viel kleineres Intervall herunterzufahren oder mehr als eine Iteration zu machen, wenn der Timer ausgelöst wird. –

7

Ich habe ein bisschen mehr darüber nachgedacht. Ich denke, die richtige Lösung ist, invalidateLater zu verwenden, um zu planen, dass Arbeit in kleinen Chunks auftritt, aber anderen reaktiven Abhängigkeiten erlauben, unseren lang andauernden Prozess zu unterbrechen, um Dinge wie das Aktualisieren von Graphen auszuführen.

Ich habe ein schnelles Beispiel unter https://gist.github.com/trestletech/8608815 zusammengestellt. Sie können diese laufen mit

runGist(8608815) 

Die Grundvoraussetzung ist, dass wir einige lang andauernde iterativen Rechen tun wie das, was in der Simulation getan, aber wir tun es in kleinere Stücke andere Reaktive laufen zu lassen dazwischen. Mein Code ist wirklich einfach auszuführen, so dass ich 100.000 Wiederholungen meiner Schleife in ~ 1 Sekunde verarbeiten kann. Dabei geht es darum, wie lange ich warten möchte, bis meine App interaktiv aktualisiert wird. Ich möchte 5 Millionen Iterationen machen, also plane ich 50 Chunks.

Jedes Mal, wenn ich einen Teil von 100.000 Iterationen ausführen, aktualisiere ich einige reaktive Werte, die einige andere Updates spawnen, die an meine UI in einem renderText gesendet werden (obwohl ein renderPlot wie Ihr genau das gleiche funktionieren würde)). Wenn Sie die App ausführen, sehen Sie, dass diese Reaktiva zwischen den einzelnen Chunks aktualisiert werden, die ausgeführt werden, bevor der nächste Chunk für die Ausführung geplant ist.

Es gibt ein wenig Overhead mit dieser Methode, so dass Ihre Berechnung nur ein wenig verlangsamen kann. Aber auf meinem Rechner benötigten 5 Millionen Iterationen 21 Sekunden, wenn sie alle gleichzeitig auf der Konsole ausgeführt wurden, und 23 Sekunden in diesem verzögerten Dispatch-Modell. Du könntest das natürlich weiter runter treiben, indem du größere Stücke machst.

Lassen Sie mich wissen, was Sie denken. Ich denke, dass es Sinn machen könnte, dies zusammenzufassen und Teile davon in Shiny oder als Erweiterungspackung einzubauen.

+0

Entschuldigung für Verspätung, ich hatte viele andere Dinge zu tun ... Netter Job, überprüfe ich gerade Ihren Code :) – user3220352

+0

Dies löste mein Problem - wünschte, diese Art von erweiterten Reaktivität fließt wurden in den Tutorials abgedeckt – ThomasP85

+0

Froh, dass es geholfen hat . Zufällig haben wir vor ein paar Minuten http://shiny.studio.com/ gestartet. Vielleicht finden Sie dort mehr Hilfe, obwohl ich glaube, dass wir noch keinen Artikel zu genau diesem Thema haben. –

Verwandte Themen