How to use dcc.Tooltip in a bar chart?

Guys I would like to know how to make a tooltip similar to this example made in powerBI just below

I found the dcc.tooltip property and I believe it can solve my problem but I still don’t know how to pass the reference and callback the right way to a bar chart.


This is the code of the tooltip graphic (The Data Frame df_t3 sums the amount of pieces in stock of each collection in each branch)

fig = go.Figure(data=[
    go.Bar(x=df_t3['clo_nom1'], y=df_t3['prl_qtp1'],
           text=df_t3['prl_qtp1'],
           textposition='outside', 
           marker_color='#00B0FF')   
])
fig.update_layout(title='Estoque por Filial Lily Belle', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)')
fig.update_yaxes(showticklabels=False)
fig.show()

This is the main chart code (The Data Frame df_per_branch sums the total number of pieces in each branch)
fig = go.Figure(data=[
    go.Bar(x=df_per_branch['PRL_FIL'], y=df_per_branch['PRL_QTP'],
           text=df_per_branch['PRL_QTP'],
           textposition='outside', 
           marker_color=colors)   
])
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(title='Estoque por Filial Lily Belle', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)')
fig.update_yaxes(showticklabels=False)

In the example above is the result I managed to get.

The result I expect is the one below, the graph inside the tooltip changes its data to the equivalent of the bar I’m hovering over

This one below is the complete plot code, I appreciate anyone who can help me with this.

import sqlalchemy as sa
from sqlalchemy import create_engine
import fdb
import pandas as pd
import plotly
import plotly.graph_objects as go
import dash 
from dash import Dash, dcc, html, Input, Output, no_update

conection_url = sa.engine.URL.create(
    'firebird+fdb',
    username='SYSDBA',
    password='masterkey',
    host='localhost',
    database='D:/REDE-NOVOSYS/CLIENTES/LILY BELLE/BD/SIGAWEAR.FDB',
)

engine = sa.create_engine(conection_url)

df_Coleção = pd.read_sql_query("select PRL_FIL, PRL_QTP, PRL_PRO, CLO_NOM from PRODUTOLOCAL INNER JOIN PRODUTO ON PRODUTOLOCAL.PRL_PRO = PRODUTO.PRO_COD INNER JOIN COLECAO ON PRODUTO.PRO_CLO = COLECAO.CLO_COD Where PRL_LCD='1' and PRL_FIL in('2', '7', '6', '3', '15', '9')",engine)
df_Coleção['prl_fil'] = df_Coleção['prl_fil'].apply(lambda x: str(x))
df_por_filial = df_Coleção.groupby('prl_fil')['prl_qtp'].sum().sort_values().reset_index()
df_por_filial['prl_fil'] = df_por_filial['prl_fil'].map({'2':'Loja Fábrica',
                                                        '6':'Mirassol',
                                                        '15':'Cianorte',
                                                        '7':'Maringa',
                                                        '3':'Mega',
                                                        '9':'Bom Retiro'})
df_por_filial.rename(columns={'prl_fil':'PRL_FIL', 'prl_qtp':'PRL_QTP'}, inplace=True)
df_t3=df_Coleção.groupby(['prl_fil','clo_nom'])['prl_qtp'].sum().sort_values().reset_index()
df_t3=df_t3[(df_t3['prl_qtp']>0)&(df_t3['prl_fil']=='2')]
colors = ['#00B0FF',]*6
fig = go.Figure(data=[
    go.Bar(x=df_por_filial['PRL_FIL'], y=df_por_filial['PRL_QTP'],
           text=df_por_filial['PRL_QTP'],
           textposition='outside', 
           marker_color=colors)   
])
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(title='Estoque por Filial Lily Belle', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)')
fig.update_yaxes(showticklabels=False)

fig2 = go.Figure(data=[
    go.Bar(x=df_t3['clo_nom'], y=df_t3['prl_qtp'],
           text=df_t3['prl_qtp'],
           textposition='outside', 
           marker_color='#00B0FF')   
])
fig2.update_layout(title='Estoque por Filial Lily Belle', paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)')
fig2.update_yaxes(showticklabels=False)

app = Dash(__name__)

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

@app.callback(
    Output("graph-tooltip", "show"),
    Output("graph-tooltip", "bbox"),
    Output("graph-tooltip", "children"),
    Input("graph", "hoverData"),
)

def display_hover(hoverData):
    if hoverData is None:
        return False, no_update, no_update
    pt = hoverData['points'][0]
    bbox = pt["bbox"]
    
    children= [
            html.Div([
            dcc.Graph(id="graph2", figure=fig2),
        ], style={'width': '600px', 'white-space': 'normal'})
    ]
    return True, bbox, children


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

Hi @NOVOSYS
In order for the graph inside the Tooltip to change based on the hover data, you need to update the figure in the callback.

Here is a minimal example:

from dash import Dash, dcc, html, Input, Output, no_update
import plotly.express as px

df = px.data.tips()
fig = px.histogram(df, x="sex", y="total_bill")
fig.update_traces(
    hoverinfo="none",
    hovertemplate=None,
)

app = Dash(__name__)

app.layout = html.Div(
    children=[
        dcc.Graph(id="graph-3", figure=fig, clear_on_unhover=True),
        dcc.Tooltip(id="graph-tooltip-3", direction="bottom"),
    ],
    style={"height": 800, "padding": 50},
)


@app.callback(
    Output("graph-tooltip-3", "show"),
    Output("graph-tooltip-3", "bbox"),
    Output("graph-tooltip-3", "children"),
    Input("graph-3", "hoverData"),
)
def update_tooltip_content(hoverData):
    if hoverData is None:
        return no_update

    pt = hoverData["points"][0]
    bbox = pt["bbox"]
    dff = df[df.sex == pt["x"]]
    fig = px.bar(dff, x="day", y="total_bill", title=f"Total Bill by Day - {pt['x']}")
    children = [dcc.Graph(figure=fig, style={"height": 300})]

    return True, bbox, children


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

2 Likes

Thank you very much, this way of doing it solved my problem.

1 Like