[Python] Draw a directed graph with Dash Cytoscape

I want to draw a movable directed graph

I wanted to draw a directed graph that can be run on a browser like R's visNetwork in Python.

NetworkX seems to be famous as a Python graph library, but this time I thought that Dash Cytoscape could be used with an image close to R's visNetwork, so I will sample I will write it down.

Start the server locally and check the graph from the browser.

Target

--Visualize the directed graph from the two-column data frame from and to. --input image image.png

--Delivery image forqiita2.gif

environment

Preparation

Prepare an edge data frame with from and to and nodes

app.py


import pandas as pd

edges = pd.DataFrame.from_dict({'from':['TABLE_B', 'TABLE_C', 'TABLE_D', 'TABLE_A', 'TABLE_X', 'TABLE_X'],
                               'to': ['TABLE_A', 'TABLE_A', 'TABLE_A','TABLE_X', 'TABLE_K', 'TABLE_Z']})
nodes = set()
Store the contents of edge and node in a list

app.py


cy_edges = []
cy_nodes = []

for index, row in edges.iterrows():
    source, target = row['from'], row['to']

    if source not in nodes:
        nodes.add(source)
        cy_nodes.append({"data": {"id": source, "label": source}})
    if target not in nodes:
        nodes.add(target)
        cy_nodes.append({"data": {"id": target, "label": target}})

    cy_edges.append({
        'data': {
            'source': source,
            'target': target
        }
    })

<img width=""30%" alt="img" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143058/7b672b05-fa5b-8f75-f2df-97f48e0ddfbd.png ">

Define the style of node / edge

app.py


stylesheet = [
    {
        "selector": 'node', #For all nodes
        'style': {
            "opacity": 0.9,
            "label": "data(label)", #Label of node to display
            "background-color": "#07ABA0", #node color
            "color": "#008B80" #node label color
        }
    },
    {
        "selector": 'edge', #For all edges
        "style": {
            "target-arrow-color": "#C5D3E2", #Arrow color
            "target-arrow-shape": "triangle", #Arrow shape
            "line-color": "#C5D3E2", #edge color
            'arrow-scale': 2, #Arrow size
            'curve-style': 'bezier' #Default curve-If it is style, the arrow will not be displayed, so specify it
    }
}]

――It is possible to customize by referring to the following, such as the style of the arrow. - Cytoscape Styling / Edge Arrows

--Center the position of the arrow

app.py


        "style": {
            "mid-target-arrow-color": "#C5D3E2",
            "mid-target-arrow-shape": "triangle",
        }

image.png

--It is also possible to assign a style to a specific edge or node by defining a condition in "selector".

app.py


stylesheet  = [
    {
        "selector": 'node',
        'style': {
            "opacity": 0.9,
            "label": "data(label)",
            "background-color": "#07ABA0",
            "color": "#008B80"
        }
    },
    {
        "selector": '[label *= "alarm"]', #Only node whose label is alarm"red"To
        'style': {
            "opacity": 0.9,
            "label": "data(label)",
            "background-color": "red",
            "color": "#008B80"
        }
    },
    {
        "selector": 'edge',
        "style": {

            "target-arrow-color": "#C5D3E2",
            "target-arrow-shape": "triangle",
            "line-color": "#C5D3E2",
            'arrow-scale': 2,
            'curve-style': 'bezier'
        }
    }
]

image.png

Define layout

app.py


app.layout = html.Div([
    dcc.Dropdown(
            id='dropdown-layout',
            options=[
                {'label': 'random',
                 'value': 'random'},
                {'label': 'grid',
                 'value': 'grid'},
                {'label': 'circle',
                 'value': 'circle'},
                {'label': 'concentric',
                 'value': 'concentric'},
                {'label': 'breadthfirst',
                 'value': 'breadthfirst'},
                {'label': 'cose',
                 'value': 'cose'}
            ], value='grid'
        ),
    html.Div(children=[
        cyto.Cytoscape(
            id='cytoscape',
            elements=cy_edges + cy_nodes,
            style={
                'height': '95vh',
                'width': '100%'
            },
            stylesheet=stylesheet #Give the style you just defined
        )
    ])

])

――This time, the layout of the graph can be selected from Dropdown.

Create a callback that updates the layout

app.py


@app.callback(Output('cytoscape', 'layout'),
              [Input('dropdown-layout', 'value')])
def update_cytoscape_layout(layout):
    return {'name': layout}

Complete

Full text

app.py


import pandas as pd

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

import dash_cytoscape as cyto

app = dash.Dash(__name__)
server = app.server

# prepare data
edges = pd.DataFrame.from_dict({'from':['earthquake', 'earthquake', 'burglary', 'alarm', 'alarm'],
                               'to': ['report', 'alarm', 'alarm','John Calls', 'Mary Calls']})
nodes = set()

cy_edges = []
cy_nodes = []

for index, row in edges.iterrows():
    source, target = row['from'], row['to']

    if source not in nodes:
        nodes.add(source)
        cy_nodes.append({"data": {"id": source, "label": source}})
    if target not in nodes:
        nodes.add(target)
        cy_nodes.append({"data": {"id": target, "label": target}})

    cy_edges.append({
        'data': {
            'source': source,
            'target': target
        }
    })

