Boxplot hoverinfo/hovertext fails to take
Hello! I'm trying to customize the hover behavior of a box plot, and it doesn't seem to be working in the way I'd expect.
Reproduction of the issue here: https://codepen.io/lswainemoore/pen/MYgJQJp
In the first two plots, I've tried the two methods that I'd expect to work based on the documentation and other plot types. In A, which uses the hovertemplate method that works for scatter C, the original hovers are unchanged. In B, which uses the text + hoverinfo method that works for scatter D, the hovers disappear. The style of the hovers is customizable via layout, but content seems not to be.
I see some mention of this issue here / here (in python, though I trust the issue is the same), but no resolution yet. Hopefully my reproduction above is helpful for making progress on this! If a fix isn't possible in the short term, it would be nice to confirm that this is a known issue at least, and that I'm not just holding it wrong.
Appreciate any thoughts and help with this.
@gvwilson does the P3 tag imply that this is fixed in the 3.0.0 release candidate, or that it's not fixable until that gets released or something else?
If it's not fixed yet, and there's a good branch to start on, I'm happy to try to investigate/propose a fix, because I'd love to get this sorted for my use case.
Thanks again for any help.
Hi @lswainemoore - the P3 tag means it's a priority-3 issue, which in turn means it's in our backlog but not likely to be scheduled for work this quarter. If you'd like to try putting together a PR, we'd be very happy to prioritize review - thanks!
I don't know if this is the right way to do it, but the following patch against plotly-cartesian-3.1.2.js makes the hovertemplate option work.
If hovertemplate is a string, it is displayed next to the max
If hovertemplate is an array, its elements are used to build the labels for min, lowerfence (if present), q1, mean (if present), med, q3, upperfence (if present) and max.
--- plotly-cartesian-3.1.2.js.orig 2025-10-16 21:14:15.000000000 +0200
+++ plotly-cartesian-3.1.2.js 2025-10-29 14:55:52.602997813 +0100
@@ -32787,7 +32787,7 @@
for (itemnum = 0; itemnum < hoverData.length; itemnum++) {
var pt = hoverData[itemnum];
var eventData = helpers.makeEventData(pt, pt.trace, pt.cd);
- if (pt.hovertemplate !== false) {
+ if (pt.hovertemplate !== false && pt.trace.type !== "box" && pt.trace.type !== "violin") {
var ht = false;
if (pt.cd[pt.index] && pt.cd[pt.index].ht) {
ht = pt.cd[pt.index].ht;
@@ -62502,8 +62529,11 @@
var hasFences = trace.boxpoints || trace.points;
var attrs = hasFences && hasMean ? ["max", "uf", "q3", "med", "mean", "q1", "lf", "min"] : hasFences && !hasMean ? ["max", "uf", "q3", "med", "q1", "lf", "min"] : !hasFences && hasMean ? ["max", "q3", "med", "mean", "q1", "min"] : ["max", "q3", "med", "q1", "min"];
var rev = vAxis.range[1] < vAxis.range[0];
+ var hovertemplate = trace.hovertemplate.slice();
if (trace.orientation === (rev ? "v" : "h")) {
attrs.reverse();
+ } else if (Array.isArray(hovertemplate)) {
+ hovertemplate.reverse();
}
var spikeDistance = pointData.spikeDistance;
var spikePosition = pointData[spikePosAttr];
@@ -62515,14 +62545,24 @@
var valPx = vAxis.c2p(val, true);
var pointData2 = Lib.extendFlat({}, pointData);
pointData2.attr = attr;
- pointData2[vLetter + "0"] = pointData2[vLetter + "1"] = valPx;
- pointData2[vLetter + "LabelVal"] = val;
- pointData2[vLetter + "Label"] = (t.labels ? t.labels[attr] + " " : "") + Axes.hoverLabelText(vAxis, val, trace[vLetter + "hoverformat"]);
- pointData2.hoverOnBox = true;
- if (attr === "mean" && "sd" in di && (trace.boxmean === "sd" || trace.sizemode === "sd")) {
- pointData2[vLetter + "err"] = di.sd;
+ if (!hovertemplate) {
+ pointData2[vLetter + "0"] = pointData2[vLetter + "1"] = valPx;
+ pointData2[vLetter + "LabelVal"] = val;
+ pointData2[vLetter + "Label"] = (t.labels ? t.labels[attr] + " " : "") + Axes.hoverLabelText(vAxis, val, trace[vLetter + "hoverformat"]);
+ pointData2.hoverOnBox = true;
+ if (attr === "mean" && "sd" in di && (trace.boxmean === "sd" || trace.sizemode === "sd")) {
+ pointData2[vLetter + "err"] = di.sd;
+ }
+ } else {
+ if (typeof hovertemplate === "string" && attr === "max") {
+ pointData2[vLetter + "0"] = pointData2[vLetter + "1"] = valPx;
+ pointData2.hovertemplate = hovertemplate;
+ }
+ if (Array.isArray(hovertemplate) && hovertemplate[i]) {
+ pointData2[vLetter + "0"] = pointData2[vLetter + "1"] = valPx;
+ pointData2.hovertemplate = hovertemplate[i]
+ }
}
- pointData2.hovertemplate = false;
closeBoxData.push(pointData2);
}
pointData.name = "";
6.5.0, the Boxplot hoverinfo still cannot be customized