Shiny reactive values using lists of dataframes

Hi,

I have a shiny problem I was hoping someone could help with
Its related to using lists in reactive values.
Im quite new to Shiny so any help that you can provide would be great.

The core questions is

How can I use my list of data frames within a shiny reactiveValues to pass to my charting function called create_charts

In more detail, I have the code below which first creates a list of data frames. The data frames are from the famous iris dataset where one is artificially smaller than the other
When you run it, you should get two different charts related to the two different data-frames contained within the list called startup_data. One is a point chart and the other a bar chart. The results are created by the function create_charts which returns a chart object created by the gridExtra package

suppressMessages(library(tidyverse))
suppressMessages(library(gridExtra))
suppressMessages(library(shinydashboard))
suppressMessages(library(shiny))

# First im going to create two dataframes in a list
iris_short <- slice(iris, 1:70)

# Two Data sets are now contained in a list
startup_data <- list(iris = iris, iris_short = iris_short)

create_charts <- function(list){
  
  p <- startup_data$iris %>% 
    ggplot(aes(x=Sepal.Length, y=Sepal.Width)) + geom_point()
  
  q <- startup_data$iris_short %>% group_by(Species) %>%  summarise(num_flowers = n()) %>% 
    ggplot(aes(x=Species, y=num_flowers)) + 
    geom_bar(stat = "identity")
  
  # Create our two useful charts
  z <- grid.arrange(p, q)
  
}

# Just demonstrates the function in action
# End result should be two gray plots (upper is point plot, lower is bar graph)
create_charts(startup_data)

So I tried then to create a shinydashboard which would look at the reactive values from the startup_data and then allow me to call my chart function. Unfortunately, I cant get it to work. Can anyone see the problem. You will have to put the proceeding code into your editor as well before you can run it.

Thank you for your time

# -----------------------------------------
# Shiny Bit
# -----------------------------------------
# First Up is the UI
header <- dashboardHeader(title = "Iris Demo")
sidebar <- dashboardSidebar(disable = TRUE)

body <- dashboardBody(
  fluidRow(
  tabBox(title = "Charting Information",width = 9,
         tabPanel("Lovely Plot",
                  plotOutput(outputId = "iris_plot", height = "500px")))
  )
)

server  <- shinyServer(function(input, output, session){
  
  # Kills the session once the user exits
  session$onSessionEnded(stopApp)
  
  # First up i want to declare my reactive values which is basically the two iris dataframe lists
  values <- reactiveValues(details = startup_data)
  
  # Now we need some charts to look at it
  # Chart Produces the Running Total Chart
  output$iris_plot <- renderPlot({
    
    # basic error checking
    # if the data frame is null or the number of rows is null return NUll
    if (is.null(values$details()))
      return(NULL)
    if (nrow(values$details_uv()) == 0)
      return(NULL)
    
    # This is the problem
    mychart <- values$details() %>%
      create_charts(.)
    
    print(mychart)
    
  })

})  
  
# Pulling it all together
ui <- dashboardPage(
  skin = "blue",
  header,
  sidebar,
  body
)  


shinyApp(ui, server)

This doesn't look right to me:
values <- reactiveValues(details = startup_data)

Try:

values <- reactiveVaues()
values$details <- startup_data

However, it's not clear to me what you're trying to accomplish by assigning your data to a reactiveValue. A reactiveValue is basically a buzzer. When the value of a reactiveValue changes, any render functions, reactive expressions, or observers that use that reactiveValue will run.

However, when you put a list in a reactive value, and then change an item in the list, the whole list buzzes, which probably isn't what you want.

For example:

rv <- reactiveValues()
rv$myList <- list()
rv$myList$a <- 1
rv$myList$b <- 1

Now imagine you have one observer that uses rv$myList$a and a second one that uses rv$mylist$b. If you now do:

rv$myList$a <- rv$myList$a + 1

you expect only the first observer to run. However, both observers will run. This is a consequence of putting a list in a reactive value. Instead, just create more reactive values. Each one is list-like. You can have as many as you want.

Tom

2 Likes

Hi Tom,

Thanks very much for replying. I was probably staring at it too long
Your comments about the lists make sense, I should stick to the single variables for the reactive values other wise my app seems like it would become excessively slow

Thanks