Home > Software engineering >  In R/Shiny best alternative to htmlOutput()/renderUI()?
In R/Shiny best alternative to htmlOutput()/renderUI()?

Time:11-15

Hello This chart bellow is a part of my dashboard but its making the dashboard have a bad performance.

It takes time do update.

Is there any alternative to the functions htmlOutput() renderUI() ?

How can I improve the performance? Is it the case to create and generate the charts outside the server?

library(shiny)
    library(highcharter)
    library(tidyverse)
    
    df <-tibble(months = month.abb, value = ts(cumsum(rnorm(100)))[1:12]  )
    
    ui <- fluidPage(
      
      h1("Highcharts"),
      htmlOutput('chart_grid')
      
    )
    
    server <- function(input, output, session) {
      
      output$chart_grid<- renderUI({
        
        charts <- lapply(1:9, function(x) {
        
        highchart() %>% 
            hc_add_series(type = 'spline',data = df, hcaes(x = months,y = value))%>%
            hc_xAxis(categories = df$months)
        })
          
          hw_grid(charts, rowheight = 300,add_htmlgrid_css = TRUE)%>%
            htmltools::browsable()  
    
    })
    }
    
    shinyApp(ui, server)

CodePudding user response:

TL;DR highcharts JS boost module for many data points, static HTML for a plot if there is one or a few plot versions, own grid and highcharter::highchartOutput

Static HTML

Strategy is to create the needed plot before the shiny app is started, but we have to assume that the plot have one or a few versions as a huge collection of html's could be a wrong direction too. Usually we are using htmlwidgets::saveWidget to save any shiny widgets so we could get its html representation. As the hw_grid is not returning a shiny widgets I save it as a regular html but we have to take care of the dependencies.

Here I use the hchart (not highchart) as it persists labels on the plots.

You do not have to leave the code for html creation in the app.R file. But in my example you need still leave the dependencies list. Then you could add dependencies in the DOM head with htmltools::renderDependencies(htmltools::resolveDependencies(DEPS)). Remember that when you deploy the shiny app you have to add static files with e.g. addResourcePath https://shiny.rstudio.com/reference/shiny/1.0.2/addResourcePath.html

library(shiny)
library(highcharter)
library(tidyverse)
library(magrittr)

df <- tibble::tibble(months = month.abb, value = ts(cumsum(rnorm(100)))[1:12])

charts <- lapply(1:9, function(x) {
  hchart(df, type = "spline", hcaes(x = months, y = value)) %>%
    hc_xAxis(categories = df$months) %>%
    hc_boost(enabled = TRUE)
})

hc_test <- hw_grid(charts, rowheight = 300, add_htmlgrid_css = TRUE, browsable = TRUE)
# get HTML of the plot
# we could not use htmlwidgets::saveWidget as it is not a widget
writeLines(as.character(hc_test), "hc_test.html")
# get the dependencies of the plot
hc_deps <- htmltools::findDependencies(hc_test)

# unique dependencies in the HTML format, could be added in the head
# htmltools::renderDependencies(htmltools::resolveDependencies(hc_deps))

ui <- fluidPage(
  h1("Highcharts"),
  htmlOutput("chart_grid")
)

server <- function(input, output, session) {
  output$chart_grid <- renderUI({
    # Load HTML with proper dependencies
    htmltools::attachDependencies(
      shiny::HTML(readLines("hc_test.html")), 
      htmltools::resolveDependencies(hc_deps)
    )

  })
}

shinyApp(ui, server)

Boost module

The source highcharts JS library offers a boost module which could boost the performance. From the perspective of R it is as easy as adding hc_boost(enabled = TRUE) to your pipeline. https://www.highcharts.com/docs/advanced-chart-features/boost-module

As I understand the hc_boost could improve performance only in specific scenarios and for the cost of losing some functionality. I did not test if it truly works as expected.

library(shiny)
library(highcharter)
library(tidyverse)

df <- tibble(months = month.abb, value = ts(cumsum(rnorm(100)))[1:12])

ui <- fluidPage(
  h1("Highcharts"),
  htmlOutput("chart_grid")
)

server <- function(input, output, session) {
  output$chart_grid <- renderUI({
    charts <- lapply(1:9, function(x) {
      highchart() %>%
        hc_add_series(type = "spline", data = df, hcaes(x = months, y = value)) %>%
        hc_xAxis(categories = df$months) %>%
        hc_boost(enabled = TRUE)
    })

    hw_grid(charts, rowheight = 300, add_htmlgrid_css = TRUE, browsable = TRUE)
  })
}

shinyApp(ui, server)

Highcharts and own grid

library(shiny)
library(highcharter)
library(tidyverse)

df <- tibble(months = month.abb, value = ts(cumsum(rnorm(100)))[1:12])

ui <- fluidPage(
  h1("Highcharts"),
  shiny::tags$div(
    style = "display:flex;flex-wrap: wrap;",
    lapply(1:9, function(x) shiny::tags$div(
      style = "flex: 1 1 30%;",
      highcharter::highchartOutput(sprintf("hplot%s", x)))
    )
  )
)

server <- function(input, output, session) {
  
  charts <- lapply(1:9, function(x) {
    output[[sprintf("hplot%s", x)]] <- highcharter::renderHighchart(
      highchart(width = 600) %>%
        hc_add_series(type = "spline", data = df, hcaes(x = months, y = value)) %>%
        hc_xAxis(categories = df$months)
    )
  })
}

shinyApp(ui, server)

BTW.

My personal opinion is that the highcharter package need much work regarding the code quality and documentation, e.g. hw_grid does not even have documented the return value.

  • Related