I am trying to create an interactive PCA plot where I want to be able to hover over each point and display an image for that point. It has been done before, however, I am unable to replicate the example.
I was wondering whether anyone has been able to replicate this example successfully using R 4.3.1?
I am currently getting this error: [WARNING] Deprecated: --self-contained. use --embed-resources --standalone.
Example link: https://plotly-r.com/supplying-custom-data
x <- 1:3
y <- 1:3
logos <- c("r-logo", "penguin", "rstudio")
# base64 encoded string of each image
uris <- purrr::map_chr(
logos, ~ base64enc::dataURI(file = sprintf("images/%s.png", .x)) # i created a folder called images with 3 random photos
)
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
plot_ly(hoverinfo = "none") %>%
add_text(x = x, y = y, customdata = uris, text = logos) %>%
htmlwidgets::onRender(readLines("tooltip-image.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[10];
var y = pt.yaxis.range[6];
// 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);
});
}
\n
Plotly.d3
is undefined, one has to include d3 as a HTML dependency:
library(plotly)
d3 <- htmltools::htmlDependency(
"d3", "7.3",
src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/"),
script = "d3.min.js"
)
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];
var x = pt.xaxis.range[0];
var y = pt.yaxis.range[1];
var xPixel = pt.xaxis.l2p(x) + pt.xaxis._offset;
var yPixel = pt.yaxis.l2p(y) + pt.yaxis._offset;
var img = "<img src=\\\"" + pt.customdata + "\\\" width=100>";
tooltip.html(img)
.style("position", "absolute")
.style("left", xPixel + "px")
.style("top", yPixel + "px");
tooltip.transition()
.duration(300)
.style("opacity", 1);
});
el.on("plotly_unhover", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
});
}
'
x <- 1:3
y <- 1:3
logos <- c("img1", "img2", "img3")
# base64 encoded string of each image
uris <- purrr::map_chr(
logos, ~ base64enc::dataURI(file = sprintf("images/%s.png", .x))
)
# hoverinfo = "none" will hide the plotly.js tooltip, but the
# plotly_hover event will still fire
fig <- plot_ly(hoverinfo = "none") %>%
add_text(x = x, y = y, customdata = uris, text = logos) %>%
htmlwidgets::onRender(js)
fig$dependencies <- c(fig$dependencies, list(d3))
fig