R plotly:悬停时显示图像

R plotly: Display image on hover

我正在尝试重现 this simple plotly graph that shows images on datapoint hover. The code is available here

但是,我无法重现它。这是我目前所拥有的:

library(htmlwidgets)
library(magrittr)
library(plotly)

js <- "
function(el) {
    var tooltip = Plotly.d3.select('#' + el.id + ' .svg-container')
      .append(\"div\")
      .attr(\"class\", \"my-custom-tooltip\");
  
    el.on('plotly_hover', function(d) {
      var pt = d.points[0];
      // Choose a location (on the data scale) to place the image
      // Here I'm picking the top-left corner of the graph
      var x = pt.xaxis.range[0];
      var y = pt.yaxis.range[1];
      // Transform the data scale to the pixel scale
      var xPixel = pt.xaxis.l2p(x) + pt.xaxis._offset;
      var yPixel = pt.yaxis.l2p(y) + pt.yaxis._offset;
      // Insert the base64 encoded image
      var img = \"<img src='\" +  pt.customdata + \"' width=100>\";
      tooltip.html(img)
        .style(\"position\", \"absolute\")
        .style(\"left\", xPixel + \"px\")
        .style(\"top\", yPixel + \"px\");
      // Fade in the image
      tooltip.transition()
        .duration(300)
        .style(\"opacity\", 1);
    });
  
    el.on('plotly_unhover', function(d) {
      // Fade out the image
      tooltip.transition()
        .duration(500)
        .style(\"opacity\", 0);
    });
};
"

x <- 1:3 
y <- 1:3

artists <- c("Bethoven", "Mozart", "Bach")

image_links <- c(
  "https://upload.wikimedia.org/wikipedia/commons/6/6f/Beethoven.jpg",
  "https://upload.wikimedia.org/wikipedia/commons/4/47/Croce-Mozart-Detail.jpg",
  "https://upload.wikimedia.org/wikipedia/commons/6/6a/Johann_Sebastian_Bach.jpg"
)

# hoverinfo = "none" will hide the plotly.js tooltip, but the 
# plotly_hover event will still fire
plot_ly(hoverinfo = "none") %>%
  add_text(x = x, y = y, customdata = image_links, text = artists) %>%
  htmlwidgets::onRender(js)

悬停时没有任何反应,控制台抛出以下错误:

htmlwidgets.js:261 Uncaught SyntaxError: Unexpected token ';'
    at tryEval (htmlwidgets.js:252:32)
    at htmlwidgets.js:236:24
    at Array.forEach (<anonymous>)
    at forEach (htmlwidgets.js:55:14)
    at evalAndRun (htmlwidgets.js:230:7)
    at htmlwidgets.js:654:11
    at Array.forEach (<anonymous>)
    at forEach (htmlwidgets.js:55:14)
    at htmlwidgets.js:576:7
    at Array.forEach (<anonymous>)

我做错了什么?

此外,是否可以在悬停显示图像时显示工具提示(例如,如 text 中所定义)?

plotly.js 的 2.0 版本删除了 d3 作为捆绑依赖项,因此您现在需要单独引入它:

library(htmlwidgets)
library(magrittr)
library(plotly)

x <- 1:3 
y <- 1:3

artists <- c("Bethoven", "Mozart", "Bach")

image_links <- c(
  "https://upload.wikimedia.org/wikipedia/commons/6/6f/Beethoven.jpg",
  "https://upload.wikimedia.org/wikipedia/commons/4/47/Croce-Mozart-Detail.jpg",
  "https://upload.wikimedia.org/wikipedia/commons/6/6a/Johann_Sebastian_Bach.jpg"
)

d3 <- htmltools::htmlDependency(
  "d3", "7.3",
  src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/"),
  script = "d3.min.js"
)

# hoverinfo = "none" will hide the plotly.js tooltip, but the 
# plotly_hover event will still fire
p <- plot_ly(hoverinfo = "none") %>%
  add_text(x = x, y = y, customdata = image_links, text = artists) %>%
  htmlwidgets::onRender(readLines("hover_tooltip.js"))

p$dependencies <- c(p$dependencies, list(d3))
p

然后您需要在 JavaScript 中将 Plotly.d3 更改为 d3:

// hover_tooltip.js
function(el) {
    var tooltip = d3.select('#' + el.id + ' .svg-container')
      .append("div")
      .attr("class", "my-custom-tooltip");

    el.on('plotly_hover', function(d) {
      var pt = d.points[0];
      // Choose a location (on the data scale) to place the image
      // Here I'm picking the top-left corner of the graph
      var x = pt.xaxis.range[0];
      var y = pt.yaxis.range[1];
      // Transform the data scale to the pixel scale
      var xPixel = pt.xaxis.l2p(x) + pt.xaxis._offset;
      var yPixel = pt.yaxis.l2p(y) + pt.yaxis._offset;
      // Insert the base64 encoded image
      var img = "<img src='" +  pt.customdata + "' width=100>";
      tooltip.html(img)
        .style("position", "absolute")
        .style("left", xPixel + "px")
        .style("top", yPixel + "px");
      // Fade in the image
      tooltip.transition()
        .duration(300)
        .style("opacity", 1);
    });

    el.on('plotly_unhover', function(d) {
      // Fade out the image
      tooltip.transition()
        .duration(500)
        .style("opacity", 0);
    });
}