# define stylesheet
stylesheet = [
    {
        "selector": 'node', #For all nodes
        'style': {
            "opacity": 0.9,
            "label": "data(label)", #Label of node to display
            "background-color": "#07ABA0", #node color
            "color": "#008B80" #node label color
        }
    },
    {
        "selector": 'edge', #For all edges
        "style": {
            "target-arrow-color": "#C5D3E2", #Arrow color
            "target-arrow-shape": "triangle", #Arrow shape
            "line-color": "#C5D3E2", #edge color
            'arrow-scale': 2, #Arrow size
            'curve-style': 'bezier' #Default curve-If it is style, the arrow will not be displayed, so specify it
    }
}]

# define layout
app.layout = html.Div([
    dcc.Dropdown(
            id='dropdown-layout',
            options=[
                {'label': 'random',
                 'value': 'random'},
                {'label': 'grid',
                 'value': 'grid'},
                {'label': 'circle',
                 'value': 'circle'},
                {'label': 'concentric',
                 'value': 'concentric'},
                {'label': 'breadthfirst',
                 'value': 'breadthfirst'},
                {'label': 'cose',
                 'value': 'cose'}
            ], value='grid'
        ),
    html.Div(children=[
        cyto.Cytoscape(
            id='cytoscape',
            elements=cy_edges + cy_nodes,
            style={
                'height': '95vh',
                'width': '100%'
            },
            stylesheet=stylesheet
        )
    ])
])

@app.callback(Output('cytoscape', 'layout'),
              [Input('dropdown-layout', 'value')])
def update_cytoscape_layout(layout):
    return {'name': layout}

if __name__ == '__main__':
    app.run_server(debug=False)
Run
$ python app.py

image.png

I think we have achieved network visualization like R's visNetwork. Please give it a try.

reference

What is a directed graph? Dash Cytoscape

-If you draw with NetworkX

networkx_sample.py


# https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_directed.html#sphx-glr-auto-examples-drawing-plot-directed-py
# Author: Rodrigo Dorantes-Gilardi ([email protected])
import matplotlib as mpl
import matplotlib.pyplot as plt
import networkx as nx

G = nx.generators.directed.random_k_out_graph(10, 3, 0.5)
pos = nx.layout.spring_layout(G)

node_sizes = [3 + 10 * i for i in range(len(G))]
M = G.number_of_edges()
edge_colors = range(2, M + 2)
edge_alphas = [(5 + i) / (M + 4) for i in range(M)]

nodes = nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color='blue')
edges = nx.draw_networkx_edges(G, pos, node_size=node_sizes, arrowstyle='->',
                               arrowsize=10, edge_color=edge_colors,
                               edge_cmap=plt.cm.Blues, width=2)
# set alpha value for each edge
for i in range(M):
    edges[i].set_alpha(edge_alphas[i])

pc = mpl.collections.PatchCollection(edges, cmap=plt.cm.Blues)
pc.set_array(edge_colors)
plt.colorbar(pc)

ax = plt.gca()
ax.set_axis_off()
plt.show()

image.png

Recommended Posts

[Python] Draw a directed graph with Dash Cytoscape
Draw a graph with NetworkX
Draw a graph with networkx
Draw a graph with Julia + PyQtGraph (2)
Draw a loose graph with matplotlib
Draw a graph with Julia + PyQtGraph (1)
Draw a graph with Julia + PyQtGraph (3)
Draw a graph with pandas + XlsxWriter
Let's make a graph with python! !!
Draw a graph with PySimple GUI
Study math with Python: Draw a sympy (scipy) graph with matplotlib
Draw a graph with PyQtGraph Part 1-Drawing
Draw a flat surface with a matplotlib 3d graph
Draw a graph of a quadratic function in Python
Draw a graph with Japanese labels in Jupyter
How to draw a 2-axis graph with pyplot
Draw a graph with PyQtGraph Part 3-PlotWidget settings
Draw a graph by processing with Pandas groupby
Try to draw a life curve with python
[Python] Draw a Mickey Mouse with Turtle [Beginner]
Draw a graph with PyQtGraph Part 4-PlotItem settings
Draw a graph with matplotlib from a csv file
Draw a graph with PyQtGraph Part 6-Displaying a legend
Draw graph in python
Draw a graph with PyQtGraph Part 5-Increase the Y-axis
[Python] Draw a Qiita tag relationship diagram with NetworkX
I tried to draw a route map with Python
Visualize railway line data as a graph with Cytoscape 2
Forcibly draw something like a flowchart with Python, matplotlib
Draw a graph with PyQtGraph Part 2--Detailed plot settings
[Python] How to draw a scatter plot with Matplotlib
Draw netCDF file with python
Make a fortune with Python
Draw a heart in Python
Create a directory with python
A memo when creating a directed graph using Graphviz in Python
[Visualization] I want to draw a beautiful graph with Plotly
[Python] What is a with statement?
Solve ABC163 A ~ C with Python
Operate a receipt printer with python
A python graphing manual with Matplotlib.
Let's make a GUI with python.
Solve ABC166 A ~ D with Python
Draw a scatterplot matrix in python
Create a virtual environment with Python!
I made a fortune with Python.
Draw a beautiful circle with numpy
Building a virtual environment with Python 3
Solve ABC168 A ~ C with Python
Make a recommender system with python
Draw Koch curve with Python Turtle
[Python] Generate a password with Slackbot
Solve ABC162 A ~ C with Python
Solve ABC167 A ~ C with Python
Solve ABC158 A ~ C with Python
Draw an illustration with Python + OpenCV
Draw a CNN diagram in Python
Make a nice graph with plotly
Draw Lyapunov Fractal with Python, matplotlib
[Python] Inherit a class with class variables
I made a daemon with Python