question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Callbacks cannot remove and add nodes

See original GitHub issue

I am trying to show a graph with parent and child nodes (representing clusters) and have a menu or button callback to remove/hide the parent nodes and leave the children (and appropriate edges.) I’ve tried various approaches, but essentially, they seem to all return the same error. The callback(s) return a whole new “elements” to Cytoscape and they inevitably result in a JS error in the browser like this example:

Can not create edge 7cf808c5-c6a2-4937-8ca8-8b43d1bd8893 with nonexistant source nyc

I have put together a small test/demo to show the problem, based directly on some of the examples from the documentation. As far as I can see from the documentation examples, this should do what I want, but I still get the errors. I don’t think I’m missing anything (this is pretty straightforwardly copying and pasting from the examples…) so I suspect there’s a but here.

In my debugging efforts, I noticed that if one changes the IDs of the nodes in the callback instead of leaving them the same as the originals, then it seems to work. But that would be somewhat kludgey and cumbersome to do for a graph with lots of actual data. (Note: I did try looking at the JS in the browser console tool. if I followed it correctly, it looks like it’s removing all the nodes and edges, then trying to add back edges before creating the nodes… maybe…)

Thanks in advance for your help! -Al

My Example CODE:


import dash import dash_cytoscape as cyto import dash_html_components as html from dash.dependencies import Input, Output, State

app = dash.Dash(name) app.config.suppress_callback_exceptions = True

app.layout = html.Div([ cyto.Cytoscape( id=‘cytoscape-compound’, layout={‘name’: ‘preset’}, style={‘width’: ‘100%’, ‘height’: ‘450px’}, stylesheet=[ { ‘selector’: ‘node’, ‘style’: {‘content’: ‘data(label)’} }, { ‘selector’: ‘.countries’, ‘style’: {‘width’: 5, ‘visible’: ‘false’ } }, { ‘selector’: ‘.cities’, ‘style’: {‘line-style’: ‘dashed’} } ], elements=[ # Parent Nodes { ‘data’: {‘id’: ‘us’, ‘label’: ‘United States’} }, { ‘data’: {‘id’: ‘can’, ‘label’: ‘Canada’} }, # Children Nodes { ‘data’: {‘id’: ‘nyc’, ‘label’: ‘New York’, ‘parent’: ‘us’}, ‘position’: {‘x’: 100, ‘y’: 100} }, { ‘data’: {‘id’: ‘sf’, ‘label’: ‘San Francisco’, ‘parent’: ‘us’}, ‘position’: {‘x’: 100, ‘y’: 200} }, { ‘data’: {‘id’: ‘mtl’, ‘label’: ‘Montreal’, ‘parent’: ‘can’}, ‘position’: {‘x’: 400, ‘y’: 100} }, # Edges { ‘data’: {‘source’: ‘can’, ‘target’: ‘us’}, ‘classes’: ‘countries’ }, { ‘data’: {‘source’: ‘nyc’, ‘target’: ‘sf’}, ‘classes’: ‘cities’ }, { ‘data’: {‘source’: ‘sf’, ‘target’: ‘mtl’}, ‘classes’: ‘cities’ } ] ), html.Div([ html.Button(‘Add’, id=‘btn-add-node-example’, n_clicks_timestamp=0), html.Button(‘Remove’, id=‘btn-remove-node-example’, n_clicks_timestamp=0) ]) ])

@app.callback(Output(‘cytoscape-compound’, ‘elements’), [Input(‘btn-add-node-example’, ‘n_clicks_timestamp’), Input(‘btn-remove-node-example’, ‘n_clicks_timestamp’)], [State(‘cytoscape-compound’, ‘elements’)]) def update_elements(btn_add, btn_remove, elements): if int(btn_add) > int(btn_remove): elements = [ # Children Nodes { ‘data’: {‘id’: ‘nyc’, ‘label’: ‘New York’, ‘parent’: ‘us’}, ‘position’: {‘x’: 100, ‘y’: 100} }, { ‘data’: {‘id’: ‘sf’, ‘label’: ‘San Francisco’, ‘parent’: ‘us’}, ‘position’: {‘x’: 100, ‘y’: 200} }, { ‘data’: {‘id’: ‘mtl’, ‘label’: ‘Montreal’, ‘parent’: ‘can’}, ‘position’: {‘x’: 400, ‘y’: 100} }, # Parent Nodes { ‘data’: {‘id’: ‘us’, ‘label’: ‘United States’} }, { ‘data’: {‘id’: ‘can’, ‘label’: ‘Canada’} },

        # Edges
        {
            'data': {'source': 'can', 'target': 'us'},
            'classes': 'countries'
        },
        {
            'data': {'source': 'nyc', 'target': 'sf'},
            'classes': 'cities'
        },
        {
            'data': {'source': 'sf', 'target': 'mtl'},
            'classes': 'cities'
        }
    ]
    return elements
elif int(btn_remove) > int(btn_add):
    elements = [
        {
            'data': {'id': 'nyc', 'label': 'New York'},
            'position': {'x': 100, 'y': 100}
        },
        {
            'data': {'id': 'sf', 'label': 'San Francisco'},
            'position': {'x': 100, 'y': 200}
        },
        {
            'data': {'id': 'mtl', 'label': 'Montreal'},
            'position': {'x': 400, 'y': 100}
        },
        # Edges
        {
            'data': {'source': 'nyc', 'target': 'sf'},
            'classes': 'cities'
        },
        {
            'data': {'source': 'sf', 'target': 'mtl'},
            'classes': 'cities'
        }
    ]
    return elements
return elements

if name == ‘main’: app.run_server(debug=True)

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:13

github_iconTop GitHub Comments

1reaction
xhlucacommented, Oct 19, 2020

@agersch2 @riverchen99 This definitely seems like an issue in v0.2.0, since the add/remove node example worked correctly with older versions of dash-cytoscape (v0.1.1 and v0.0.4). I’ll spend some time investigating this issue and hopefully find a fix for v0.2.1.

1reaction
agersch2commented, Oct 2, 2020

@riverchen99 Thanks for the commiseration and helpful suggestion. I had already done a similar - very kludgey - workaround. But I’d prefer a real solution to the issue to a workaround. Also, as mentioned above, it’s not only parent-child node modifications that don’t work. Removing and adding nodes exactly per the documentation example doesn’t either! I think that requires a real fix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to remove a node from its callback function?
This is an excerpt from the OpenSceneGraph Group class (from which MatrixTransform inherits): void Group::traverse(NodeVisitor& nv) ...
Read more >
Node added callback - Maya Community - Autodesk Forums
I need a callback when a node is added and already inserted into the dependency graph. The MDGMessage::addNodeAddedCallback function is called ...
Read more >
Callbacks — NUKE Python Developer's Guide v10.5v1 ...
It is not called when loading existing scripts, pasting nodes, or undoing a delete. You can use this code to change the default...
Read more >
callbacks and problem querying, modifying, and analysis - FICO
def postorder_count(node): """ Recursively count nodes to compute the cardinality of a ... and add a constraints so that their sum cannot be...
Read more >
mmaddcallback command - IBM
It cannot contain special characters (for example, a colon, semicolon, blank, tab, ... A global event triggers a callback on all nodes in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found