rplotshinyggvis

change ggvis plot layer dynamically


I would like to change the layer of a ggvis plot using a selectInput widget using a dynamic interface. The problem is that when I choose a different layer after creating the plot, it changes but it just disappear really quick. Below is a simplified version of the code to show the problem that omit all the extra dynamic content. I just plot some number of values from a dataset. I added a couple of selectInput widgets to let the user choose what type of plot and when to show the plot. Please note that I need to have all the elements inside of a renderUI.

library(shiny)
library(ggvis)

runApp(list(
  ui = shinyUI(
        fluidPage(
        sidebarLayout(
          sidebarPanel( uiOutput("controls") ),
          mainPanel( uiOutput("Plot_UI" )
          )
        )
      )
  ),


server = function(input, output, session) {

dat <- reactive(iris[sample(nrow(iris),input$numbers),])

buildPlot <- function(layer = 'points'){
  if (layer=='points'){
    dat %>% 
      ggvis(~Sepal.Width, ~Sepal.Length) %>%
      layer_points() %>%
      bind_shiny("ggvis1")
  } else {
    dat %>% 
      ggvis(~Sepal.Width, ~Sepal.Length) %>%
      layer_bars() %>%
      bind_shiny("ggvis1")
  }
}

output$controls <- renderUI({
  div(
    sliderInput("numbers", label = "Number of values to plot?", min = 1, max = 150, value = 75),
    selectInput('plot_type', 'Plot Type', c("points","bars")),
    selectInput("show", 'Show plot?', c('No','Yes'))
   )
})

output$Plot_UI <- renderUI({
  if (!is.null(input$show) && input$show == 'Yes'){
    cat("Plot_UI -> Build plot\n")
    buildPlot(input$plot_type)
    div(
      uiOutput("ggvis_ui"),
      ggvisOutput("ggvis1")
    )
  }
})
  }
))

The only way to see the plot again is by selecting to not show the plot and later select show the plot again using the "Show plot" selectInput.

I don't know if this is a bug or I'm doing it incorrectly.


Solution

  • I think the problem is that your trying to render and update the div at the same time.

    library(shiny)
    library(ggvis)
    
    runApp(list(
      ui = shinyUI(
        fluidPage(
          sidebarLayout(
            sidebarPanel( uiOutput("controls") ),
            mainPanel( uiOutput("Plot_UI" )
            )
          )
        )
      ),
    
    
      server = function(input, output, session) {
    
        dat <- reactive(iris[sample(nrow(iris),input$numbers),])
    
        buildPlot <- function(layer = 'points'){
          if (layer=='points'){
            dat %>% 
              ggvis(~Sepal.Width, ~Sepal.Length) %>%
              layer_points() %>%
              bind_shiny("ggvis1")
          } else {
            dat %>% 
              ggvis(~Sepal.Width, ~Sepal.Length) %>%
              layer_bars() %>%
              bind_shiny("ggvis1")
          }
        }
    
        output$controls <- renderUI({
          div(
            sliderInput("numbers", label = "Number of values to plot?", min = 1, max = 150, value = 75),
            selectInput('plot_type', 'Plot Type', c("points","bars")),
            selectInput("show", 'Show plot?', c('No','Yes'))
          )
        })
    
        observeEvent(input$show,{
          if (!is.null(input$show) && input$show == 'Yes'){
            output$Plot_UI <- renderUI({
              cat("Plot_UI -> Build plot\n")
              div(
                uiOutput("ggvis_ui"),
                ggvisOutput("ggvis1")
              )
            })
          }
          if (!is.null(input$show) && input$show == 'No'){
            output$Plot_UI <- renderUI({ div() })
          }
        })
    
        observe({
          if (!is.null(input$show) && input$show == 'Yes'){
            invalidateLater(100,session)
            renderPlot()
          }
        })
    
        renderPlot <- function(){
          if(is.null(input$plot_type)) return(NULL)
          buildPlot(input$plot_type)
        }
      } #
    ))