jbkunst / highcharter

R wrapper for highcharts
http://jkunst.com/highcharter/
Other
717 stars 147 forks source link

Highcharter/HighchartsJS boost module performance #773

Closed MichaelHogers closed 3 months ago

MichaelHogers commented 1 year ago

Hi there,

Here is an interesting test case using an example from the Highcharts website regarding the boost option and a large number of datapoints (500/1.000k +),

Below an example Shiny application that does two things:

  1. Loads a vanilla JS Highcharts chart that renders 1 million points in less than a second using the boost module
  2. Loads a Shiny highcharter chart

Using this application it should be possible to replicate the following: the first vanilla JS chart loads in < 1s, but once the second Shiny based chart has loaded the vanilla JS chart takes a much longer time.

Moreover, recreating the vanilla JS chart entirely in R Shiny using the highcharter package and hc_boost(enabled = TRUE) also results in very slow behaviour. Could it be that the boost module does not function as expected when using the highcharter library?

I would be very interested in knowing how to improve performance when using highcharter. The example below uses the latest versions of shiny, shinyjs, dplyr, highcharter and ggplot2, I cannot provide more details at this moment but may be able to do so later.

Best regards, Michael

image
library(shiny)
library(dplyr)
library(shinyjs)
data(diamonds, package = "ggplot2")

ui <- fluidPage(
  shinyjs::useShinyjs(),
  HTML('
      <script src="https://code.highcharts.com/highcharts.js"></script>
      <script src="https://code.highcharts.com/modules/boost.js"></script>
      <script src="https://code.highcharts.com/modules/exporting.js"></script>
  '),

  actionButton(inputId = 'updateHighchart',
               label = 'Update chart'),

  tags$div(
    id = 'highchart_manualjs_container'
  ),

  actionButton(inputId = 'loadHighchartLibrary',
               label = 'Load highcharter chart (first chart will slow down)'),
  highcharter::highchartOutput(
    outputId = 'shinyhighchart'
  )

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

  # updates a highchart with json 
  observeEvent(input$updateHighchart,{
    shinyjs::runjs(HTML("
     function getData(n) {
      var arr = [],
        i,
        a,
        b,
        c,
        spike;
      for (i = 0; i < n; i = i + 1) {
        if (i % 100 === 0) {
          a = 2 * Math.random();
        }
        if (i % 1000 === 0) {
          b = 2 * Math.random();
        }
        if (i % 10000 === 0) {
          c = 2 * Math.random();
        }
        if (i % 50000 === 0) {
          spike = 10;
        } else {
          spike = 0;
        }
        arr.push([
          i,
          2 * Math.sin(i / 100) + a + b + c + spike + Math.random()
        ]);
      }
      return arr;
    }
    var data = getData(1000000);

    console.time('area');
    Highcharts.chart('highchart_manualjs_container', {

      chart: {
        type: 'area',
        zoomType: 'x',
        panning: true,
        panKey: 'shift'
      },

      boost: {
        useGPUTranslations: true
      },

      title: {
        text: 'Highcharts drawing ' + data.length + ' points'
      },

      subtitle: {
        text: 'Using the Boost module'
      },

      tooltip: {
        valueDecimals: 2
      },

      series: [{
        data: data
      }]

    });
    console.timeEnd('area');                   
    "))
  })

  # Load the chart only after a button click, 
  # suddenly the vanilla JS solution becomes extremely slow
  observeEvent(input$loadHighchartLibrary,{
    library(highcharter)
    output$shinyhighchart <- renderHighchart({
      hchart(density(diamonds$x), type = 'column')
    })
  })
}
shinyApp(ui, server)
gaspare-mattarella commented 1 year ago

Up

stale[bot] commented 9 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. Feel free to reopen it if you find it necessary.