0

I've been fighting with a particular problem for a while now, and none of the existing (very similar) answers on Stackoverflow get me where I need to be.

I simply want to add a string variable as additional data to a tooltip in a highcharts scatter plot. What I want is similar to this question: Additional data to highcharter tooltip

I have modified the code from that question a bit to create a worked example. The problem is I cannot seem to get string variables (which are parsed as numbers if they are factors) to show up in the tooltip.

library("dplyr")
library("highcharter")

data<- data.frame(Company = c("A", "A", "A", "B", "B", "B"),
              Country = as.vector(c("A", "D", "F", "B", "B", "B")),
              Year = c(1,2,3,1,2,3),
              Value1 = c(100, 150, 170, 160, 150, 180),
              Value2 = c("hi", 1, 7, 6, 5, 4), stringsAsFactors = FALSE)


data<- data %>%
 group_by(name = Company) %>%
 do(data = .$Value1, Value2 = .$Value2, Country = .$Country)

series<- list_parse(data)


highchart()%>%
  hc_chart(type="scatter")%>%
  hc_add_series_list(series)%>%
  hc_tooltip(formatter= JS("function () { return 'Company: ' + 
  this.series.name  + ' <br /> Value1: ' + this.point.y +
                   '<br /> Country: ' + this.point.Country ;}"))

This just produces undefined as the tooltip when I try to add in 'this.point.Country'.

I have also found this: R Highcharter: tooltip customization

Which recommends to do the tooltip customization as part of the series. However, when I do this, the plot seems to fail entirely when I pass a string variable into the series. For example, this works and also allows me to pass the z variable into the tooltip:

Errors <- data.frame(Average_R = c(90,100,110,131),
                 Minimum_R = c(50, 30, 45, 65),
                 Plant_name = c("Place","holder","name","here"), 
          stringsAsFactors = F)

highchart() %>% 
  hc_plotOptions(scatter = list(
  dataLabels = list(enabled = F),
  enableMouseTracking = TRUE
       )
    ) %>% 
hc_series(
     list(type = "scatter",
          name = pollutant,
          data = Map(c,y = round(Errors$Average_R,2), z = Errors$Minimum_R))
     ) %>%
hc_tooltip(formatter = JS(paste0('function() {
                               return "<span style=\'color:" + this.point.color + "\'>\u25CF</span> " + this.series.name + " : <b>" + this.point.y + "</b> " + this.point.z + "<br/>";
    }'))) 

Result (dont have enough rep to post direct image)

enter image description here

But when I change the z variable in the data argument of hc_series to the string variable Plant_name, the entire plot fails.

Does anyone have an idea on how to fix this?

c-chavez
  • 7,237
  • 5
  • 35
  • 49
  • I have no idea of r but try to add console in the callback function like this. `"function () {console.log(this); return 'Company: ' + this.series.name + '
    Value1: ' + this.point.y + '
    Country: ' + this.point.Country ;}"` and check what its got.
    – muhammad umar farooq frank Jan 07 '19 at 12:18
  • Unfortunately that does not work. Reading the API documentation for the formatter function, leads me to believe that just using 'this.point.z' is not going to cut it: https://api.highcharts.com/highcharts/tooltip.formatter. I have found this fiddle that provides the correct output (for the client string). http://jsfiddle.net/89zyx/3/. Now only to translate this into R. – John Hekman Jan 07 '19 at 13:02

1 Answers1

1

Based on the answer here Set Additional Data to highcharts series by Nick, it is actually a matter of data representation, take a look at his fiddle here https://jsfiddle.net/burwelldesigns/jeoL5y7s/

Basically the series should be a nested list in which everything you want to use should be inside data

You might want to find a more efficient way to define your series but eventually it should be something like this :

df <- data_frame(name = c('A', 'B'))
df$data <- list(
  list(
    list(y = 100, Country = "A"), 
    list(y = 150, Country = "D"),
    list(y = 170, Country = "F")), 
  list(
    list(y = 160, Country = "B"),
    list(y = 150, Country = "B"),
    list(y = 180, Country = "B")))

series <- list_parse(df)

Then your highchart code

highchart()%>%
  hc_chart(type="scatter")%>%
  hc_add_series_list(series)%>%
  hc_tooltip(formatter= JS("function () { return 'Company: ' + 
  this.series.name  + ' <br /> Value1: ' + this.point.y +
                   '<br /> Country: ' + this.point.Country ;}"))

and here's how it looks enter image description here

Update: use can use lapply to get the nested lists you need, here's for example something that would work with your data:

Note that:

  • I used data_0 instead of data to avoid confusion

  • I changed the name of the column Value1 to y for the highchart to work

  • You can also define an x column if you want (try un-commenting the x column I added in the example)

.

data_0 <- data.frame(Company = c("A", "A", "A", "B", "B", "B"),
                     Country = as.vector(c("A", "D", "F", "B", "B", "B")),
                     Year = c(1,2,3,1,2,3),
                     y = c(100, 150, 170, 160, 150, 180),
                    # x = c(0, 1, 7, 6, 5, 4),
                     Value2 = c('hi', 1, 7, 6, 5, 4), stringsAsFactors = FALSE)

# use the unique group values as names for the lists
df <- data_frame(name = unique(data_0$Company))

# use nested lapplys to get nested lists
df$data <- lapply(df$name,                                    # for each group name
                  function(x, data_orig, cols){
                    temp_df <- data_orig[data_orig$Company==x, cols]      # get the data that belongs to this group
                    lapply(1:nrow(temp_df), 
                           function(i){
                             as.list(temp_df[i,])}               # make it a list
                           )}, 
                  data_orig = data_0, cols = c(2:5))            

series <- list_parse(df)
DS_UNI
  • 2,600
  • 2
  • 11
  • 22
  • Thanks for this, it works now! I ended up using a for loop to do the list creation, as my previous attempts using 'apply' would coerce all data types into 'character', but your lapply solution works as well. One question though, the second example I gave in my initial post contains the Highcharter structure that I use, because I want to add multiple data types in one chart (adding an errorbar to the scatter). When I try adding a series using hc_add_series and define it as an errorbar, it unfortunately does not show up. Is this due to the definition of 'scatter' in the hc_chart argument? – John Hekman Jan 08 '19 at 09:34
  • Basically, the jsfiddle you mentioned contains the structure needed to add additional chart type (https://jsfiddle.net/burwelldesigns/jeoL5y7s/), by defining the scatter chart inside the series. However, I can't get that to work with the parsed series as it is structured now, it only works when I input it under hc_add_series_list – John Hekman Jan 08 '19 at 09:55
  • Sorry for the comment overflow, I have figured this out now by transcribing the JSfiddle. It requires removing some of the levels of the list we created, but that's easy to do with some [[ .. ]] pulls, like `series[[1]][[2]]` as the data argument, to remove the first two levels. – John Hekman Jan 08 '19 at 10:17
  • No problem! glad I could help :) – DS_UNI Jan 08 '19 at 15:36