Make object created inside one reactive object ava

2019-02-23 12:41发布

问题:

This question already has an answer here:

  • Set global object in Shiny 1 answer

I have a shiny app in which I define an object based on sliders and create a data.frame from it. This gets used to create a plot, below which I'd like to include a summary table. My issue is that the plot must be defined inside of a reactive object to update based on the sliders, but I found that when I tried to access the object to print a summary inside of a different reactive object, it wasn't found.

I'd like to not run through the same calculation code twice just to get the object into the other reactive object. My two initial ideas:

  • I tried using save(object, file = "...") inside the first reactive object and then putting load(file = "...") inside the second, but it doesn't update.
  • I thought of defining my object outside of my reactive plotOutput definition, but I'm pretty sure it won't update when user inputs are changed; it will just stay with the value of the initial input object default settings.

Well, just went ahead and tried the latter idea, and it doesn't even get that far:

  • I put it before shinyServer(...) and it can't generate the data because my call depends on input and it doesn't know about input at that point.
  • I put it after shinyServer(...) but before renderPlot(...) to try and make sort of a "globally available" object for all output objects, and it scolding me for trying to do something that uses input outside of a reactive function.

Here's an example to illustrate, modified from Shiny's "Hello Shiny!" example:

ui.R

library(shiny)

# Define UI for application that plots random distributions 
shinyUI(pageWithSidebar(

  # Application title
  headerPanel("Hello Shiny!"),

  # Sidebar with a slider input for number of observations
  sidebarPanel(
    sliderInput("obs", 
                "Number of observations:", 
                min = 1,
                max = 1000, 
                value = 500)
  ),

  # Show a plot of the generated distribution
  mainPanel(
    plotOutput("distPlot"),
    tableOutput("summary")
  )
))

server.R

library(shiny)

# Define server logic required to generate and plot a random distribution
shinyServer(function(input, output) {

  output$distPlot <- renderPlot({

    # generate an rnorm distribution and plot it
    dist <- rnorm(input$obs)
    hist(dist)
  })

  output$summary <- renderTable({
    #dist <- rnorm(input$obs)
    summary <- table(data.frame(cut(dist, 10)))
  })
})

If you run it as is, cut will throw and error because it doesn't know about dist. If you uncomment the line where we re-define dist as is done in plotOutput, then it will work.

This is simple code -- mine is quite a bit more involved and I'd really prefer not to run it twice just to make the same result known to another reactive output.

Suggestions?

回答1:

Just to flesh out the example above based on the answer in the other question I consider mine to have duplicated, the code would look like this:

library(shiny)

# Define server logic required to generate and plot a random distribution
shinyServer(function(input, output) {

  dist <- reactive(rnorm(input$obs))

  output$distPlot <- renderPlot({

    # generate an rnorm distribution and plot it
    dist <- dist()
    hist(dist)
  })

  output$summary <- renderTable({
    dist <- dist()
    summary <- table(data.frame(cut(dist, 10)))
  })
})