bgbrink
bgbrink

Reputation: 663

Dynamically create plots based on number of uploaded files in Shiny

I am trying to develop a shiny app where the user can upload csv files, which are subsequently analyzed by my R script. Therefore, I would like display a dynamic number of plots, based on the number of files that are processed (one plot for each file).

I found this question extremly helpful, but I don't know the maximum number of plots in advance. Here is what I tried:

shinyServer(function(input, output) {

  # Insert the right number of plot output objects into the web page
  output$densityPlots <- renderUI({
    plot_output_list <- lapply(1:length(input$file1$datapath), function(i) {
      plotname <- paste("densityPlot", i, sep="")
      plotOutput(plotname)
    })

    # Convert the list to a tagList - this is necessary for the list of items
    # to display properly.
    do.call(tagList, plot_output_list)
  })

  # Call renderPlot for each one. Plots are only actually generated when they
  # are visible on the web page.
  for (i in 1:length(input$file1$datapath)) {
    # Need local so that each item gets its own number. Without it, the value
    # of i in the renderPlot() will be the same across all instances, because
    # of when the expression is evaluated.
    local({
      my_i <- i
      plotname <- paste("densityPlot", my_i, sep="")
      output[[plotname]] <- renderPlot({
        plot(1)
      })
    })
  }
}

However, it gives me this error:

  Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

I tried to put the for-loop inside the output function, but then no plots are created at all.

Upvotes: 3

Views: 1213

Answers (1)

bgbrink
bgbrink

Reputation: 663

I could get it to work. One has to use a reactive conductor to create the plots, as explained here

shinyServer(function(input, output) {

  createPlots <- reactive ({ 
    numberOfFiles <- length(input$files$datapath) 
    for (i in 1:numberOfFiles) {
      local({
        my_i <- i
        plotname <- paste("plot", my_i, sep="")
        File <- read.csv(input$files$datapath[my_i]) 
        output[[plotname]] <- renderPlot({
          result <- runDensity(File, f)
          plot(result$data, main=id, pch=19,cex=0.2, col= ColoursUsed[result$clusters])
        })
      })
    }
  })

  output$densityPlot <- renderUI({

    inFile <- input$files
    if (is.null(inFile))
      return(NULL)
    createPlots()
    numberOfFiles <- length(inFile$datapath) 
    plot_output_list <- lapply(1:numberOfFiles, function(i) {
      plotname <- paste("plot", i, sep="")
      plotOutput(plotname)
    })

    do.call(tagList, plot_output_list)
  })

})

Upvotes: 4

Related Questions