1
votes

When plotting to barplots in a Shiny app, the dataframes generated are only available to the first but not the second plot ("Error: Object df2 not found"). Copying and pasting the code to generate the data frames into the second renderPlot part solves the issue but is redundant and slows down the app. Is there a more elegant way to make data available acorss multiple renderPlot parts? I tried to use Shinys reactive() function but without success.

Here's a minimal example:

library(shiny)
library(ggplot2)

# Define UI for application that draws a histogram
ui <- fluidPage(

  titlePanel("Utility"),

  sidebarLayout(
    sidebarPanel(
    sliderInput("var1",
                 "N",
                 min = 1,
                 max = 100,
                 value = 20)),
    mainPanel(
      plotOutput("barplot1"),
      plotOutput("barplot2"))))



# Define server logic required to draw a barplot
server <- function(input, output) {

  output$barplot1 <- renderPlot({

  df <- as.data.frame(matrix(c(
                      "A", "1", rnorm(1, input$var1, 1),
                      "A", "2", rnorm(1, input$var1, 1),
                      "B", "1", rnorm(1, input$var1, 1),
                      "B", "2", rnorm(1, input$var1, 1)),
                      nrow = 4, ncol=3, byrow = TRUE))
  df$V3 <- as.numeric(as.character(df$V3))

  df2 <- as.data.frame(matrix(c(
                       "A", "1", rnorm(1, input$var1, df[1,3]),
                       "A", "2", rnorm(1, input$var1, df[1,3]),
                       "B", "1", rnorm(1, input$var1, df[1,3]),
                       "B", "2", rnorm(1, input$var1, df[1,3])),
                       nrow = 4, ncol=3, byrow = TRUE))
  df2$V3 <- as.numeric(as.character(df$V3))

  ggplot(df, aes(x=V1, y=V3, fill=V2)) +
  geom_bar(stat="identity") 

  })

  output$barplot2 <- renderPlot({

  ggplot(df2, aes(x=V1, y=V3, fill=V2)) +
  geom_bar(stat="identity") 

  })
}

# Run the application 
shinyApp(ui = ui, server = server)
2
Putting df2 in output$barplot2 results in the following error message: "Error: object of type 'closure' is not subsettable". I guess that has something to do with the fact that df ist created dynamically? - Alo

2 Answers

0
votes

Yes, you should never duplicate your data. To make your dataframe available to all of your functions, just generate it dynamically using reactive (since it depends on input$var1). When calling a reactive variable x, you need to use x() instead of x. Otherwise, you get the error that you got: Error: object of type 'closure' is not subsettable". So in your case, making df reactive would require you to use df() instead.

server <- function(input, output) {

  df <- reactive(
    data.frame(V1 = c("A", "A", "B", "B"),
               V2 = c("1", "2", "1", "2"),
               V3 = rnorm(1, input$var1, 5)        
               )
  )

  output$barplot1 <- renderPlot({
    ggplot(df(), aes(x=V1, y=V3, fill=V2)) +
      geom_bar(stat="identity") 
  })

  output$barplot2 <- renderPlot({
    ggplot(df(), aes(x=V1, y=V3, fill=V2)) +
      geom_bar(stat="identity") 
  })
}
0
votes

this one is working create data.frame outside in their own reactive

library(shiny)
library(ggplot2)

# Define UI for application that draws a histogram
ui <- fluidPage(

  titlePanel("Utility"),

  sidebarLayout(
    sidebarPanel(
      sliderInput("var1",
                  "N",
                  min = 1,
                  max = 100,
                  value = 20)),
    mainPanel(
      plotOutput("barplot1"),
      plotOutput("barplot2")
      )
    )
  )



# Define server logic required to draw a barplot
server <- function(input, output) {


  df <- reactive({


    df <-  as.data.frame(matrix(c(
      "A", "1", rnorm(1, input$var1, 1),
      "A", "2", rnorm(1, input$var1, 1),
      "B", "1", rnorm(1, input$var1, 1),
      "B", "2", rnorm(1, input$var1, 1)),
      nrow = 4, ncol=3, byrow = TRUE))
    df$V3 <- as.numeric(as.character(df$V3))

    df

  })

  df2 <- reactive({  

  df2 <- as.data.frame(matrix(c(
    "A", "1", rnorm(1, input$var1, df()[1,3]),
    "A", "2", rnorm(1, input$var1, df()[1,3]),
    "B", "1", rnorm(1, input$var1, df()[1,3]),
    "B", "2", rnorm(1, input$var1, df()[1,3])
    ),
    nrow = 4, ncol=3, byrow = TRUE))
   df2$V3 <- as.numeric(as.character(df()$V3))

  df2
  })

  output$barplot1 <- renderPlot({


    ggplot( df() , aes(x=V1, y=V3, fill=V2)) +
      geom_bar(stat="identity")

  })

  output$barplot2 <- renderPlot({


    ggplot(df2(), aes(x=V1, y=V3, fill=V2)) +
      geom_bar(stat="identity")

  })
}

# Run the application 
shinyApp(ui = ui, server = server)