I'm working with Plotly in R and I want to display a small data frame or table in the hover text of my plot.
I tried using HTML-like tags within the hovertemplate, but it seems that Plotly doesn't interpret these tags as expected. Here's a simple example of what I would like to do :
data <- data.frame(
Category = c("A", "B", "C"),
Value1 = c(10, 20, 30),
Value2 = c(40, 50, 60)
)
fig <- plot_ly(data, x = ~Category, y = ~Value1, type = 'bar')
fig <- fig %>% layout(
hovermode = 'closest',
hoverlabel = list(
bgcolor = "white",
font = list(size = 12)
)
) %>%
add_trace(
hovertemplate = paste(
"<b>Category:</b> %{x}<br>",
"<table>",
"<tr><td>Value1:</td><td>%{y}</td></tr>",
"<tr><td>Value2:</td><td>", data$Value2, "</td></tr>",
"</table>",
"<extra></extra>"
)
)
fig
Pltoly does not allow all HTML elements in the hovertemplate (only br). I can show you two ways to still show tables as hover info. The first one is really easy:
Since your HTML table is so simplistic, you could fake it by using <b>
+ </b>
+ spacing
custom_hover <- paste0(
"<b>Category:</b> ", data$Category, "<br>",
"<b>Value1:</b> ", data$Value1, "<br>",
"<b>Value2:</b> ", data$Value2
)
plot_ly(data, x = ~Category, y = ~Value1, type = 'bar',
hoverinfo = 'text',
hovertext = custom_hover) %>%
layout(
hovermode = 'closest',
hoverlabel = list(
bgcolor = "white",
font = list(size = 12)
)
)
giving
If you use htmlwidgets::onRender(js_code)
with plotly
you can execute your own JavaScript inlcuding plotlys's hover / unhover events. This then can be used to show / hide our own tooltip as per my answer here. The data is passed to Javascript using jsonlite::toJSON(data)
and used there to display a custom table. In this solution you can go nuts with CSS / HTML and pretty much customize the whole tooltip.
library(plotly)
library(htmlwidgets)
data <- data.frame(
Category = c("A", "B", "C"),
Value1 = c(10, 20, 30),
Value2 = c(40, 50, 60)
)
js_code <- paste0('
function(el, x) {
// Parse data to access in JavaScript
var data = ', jsonlite::toJSON(data), ';
// Create tooltip element
var tooltip = document.createElement("div");
tooltip.style.display = "none";
tooltip.style.position = "absolute";
tooltip.style.backgroundColor = "white";
tooltip.style.border = "1px solid #ddd";
tooltip.style.color = "black";
tooltip.style.padding = "8px";
tooltip.style.borderRadius = "4px";
tooltip.style.zIndex = "1000";
tooltip.style.boxShadow = "2px 2px 6px rgba(0,0,0,0.2)";
tooltip.style.fontFamily = "Arial, sans-serif";
document.body.appendChild(tooltip);
el.on("plotly_hover", function(e) {
var pt = e.points[0];
var category = pt.x;
var value1 = pt.y; // the hover event gives us the x / y value
// Find matching data row
var row = data.find(d => d.Category === category);
var value2 = row ? row.Value2 : "N/A"; // mathc for the value2 using data
tooltip.innerHTML = `
<div style="font-weight:bold; margin-bottom:6px">Category: ${category}</div>
<table style="width:100%; border-collapse: collapse; border: 1px solid black;">
<tr>
<th style="border: 1px solid black; padding: 5px;">Name</th>
<th style="border: 1px solid black; padding: 5px;">Value</th>
</tr>
<tr>
<td style="padding:3px; font-weight:bold; border: 1px solid black;">Value1:</td>
<td style="padding:3px; text-align:right; border: 1px solid black;">${value1}</td>
</tr>
<tr>
<td style="padding:3px; font-weight:bold; border: 1px solid black;">Value2:</td>
<td style="padding:3px; text-align:right; border: 1px solid black;">${value2}</td>
</tr>
</table>
`;
tooltip.style.display = "block";
tooltip.style.left = (e.event.pageX + 10) + "px";
tooltip.style.top = (e.event.pageY + 10) + "px";
});
el.on("plotly_unhover", function(e) {
tooltip.style.display = "none";
});
}
')
plot_ly(data, x = ~Category, y = ~Value1, type = 'bar') %>%
layout(
hovermode = 'closest',
hoverlabel = list(enabled = FALSE) # Disable default hover label
) %>%
config(displayModeBar = TRUE) %>%
htmlwidgets::onRender(js_code)