简体   繁体   中英

isolate conditionalPanel in shiny

I've got a shiny tab where the user can select several parameters via selectInput . After the selection, the user clicks on an actionButton and a bunch of calculations happen on the server side. Depending on both the results and the selections, one or several conditionalPanels are supposed to be shown. The problem is that once the user changes the selection, the displayed conditionalPanel changes immediately. However, I'd like the conditions only to be evaluated after the user has pushed the actionButton again and the calculations on the server side have been updated. Is there a way to tie the condition of the conditionalPanel on an actionButton ?

Here is the best MWE I could come up with to capture all the nuances (actually, the dependency of the conditional panels on some server results is still missing here):

library(shiny)
library(plyr)

ui <- fluidPage(
  selectInput("variable", "Variable:",
              c("SLength" = "Sepal.Length",
                "SWidth" = "Sepal.Width",
                "PLength" = "Petal.Length",
                "PWidth" = "Petal.Width",
                "Species" = "Species"),
              multiple = TRUE),
  br(),
  actionButton("goButton", "Go!"), 
  hr(),
  conditionalPanel(condition = "input['variable'].length == 1",
                   plotOutput("oneplot")),
  conditionalPanel(condition = "input['variable'].length == 2",
                   plotOutput("twoplot"))
)

server <- function(input, output){
  v <- reactiveValues(plot.type = NULL)

  observeEvent(input$goButton, {
    if (is.null(input$variable)) return(NULL)
    if ("Species" %in% input$variable & length(input$variable > 1)){
      sec.var <- input$variable[which(input$variable != "Species")]
      v$summary <- ldply(by(iris[,sec.var], iris$Species, mean))
      v$summary[,1] <- as.factor(v$summary[,1])
    } else if ("Species" %in% input$variable)
      v$summary <- table(iris$Species) else
        v$summary <- iris[,input$variable]
  })

  output$oneplot <- renderPlot({
    if (is.null(v$summary)) return(NULL)
    if (input$variable == "Species") return(NULL)
    hist(v$summary)
  })

  output$twoplot <- renderPlot({
    if (is.null(v$summary)) return(NULL)
    plot(v$summary)
  })
}

shinyApp(ui, server)

So let's say I start the app and select SLength and SWidth , click the Go -Button and get a dotplot. Then I'd want to show SLength vs. PLength , so I delete SWidth from the selection field and the same moment I get two histograms, one for each of the previous selections. The conditional panel immediately reacts to the change of input$variable , while the observer within the server script is still waiting for me to push the button. Obviously, that's not the behaviour the user would expect. The expected behaviour would be that the evaluation of the conditions of the conditional panels only happens upon pushing the Go -button. Is there a way to achieve this?

How about doing condition on server side?

    library(shiny)
    library(plyr)

    ui <- fluidPage(
      selectInput("variable", "Variable:",
                  c("SLength" = "Sepal.Length",
                    "SWidth" = "Sepal.Width",
                    "PLength" = "Petal.Length",
                    "PWidth" = "Petal.Width",
                    "Species" = "Species"),
                  multiple = TRUE),
      br(),
      actionButton("goButton", "Go!"), 
      hr(),
       plotOutput("oneplot")
     # conditionalPanel(condition = "input['variable'].length == 1",
     #                  plotOutput("oneplot")),
     # conditionalPanel(condition = "input['variable'].length == 2",
      #                 plotOutput("twoplot"))
    )

    server <- function(input, output){
      v <- reactiveValues(plot.type = NULL)

      observeEvent(input$goButton, {
        if (is.null(input$variable)) return(NULL)
        if ("Species" %in% input$variable & length(input$variable > 1)){
          sec.var <- input$variable[which(input$variable != "Species")]
          v$summary <- ldply(by(iris[,sec.var], iris$Species, mean))
          v$summary[,1] <- as.factor(v$summary[,1])
        } else if ("Species" %in% input$variable)
          v$summary <- table(iris$Species) else
            v$summary <- iris[,input$variable]
      })

      output$oneplot <- renderPlot({
        #Added actionButton dependency here
        input$goButton
        isolate({
        if(length(input$variable)== 1) {
            if (is.null(v$summary)) return(NULL)
            if (input$variable == "Species") return(NULL)
            hist(v$summary)
        }
        else {
             if (is.null(v$summary)) return(NULL)
            plot(v$summary)
        }
        })
      })

      #output$twoplot <- renderPlot({

        #if (is.null(v$summary)) return(NULL)
        #plot(v$summary)

      #})
    }

shinyApp(ui, server)         

EDIT: Added another option by using submitButton

You can also use submitButton() and attach observeEvent() to input$variable() . "Forms that include a submit button do not automatically update their outputs when inputs change, rather they wait until the user explicitly clicks the submit button." submitButton

library(shiny)
library(plyr)

ui <- fluidPage(
  selectInput("variable", "Variable:",
              c("SLength" = "Sepal.Length",
                "SWidth" = "Sepal.Width",
                "PLength" = "Petal.Length",
                "PWidth" = "Petal.Width",
                "Species" = "Species"),
              multiple = TRUE),
  br(),
  submitButton("Go!"), 
  hr(),
  conditionalPanel(condition = "input['variable'].length == 1",
                   plotOutput("oneplot")),
  conditionalPanel(condition = "input['variable'].length == 2",
                   plotOutput("twoplot"))
)

server <- function(input, output){
  v <- reactiveValues(plot.type = NULL)

  observeEvent(input$variable, {
    if (is.null(input$variable)) return(NULL)
    if ("Species" %in% input$variable & length(input$variable > 1)){
      sec.var <- input$variable[which(input$variable != "Species")]
      v$summary <- ldply(by(iris[,sec.var], iris$Species, mean))
      v$summary[,1] <- as.factor(v$summary[,1])
    } else if ("Species" %in% input$variable)
      v$summary <- table(iris$Species) else
        v$summary <- iris[,input$variable]
  })

  output$oneplot <- renderPlot({
    if (is.null(v$summary)) return(NULL)
    if (input$variable == "Species") return(NULL)
    hist(v$summary)
  })

  output$twoplot <- renderPlot({
    if (is.null(v$summary)) return(NULL)
    plot(v$summary)
  })
}

shinyApp(ui, server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM