Skip to content

Include xPixel and yPixel in hoverdata and clickdata in dcc.Graph - #3961

Draft
AnnMarieW wants to merge 1 commit into
plotly:devfrom
AnnMarieW:update-clickanywhere-hoveranywhere
Draft

Include xPixel and yPixel in hoverdata and clickdata in dcc.Graph#3961
AnnMarieW wants to merge 1 commit into
plotly:devfrom
AnnMarieW:update-clickanywhere-hoveranywhere

Conversation

@AnnMarieW

@AnnMarieW AnnMarieW commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

This is a continuation of PR #3852

To do (changes needed in plotly.js):

  • Add pixel coordinates to make it possible to use dcc.Tooltip to create custom tooltips. In the PR 7707 to add this feature in Plotly.js, , xPixel and yPixel are added to the event data, but it's only available on points. You can see this when running the sample app below.
  • It's not currently possible to clear the hover data on unhover - it always shows the last hovered point. I'd like to suggest adding an unhover event in plotly.js when the cursor leaves the plot area.

Both of these issues were fixed in plotly/plotly.js#7966 and are now available in Plotly 7. Thanks @emilykl 🙂

The Plotly.js PR #7966 adds xPixel and yPixel (the cursor coordinates) to all hover and click events, regardless of whether hoveranywhere or clickanywhere are enabled.

This PR includes xPixel and yPixel data in the dcc.Graph hoverData and clickData props only when hoveranywhere or clickanywhere option is enabled in the figure. This avoids triggering Dash callbacks when the cursor coordinates aren't needed.

I'll provide some sample apps as a separate comment.

@sonarqubecloud

Copy link
Copy Markdown

@AnnMarieW

Copy link
Copy Markdown
Collaborator Author

@T4rk1n - The test fails because it requires Plotly 7 - what's the best way to handle that?

@T4rk1n

T4rk1n commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

@T4rk1n - The test fails because it requires Plotly 7 - what's the best way to handle that?

You can either install plotly.py 7.0.0 to install it globally (Probably best), or if it's just a few tests can put the plotly.js version in assets and set it for the test.

@AnnMarieW

AnnMarieW commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Here's a sample app - the xPixel and yPixel are used to create a floating custom tooltip with dcc.Tooltip:

image image
from dash import Dash, dcc, html, Input, Output
import numpy as np
import pandas as pd
import plotly.graph_objects as go

app = Dash(__name__)

np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=500, freq="B")

price_changes = np.random.normal(0, 1.5, len(dates))
prices = 100 + np.cumsum(price_changes)

df = pd.DataFrame(
    {
        "date": dates,
        "price": prices,
    }
)

fig = go.Figure(
    go.Scatter(
        x=df["date"],
        y=df["price"],
        mode="lines",
        name="Stock",
    )
)

fig.update_layout(
    hoveranywhere=True,
    xaxis=dict(
        title="Date",
        showspikes=False,
    ),
    yaxis=dict(
        title="Price",
        showspikes=True,
        spikemode="toaxis+across",
        spikesnap="cursor",
        spikecolor="#FF4136",
        spikethickness=1.5,
    ),
)

app.layout = html.Div(
    [
        dcc.Graph(
            id="stock-chart",
            figure=fig,
            clear_on_unhover=True
        ),
        dcc.Tooltip(
            id="tooltip",
            direction="top",
        ),
    ]
)


@app.callback(
    Output("tooltip", "show"),
    Output("tooltip", "bbox"),
    Output("tooltip", "children"),
    Input("stock-chart", "hoverData"),
)
def update_tooltip(hover_data):
    if not hover_data:
        return False, {}, None

    price = hover_data["yvals"][0]

    count = (df["price"] > price).sum()

    children = html.Div(
        [
            html.Div(
                f"Price: ${price:.2f}",
                style={"fontWeight": "bold"},
            ),
            html.Div(
                f"Times above this price: {count}",
            ),
        ]
    )

    return (
        True,
        {
            "x0": hover_data["xPixel"],
            "x1": hover_data["xPixel"] + 10,
            "y0": hover_data["yPixel"],
            "y1": hover_data["yPixel"] + 10,
        },
        children,
    )


if __name__ == "__main__":
    app.run(debug=True)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants