Mr K
Mr K

Reputation: 446

updating plot output in shiny r

For a Shiny app that I am working on, given a data file, I need to display a barplot (for which I am using ggplot2) on the starting page of the app. So when the user runs the app, and uploads a file, they would immediately get to see the barplot in main panel.

After the app has started, the user should be able to click an actionButton to bootstrap the data and add error bars to the same barplot. I don't want to add the error bars to start with, because my users might not be interested in the error bars and adding error bars with bootstrapping would keep them waiting. So, I must add the error bars only if they want to see it and are willing to wait for bootstrapping to be over.

I tried many ways to update the plot but haven't been successful. I could of course render another plot with the error bars but it is not what I would like to do ideally. Is there a way to update plots or add features to them?

Upvotes: 3

Views: 11878

Answers (2)

user2359902
user2359902

Reputation: 121

I tried doing this in shiny using Plotly but without layers as shown above. Although this may be an old thread, it may be helpful for others.

In the following example:

  • first a plot is shown based on one person's scores.
  • then as we select input from the list other scores of other persons are updated on the same plot.
library(shiny)
library(plotly)

ui <- fluidPage(
  selectizeInput(
    inputId = "Player",
    selected = NULL,
    multiple = TRUE,
    label = " Choose Player",
    choices = c("Sam", "Bennet", "Orlando"),
    options = list('plugins' = list('remove_button'))
  ),
  plotlyOutput("Plot1")
)

server <- function(input, output, session) {
  output$Plot1 <-  renderPlotly({
    
    scores <- data.frame(Name = c("Sam", "Bennet", "Orlando", "Sam", "Bennet", "Orlando", "Sam", "Bennet", "Orlando" ), 
                        Number= c(47, 35, 40, 49, 32, 31, 51, 49, 44 ),
                        Year = c("2018","2018","2018", "2017", "2017", "2017", "2016","2016","2016")
    )  
    
    chris_goals <- data.frame(Name = c("Chris", "Chris", "Chris"), 
                        Number= c(90, 95, 100 ),
                        Year = c("2018","2017","2016")
    ) 
    
    filteredScores <- reactive({
      
      plot_ly(chris_goals, x = ~Year, y = ~Number, type = 'scatter', mode = 'lines', color = ~Name)%>% layout(showlegend = TRUE) %>%
        layout(title = 'Scores') %>%
        add_trace(data =  scores[scores$Name %in% input$Player, ], x = ~Year, y = ~Number, type = 'scatter', mode = 'lines', color = ~Name)
    })
    
    filteredScores()
  })
}
shinyApp(ui, server)

Default: enter image description here

enter image description here

Upvotes: 0

RmIu
RmIu

Reputation: 4467

I think that you always will have to go through renderPlot in order to update the plot output (unless you save the plot as a image, and load it on-top of your plot within an invisible div or something like this). What you could do is save the layers of your plot separately splitting it into 2 part, one with the bar plot and one with the error bar and then just layer the error bars on top if need be.

data(iris)
require(shiny)

sepal.length <- sapply(unique(iris$Species),function(s){ iris[which(iris$Species==s),"Sepal.Length"] })
data         <- data.frame("mean"=apply(sepal.length,2,mean),"sd"=apply(sepal.length,2,sd),"species"=unique(iris$Species))

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

  # Save plot in reactive
  plot.dat <- reactiveValues(main=NULL, layer1=NULL)
  plot.dat$main <- ggplot(data=data,aes(x=species,y=mean,fill=species)) + 
    geom_bar(stat="identity") 

  observe({
    print("render")
    output$plot <- renderPlot({ plot.dat$main + plot.dat$layer1 })
  })

  observeEvent(input$add_bars,{
    # Calculate standard deviation
    plot.dat$layer1 <- geom_errorbar(aes(ymin=mean-sd,ymax=mean+sd))
  })
})

ui <- shinyUI(fluidPage(
  plotOutput("plot"),
  actionButton("add_bars","Add error bars")
))

shinyApp(ui = ui, server = server)  

Upvotes: 2

Related Questions