3

I would like to hover over the x-axis of p1 and for this hover to be shared on the x-axis of p2.

library(plotly)

p1 <- plot_ly(economics, x = ~date, y = ~unemploy) %>%
  add_lines(name = ~"unemploy")

p2 <- plot_ly(economics, x = ~date, y = ~uempmed) %>%
  add_lines(name = ~"uempmed")

p <- subplot(p1, p2)

p

For example, if I hover over June 1992 on p1, the hover should also occur on June 1992 on p2.

Is there a way to do this? It would be something like, but with the graphics side by side.

Kat
  • 15,669
  • 3
  • 18
  • 51
neves
  • 796
  • 2
  • 10
  • 36
  • According to this [issue](https://github.com/plotly/plotly.js/issues/2114#issuecomment-535259328), it is at the moment not possible in python and R. Maybe there is a good javascript solution. – Quinten Oct 29 '22 at 15:52
  • 1
    It looks like it's not too difficult to implement using the `highcharter` library. If you're interested in using that library, let me know. I can add answer that shows you how you can create it. – Kat Nov 06 '22 at 21:58
  • Hello, @Cat. Could you post an answer with `highcharter` please? Greetings from Brazil. – neves Nov 23 '22 at 23:09

1 Answers1

4

Based on your comment, Highcharts will work as an alternative to Plotly.

Here is a solution to creating two charts side by side with synchronized tooltips regardless of whether you hover on the left or right chart.

enter image description here

Hey you; greetings from the States! BTW, if you don't spell the tag name (Kat) correctly, SO won't notify me. I just happened to come across your question again.

I ended up having some failsafe code added that will likely only really work if you only have two plots side by side. There is so much data in economics, that many times the two tips would be off by up to a year. The extra code just makes sure that they match.

Since I'm sure that using economics isn't your end goal, let me know if whatever configuration you're using doesn't work with this code.

I've added a lot of comments to the Javascript coding quoted in tags$script. I hope that this information is enough for you to understand what's happening.

There are two different plotting methods in Highcharts for R.

  • If you're familiar with Python's Plotly, there are two versions: express and go. That's kind of what happens in R's Highcharts. (hchart() is more like express; highchart() is more like go)
  • If you're not familiar with Python's Plotly, then it's good to know that plots either start with hchart() or highchart(). They don't work quite the same way.

If you want to learn more about Highcharts for R, read more about it here.

This answer uses economics (as you did in your question), which comes from the library ggplot2. The other libraries used in this answer are highcharter and htmltools. The graphs are set exactly as your question established for Plotly, only they're rendered in Highcharter.

library(highcharter)
library(htmltools)

data(economics, package = 'ggplot2')

(hc1 <- highchart(elementId = "myChart") %>%
    hc_xAxis(categories = economics$date, type = "datetime") %>% 
    hc_add_series(name = "Unemployed", data = economics$unemploy) %>% 
    hc_tooltip(useHTML = T))

(hc2 <- highchart(elementId = "myChart2") %>% 
    hc_xAxis(categories = economics$date, type = "datetime") %>% 
    hc_add_series(name = "Unemployment Duration",
                  data = economics$uempmed) %>% 
    hc_tooltip(useHTML = T))

This next chunk of code aligns these two plots laterally and establishes the synchronized tooltip.

browsable(tagList(
  tags$script(HTML("
  setTimeout(function() {                               /* using id from div */
    $('#hc_container').bind('mousemove touchmove touchstart', function(e) {
      var chart, point, i, event;
      for (i = 0; i < Highcharts.charts.length; i++) {      /* loop through both charts */
          chart = Highcharts.charts[i];                     /* identify the chart */
          event = chart.pointer.normalize(e.originalEvent); /* find chart coordinates */
                             /* evaluate for synchronization, to address lateral charts */
          event.chartX = (event.chartX + $('[id$=Chart]').width()) % $('[id$=Chart]').width();
          point = chart.series[0].searchPoint(event, true); /* get closest point */
          if (point) {                                      /* if point found, tip it */
              point.highlight(e);                           /* trigger tooltip */
          }
      }  /* this code is to ensure the tooltips match */
      var gr = $('div.highcharts-label.highcharts-tooltip');/* collect visible tooltips */
      var gr0 = gr[0].firstChild.firstChild.textContent;    /* collect 1st x-axis tooltip text */
      var gr1 = gr[1].firstChild.firstChild.textContent;    /* collect 2nd x-axis tooltip text */
      if(gr0 !== gr1) {            /* the tips don't match due to data point proximity, fix it */
        var p = Highcharts.charts[1].series[0].points;      /* find all points in chart 1 */
        point = p.find(o => o.category === gr0);            /* get point matching chart 0 tip */
        if(point) {                                         /* if point found, tip it */
          point.highlight(e);                               /* trigger tooltip */
        }
      }
    });
  }, 500);
  Highcharts.Pointer.prototype.reset = function() {        /* reset tooltip */
    return null;
  };
  Highcharts.Point.prototype.highlight = function(event) { /* executes tooltip from trigger */
    event = this.series.chart.pointer.normalize(event);    /* capture that event occurred */
    this.onMouseOver();                                    /* show marker */
    this.series.chart.tooltip.refresh(this);               /* show tooltip */
    this.series.chart.xAxis[0].drawCrosshair(event, this); /* show crosshair */
  };
")),
div(id = "hc_container",     # this id is used in the JQuery/Javascript above
    div(hc1, style = 'height:100%; width: 50%; float:left;'), # first plot
    div(hc2, style = 'height:100%; width: 50%; float:left;'), # second plot
    style = "height:100%; width:100%; float:left;"))) # container styles

enter image description here

Kat
  • 15,669
  • 3
  • 18
  • 51