rshinyr-highcharter

Inconsistent colors between legend and lines in Highcharter line chart


I'm creating a shiny dashboard with a line chart using the Highcharter package in R to visualize export data over time for various countries. My goal is to have a unique color for each country, which remains consistent across both the chart lines and the legend. However, I'm running into a couple of issues.

Inconsistent Colors: The colors in the legend are assigned alphabetically, while the colors on the chart lines follow the order of selection, leading to mismatches. Attempted Solution with hc_colors: I tried using hc_colors() to set colors manually, but the chart lines and legend still don't align correctly.

Code:

Here's the code I'm using to generate the chart. The dataset is a simplified example, but it illustrates the same issue.

# Amostra de Dados
g_553 <- tribble(
  ~Ano, ~Nome_Pais, ~US_FOB, ~Peso_Liquido, ~Mean_Price,
  "2011", "Alemanha", 0.00904, 16916796, 5.34e-10,
  "2011", "Argentina", 0.0227, 15635607, 1.45e-9,
  "2011", "Estados Unidos", 0.0258, 25018307, 1.03e-9,
  "2011", "Países Baixos", 0.0124, 28620025, 4.34e-10,
  "2012", "Alemanha", 0.00727, 13638592, 5.33e-10,
  "2012", "Argentina", 0.0180, 12255622, 1.47e-9,
  "2012", "Estados Unidos", 0.0266, 27089444, 9.83e-10,
  "2012", "Países Baixos", 0.0134, 27368500, 4.89e-10,
  "2013", "Alemanha", 0.00655, 14129010, 4.64e-10,
  "2013", "Argentina", 0.0196, 13934551, 1.41e-9,
  "2013", "Estados Unidos", 0.0224, 23668917, 9.45e-10,
  "2013", "Países Baixos", 0.0133, 32895660, 4.06e-10,
  "2014", "Alemanha", 0.00663, 13030649, 5.09e-10,
  "2014", "Argentina", 0.0143, 15450241, 9.24e-10,
  "2014", "Estados Unidos", 0.0270, 28510546, 9.47e-10,
  "2014", "Países Baixos", 0.0110, 26537257, 4.14e-10,
  "2015", "Alemanha", 0.00518, 9105968, 5.68e-10,
  "2015", "Argentina", 0.0128, 11874210, 1.08e-9,
  "2015", "Estados Unidos", 0.0240, 29218576, 8.22e-10,
  "2015", "Países Baixos", 0.00782, 31780201, 2.46e-10,
  "2016", "Alemanha", 0.00486, 6895825, 7.05e-10,
  "2016", "Argentina", 0.0134, 10772268, 1.25e-9,
  "2016", "Estados Unidos", 0.0231, 26001840, 8.90e-10,
  "2016", "Países Baixos", 0.00695, 32095643, 2.17e-10,
  "2017", "Alemanha", 0.00491, 6863967, 7.15e-10,
  "2017", "Argentina", 0.0176, 11711823, 1.50e-9,
  "2017", "Estados Unidos", 0.0269, 31227817, 8.60e-10,
  "2017", "Países Baixos", 0.00742, 28361090, 2.62e-10,
  "2018", "Alemanha", 0.00520, 6426912, 8.10e-10,
  "2018", "Argentina", 0.0149, 11492885, 1.30e-9,
  "2018", "Estados Unidos", 0.0287, 30565639, 9.38e-10,
  "2018", "Países Baixos", 0.00823, 26976811, 3.05e-10,
  "2019", "Alemanha", 0.00473, 5415819, 8.73e-10,
  "2019", "Argentina", 0.00979, 7428020, 1.32e-9,
  "2019", "Estados Unidos", 0.0297, 35390842, 8.39e-10,
  "2019", "Países Baixos", 0.00716, 22950298, 3.12e-10,
  "2020", "Alemanha", 0.00412, 4842317, 8.51e-10,
  "2020", "Argentina", 0.00849, 6305341, 1.35e-9,
  "2020", "Estados Unidos", 0.0215, 27669631, 7.75e-10,
  "2020", "Países Baixos", 0.00670, 20548583, 3.26e-10
)

global.R

