Search code examples
rr-highcharter

Highmap with overlaid pie chart series


I am looking to create a highmap with overlaid piecharts based on this JSfiddle. I have used the events = list(load = JS() construct to call the JS code, copied from the demo above. The problem I have, as shown below, is that the output contains only a single piechart, whereas it should include a piechart for each non-missing point in the series.

Additionally, I note that the pie chart renders in the centre of the map, but the tooltip and data is for the last point of the data series - here SE (Sweden, I think!). It is also significant that the pie chart always renders in the same spot, regardless of the id of the last country of data. What am I doing wrong here? I attach an image of the output below, as well as the code to replicate the map.

[Image of highmap output with single overlaid piechart](https://i.sstatic.net/VbhCc.png)

Update Thanks to Felix Jassler's comment I realised that each individual pie chart is in fact being plotted, but the problem is then that they all plotted in the same place. Enabling labels on the pie chart makes this clear to see, as shown in the updated image output below. Additionally, I have also since found this post, where a user on highcharts in vue.JS encountered the exact same problem. The solution here was the user to update to the latest version of highcharts v10.2. I have the latest version of highcharter (v9.4), and so I think that that solution would probably require some input from the developers of highcharter. I have opened an issue here on the highcharter git.

Final update The answer given below by jedrzerjuta has been accepted with much gratitude and the result can be seen below. Correct rendering of overlaid piecharts using Highcharter 10.2.0

# Required
library(tidyverse)
library(highcharter)

# Create data
data <- tibble(
  id = c(
    "PL",
    "NO",
    "DE",
    "BY",
    "FR",
    "CZ",
    "SE"
  ),
  successes = c(
    15,
    20,
    10,
    10,
    1,
    20,
    20
  ),
  failures = c(
    3,
    2,
    10,
    15,
    2,
    20,
    8
    
  )
)
data$value <- data$successes-data$failures

# Plot
hcmap("custom/world-highres",
      data = data,
      joinBy = c("iso-a2", "id"),
      keys =c('id', 'successes', 'failures', 'value')
)%>%
  hc_colorAxis(
    dataClasses=list(
      list(
        from = -15,
        to = -1,
        color = '#faa',
        name = 'Successes'
      ),
      list(
        from = 0,
        to = 0,
        color = '#ddd',
        name = 'Neutral'
      ),
      list(
        from = 1,
        to = 18,
        color = '#adf',
        name = 'Neutral'
      )
    )
  )%>%
  hc_chart(events = list(load = JS("function() {
  var chart = this;
  chart.series[0].points.forEach(country => {
  if (!country.isNull) {
    chart.addSeries({
      type: 'pie',
      name: country.id,
      zIndex: 4,
      size: 40,
      dataLabels: {
        enabled: false
      },
      onPoint: {
        id: country.id
      },
      states: {
        inactive: {
          enabled: true
        }
      },
      data: [{
        name: 'Successes',
        y: country.successes,
        color: '#adf'
      }, {
        name: 'Failures',
        y: country.failures,
        color: '#faa'
      }]
    }, false);
  }
        }
        );
  chart.redraw();
}
"
  )
  )
  )


Solution

  • The problem with the pie charts not being laid on countries coordinates is strictly linked to Highcharts v9.3.1 being used in the latest Highcharter version available on CRAN. Above code uses onPoint object property, which requires series-on-point module, that is available from Highcharts > v10 version.

    As a workaround, you can install the development version from Highcharter GitHub repository: https://github.com/jbkunst/highcharter?tab=readme-ov-file#installation and add the series-on-point module using highcharter::hc_add_dependency method. This version uses Highcharts v10.2.0, so it should work correctly.

    Below you will find updated R code:

    # Required
    library(tidyverse)
    remotes::install_github("jbkunst/highcharter")
    
    # Create data
    data <- tibble(
      idd = c(
        "PL",
        "NO",
        "DE",
        "BY",
        "FR",
        "CZ",
        "SE"
      ),
      successes = c(
        15,
        20,
        10,
        10,
        1,
        20,
        20
      ),
      failures = c(
        3,
        2,
        10,
        15,
        2,
        20,
        8
        
      )
    )
    data$value <- data$successes-data$failures
    
    # Plot
    highcharter::hcmap("custom/world-highres",
          data = data,
          joinBy = c("iso-a2", "idd"),
          keys =c('idd', 'successes', 'failures', 'value')#,
          #dataLabels = list(enabled = TRUE, format = "{point.idd}",
          #style=list(fontSize='10'))
    )%>%
      highcharter::hc_add_dependency("modules/series-on-point.js")%>%
      highcharter::hc_colorAxis(
        dataClasses=list(
          list(
            from = -15,
            to = -1,
            color = '#faa',
            name = 'Successes'
          ),
          list(
            from = 0,
            to = 0,
            color = '#ddd',
            name = 'Neutral'
          ),
          list(
            from = 1,
            to = 18,
            color = '#adf',
            name = 'Neutral'
          )
        )
      )%>%
      highcharter::hc_chart(events = list(load = highcharter::JS("function() {
      var chart = this;
      chart.series[0].points.forEach(country => {
      if (!country.isNull) {
        chart.addSeries({
          type: 'pie',
          name: country.idd,
          zIndex: 6,
          size: 40,
          dataLabels: {
            enabled: true
          },
          onPoint: {
            id: country.id
          },
          states: {
            inactive: {
              enabled: true
            }
          },
          data: [{
            name: 'Successes',
            y: country.successes,
            color: '#adf'
          }, {
            name: 'Failures',
            y: country.failures,
            color: '#faa'
          }]
        }, false);
      }
            }
            );
      chart.redraw();
    }
    "
      )
      )
      )