Cytoscape raises an error of nonexistent edge and gets crashed. How to mute the error to keep it working?

Currently, i send new edges and nodes to a graph in a callback using a patch. I’m not sure if sending them is a proper approach of working wtih Cytoscape, but it works.

Error

But i get the error on a client side in JavaScript code

Error: Can not create edge `acbdf38b-59f1-4846-b68f-fdc5d43ea806` with nonexistant target `16f47ca5a21.899f668480dacc9a.png`
    at he (dash_cytoscape.v0_2_0m1678614432.min.js:1:29249)
    at aa.restore (dash_cytoscape.v0_2_0m1678614432.min.js:7:72184)
    at new ia (dash_cytoscape.v0_2_0m1678614432.min.js:7:68712)
    at Va.add (dash_cytoscape.v0_2_0m1678614432.min.js:7:76148)
    at l (dash_cytoscape.v0_2_0m1678614432.min.js:1:18688)
    at dash_cytoscape.v0_2_0m1678614432.min.js:1:17625
    at Va.batch (dash_cytoscape.v0_2_0m1678614432.min.js:10:9099)
    at t.patch (dash_cytoscape.v0_2_0m1678614432.min.js:1:17562)
    at t.value (dash_cytoscape.v0_2_0m1678614432.min.js:1:15598)
    at t.value (dash_cytoscape.v0_2_0m1678614432.min.js:1:15685)

It is quite obvious, a callback delivered a patch with edge referring an unknown node.

Callback

A snippet, not full code

@callback(
    Output('cytoscape', 'elements'),
    Input('cytoscape', 'tapNodeData'),
    State('cytoscape', 'elements'))
def handle_elements(tap_data, elements_state):
    trigger = get_conditional_trigger(ctx.triggered_id)
    if trigger == 'cytoscape':
        selected_card_id = extract_card_id()
        if not selected_card_id:
            return no_update

        card_attrs = get_similar_card_ids()
        card_ids = [ca.id for ca in card_attrs]
        patch = PatchFabric().display_edges(selected_card_id, card_ids, elements_state)

        return patch

Component

cyto.Cytoscape(
    id='cytoscape',
    style={'width': '100%', 'height': '100%'},
    stylesheet=[
        {
            'selector': 'node',
            'style': {
                'width': 12,
                'height': 12,
            }
        },
        {
            'selector': 'edge',
            'style': {
                'width': 1,
                'line-color': '#17141F'
            }
        },
    ],
    responsive=True,
 ) 

Patch

class PatchFabric:

    def display_edges(self, source_card_id, card_ids, elements):
        patch = Patch()

        # Highlight nodes
        for idx, node in enumerate(elements['nodes']):
            if node['data']['id'] in card_ids:
                patch['nodes'][idx]['classes'].append('similar-node')
            else:
                patch['nodes'][idx]['classes'].remove('similar-node')
                
        # Highlight edges
        patch['edges'] = [{'data': {'source': source_card_id,
                                    'target': target_card_id},
                           'classes': 'similar-edge'}
                           for target_card_id in card_ids]

        return patch

As you see in the patch some nodes are appended, removed. Edges are fully replaced.

Question

Unfortunetelly, after the error is raised all the Cytoscape JavaScript code is stopped working , to get it working back a i have to refresh a page to reoload a js script.

IS there a way to configure Cytoscape to bloat the error and simply not render what is not found and can’t be rendered?

To address the error, it would be beneficial to ensure that all card_ids are loaded nodes before calling the display_edges function. Additionally, I would suggest not muting the error, but rather attempting to fix it in some way. Just a recommendation.

Well, it would not be. It is quite common to not maintain graph integrity as it is very complex task and u has to have a strong reason for it.

Just image a graph of millions of nodes that contain usefull information, would u like to see 95% of all the information and 5% you couldn’t due to errors? Or you need 100% only, all or noting your choice? I find having 95% on hands beneficial.

Therefore, I would prefer to simply pass an error and work with all the nodes and edges exist.

You probably didn’t work with graphs, that’s ok if a few edges, nodes are broken. It shouldn’t affect all the others.

100% of all working is what i would like to have of course, but a cost in terms of time and efforts doesn’t woth it for now.

Okay if you say so, but please give this a try:

valid_ids = [element['data']['id'] for element in elements if 'id' in element['data']]
# or valid_ids = [node['data']['id'] for node in elements['nodes']]
patch['edges'] = [{'data': {'source': source_card_id,
                                    'target': target_card_id},
                           'classes': 'similar-edge'}
                           for target_card_id in card_ids if target_card_id in valid_ids]

1 Like

Looks promising, your idea is to filter returning nodes with those nodes that Cytoscape contains, that simple :grinning:. i’ll try it thank you and feel it can work.

1 Like

@Louis Done, check it out.

edges

2 Likes