Search code examples
javascriptrggplot2plotly

Plotly R open URL on click with facetting


I have a ggplot2 plot which I then pass on to plotly and afterwards output to html with Rmarkdown. I am trying to set up a JS function to open the underlying URL when clicking on the points. My question is very similar to this one (Add onclick open hyperlink event to an html widget created in R) but the faceting seems to change the order of the points and neither of the solutions available work.

This post (Open hyperlink on click on an ggplot/plotly chart) seems also relevant and I tried implementing the suggested solution but it was not working.

An example of the data would look like:

library(ggplot2)
library(plotly)
library(htmlwidgets)
library(htmltools)

myData <- data.frame(x=c(1,2,3, 4, 6), y=c(3,2,1, 5, 4), type = c("a", "b", "c", "a", "b"), urls=c("https://www.google.com/", "http://stackoverflow.com/", "https://www.r-project.org/", "https://www.reddit.com/", "https://www.yahoo.com/"))

ggp <- ggplot(data=myData, aes(x=x, y=y)) +
              geom_point() +
              facet_wrap(type ~ .)
ply <- plotly_build(ggp)

ply$elementId <- "PlotlyGraph"



# javascript <- HTML(paste("var myPlot = document.getElementById('PlotlyGraph');
# myPlot.on('plotly_click', function(data){
# var urls = ['", paste(myData$urls, collapse = "', '"), "'];
# window.open(urls[data.points[0].pointNumber],'_blank');
# });", sep=''))


javascript <- HTML(paste("var myPlot = document.getElementById('PlotlyGraph');
                     myPlot.on('plotly_click', function(data){
                     var urls = ", toJSON(split(myData, myData$type)), ";
                     window.open(urls[data.points[0].data.name][data.points[0].pointNumber]['urls'],'_blank')
                     });", sep=''))


ply <- prependContent(ply, onStaticRenderComplete(javascript))

ply

I think the problem is that ggplot does not put the same order as JS expects the data to be in, but I do not know how to handle this case. Any ideas?


Solution

  • One option which worked for me was to follow the example in the plotly book where you pass the urls via the customdata attribute. I also tested in a Rmarkdown file. Only issue I encountered was that in the RStudio Viewer the click event did not work for the first point (but for all other points) but works fine when opening in the browser:

    library(ggplot2)
    library(plotly)
    library(htmlwidgets)
    
    myData <- data.frame(
      x = c(1, 2, 3, 4, 6), y = c(3, 2, 1, 5, 4),
      type = c("a", "b", "c", "a", "b"),
      urls = c("https://www.google.com/", "http://stackoverflow.com/", "https://www.r-project.org/", "https://www.reddit.com/", "https://www.yahoo.com/")
    )
    
    ggp <- ggplot(data = myData, aes(x = x, y = y, customdata = urls)) +
      geom_point() +
      facet_wrap(type ~ .)
    
    ply <- ggplotly(ggp)
    
    onRender(
      ply, "
      function(el) {
        el.on('plotly_click', function(d) {
          var url = d.points[0].customdata;
          window.open(url);
        });
      }
    ")