Search code examples
rplotshinydistributionreactive

How to produce two plots from the same distribution based on user input in shiny?


I'm trying to produce two plots from the same distribution that is generated from data provided by the users - which is subject to change. I want the two plots to use the same distribution, but I can't figure out how to make the first distribution visible to the second renderPlot function. Clearly, I can't just reuse the code and create another distribution because it won't be the same data.

ui.R

library(shiny)

shinyUI(fluidPage(
  headerPanel(title = "Test"),
  sidebarLayout(
    sidebarPanel(
      sliderInput("input.a", "A", min = 0, max = 100, value = 50),
      sliderInput("input.b", "B", min = 0, max = 100, value = 50),
      sliderInput("input.c", "C", min = 0, max = 100, value = 50)
    ),
    
    mainPanel(
      
      tabsetPanel( type = "tabs", #Open panel
                   tabPanel("Distributions 1",plotOutput("hist1.plot"))
                   ),
      tabsetPanel( type = "tabs", #Open panel
                   tabPanel("Distributions 2",plotOutput("hist2.plot"))
      )
                
) # close mainPanel
) # close sidebarLayout
) # close fluidPage
) # close shinyUI

server.R

library(dplyr)
library(tidyr)
library(plyr)
library(ggplot2)

shinyServer(function(input,output){ # open shiny server
  
  output$hist1.plot = renderPlot({
  
     # open renderPlot
      
    a = runif(1000,1,(input$input.a))
    b = runif(1000,1,(input$input.b))
    c = runif(1000,1,(input$input.c))

    amount = c(a,b,c)

    cat = c(rep("a",1000), rep("b",1000), rep("c",1000))

    hist.data = data.frame(amount,cat)
    names(hist.data) = c("amount","cat")

    hist.data$cat = factor(hist.data$cat, levels = c("a","b","c"))
    pricedata = ddply(hist.data, c("cat"), summarize, avg = mean(amount), minus.stdev = mean(amount)-sd(amount),
                      plus.stdev = mean(amount) + sd(amount))
    pricedata = pricedata[order(pricedata$avg),]


    ggplot(hist.data, aes(x=amount, fill = cat))+
      geom_histogram(color="white", alpha = .8, position = 'identity', binwidth = 5)+
      theme_test()+
      geom_vline(aes(xintercept = avg), data = pricedata, color = "black", size = 1)+


      geom_vline(aes(xintercept = minus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+


      geom_vline(aes(xintercept = plus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+


      facet_grid(cat ~., scales = "free")+
      scale_y_continuous(expand = c(0,0),name = "Count")+
      scale_x_continuous(labels = scales::dollar, name="\nAmount", limits = c(0,100))

  }) #close renderPlot
  
    
    output$hist2.plot = renderPlot({ # open renderPlot
      
      a = runif(1000,1,(input$input.a))
      b = runif(1000,1,(input$input.b))
      c = runif(1000,1,(input$input.c))
      
      amount = c(a,b,c)
      
      cat = c(rep("a",1000), rep("b",1000), rep("c",1000))
      
      hist.data = data.frame(amount,cat)
      names(hist.data) = c("amount","cat")
      
      hist.data$cat = factor(hist.data$cat, levels = c("a","b","c"))
      pricedata = ddply(hist.data, c("cat"), summarize, avg = mean(amount), minus.stdev = mean(amount)-sd(amount),
                        plus.stdev = mean(amount) + sd(amount))
      pricedata = pricedata[order(pricedata$avg),]
      
      
      ggplot(hist.data, aes(x=amount, fill = cat))+
        geom_histogram(color="white", alpha = .8, position = 'identity', binwidth = 5)+
        theme_test()+
        geom_vline(aes(xintercept = avg), data = pricedata, color = "black", size = 1)+
        
        
        geom_vline(aes(xintercept = minus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
        
        
        geom_vline(aes(xintercept = plus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
        
        
        facet_grid(cat ~., scales = "free")+
        scale_y_continuous(expand = c(0,0),name = "Count")+
        scale_x_continuous(labels = scales::dollar, name="\nAmount", limits = c(0,100))
      
    }) #close renderPlot
 
}) # close shinyServer

enter image description here


Solution

  • Use reactiveValues() to create the distributions from the inputs, then create the distributions inside an observer. That way the same distribution is available to both plots.

    server.R

    library(dplyr)
    library(tidyr)
    library(plyr)
    library(ggplot2)
    
    shinyServer(function(input,output){ # open shiny server
      
      vals <- reactiveValues()
      
      observe({vals$a = runif(1000,1,(input$input.a))
               vals$b = runif(1000,1,(input$input.b))
               vals$c = runif(1000,1,(input$input.c))
               })
        
      
      output$hist1.plot = renderPlot({
        
        # open renderPlot
    
        amount = c(vals$a, vals$b, vals$c)
        
        cat = c(rep("a",1000), rep("b",1000), rep("c",1000))
        
        hist.data = data.frame(amount,cat)
        names(hist.data) = c("amount","cat")
        
        hist.data$cat = factor(hist.data$cat, levels = c("a","b","c"))
        pricedata = ddply(hist.data, c("cat"), summarize, avg = mean(amount), minus.stdev = mean(amount)-sd(amount),
                          plus.stdev = mean(amount) + sd(amount))
        pricedata = pricedata[order(pricedata$avg),]
        
        ggplot(hist.data, aes(x=amount, fill = cat))+
          geom_histogram(color="white", alpha = .8, position = 'identity', binwidth = 5)+
          theme_test()+
          geom_vline(aes(xintercept = avg), data = pricedata, color = "black", size = 1)+
          
          
          geom_vline(aes(xintercept = minus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
          
          
          geom_vline(aes(xintercept = plus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
          
          
          facet_grid(cat ~., scales = "free")+
          scale_y_continuous(expand = c(0,0),name = "Count")+
          scale_x_continuous(labels = scales::dollar, name="\nAmount", limits = c(0,100))
        
      }) #close renderPlot
      
      
      output$hist2.plot = renderPlot({ # open renderPlot
        
        a = runif(1000,1,(input$input.a))
        b = runif(1000,1,(input$input.b))
        c = runif(1000,1,(input$input.c))
        
        amount = c(vals$a, vals$b, vals$c)
        
        cat = c(rep("a",1000), rep("b",1000), rep("c",1000))
        
        hist.data = data.frame(amount,cat)
        names(hist.data) = c("amount","cat")
        
        hist.data$cat = factor(hist.data$cat, levels = c("a","b","c"))
        pricedata = ddply(hist.data, c("cat"), summarize, avg = mean(amount), minus.stdev = mean(amount)-sd(amount),
                          plus.stdev = mean(amount) + sd(amount))
        pricedata = pricedata[order(pricedata$avg),]
        
        
        ggplot(hist.data, aes(x=amount, fill = cat))+
          geom_histogram(color="white", alpha = .8, position = 'identity', binwidth = 5)+
          theme_test()+
          geom_vline(aes(xintercept = avg), data = pricedata, color = "black", size = 1)+
          
          
          geom_vline(aes(xintercept = minus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
          
          
          geom_vline(aes(xintercept = plus.stdev), data = pricedata, color = "black", size = .75, linetype = "dotted")+
          
          
          facet_grid(cat ~., scales = "free")+
          scale_y_continuous(expand = c(0,0),name = "Count")+
          scale_x_continuous(labels = scales::dollar, name="\nAmount", limits = c(0,100))
        
      }) #close renderPlot
      
    }) # close shinyServer
    

    enter image description here