◐ Shell
clean mode source ↗

feat: Make hover label triangle optional by emilykl · Pull Request #7451 · plotly/plotly.js

@emilykl

Closes #7278

Adds trace.hoverlabel.showarrow and layout.hoverlabel.showarrow attributes (default: true) to enable hiding the triangular carat on the hover text box.

Also adds a Jasmine test for the new attributes.

With showarrow: true (default; same as current behavior):
Screenshot 2025-07-22 at 1 32 27 PM

With showarrow: false:
Screenshot 2025-07-22 at 1 32 36 PM

@archmoj

@emilykl
Is this PR ready for review?
Would you please merge master into this branch?
Thank you 🙏

@emilykl

@archmoj not quite ready for review but I'll merge master — will ping you later today when ready for review

gvwilson

'V' + pY(offsetY - HOVERARROWSIZE) +
'Z'));
pathStr = 'M0,0L' + pX(horzSign * HOVERARROWSIZE + offsetX) + ',' + pY(HOVERARROWSIZE + offsetY) +
'v' + pY(d.by / 2 - HOVERARROWSIZE) +

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG math

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gvwilson Coming up with the new SVG path string with no arrow was Claude Code's only helpful contribution to this PR (but it's a doozy, so, worth it)

@emilykl emilykl marked this pull request as ready for review

July 22, 2025 20:57

@emilykl

@archmoj This is ready for review. A couple questions for you —

  • I had to remove arrayOk: true for showarrow in 23a8f8a due to a failing test . Looking at plot-schema.json it seems arrayOk is not supported for boolean attributes, does that make sense?

  • It would be nice to support showarrow for parcats traces but it looks like all hoverlabel attributes are not supported for parcats, do you know why? I looked into enabling hoverlabel for parcats but it was not straightforward.

@emilykl emilykl changed the title 7278 make triangle optional Make hover label triangle optional (#7278)

Jul 24, 2025

@emilykl emilykl changed the title Make hover label triangle optional (#7278) feat: Make hover label triangle optional

Jul 25, 2025

@archmoj

  • I had to remove arrayOk: true for showarrow in 23a8f8a due to a failing test . Looking at plot-schema.json it seems arrayOk is not supported for boolean attributes, does that make sense?

One could possibly add arrayOk to the otherOpts here:


For this PR I don't see a strong use case for that option.
So IMHO it's a good idea to set arrayOk to false as you did.

@archmoj

  • It would be nice to support showarrow for parcats traces but it looks like all hoverlabel attributes are not supported for parcats, do you know why? I looked into enabling hoverlabel for parcats but it was not straightforward.

We could handle this option for parcats as follow:
Add

hoverItems.trace._hoverlabel = {showarrow: false};

before calling Fx.loneHover in parcats.js.

Then make the following change

var showArrow = (d.trace._hoverlabel || d.trace.hoverlabel)?.showarrow;

@archmoj

In addition to parcats trace, we should handle this option in sankey trace.

@emilykl

  • It would be nice to support showarrow for parcats traces but it looks like all hoverlabel attributes are not supported for parcats, do you know why? I looked into enabling hoverlabel for parcats but it was not straightforward.

We could handle this option for parcats as follow: Add

hoverItems.trace._hoverlabel = {showarrow: false};

before calling Fx.loneHover in parcats.js.

Then make the following change

var showArrow = (d.trace._hoverlabel || d.trace.hoverlabel)?.showarrow;

Oh that's clever, I like that. Maybe for another PR. It would be cool too if we could just support all the hoverlabel options in parcats but not sure if there's a blocker for that.

@archmoj

Instead of the solution proposed above,
you could directly look into gd._fullLayout.hoverlabel.showarrow inside loneHover and pass it through.

exports.loneHover = function loneHover(hoverItems, opts) {
...
var gd = opts.gd;

camdecoster

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I left some suggested feedback for you to consider.

Comment on lines +1930 to +1931

pathStr = 'M-' + pX(d.bx / 2 + d.tx2width / 2) + ',' + pY(offsetY - d.by / 2) +
'h' + pX(d.bx) + 'v' + pY(d.by) + 'h-' + pX(d.bx) + 'Z';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be up for using a template literal here and elsewhere?

pathStr = 'M-' + pX(d.bx / 2 + d.tx2width / 2) + ',' + pY(offsetY - d.by / 2) +
'h' + pX(d.bx) + 'v' + pY(d.by) + 'h-' + pX(d.bx) + 'Z';
pathStr = `M-${pX(d.bx / 2 + d.tx2width / 2)},${pY(offsetY - d.by / 2)}h${pX(d.bx)}v${pY(d.by)}h-${pX(d.bx)}Z`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. Slower in Chrome but not in Safari.
Screenshot 2025-07-25 at 4 50 20 PM
Screenshot 2025-07-25 at 4 48 45 PM

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen any issues with this kind of calculation? I imagine that most computers are powerful enough where this isn't an issue.

Co-authored-by: Cameron DeCoster <cameron.decoster@gmail.com>

@archmoj

Instead of the solution proposed above, you could directly look into gd._fullLayout.hoverlabel.showarrow inside loneHover and pass it through.

exports.loneHover = function loneHover(hoverItems, opts) {
...
var gd = opts.gd;

@emilykl Wondering if you tried this solution to fix the parcats and sankey traces?

@emilykl

Instead of the solution proposed above, you could directly look into gd._fullLayout.hoverlabel.showarrow inside loneHover and pass it through.

exports.loneHover = function loneHover(hoverItems, opts) {
...
var gd = opts.gd;

@emilykl Wondering if you tried this solution to fix the parcats and sankey traces?

I did, but I didn't like the complexity of the if/else logic it required. It felt like building a parallel system for logic that is already handled for traces which support trace.hovertext.showarrow. It seems to me the correct approach is to allow the use of trace.hovertext.showarrow for these traces; then we get the logic for handling layout.showarrow for free, since that's how it's handled for the other traces.

@emilykl emilykl deleted the 7278-make-triangle-optional branch

July 29, 2025 17:43