purple1437
purple1437

Reputation: 313

How to assign global variables that can be accessed by other output$function in R shiny?

So I'm creating an R shiny app where I need to upload a few files and operate on them to output some (let's say 3) plots. So in every renderPlot() function in server I need to repeat the operations for it to work (code is chunky now). I was wondering if there's any way to assign the ingested file and operations to a global variable and access it in every renderplot() function? Is there a way to actually access it outside the server() at all (I've been told no)?

In other threads, I was told to use reactive() or reactiveValues() but to no avail. Below is the sample code:

sample2 <- as.data.frame(matrix(rnorm(10*100, 1, .5), ncol=10))
write.csv(sample, "sample.csv") #Creating sample csv to be ingested in R shiny

ui <- fluidPage(
  headerPanel("Webpapp"),
  sidebarPanel(
    
    fileInput(inputId = "filedata", #Upload sample.csv here
              label = "Upload the Raw Data File",
              accept = c("text/csv", "text/comma-separated-values,text/plain",
                         ".csv")),
    
    selectInput("title", "Select title:", choices = list("hi", "hello"), selected = "Hi"),
  ),
  mainPanel(plotOutput('plot')),
  mainPanel(plotOutput('normalized_plot')),
  mainPanel(plotOutput('advanced_normalized_plot'))
)

server <- function(session, input, output) { #original code I have needs session
  
  data <- reactive({
    req(input$filedata)
    read.csv(input$filedata$datapath, header = T)
  })
  
  normalized <- reactive({ 
#I want to assign these objects as a global variable which can be use by other output functions
    df <- data()
    normalizd_df <- df + 1.5
    colnames(normalizd_df) <- paste(input$title,rep(1:10)) #I do need to use input in this reactive function
    advanced_normalized <- normalized_df * 15.454
  })
  
  output$plot <- renderPlot({
    #This works but I do not want to do this every output function
    sample_d <- data()
    plot(density(sample_d[,1]), main = input$title) 
  })
  
  output$normalized_plot <- renderPlot({ #Does not work
    plot(density(normalized$normalizd_df[,1]), main = input$title) 
  })
  
  output$advanced_normalized_plot <- renderPlot({
    sample_a <- advanced_normalized - normalized_df  #This doesn't work
    plot(density(normalized$advanced_normalized[,1]), main = input$title) 
  })
  
}

shinyApp(ui = ui, server = server)
  

Upvotes: 0

Views: 1264

Answers (1)

Kent Orr
Kent Orr

Reputation: 504

If you really want to assign something to global, you can use the <<- operator. Or assign("x", value = data, envir = .GlobalEnv).

But, you really don't want to. It's almost never, ever a good idea. Especially since you need to make use of reactive inputs.

If sample_d <- data() is too many keystrokes, just ignore assigning within the local environment (the output object) and use data().

output$plot <- renderPlot({
    plot(density(data()[,1]), main = input$title) 
  })

If you want an object with multiple values, a list of objects, make your reactive object into a list and reference with $

Be sure to note however, your reactive object is a function call. So if the reactive object is data and we want the list item normalized_df we would call the reactive object data() with () and then index into the list that function returns with $. So all together we would have data()$normalized_df.

  data <- reactive({
    req(input$filedata)
    d <- read.csv(input$filedata$datapath, header = T)
    list(data = d,
         normalized_df = d + 1.5,
         advanced_normalized = df + 1.5 * 45.454)
  })

  output$normalized_plot <- renderPlot({ #Does not work
    plot(density(data()$normalizd_df[,1]), main = input$title) 
  })
  
  output$advanced_normalized_plot <- renderPlot({
    plot(density(data()$advanced_normalized[,1]), main = input$title) 
  })

Below is a minimal example that shows this in action:

library(shiny)

ui <- fluidPage(
    titlePanel("Old Faithful Geyser Data"),
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 10,
                        value = 2)
        ),
        mainPanel(
            column(6, verbatimTextOutput("console1")),
            column(6, verbatimTextOutput("console2"))
        )
    )
)

server <- function(input, output) {
    
    data1 <- reactive({
        datum <- mtcars
        d1 <- mtcars[1:input$bins]
        d2 <- d1 + 1
        d3 <- d1 * 1.5
        list(d1, d2, d3)
    })
    
    data2 <- reactive({
        datum <- mtcars
        list(d1 = mtcars[1:input$bins],
             d2 = mtcars[1:input$bins] + 1,
             d3 = mtcars[1:input$bins] * 1.5)
    })
    
    output$console1 <- renderPrint({
        data1()
    })
    
    output$console2 <- renderPrint({
        data2()
    })
}

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

Upvotes: 1

Related Questions