Linking timeline graph with Dash table

I am trying to use the hoverdata feature of the px.timeline graph and link it with the dash table in order to highlight the line on which my mouse cursor is hovering. Can someone please tell if I am missing something as I cannot see it working.

import dash
import dash_table
from dash.dependencies import Input, Output

import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd

app = dash.Dash(__name__)

df = pd.DataFrame([
    dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28', Resource="Alex"),
    dict(Task="Job A", Start='2009-02-28', Finish='2009-04-15', Resource="Max"),
    dict(Task="Job B", Start='2009-02-20', Finish='2009-05-30', Resource="Max")
])

fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Resource")
fig.update_yaxes(autorange="reversed") 

app.layout = html.Div(
    [
        html.H4(id="title"),
        html.Div(
            [
                dcc.Graph(
                    id="timeline",
                    figure=fig
                )
            ]
        ),
        html.Div(
            [
                dash_table.DataTable(
                    id="table",
                    columns=[{"name": i, "id": i, "type": 'text'} for i in df.columns],
                    data=df.to_dict("records"),
                    sort_action="native",
                )
            ]
        ),
    ]
)

@app.callback(    
    [
        Output("table", "data"),
        Output("table", "style_data_conditional"),
    ],
    [Input("timeline", "hoverData")],
)
def highlight(hoverData):    

    data = df.to_dict("records")
    selected_styles = []
    
    if hoverData:
        task_selected = []
        for point in hoverData['points']:
            task_selected.append(point['y'])           
       
        selected_styles = [{'if': {
                                'filter_query': '{Task} = tolook'
                            },            
                
                            'backgroundColor': '#FFFF00'}]
        
    return data, selected_styles

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

Hi @bestever and welcome to Dash!

You ask a great question! There is an example in the docs here for selecting a row in a table and highlighting a graph, but there isn’t one for doing it the other way around.

The trick is to find which row to highlight based on the hover data. You can do this by adding a row id to the dataframe, and including it as custom data when you create the figure. The custom data is included with the hover data – see more info on that here.

Note that it’s necessary to have a row id in order to highlight the correct row after sorting the table.

Here is an example:


import dash
import dash_table
from dash.dependencies import Input, Output

import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd

app = dash.Dash(__name__)

df = pd.DataFrame(
    [
        dict(Task="Job A", Start="2009-01-01", Finish="2009-02-28", Resource="Alex"),
        dict(Task="Job A", Start="2009-02-28", Finish="2009-04-15", Resource="Max"),
        dict(Task="Job B", Start="2009-02-20", Finish="2009-05-30", Resource="Max"),
    ]
)
df["id"] = df.index

fig = px.timeline(
    df, x_start="Start", x_end="Finish", y="Task", color="Resource", custom_data=["id"]
)
fig.update_yaxes(autorange="reversed")

app.layout = html.Div(
    [
        html.H4(id="title"),
        html.Div([dcc.Graph(id="timeline", figure=fig)]),
        html.Div(
            [
                dash_table.DataTable(
                    id="table",
                    columns=[{"name": i, "id": i, "type": "text"} for i in df.columns],
                    data=df.to_dict("records"),
                    sort_action="native",
                )
            ]
        ),
    ]
)


@app.callback(Output("table", "style_data_conditional"), Input("timeline", "hoverData"))
def highlight(hoverData):
    if hoverData is None:
        return None

    row = hoverData["points"][0]["customdata"][0]

    return [
        {"if": {"filter_query": "{{id}}={}".format(row)}, "backgroundColor": "lightgrey"}
    ]


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

highlight_table

3 Likes

Thank you this is so helpful.
I have another question wrt hovertemplate string, can we have if else construct to include or exclude information in hovertemplate. An example would be greatly appreciated.
e.g.
something on these lines
hovertemplate="%{customdata[1]" if customdata[1] > 0 else “”