plotly / plotly/plotly.js

Feature Request: Plotly.Fx.hover() should support unified hover mode with categorical x-axes

Abierto
#7,682 3 comentarios 0 reacciones 1 asignado Ver en GitHub

@timdonohue-aerology ya está trabajando en esto.

Desde el 27/3/2026.

Lenguaje dominante
JavaScript
Estrellas
18.3k
Forks
2k
Merge medio
2 d 12 h
PR fusionados (30 d)
28

Descripción

Use Case

I'm building a Dash app with synchronized hover between an AG Grid table and a Plotly chart. When a user hovers over a table row, I want to trigger the chart's hover tooltip at the corresponding time point to show all trace values (runway configuration probabilities over time).

The chart uses layout.hovermode = "x unified" to show all traces together in one tooltip when hovering naturally with the mouse.

Current Behavior & Limitations

Attempt 1: Point-based hover

// Shows only a single trace, not unified
Plotly.Fx.hover(plotElement, [{curveNumber: 0, pointNumber: 5}]);

Result: Shows tooltip for only trace 0, ignores hovermode: "x unified"

Attempt 2: X-value based hover

// Fails with categorical x-axis (time strings like "01/03 12:00")
Plotly.Fx.hover(plotElement, {xval: "01/03 12:00"}, ['xy']);

Result: Logs Fx.hover failed - doesn't work with categorical/string x-axis values

Attempt 3: Multiple points

// Shows 5 separate tooltips instead of unified
const points = [];
for (let i = 0; i < plotElement.data.length; i++) {
    points.push({curveNumber: i, pointNumber: 5});
}
Plotly.Fx.hover(plotElement, points);

Result: Shows individual tooltip per trace (not unified)

Current Workaround

I'm using synthetic MouseEvent dispatch with pixel coordinate calculation:

// Calculate pixel position using internal APIs
const layout = plotElement._fullLayout;  // ⚠️ Internal API
const xaxis = layout.xaxis;
const yaxis = layout.yaxis;

const xPixel = xaxis.l2p(rowIndex) + xaxis._offset;  // ⚠️ l2p() is internal
const yPixel = yaxis._offset + yaxis._length / 2;

// Dispatch synthetic mouse event
const plotArea = plotElement.querySelector('.nsewdrag');  // ⚠️ Internal class
const rect = plotElement.getBoundingClientRect();
plotArea.dispatchEvent(new MouseEvent('mousemove', {
    bubbles: true,
    cancelable: true,
    clientX: rect.left + xPixel,
    clientY: rect.top + yPixel,
    view: window
}));

This works but is fragile because it relies on:

  • _fullLayout (internal object)
  • xaxis.l2p() (internal method)
  • xaxis._offset, yaxis._offset, yaxis._length (internal properties)
  • .nsewdrag (internal CSS class)

These could break on Plotly.js upgrades.

Proposed Solution

Enhance Plotly.Fx.hover() to respect layout.hovermode when triggered programmatically:

Option 1: Auto-detect from layout

// When layout.hovermode = "x unified", show unified tooltip
Plotly.Fx.hover(plotElement, {xval: "01/03 12:00"});

Option 2: Explicit unified flag

Plotly.Fx.hover(plotElement, {xval: "01/03 12:00"}, {unified: true});

Option 3: Support categorical x-values with point index

// Use point index for categorical axes, auto-triggers unified mode
Plotly.Fx.hover(plotElement, {pointIndex: 5, unified: true});

Benefits

  • ✅ Uses public API instead of internal DOM/pixel manipulation
  • ✅ Won't break on Plotly.js version upgrades
  • ✅ Enables common use cases: table/chart sync, timeline controls, external hover triggers
  • ✅ Respects existing hovermode configuration
  • ✅ More intuitive API (matches how manual hover works)

Environment

  • Plotly.js version: 6.5.0 (via Dash 3.3.0)
  • Browser: Chrome/Safari (reproduced in both)
  • Chart type: Area chart with categorical x-axis (time strings)
  • Hovermode: "x unified"

Willingness to Contribute

I'm willing to submit a PR for this if the approach is acceptable to maintainers. Please advise on preferred API design before I start implementation.

Related Use Cases

This would benefit anyone needing programmatic hover control:

  • Synchronized charts and data tables
  • Timeline scrubbing controls
  • External search/filter highlighting
  • Keyboard navigation of data points
  • Accessibility features (screen reader integration)

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.