Dcc Tooltip with Sankey Chart appearing at incorrect locations

Hello,

I am plotting a Sankey chart on my Dash app along with the dcc.Tooltip to display info on hover as the styling of the default graph tooltip doesn’t fit my requirements.

However the tooltip positioning is not aligned to the center of the sankey node

I’m passing the bbox coordinates from the hoverData of the graph like we do for any other graph when using the dcc.Tooltip but it seems to be not working or misaligned for Sankey figures.

Here’s the code to reproduce the above graph:

# imports
from dash import Dash, dcc, html, Output, Input, no_update
import plotly.graph_objects as go

# -----------------------------------------APP Definition---------------------------------------------------------------

app = Dash(__name__)


def genSankey():
    fig = go.Figure(
        data=[
            go.Sankey(
                node=dict(
                    pad=15,
                    thickness=20,
                    line=dict(color="black", width=0.5),
                    label=["A1", "A2", "B1", "B2", "C1", "C2"],
                    color="blue",
                ),
                link=dict(
                    source=[
                        0,
                        1,
                        0,
                        2,
                        3,
                        3,
                    ],  # indices correspond to labels, eg A1, A2, A1, B1, ...
                    target=[2, 3, 3, 4, 4, 5],
                    value=[8, 4, 2, 8, 4, 2],
                ),
            )
        ]
    )
    fig.update_traces(hoverinfo="none")
    fig.update_layout(title_text="Basic Sankey Diagram", font_size=10)
    return fig


# -----------------------------------------APP Layout-------------------------------------------------------------------
app.layout = html.Div(
    [dcc.Graph(id="sankey-graph", figure=genSankey()), dcc.Tooltip(id="graph-tooltip")],
)

# -----------------------------------------App Callback-------------------------------------------------------------------
@app.callback(
    Output("graph-tooltip", "show"),
    Output("graph-tooltip", "bbox"),
    Output("graph-tooltip", "children"),
    Input("sankey-graph", "hoverData")
)
def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update
    print(hoverData, "\n")
    # demo only shows the first point, but other points may also be available
    pt = hoverData["points"][0]
    try:
        bbox = {"x0": pt["x0"], "x1": pt["x1"], "y0": pt["y0"], "y1": pt["y1"]}
    except KeyError:
        return False, no_update, no_update

    children = [
        html.Div(
            [
                html.P(f"x0: {pt['x0']}, x1: {pt['x1']:0.2f}"),
                html.P(f"y0: {pt['y0']}, y1: {pt['y1']:0.2f}"),
            ],
            style={"width": "200px", "white-space": "normal"},
        )
    ]

    return True, bbox, children


# -----------------------------------------Run Server-------------------------------------------------------------------
if __name__ == "__main__":
    app.run_server(debug=True)

@dataturnsmeon

It seems the bbox cordinates returned by hoverdata of sankey graph does not factor in the default margin of the graph. Each plotly graph has some default margin on four sides. When I set the margin=dict(t=0,b=0,l=0,r=0) in update_layout the tooltip appears at the correct position

However as we can see in the above image if the margins are set to 0 the title or other parts of the graph may get cropped or overlap with the modebar. So if we add a top margin to the graph we also need to add the same value to the bbox coordiantes (in this case y0 and y1 for top margin).

fig.update_layout(margin=dict(t=50,b=0,l=0,r=0))

#inside the callback for tooltip
    pt = hoverData["points"][0]
    try:
        bbox = {"x0": pt["x0"], "x1": pt["x1"], "y0": pt["y0"]+50, "y1": pt["y1"]+50} #adding 50px to y0 and y1
    except KeyError:
        return False, no_update, no_update

1 Like

@atharvakatre Thanks so much dude!!!

You saved me hours, and very keen observation about the plot margins.