2017-04-11 4 views
0

Ich arbeite an einer Shiny-Anwendung, in der zwei Schieberegler-Eingänge vorhanden sind. Diese eingegebenen Werte unterteilen ein Datenframe unterschiedlich und die Teilmenge dieses Datenframes wird dann in ein Streudiagramm geplottet.Das Objekt wurde nicht gefunden, wenn es aus der Funktion isolate() in Shiny erstellt wurde.

Ich versuche zu verhindern, dass das Scatterplot neu plottiert wird, es sei denn, der Benutzer klickt auf ein "Go!" Taste. Um dies zu erreichen, verwende ich die Funktion isolate() auf den Schieberegler-Eingabewerten, so dass der Datenrahmen und das Diagramm nur aktualisiert werden, wenn das "Go!" Schaltfläche wird geändert.

Das scheint in Ordnung zu sein, aber ich versuche auch, dem Benutzer zu ermöglichen, das Auswahlwerkzeug in Plotly zu verwenden und die Datenrahmenzeilen zu sehen, die dieser Auswahl entsprechen. Wenn ich dies jedoch versuche, erhalte ich einen Fehler ("Fehler: Objekt 'datInput' nicht gefunden"). Diese Zeile ist im folgenden Beispiel kommentiert:

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1"), 
    verbatimTextOutput("click") 
) 
)) 

server <- shinyServer(function(input, output) { 

    set.seed(1) 
    dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
    dat$Case <- as.character(dat$Case) 

    xMax = max(dat$val1) 
    xMin = min(dat$val1) 
    yMax = max(dat$val2) 
    yMin = min(dat$val2) 
    maxTemp = max(abs(xMax), abs(xMin)) 

    observeEvent(input$goButton, 
     output$plot1 <- renderPlotly({ 
     # Use isolate() to avoid dependency on input$val1 and input$val2 
     datInput <- isolate(subset(dat, val1 > input$val1 & val2 > input$val2)) 
     p <- qplot(datInput$val1, datInput$val2) +xlim(0, ceiling(maxTemp)) +ylim(0,1) 
     ggplotly(p) 
     }) 
) 

    d <- reactive(event_data("plotly_selected")) 

    output$click <- renderPrint({ 
    if (is.null(d())){ 
     "Click on a state to view event data" 
    } 
    else{ 
     #str(d()$pointNumber) #Seems to be working 
     datInput[d()$pointNumber,] #Error: object 'datInput' not found 
    } 
    }) 
}) 

shinyApp(ui, server) 

Alle Ideen für eine Problemumgehung für dieses Problem würden wir uns freuen!

EDIT:

Hier ist die Lösung gemäß @mlegge. Ich habe einfach die Ausgabe, nachdem der Benutzer bestimmte Punkte auswählt:

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1"), 
    verbatimTextOutput("click") 
) 
)) 

set.seed(1) 
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
dat$Case <- as.character(dat$Case) 

xMax = max(dat$val1) 
xMin = min(dat$val1) 
yMax = max(dat$val2) 
yMin = min(dat$val2) 
maxTemp = max(abs(xMax), abs(xMin)) 

server <- shinyServer(function(input, output) { 

    # datInput only validated once the go button is clicked 
    datInput <- eventReactive(input$goButton, { 
    subset(dat, val1 > input$val1 & val2 > input$val2) 
    }) 

    output$plot1 <- renderPlotly({ 
    # will wait to render until datInput is validated 
    plot_dat <- datInput() 

    p <- qplot(plot_dat$val1, plot_dat$val2) + xlim(0, ceiling(maxTemp)) +ylim(0,1) 
    ggplotly(p) 
    }) 

    d <- reactive(event_data("plotly_selected")) 
    output$click <- renderPrint({ 
    if (is.null(d())){ 
     "Click on a state to view event data" 
    } 
    else{ 
     #str(d()$pointNumber) 
     datInput()[d()$pointNumber+1,] #Working now 
    } 
    }) 
}) 

shinyApp(ui, server) 

Antwort

2

Sie nicht isolate richtig verwenden, eine bessere Lösung ist ein eventReactive:

library(shiny) 
library(plotly) 

ui <- shinyUI(pageWithSidebar(
    headerPanel("Click the button"), 
    sidebarPanel(
    sliderInput("val1", "Value 1:", min = 0, max = 1, value=0.5, step=0.1), 
    sliderInput("val2", "Value 2:", min = 0, max = 1, value=0.5, step=0.1), 
    actionButton("goButton", "Go!") 
), 
    mainPanel(
    plotlyOutput("plot1") 
) 
)) 

set.seed(1) 
dat <- data.frame(Case = paste0("case",1:15), val1=runif(15,0,1), val2=runif(15,0,1)) 
dat$Case <- as.character(dat$Case) 

xMax = max(dat$val1) 
xMin = min(dat$val1) 
yMax = max(dat$val2) 
yMin = min(dat$val2) 
maxTemp = max(abs(xMax), abs(xMin)) 

server <- shinyServer(function(input, output) { 

    # datInput only validated once the go button is clicked 
    datInput <- eventReactive(input$goButton, { 
    subset(dat, val1 > input$val1 & val2 > input$val2) 
    }) 

    output$plot1 <- renderPlotly({ 
    # will wait to render until datInput is validated 
    plot_dat <- datInput() 

    p <- qplot(plot_dat$val1, plot_dat$val2) + xlim(0, ceiling(maxTemp)) +ylim(0,1) 
    ggplotly(p) 
    }) 
}) 

shinyApp(ui, server) 

Sie werden feststellen, dass Ihre Daten Generation hat Außerhalb der server verschoben, ist dies, weil es nur einmal ausgeführt werden muss.

Sie sollten auch nie ein output Objekt in einen Observer einbinden, sondern die Eingabedaten mit reaktiven Elementen steuern.

enter image description here

+0

Vielen Dank für die hilfreiche Antwort! Könnten Sie bitte erklären "Sie werden feststellen, dass Ihre Datengenerierung außerhalb des Servers verschoben wurde, weil sie nur einmal ausgeführt werden muss." Wie könnte ich das wissen, und hat das irgendwelche Nachteile? Insbesondere macht das Generieren von Daten außerhalb des Servers es für große Datasets langsamer (wofür ich als mein Ziel arbeite!) Danke. – LanneR

+1

Der 'Server' wird jedes Mal ausgeführt, wenn etwas ungültig gemacht wird, also lade/erzeuge immer große Datenmengen in' global.R' (oder einfach in deiner Session, wenn du eine einzige 'app.R' ausführst) an vermeiden Sie, diesen großen Datenprozess immer und immer wieder zu haben. – mlegge

+1

Hier ist, was ich spreche über https://shiny.rstudio.com/articles/scoping.html#objects-visible-across-all-sessions und https://shiny.rstudio.com/articles/scoping.html # global-objects – mlegge

Verwandte Themen