Search code examples
shinyhighchartsgrid-layoutr-highcharterprofvis

renderHighcharts vs renderUI; Which one is faster when rendering several plots


I am building an App that at some point renders 7-16 Highcharts in a grid-layout. The rendering of these Highcharts is quite slow and I am trying to make it faster.

Right now I am using renderUI(), htmlOutput() and highcharter::hw_grid() to render the graphs. ( See Code chunk 1) I have come upon this Post where they tried to improve the performance by first using highcharter::renderHighchart() to render the Graphs and then using highcharter::higchartOutput() in renderUI() function. I have changed the code a bit so that it's output is the same as in my first Version, but the Idea should have stayed the same.(see Code chunk 2)

I have now Implemented both versions in two shiny-Apps and tried to evaluate them with profvis. I am very new to profvis and i am not sure where to look exactly to compare these two options. So I have just looked at the total time RunApp() takes. My first Version using renderUI() and htmlOutput() seemst to be faster than version two. This contradicts the results of the beforementioned Post.

Now I am wondering which options is faster and why. Should I change my code from Version 1 to version 2 to improve performance?

Code Chunk 1


samp <- sample(5000, 100, replace = TRUE)
library("highcharter")
library(shiny)

ui <- shinyUI(fluidPage(
    htmlOutput('plots')
))



server <- shinyServer(function(input, output) {
    

    
    output$plots <- renderUI({
        
        output=list()
        for (i in 1:50) {
            n <- i # Make local variable
            plotname <- paste("plot", n , sep="")
            
            output[[plotname]] <- 
                highchart() %>%
                hc_chart(type = "column") %>%
                hc_title(text = "renderHighchart()") %>%
                hc_xAxis(categories = seq_along(samp)) %>%
                hc_add_series(
                    data = samp,
                    name = "Downloads"
                )
        }
        hw_grid(output,ncol=3)
    })
})

app=shinyApp(ui=ui,server=server)

profvis::profvis(runApp(app))

Code chunk 2

samp <- sample(5000, 100, replace = TRUE)
library("highcharter")
library(shiny)


ui <- shinyUI(fluidPage(
    uiOutput('plots')
))


server <- shinyServer(function(input, output) {
    
    n.col <- 3
    
    output$plots <- renderUI({
        col.width <- round(12/n.col) # Calculate bootstrap column width
        n.row <- ceiling(50/n.col) # calculate number of rows
        cnter <<- 0 # Counter variable
        
        # Create row with columns
        rows  <- lapply(1:n.row,function(row.num){
            cols  <- lapply(1:n.col, function(i) {
                cnter    <<- cnter + 1
                plotname <- paste("plot", cnter, sep="")
                column(col.width, highchartOutput(plotname))
            }) 
            fluidRow( do.call(tagList, cols) )
        })
        
        do.call(tagList, rows)
    })
    
    for (i in 1:50) {
        local({
            n <- i # Make local variable
            plotname <- paste("plot", n , sep="")
            output[[plotname]] <- renderHighchart({
                highchart() %>%
                    hc_chart(type = "column") %>%
                    hc_title(text = "renderHighchart()") %>%
                    hc_xAxis(categories = seq_along(samp)) %>%
                    hc_add_series(
                        data = samp,
                        name = "Downloads"
                    )
            })
        })
    }
})

app=shinyApp(ui=ui,server=server)

profvis::profvis(runApp(app))


Solution

  • I have now put the two options in one app

    samp <- sample(5000, 100, replace = TRUE)
    library("highcharter")
    library(shiny)
    
    
    ui <- shinyUI(
        fluidPage(
        fluidRow(uiOutput('plots')),
        fluidRow(htmlOutput('rUI')))
    )
    
    
    server <- shinyServer(function(input, output) {
        
        n.col <- 3
        
        output$plots <- renderUI({
            col.width <- round(12/n.col) # Calculate bootstrap column width
            n.row <- ceiling(50/n.col) # calculate number of rows
            cnter <<- 0 # Counter variable
            
            # Create row with columns
            rows  <- lapply(1:n.row,function(row.num){
                cols  <- lapply(1:n.col, function(i) {
                    cnter    <<- cnter + 1
                    plotname <- paste("plot", cnter, sep="")
                    column(col.width, highchartOutput(plotname))
                }) 
                fluidRow( do.call(tagList, cols) )
            })
            
            do.call(tagList, rows)
        })
        
        for (i in 1:50) {
            local({
                n <- i # Make local variable
                plotname <- paste("plot", n , sep="")
                output[[plotname]] <- renderHighchart({
                    highchart() %>%
                        hc_chart(type = "column") %>%
                        hc_title(text = "renderHighchart()") %>%
                        hc_xAxis(categories = seq_along(samp)) %>%
                        hc_add_series(
                            data = samp,
                            name = "Downloads"
                        )
                })
            })
        }
        
        output$rUI <- renderUI({
            
            output=list()
            for (i in 1:50) {
                n <- i # Make local variable
                plotname <- paste("plot", n , sep="")
                
                output[[plotname]] <- 
                    highchart() %>%
                    hc_chart(type = "column") %>%
                    hc_title(text = "renderUI") %>%
                    hc_xAxis(categories = seq_along(samp)) %>%
                    hc_add_series(
                        data = samp,
                        name = "Downloads"
                    )
            }
            hw_grid(output,ncol=3)
        })
    })
    
    app=shinyApp(ui=ui,server=server)
    
    profvis::profvis(runApp(app))
    
    

    If I now look at the aggregated time of output$plots and output$rUi in profvis, I can see that the aggregated time for output$plots is indeed faster