Sync cytoscape and dropdown menu selections

Hello all,

I’m having trouble syncing cytoscape with other components (such as dropdown menus) and would appreciate any advice/suggestions.

I’m attempting to sync cytoscape selected nodes (selectedNodesData) bidirectionally with a dropdown menu selection. That is, selecting nodes from the dropdown menu highlights the network on the fly, and vice versa. While I have managed the first step: updating the dropdown menu value using a cytoscape node. It works as follows:

step1_gif

code:

from gc import callbacks

import dash
import dash_cytoscape as cyto
import pandas as pd
from dash import callback_context, dcc, html, no_update
from dash.dependencies import Input, Output

graphs = ["A", "B"]

app = dash.Dash(__name__)

my_layout = {"name": "grid"}
my_style = {
    "display": "inline-block",
    "width": "1000px",
    "height": "800px",
    "border": "2px black solid",
}

app.layout = html.Div(
    children=[
        html.H1("My Network", style={"color": "black", "fontSize": 32}),
        html.Br(),
        dcc.Dropdown(
            id="dropdown",
            options=["A", "B"],
            disabled=False,
            multi=True,
        ),
        html.Br(),
        cyto.Cytoscape(
            id="network",
            elements=[
                {
                    "data": {"id": "A", "label": "A"},
                    "position": {"x": 75, "y": 75},
                    "classes": "A",
                },
                {
                    "data": {"id": "B", "label": "B"},
                    "position": {"x": 200, "y": 200},
                    "classes": "B",
                },
                {"data": {"source": "A", "target": "B"}},
            ],  # How do I have an option for different elements here?
            layout=my_layout,
            style=my_style,
            stylesheet=[
                {
                    "selector": "node",
                    "style": {"width": "50px", "height": "50px"},
                }
            ],
        ),
        html.Br(),
    ]
)


@app.callback(
    Output(component_id="dropdown", component_property="value"),
    Input(component_id="network", component_property="selectedNodeData"),
)
def sync(selected_nodes):
    if selected_nodes is None:
        raise dash.exceptions.PreventUpdate
    else:
        return [i['id'] for i in selected_nodes]


# @app.callback(
#     [
#         Output(component_id="dropdown", component_property="value"),
#         Output(component_id="network", component_property="selectedNodeData"),
#     ],
#     [
#         Input(component_id="dropdown", component_property="value"),
#         Input(component_id="network", component_property="selectedNodeData"),
#     ],
# )
# def sync(value_dropdown, value_network):
#     match callback_context.triggered[0]["prop_id"].split(".")[0]:
#         case "dropdown":
#             return no_update, [{"id": i, "label": i} for i in value_dropdown]
#         case "network":
#             return [i["id"] for i in value_network], no_update
#         case _:
#             return no_update, no_update


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

However, when I attempted to take this a step further by using a bidirectional callback like this:

@app.callback(
    [
        Output(component_id="dropdown", component_property="value"),
        Output(component_id="network", component_property="selectedNodeData"),
    ],
    [
        Input(component_id="dropdown", component_property="value"),
        Input(component_id="network", component_property="selectedNodeData"),
    ],
)
def sync(value_dropdown, value_network):
    match callback_context.triggered[0]["prop_id"].split(".")[0]:
        case "dropdown":
            return no_update, [{"id": i, "label": i} for i in value_dropdown]
        case "network":
            return [i["id"] for i in value_network], no_update
        case _:
            return no_update, no_update

The dropdown menu updates as expected when nodes are selected, but it does not update network selection:

step2

I reasoned that this could be because cytoscape does not support callbacks on the selectedNodesData attribute. So, my question is, is there a hack/workaround for this?

Appreciate any feedbacks,
Don