如何在 Python 上高效地创建交互式有向网络图(带箭头)?
How to efficiently create interactive directed network graphs (with arrows) on Python?
为了构建有向网络图,Plotly目前的做法似乎是使用注解。当边缘很少并且可以通过图形布局手动填充每个边缘时,这会起作用,例如 this example.
但是如果我要创建一个复杂得多的图,有没有一种好的方法可以迭代定义所有边的箭头坐标(我只能考虑构造一个字符串然后使用 eval()
,虽然我知道这是不好的做法)? (编辑:似乎这种连接迭代生成的 dict()
定义字符串的方法不起作用——仅适用于一个 dict()
定义)
编辑:添加代码片段以更好地说明场景(注释掉 eval()
行以进行比较):
import plotly.offline as py
import plotly.graph_objs as go
trace = go.Scatter(
x=[1, 2, 2, 1],
y=[3, 4, 3, 4],
mode='markers',
marker=dict(size=[100, 100, 100, 100])
)
fig = go.Figure(
data=[trace],
layout=go.Layout(
annotations = [
dict(
ax=1, ay=3, axref='x', ayref='y',
x=2, y=4, xref='x', yref='y'
),
# eval("dict(ax=2, ay=3, axref='x', ayref='y', x=1, y=4, xref='x', yref='y')")
]
)
)
py.plot(fig)
如果在 Bokeh 或其他工具下有好的方法,我也愿意尝试其他可视化包。
下面是使用循环在 Plotly 图中创建箭头的示例,它很容易应用于有向图的 NetworkX 可视化。
import plotly.offline as py
import plotly.graph_objs as go
trace = go.Scatter(
x=[1, 2, 2, 1],
y=[3, 4, 3, 4],
mode='markers',
marker=dict(size=[100, 100, 100, 100])
)
# Edges
x0 = [1, 2]
y0 = [3, 3]
x1 = [2, 1]
y1 = [4, 4]
fig = go.Figure(
data=[trace],
layout=go.Layout(
annotations = [
dict(ax=x0[i], ay=y0[i], axref='x', ayref='y',
x=x1[i], y=y1[i], xref='x', yref='y',
showarrow=True, arrowhead=1,) for i in range(0, len(x0))
]
)
)
py.plot(fig)
是的,我同意注释解决方案效率不高。这是否适用于您正在尝试做的事情:https://github.com/redransil/plotly-dirgraph
import plotly.graph_objects as go
import networkx as nx
import dash
import dash_core_components as dcc
import dash_html_components as html
from addEdge import addEdge
# Controls for how the graph is drawn
nodeColor = 'Blue'
nodeSize = 20
lineWidth = 2
lineColor = '#000000'
# Make a random graph using networkx
G = nx.random_geometric_graph(5, .5)
pos = nx.layout.spring_layout(G)
for node in G.nodes:
G.nodes[node]['pos'] = list(pos[node])
# Make list of nodes for plotly
node_x = []
node_y = []
for node in G.nodes():
x, y = G.nodes[node]['pos']
node_x.append(x)
node_y.append(y)
# Make a list of edges for plotly, including line segments that result in arrowheads
edge_x = []
edge_y = []
for edge in G.edges():
# addEdge(start, end, edge_x, edge_y, lengthFrac=1, arrowPos = None, arrowLength=0.025, arrowAngle = 30, dotSize=20)
start = G.nodes[edge[0]]['pos']
end = G.nodes[edge[1]]['pos']
edge_x, edge_y = addEdge(start, end, edge_x, edge_y, .8, 'end', .04, 30, nodeSize)
edge_trace = go.Scatter(x=edge_x, y=edge_y, line=dict(width=lineWidth, color=lineColor), hoverinfo='none', mode='lines')
node_trace = go.Scatter(x=node_x, y=node_y, mode='markers', hoverinfo='text', marker=dict(showscale=False, color = nodeColor, size=nodeSize))
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
showlegend=False,
hovermode='closest',
margin=dict(b=20,l=5,r=5,t=40),
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
)
# Note: if you don't use fixed ratio axes, the arrows won't be symmetrical
fig.update_layout(yaxis = dict(scaleanchor = "x", scaleratio = 1), plot_bgcolor='rgb(255,255,255)')
app = dash.Dash()
app.layout = html.Div([dcc.Graph(figure=fig)])
app.run_server(debug=True, use_reloader=False)
示例:
directed graph output
library d3graph may be use. You can specify directed edges. It is a force-directed d3-graph. More information is posted here: Django and interactive graph/network visualization
为了构建有向网络图,Plotly目前的做法似乎是使用注解。当边缘很少并且可以通过图形布局手动填充每个边缘时,这会起作用,例如 this example.
但是如果我要创建一个复杂得多的图,有没有一种好的方法可以迭代定义所有边的箭头坐标(我只能考虑构造一个字符串然后使用 eval()
,虽然我知道这是不好的做法)? (编辑:似乎这种连接迭代生成的 dict()
定义字符串的方法不起作用——仅适用于一个 dict()
定义)
编辑:添加代码片段以更好地说明场景(注释掉 eval()
行以进行比较):
import plotly.offline as py
import plotly.graph_objs as go
trace = go.Scatter(
x=[1, 2, 2, 1],
y=[3, 4, 3, 4],
mode='markers',
marker=dict(size=[100, 100, 100, 100])
)
fig = go.Figure(
data=[trace],
layout=go.Layout(
annotations = [
dict(
ax=1, ay=3, axref='x', ayref='y',
x=2, y=4, xref='x', yref='y'
),
# eval("dict(ax=2, ay=3, axref='x', ayref='y', x=1, y=4, xref='x', yref='y')")
]
)
)
py.plot(fig)
如果在 Bokeh 或其他工具下有好的方法,我也愿意尝试其他可视化包。
下面是使用循环在 Plotly 图中创建箭头的示例,它很容易应用于有向图的 NetworkX 可视化。
import plotly.offline as py
import plotly.graph_objs as go
trace = go.Scatter(
x=[1, 2, 2, 1],
y=[3, 4, 3, 4],
mode='markers',
marker=dict(size=[100, 100, 100, 100])
)
# Edges
x0 = [1, 2]
y0 = [3, 3]
x1 = [2, 1]
y1 = [4, 4]
fig = go.Figure(
data=[trace],
layout=go.Layout(
annotations = [
dict(ax=x0[i], ay=y0[i], axref='x', ayref='y',
x=x1[i], y=y1[i], xref='x', yref='y',
showarrow=True, arrowhead=1,) for i in range(0, len(x0))
]
)
)
py.plot(fig)
是的,我同意注释解决方案效率不高。这是否适用于您正在尝试做的事情:https://github.com/redransil/plotly-dirgraph
import plotly.graph_objects as go
import networkx as nx
import dash
import dash_core_components as dcc
import dash_html_components as html
from addEdge import addEdge
# Controls for how the graph is drawn
nodeColor = 'Blue'
nodeSize = 20
lineWidth = 2
lineColor = '#000000'
# Make a random graph using networkx
G = nx.random_geometric_graph(5, .5)
pos = nx.layout.spring_layout(G)
for node in G.nodes:
G.nodes[node]['pos'] = list(pos[node])
# Make list of nodes for plotly
node_x = []
node_y = []
for node in G.nodes():
x, y = G.nodes[node]['pos']
node_x.append(x)
node_y.append(y)
# Make a list of edges for plotly, including line segments that result in arrowheads
edge_x = []
edge_y = []
for edge in G.edges():
# addEdge(start, end, edge_x, edge_y, lengthFrac=1, arrowPos = None, arrowLength=0.025, arrowAngle = 30, dotSize=20)
start = G.nodes[edge[0]]['pos']
end = G.nodes[edge[1]]['pos']
edge_x, edge_y = addEdge(start, end, edge_x, edge_y, .8, 'end', .04, 30, nodeSize)
edge_trace = go.Scatter(x=edge_x, y=edge_y, line=dict(width=lineWidth, color=lineColor), hoverinfo='none', mode='lines')
node_trace = go.Scatter(x=node_x, y=node_y, mode='markers', hoverinfo='text', marker=dict(showscale=False, color = nodeColor, size=nodeSize))
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
showlegend=False,
hovermode='closest',
margin=dict(b=20,l=5,r=5,t=40),
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
)
# Note: if you don't use fixed ratio axes, the arrows won't be symmetrical
fig.update_layout(yaxis = dict(scaleanchor = "x", scaleratio = 1), plot_bgcolor='rgb(255,255,255)')
app = dash.Dash()
app.layout = html.Div([dcc.Graph(figure=fig)])
app.run_server(debug=True, use_reloader=False)
示例: directed graph output
library d3graph may be use. You can specify directed edges. It is a force-directed d3-graph. More information is posted here: Django and interactive graph/network visualization