plotly / dash-cytoscape

Interactive network visualization in Python and Dash, powered by Cytoscape.js

Home Page:https://dash.plot.ly/cytoscape

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

edgelength proportional to weight

spike4848 opened this issue · comments

Description

I am trying to create a physics direct network graph using Dash Cytoscape. I have tried using Cose, Cose-Bilkent and now Cola, but my issue is that I cannot get the edge lengths to be clearly directly proportional to the weight.

In JS in Cola you can in the layout parameters for 'edgeLength' set to a function e.g. function(e){ return params.edgeLengthVal / e.data('weight'); }, but in Python I can't work out the alternative. Passing a defined function doesn't work, nor does passing a dict to layout, or specifying the EdgeLength for each element within the data dict.

If I could achieve something like this but in Python that would be ideal. I want to do it in Python as this is one of a series of Dash graphs which are part of a larger project entirely built in Python, and I am not familiar with JS.

Steps/Code to Reproduce

Example:

import json

import dash
import dash_html_components as html

import dash_cytoscape as cyto
cyto.load_extra_layouts()
app = dash.Dash(__name__)
server = app.server

app.scripts.config.serve_locally = True
app.css.config.serve_locally = True

# Load Data
with open('data.json', 'r') as f:
    elements = json.loads(f.read())

nodes = [{"data":{"id":"1",'name':'1','score':1},"group": "nodes"},
         {"data":{"id":"2",'name':'2','score':0.1},"group": "nodes"},
         {"data":{"id":"3",'name':'3','score':0.1},"group": "nodes"},
         {"data":{"id":"4",'name':'4','score':0.1},"group": "nodes"}]

edges = [
    {"data":{"id":"1-2","source":"1","target":"2","weight":1},"group": "edges"},
    {"data":{"id":"1-3","source":"1","target":"3","weight":0.1},"group": "edges"},
    {"data":{"id":"1-4","source":"1","target":"4","weight":0.1},"group": "edges"},
    {"data":{"id":"2-3","source":"2","target":"3","weight":0.1},"group": "edges"},
    {"data":{"id":"2-4","source":"2","target":"4","weight":0.1},"group": "edges"},
    {"data":{"id":"3-4","source":"3","target":"4","weight":0.1,"edgeLength":20000},"group": "edges"}
]
elements = nodes + edges
print(elements)


with open('cy-style_2.json', 'r') as f:
    stylesheet = json.loads(f.read())

def length(edge):
    distance = 100/edge['data']['weight']
    return distance

# App
app.layout = html.Div([
    cyto.Cytoscape(
        id='cytoscape',
        elements=elements,
        stylesheet=stylesheet,
        style={
            'width': '100%',
            'height': '100%',
            'position': 'absolute',
            'left': 0,
            'top': 0,
            'z-index': 999

        },
        layout={
            'name': 'cola',
            'EdgeLength': length,
            'maxSimulationTime': 8000,
            'convergenceThreshold': 0.001,
            'nodeOverlap': 20,
            'refresh': 20,
            'fit': True,
            'padding': 30,
            'randomize': True,
            'componentSpacing': 100,
            'nodeRepulsion': 400000,
            'edgeElasticity': 100000,
            'nestingFactor': 5,
            'gravity': 80,
            'numIter': 1000,
            'initialTemp': 200,
            'coolingFactor': 0.95,
            'minTemp': 1.0
        }
    )
])
print(app.layout)
if __name__ == '__main__':
    app.run_server(debug=True)

It would also be great to be able to make the attractive force proportional to the weight