Search code examples
rplotlyselectize.jscrosstalk

How to add a custom javascript call to a plotly highlight/selectize menu?


I'm building an interactive Rmarkdown html document with plotly in R. It is composed by 3 elements: a main scatterplot (interactive), a secondary scatterplot, and a table.

The design looks like this:

figures outline

Each figure is built using different data. However, they all share a main key.

The main scatterplot is made with plot_ly. It uses highlight_key and highlight to, well, highlight all the points that share that key. It also has a ¿selectize? drop-down menu on top that lets them search for a specific key.

The secondary scatterplot is made with ggplotly + highlight_key. It uses crosstalk::filter_select + bscols to subset the data shown, to only those of the specific key.

The table is made with reactable. Like the secondary plot, it also uses crosstalk::filter_select (a different one, though, on a different data.frame) + bscols to subset the data shown, to only those of the specific key.

What I have right now:

When the user hovers or clicks on a point of the main scatterplot, I have added a piece of JavaScript code that takes the key of the newly selected element on the main plot, and changes the value of the two separate filter_select menus on both the secondary plot and the table.

When there is a on('plotly_click') event in figure1, capture the new key and change the value of the filter_select fields:

fig1_plotly(.....) %>%
  highlight(on = "plotly_hover", off = "plotly_doubleclick", selectize=TRUE) %>%
  onRender("function(el) { 
      el.on('plotly_click', function(d) { 
      
        console.log('Click detail: ', d.points[0].data.key);
        document.getElementById('id_filter_counts').getElementsByClassName('selectized')[0].selectize.setValue(d.points[0].data.key, false)
        document.getElementById('id_filter_table').getElementsByClassName('selectized')[0].selectize.setValue(d.points[0].data.key, false)
      });
      
      
    }
  ")  

I also added this chunk to give a default starting value to the secondary plot and the table, because their full data is too large and useless to look into. It also hides the filter_select dropdown menus from them both, so the user only interacts with the main one:

```{js}
function filter_default() {
    document.getElementById("id_filter_counts").getElementsByClassName("selectized")[0].selectize.setValue(****DEFAULT_VALUE****, false);
    document.getElementById("id_filter_table").getElementsByClassName("selectized")[0].selectize.setValue(****DEFAULT_VALUE****, false);
 
    document.getElementById("id_filter_counts").style.display="none"
    document.getElementById("id_filter_table").style.display="none"
 }
window.onload = filter_default;
```

This is 100% working as intended. When I click on a point in figure1, it automatically changes the filter field on both figure2 and the table, which updates them both.

What I want to do now and I need help with:

When the user interacts with figure 1's highlight/selectize menu, it correctly updates figure1. However, that doesn't trigger my custom on('plotly_click'), and neither the secondary plot nor the table change.

I want to add the code in my snippet to whatever triggers when the user changes figure1's menu. However, so far, I haven't been able to come up with any solution.

I have tried adding this to my JS snippet, but it isn't triggering anything.

document.getElementsByClassName('selectize-control multi')[0].parentElement.getElementsByClassName("selectized")[0].selectize.onChange = function(d){console.log('Menu change: ', d)}

I haven't toyed with JavaScript in nearly 20 years and I'm a bit lost.

How do I find and modify the event that triggers when changing the highlight/selectize menu?

Thanks


Solution

  • It seems I almost had it.

    It was .on("change", function(d){....}):

    document.getElementsByClassName('selectize-control multi')[0].parentElement.getElementsByClassName("selectized")[0].selectize.on("change",
        function(d){....})