I have a plot using the following generic code:
p1 <- df %>%
mutate(groupingvar= fct_reorder(groupingvar, datefield)) %>%
mutate(typeinfo= paste(typenumber, "-", typename)) %>%
ggplot(mapping = aes(x = groupingvar, y = testvalue)) +
geom_line() +
facet_wrap(~ testvalue, scales = "free", ncol = 2) +
labs(x = "groupingvar", color = "") +
theme_bw() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(),
strip.text.x = element_text(size = 8, vjust = 0.5, margin = margin(0.25, 0, 0.25, 0, "cm")))
# this is where I set a color scheme that needs to be kept throughout the graph later
p1 <- p1 + scale_color_manual(values = c("No category" = "black",
"category 1" = "blue",
"category 2" = "green",
"category 3" = "red"))
p1 <- p1 +
geom_hline(data = df,
mapping = aes(yintercept = calculatedvalue, color = "calculatedvalue",
text = paste("calculatedvalue: ", calculatedvalue)), size = 0.6)
ggplotly(p1, tooltip = "text")
Essentially, I'm trying different methods to take a graph that would look like this:
and get something like this:"
Or just make the tooltip transparent without changing the existing color scheme.
What I've tried so far:
The problem with this layout(hovermode = "x unified")
is that it changes the bakground color of the tooltip.
This did nothing: layout(hoverlabel = list(align = "left"))
This turned the background grey and not transparent: layout(hoverlabel = list(bgcolor = "rgba(0,0,0,0)")) also for this: hoverlabel = list(bgcolor = "rgba(255, 255, 255, 0.8)
this causes the entire tooltip to go grey, hiding all the text: layout(hoverlabel = list(bgcolor = "rgba(255,255,255,0)", bordercolor = "rgba(0,0,0,0)"))
I tried adding an invisible offsent point but that didnt seem to work and sometimes the tooltip just didnt show up:
p1 <- p1 +
geom_point(mapping = aes(x = groupingvar, y = testvalue+ 0.1*testvalue), alpha = 0.8)
Id like to avoid using CSS or Javascript, or padding space in the tooltip with erroneous <br>
's.
Example pics from here: https://plotly-r.com/controlling-tooltips
Example fake data (its longer and more detailed and I'm making it generic here):
# A tibble: 6 × 9
groupingvar testvalue typeinfo datefield typenumber typename testvalue calculatedvalue colorkey
<fct> <chr> <chr> <chr> <chr> <chr> <num> <num> <chr>
1 123abc SomeTestValue 01, xyz123, 2024-11-17 abc12341234 some naming var 0.897 1.897 "Category 1"
2 123abc SomeTestValue 02, xyzz123, 2024-12-17 abc12341234 some naming var 0.888 1.888 "Category 2"
3 123abc SomeTestValue 03, xyz123, 2025-01-17 abc12341234 some naming var 0.887 1.887 "Category 3"
4 123abc SomeTestValue 14, xyz123, 2026-11-17 abc12341234 some naming var 0.777 1.777 "Category 2"
5 123abc SomeTestValue 19, xyyz123, 2026-11-17 abc12341234 some naming var 0.770 1.770 "Category 3"
6 123abc SomeTestValue 34, xyz123, 2027-11-17 abc12341234 some naming var 0.600 1.600 "Category 1"
library(tibble)
# Create the tibble manually
df <- tibble(
groupingvar = factor(rep("123abc", 6)),
testvalue = c("SomeTestValue 01",
"SomeTestValue 02",
"SomeTestValue 03",
"SomeTestValue 14",
"SomeTestValue 19",
"SomeTestValue 34"),
typeinfo = c("xyz123", "xyzz123", "xyz123", "xyz123", "xyyz123", "xyz123"),
datefield = as.character(c("2024-11-17", "2024-12-17", "2025-01-17",
"2026-11-17", "2026-11-17", "2027-11-17")),
typenumber = rep("abc12341234", 6),
typename = rep("some naming var", 6),
testvalue_num = c(0.897, 0.888, 0.887, 0.777, 0.770, 0.600),
calculatedvalue = c(1.897, 1.888, 1.887, 1.777, 1.770, 1.600),
colorkey = c("Category 1", "Category 2", "Category 3", "Category 2", "Category 3", "Category 1")
)
This was helpful in that its transparent, but the original color scheme was really important for my application. Is there any way to pass the original color scale through to this transparent version of the tooltip?
Edit: Thanks to Tim G I was able to implement a solution that worked. Here's essentially how I updated the js:
js_code <- '
function(el, x) {
var tooltip = document.createElement("div");
tooltip.style.display = "none";
tooltip.style.position = "absolute";
tooltip.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
tooltip.style.color = "white";
tooltip.style.padding = "6px 10px";
tooltip.style.borderRadius = "6px";
tooltip.style.zIndex = "1000";
tooltip.style.pointerEvents = "none";
tooltip.style.fontSize = "12px";
tooltip.style.maxWidth = "300px";
tooltip.style.fontFamily = "Arial, sans-serif";
document.body.appendChild(tooltip);
// Define mapping of labels to colors (matches scale_color_manual)
const colorMap = {
"xyz123": "rgba(255, 196, 36, 0.6)",
"xyz122": "rgba(0, 177, 89, 0.6)",
"xyy123": "rgba(255, 17, 65, 0.6)",
"xxyy123": "rgba(243, 119, 53, 0.6)",
"yyzzz1": "rgba(0,0,257,0.6)",
"zyzyy": "rgba(0,150,0,0.6)",
"somelabelforhline1": "rgba(275,0,0,0.6)",
"zxzxz123": "rgba(0,0,0,0.6)"
};
el.on("plotly_hover", function(e) {
var pt = e.points[0];
var custom = pt.customdata || "No details available";
tooltip.innerHTML = custom;
var groupLabel = pt.data.name || pt.fullData.name || "No Annotation";
var bgColor = colorMap[groupLabel] || "rgba(0,0,0,0.7)";
tooltip.style.backgroundColor = bgColor;
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() {
tooltip.style.display = "none";
});
}
'
Where every color is related to a geom_point thats condition on a column except the one for somelabelforhline1 which is a line color for a horizontal line.
The final call was this where you have to NULL out the tooltip in plotly:
ggplotly(p1, tooltip = NULL) %>%
htmlwidgets::onRender(js_code)
With the custom Javascript colorMap I'm able to get the tooltip to match the color of the geom_point that is conditionally colored based on a value of a char/factor column separate from the y axis value.
First, I fixed your code and made it reproducible. Then, I reused my code to show custom hover labels based on linecolor defined in your style e.points[0].data.line.color
obtained from the plotly hover event with adjusted alpha to make it transparent. You can adjust the transparency by increasing the alpha value 0.5
. Make sure to choose a text-color tooltip.style.color = "white";
that has a good contrast to all your colors - I chose white here. I also suppressed the normal hover-label using text=""
.
library(ggplot2)
library(plotly)
library(tidyverse)
library(tibble)
# Create the tibble manually
df <- tibble(
groupingvar = factor(c("1", "1", "2", "2")), # Corrected factor definition
testvalue = c("SomeTestValue 01", "SomeTestValue 01", "SomeTestValue 02", "SomeTestValue 02"),
typeinfo = c("x1", "x1", "x2", "x2"),
datefield = as.Date(c("2024-11-17", "2024-11-17", "2024-12-17", "2024-12-17")),
testvalue_num = c(0.897, 0.888, 1, 1.3),
calculatedvalue = c(1.897, 1.888, 2, 3),
colorkey = c("Category 1", "Category 1", "Category 2", "Category 2")
)
p1 <- df %>%
mutate(groupingvar = fct_reorder(groupingvar, as.numeric(datefield))) %>%
ggplot(mapping = aes(x = groupingvar, y = testvalue_num, color = colorkey, group = typeinfo)) +
geom_line(size = 1.2) +
facet_wrap(~ testvalue, scales = "free", ncol = 2) +
labs(x = "Grouping Variable", y = "Test Value") +
theme_bw() +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
strip.text.x = element_text(size = 8, vjust = 0.5, margin = margin(0.25, 0, 0.25, 0, "cm"))) +
scale_color_manual(values = c("Category 1" = "blue","Category 2" = "green")) + # Apply color scheme
geom_hline(data = df, aes(yintercept = calculatedvalue, color = colorkey, text = ""), linewidth = 0.6, linetype = "dashed")
js_code <- paste0('
function(el, x) {
// 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 = "white";
tooltip.style.padding = "2px";
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 lineColor = pt.data.line.color;
lineColor = lineColor.replace(/rgba\\((.+?),\\s*[\\d\\.]+\\)/, "rgba($1, 0.5)"); // adjust alpha 0.5 here
tooltip.innerHTML = `
<table style="width:100%; border-collapse: collapse">
<tr>
<td>Calculated Value:</td>
<td>${pt.y}</td>
</tr>
</table>
`;
tooltip.style.backgroundColor = lineColor; // set background to lineColor
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";
});
}
')
# Convert to interactive plot
ggplotly(p1, tooltip = c("text")) %>%
htmlwidgets::onRender(js_code)