How do you accomplish two way syncing graph selection with table selection

Im trying to synchronize selections between a table and a graph in both directions. So when a point is selected on the graph i’d like to select the corresponding rows in a table and when rows are selected in the table the corresponding points in the graph should be selected.

here is a minimal prototype, it uses selected_rows to update the table and selectedpoints in the graph to update the graph.

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table as dt
from dash.dependencies import Input, Output

app = dash.Dash("simple repro")

figure_data = {
    "data": [{
        "x": [1, 2, 3],
        "y": [1, 2, 3],
        'selectedpoints': [],
        "mode": "markers",
        'marker': {'size': 20}
    }],
    'layout': {
        'clickmode': 'event+select'
    }
}


app.layout = html.Div(
    className="grid",
    children=[
        html.Div(
            [
                dcc.Graph(id="graph", figure=figure_data),
                dt.DataTable(
                    id="table",
                    sorting=True,
                    row_selectable='multi',
                    columns=[{"name": "x", "id": "x"}, {"name": "y", "id": "y"}],
                    data=[
                        {"x": 1, "y": 1},
                        {"x": 2, "y": 2},
                        {"x": 3, "y": 3},
                    ],
                )
            ],
        ),
    ],
)


@app.callback(Output("table", "selected_rows"), [Input("graph", "selectedData")])
def update_table_selection(selected_data):
    if not selected_data or not selected_data.get('points'):
        return []
    return [point['pointIndex'] for point in selected_data['points']]


@app.callback(Output("graph", "figure"), [Input("table", "selected_rows")])
def update_graph_selection(selected_rows):
    if selected_rows:
        figure_data['data'][0]['selectedpoints'] = selected_rows
    else:
        figure_data['data'][0]['selectedpoints'] = []

    return figure_data


if __name__ == "__main__":
    app.run_server(debug=True, host="0.0.0.0", port=8050)

This almost works but theres a problem. If you select a row in the table and then shift + click a point on the graph the original row and point selected is lost. I believe this is because when a table row is selected the figure’s selectedpoints is updated but the selectedData isn’t so when you click on the graph the information is lost.

But i dont know how to keep those in sync without resulting in an infinite callback loop.

2 Likes

I’m going through the exact same challenge. If I find a solution, I’ll let you know. Thank you for bringing this up to the forum.

Do you think it would work if you limited selection of markers and rows to single instead of mutli? Or you prefer not doing that?

That would work. but i need to select multiple points/rows for my use case.

Synchronising components (at least through Dash callbacks) is a current limitation of Dash’s, as discussed in this thread: Synchronize components bidirectionally

Any chance this limitation has been updated? I’m working on other ways to highlight, but would like to just have both selected.

Thanks!