plotly / dash-cytoscape

Interactive network visualization in Python and Dash, powered by Cytoscape.js
https://dash.plot.ly/cytoscape
MIT License
601 stars 119 forks source link

Dagre Rendering Fails Based On Compound Node Element Order #112

Open riverchen99 opened 3 years ago

riverchen99 commented 3 years ago

Description

The "dagre" layout produces badly formatted layouts when the parent node follows children nodes in the list of elements. This isn't noted in the documentation, to my knowledge.

Steps/Code to Reproduce

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

import dash_cytoscape as cyto

cyto.load_extra_layouts()

app = dash.Dash(__name__)

elements = [
    {
        "data": { 
            "id": "1",
            "label": "1",
        }
    },

    {
        "data": { 
            "id": "2_parent",
            "label": "2_parent",
        }
    },

    {
        "data": { 
            "id": "2",
            "label": "2",
            "parent": "2_parent",
        }
    },

    {
        "data": {
            "source": "1",
            "target": "2",
        }
    }
]

app.layout = html.Div([
    cyto.Cytoscape(
        id='cytoscape-compound',
        layout={
            "name": "dagre",
            "nodeDimensionsIncludeLabels": "true",
            "animate": "true",
        },
        style={'width': '50%', 'height': '400px', "background-color": "azure",},
        stylesheet=[
            {
                'selector': 'node',
                'style': {'content': 'data(label)'}
            },
            {
                "selector": "edge",
                "style": {
                    "curve-style": "straight",
                    "target-arrow-shape": "triangle",
                    "arrow-scale": 2,
                },
            },
        ],
        elements=elements,
    )
])

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

Above is the working code. To reproduce, swap the 2nd and 3rd elements in the elements list.

elements = [
    {
        "data": { 
            "id": "1",
            "label": "1",
        }
    },

    {
        "data": { 
            "id": "2",
            "label": "2",
            "parent": "2_parent",
        }
    },

    {
        "data": { 
            "id": "2_parent",
            "label": "2_parent",
        }
    },

    {
        "data": {
            "source": "1",
            "target": "2",
        }
    }
]

Alternatively, insert elements = elements[::-1].

Expected Results

From working example: image

Actual Results

From broken example: image

Notice that not all elements are in the viewport. This is the output after zooming out: image

The output is also not deterministic. Sometimes the layout renders like this: image

Zoomed out: image

However, the rendering is fine in any order when the "animate" option isn't specified in the layout dictionary ("animate": "false" still fails). Omitting the "animate" option yields: image

Versions

Dash 1.16.0 Dash Core Components 1.1.1 Dash HTML Components 1.12.0 Dash Renderer 1.8.0 Dash Cytoscape 0.2.0

riverchen99 commented 3 years ago

For larger graphs, the issue is worse, with the layout producing: image or image The expected output should be like: image

xhluca commented 3 years ago

This is definitely a strange issue. I tried to run it locally and it seems to work in v0.1.1 but not in v0.2.0, so I'm suspecting it is linked to #106 .

Were you able to run the steps described in this comment with your graph? If it has the same behavior (i.e. the problem appears after 4cba5bcc8aa8110b5365c0995e177b318e09c18d), then I believe this problem can be solved at the same time as #106

Given sufficient bandwidth, I'll spend some time looking into this issue (along with the previous issue). In the meantime, I recommend using Dash Cytoscape v0.1.1 if you do not need image export and responsive relayout.

xhluca commented 3 years ago

Actually I just tried this with pure HTML/JavaScript (see this gist) and it seems like the problem also exists there. I'm lead to believe this is an issue with Cytoscape.js.

@riverchen99 Let me know if you can run the gist and if it matches the undesired behavior. If that's the case I think it's good to open a PR in this repo and link to this issue.

riverchen99 commented 3 years ago

Thanks for your help @xhlulu ! Your gist with reproduces the error when I try to run it. Will open a PR in the dagre repo. Appreciate your help!

xhluca commented 3 years ago

Let me know when the fix is merged & published, so I can add it to the roadmap for future dash-cytoscape versions