generate_country_analytics <- function(data, measure, country_filter) {
  measure_column <- ifelse(measure == "value", "US_FOB", "Peso_Liquido")
  
  # Filtrar e agrupar os dados
  country_data <- data %>%
    filter(Nome_Pais %in% country_filter) %>%
    group_by(Ano, Nome_Pais) %>%
    summarise(Measure = sum(!!as.symbol(measure_column), na.rm = TRUE), .groups = 'drop') %>%
    ungroup() %>%
    complete(Ano, Nome_Pais, fill = list(Measure = NA)) %>%
    arrange(match(Nome_Pais, country_filter))
  
  # Definir cores
  colors <- RColorBrewer::brewer.pal(length(country_filter), "Dark2")[seq_along(country_filter)]
   
  # Definir título e tooltip
  title_measure <- ifelse(measure == "value", "Valor Exportado (US$)", "Peso Exportado (Toneladas)")
  title_title <- paste0("Exportações por Ano e País - ", title_measure)
  tooltip_text <- paste(
    "<b>{point.Nome_Pais}</b><br>",
    ifelse(
      measure == "value",
      "<b> Valor Exportado</b>: US$ {point.y:,.2f} mi",
      "<b> Peso Exportado</b>: {point.y:,.2f} toneladas"
    )
  )

  # Gráfico com Highcharts
  highchart() %>%
    hc_chart(zoomType = "x", backgroundColor = "#fff") %>%
    hc_title(text = title_title) %>%
    hc_xAxis(
      title = list(text = "Ano"),
      categories = unique(country_data$Ano),
      gridLineColor = NULL,
      lineColor = "#999999",
      tickColor = "#999999"
    ) %>%
    hc_yAxis(
      title = list(text = title_measure),
      gridLineColor = NULL,
      lineColor = "#999999",
      tickColor = "#999999"
    ) %>%
    hc_add_series(
      data = country_data,
      type = "spline",
      hcaes(x = Ano, y = Measure, group = Nome_Pais),
      marker = list(enable = TRUE, symbol = "circle", radius = 3),
      name = country_filter
    ) %>%
    hc_colors(colors) %>%
    hc_tooltip(useHTML = TRUE, pointFormat = tooltip_text) %>%
    hc_legend(enabled = TRUE, align = 'center', layout = 'horizontal') %>%
    hc_add_theme(hc_theme_smpl()) %>%
    hc_exporting(enabled = TRUE)
}

server.R

 filtered_data_country_analytics <- reactive({
    req(input$value_country_analytics, input$country_country_analytics)
    
    data_filtered <- g_553  
    
    if (!is.null(input$country_country_analytics)) {
      data_filtered <- data_filtered %>%
        filter(Nome_Pais %in% input$country_country_analytics)
    }
    
    return(data_filtered)
  })
  
  # renderização do gráfico
  output$country_analytics <- renderHighchart({
    data_filtered <- filtered_data_country_analytics()  
    
    generate_country_analytics(
      data_filtered,
      input$value_country_analytics,
      input$country_country_analytics
    )
  })
  
  
  # select the country
  observe({
    unique_countries <- unique(g_553$Nome_Pais)
    
    updateSelectInput(
      session,
      inputId = "country_country_analytics",
      choices = unique_countries,
      selected = NULL
    )
  })

enter image description here


Solution

  • One option to fix your issue would be to convert Name_Pais to a factor with the levels set according to country_filter. Also, in that case you can drop the name= parameter in hc_add_series. The latter was the reason for the inconsistency as you did not account for the order of the series.

    library(highcharter)
    library(tidyverse)
    
    generate_country_analytics <- function(data, measure, country_filter) {
      measure_column <- ifelse(measure == "value", "US_FOB", "Peso_Liquido")
    
      # Filtrar e agrupar os dados
      country_data <- data %>%
        filter(Nome_Pais %in% country_filter) %>%
        group_by(Ano, Nome_Pais) %>%
        summarise(Measure = sum(.data[[measure_column]], na.rm = TRUE), .groups = "drop") %>%
        ungroup() %>%
        complete(Ano, Nome_Pais, fill = list(Measure = NA)) %>%
        mutate(Nome_Pais = factor(Nome_Pais, country_filter))
    
      # Definir cores
      colors <- RColorBrewer::brewer.pal(
        length(country_filter), "Dark2"
      )
    
      # Definir título e tooltip
      title_measure <- ifelse(measure == "value", "Valor Exportado (US$)", "Peso Exportado (Toneladas)")
      title_title <- paste0("Exportações por Ano e País - ", title_measure)
      tooltip_text <- paste(
        "<b>{point.Nome_Pais}</b><br>",
        ifelse(
          measure == "value",
          "<b> Valor Exportado</b>: US$ {point.y:,.2f} mi",
          "<b> Peso Exportado</b>: {point.y:,.2f} toneladas"
        )
      )
    
      # Gráfico com Highcharts
      highchart() %>%
        hc_chart(zoomType = "x", backgroundColor = "#fff") %>%
        hc_title(text = title_title) %>%
        hc_xAxis(
          title = list(text = "Ano"),
          categories = unique(country_data$Ano),
          gridLineColor = NULL,
          lineColor = "#999999",
          tickColor = "#999999"
        ) %>%
        hc_yAxis(
          title = list(text = title_measure),
          gridLineColor = NULL,
          lineColor = "#999999",
          tickColor = "#999999"
        ) %>%
        hc_add_series(
          data = country_data,
          type = "spline",
          hcaes(x = Ano, y = Measure, group = Nome_Pais),
          marker = list(enable = TRUE, symbol = "circle", radius = 3)
        ) %>%
        hc_colors(colors) %>%
        hc_tooltip(useHTML = TRUE, pointFormat = tooltip_text) %>%
        hc_legend(enabled = TRUE, align = "center", layout = "horizontal") %>%
        hc_add_theme(hc_theme_smpl()) %>%
        hc_exporting(enabled = TRUE)
    }
    
    generate_country_analytics(
      g_553,
      "value",
      c("Alemanha", "Estados Unidos", "Argentina")
    )