0

I am working on a Shiny App that takes a simple input (I1) and creates a large amount (N1 > 100) of plots (using ggplot2) from that. I want to arrange the plots in a grid. The number of rows of this grid is fixed (N2), but the number of columns (N3) will depend on the input (I1) provided by the user. I have managed to get the desired result but the computation takes much too long and I am looking for a faster way to do this.

So far I have tried the following R packages to combine plots into a single grid plot: cowplot, gridExtra, ggplot2 (facet_wrap, facet_grid), plotly. But they have all performed too slowly to be of use.

My next idea is to somehow merge all of these plots outside of R, but I am unsure how to go about this. Does anyone have any ideas how to process a large amount of plots into a structured single plot?

Here is an example version of the app and my current implementation with cowplot:

library(ggplot2)
library(gridExtra)
library(shiny)
library(shinyBS)
library(shinyWidgets)
library(cowplot)

ui =   fluidPage(
  sidebarLayout(
    sidebarPanel(
      style = "position:fixed;width:inherit;",
      textInput(inputId = "I1", label = "Input1", value = 1),
      actionBttn(inputId = "StartPlot", label = "Plot", style = "jelly",
                 color = "primary", size = "s"),
      width=2
    ),

    # Show a plot of the generated distribution
    mainPanel(
      imageOutput("mainPlot", click = clickOpts(id="plot_click")),
    )
  )
)

server = function(input, output, session) {
  plotWidth = 1350
  plotHeight = 6000
  plotQuality = 1

  randomPlots = function(n = 100) {
    l = list()
    for(i in 1:n) {
      data = data.frame(runif(n = 1000), runif(n = 1000))
      colnames(data) = c("x", "y")
      l[[i]] = ggplot(data = data, aes(x = x, y = y)) + geom_point()
    }
    l
  }

  # Create Plots and store as reactive
  plotsReactive = reactive({
    req(input$StartPlot)
    p <- randomPlots()
    p
  })

  # Arrange plots in a grid
  plotGridReactive = reactive({
    req(plotsReactive())

    plotList = plotsReactive()

    print(do.call(plot_grid, plotList))
  })

  # Render Grid Plot
  output$mainPlot <- renderImage({
    # A temp file to save the output.
    # This file will be removed later by renderImage
    outfile <- tempfile(fileext = '.png')

    # Generate the PNG
    png(outfile,
        # width = plotWidth * plotQuality,
        # height = plotHeight * plotQuality,
        width = plotWidth,
        height = plotHeight,
        res = 72*plotQuality
        )
    plotGridReactive()
    dev.off()

    # Return a list containing the filename
    list(src = outfile,
         contentType = 'image/png',
         width = plotWidth,
         height = plotHeight,
         res = 72*plotQuality,
         alt = "This is alternate text")
  }, deleteFile = TRUE)

}

shinyApp(ui, server)

Thomas
  • 1,252
  • 6
  • 24
AR Dancer
  • 1
  • 2
  • Hi AR Dancer, if you can provide some of your code, it will be much easier to help build off what you already have. See [How to make a reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) for more info. – Ian Campbell Apr 08 '20 at 13:56
  • @IanCampbell I have attached an example version – AR Dancer Apr 08 '20 at 14:28
  • If it's just a heavy loading process think about building a plumber API. The process won't affect the shiny app then as it's "outsourced". See https://github.com/rstudio/plumber – Thomas Apr 08 '20 at 15:14
  • Thank you for your comment! I have never worked with a plumber API before. I tried to read up on it and if I understand it correctly, you suggest to outsource the heavy process of creating those plots into a different R process and then return the finished plots to the App? In order for that to work the R process from the plumber API would have to be more powerful, in order to render those plots more quickly, no? – AR Dancer Apr 14 '20 at 07:24

0 Answers0