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.
--Visualize the directed graph from the two-column data frame from and to. --input image
--Delivery image
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()
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 ">
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",
}
--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'
}
}
]
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.
app.py
@app.callback(Output('cytoscape', 'layout'),
[Input('dropdown-layout', 'value')])
def update_cytoscape_layout(layout):
return {'name': layout}
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)
$ python app.py
I think we have achieved network visualization like R's visNetwork. Please give it a try.
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()
Recommended Posts