如何在Python中高效地创建交互式有向网络图(带箭头)?

edqdpe6u  于 2023-02-07  发布在  Python
关注(0)|答案(4)|浏览(175)

为了构建一个有向网络图,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)

我也愿意尝试其他可视化软件包,如果在散景或其他情况下有好的方法的话。

qvtsj1bj

qvtsj1bj1#

下面是一个使用循环在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)
55ooxyrt

55ooxyrt2#

我是gravis的作者,这是Python中的一个交互式图形可视化包,它可以识别来自几个网络分析包(如NetworkX、igraph或graph-tool)的图形对象。
下面是一个用NetworkX创建有向图并用gravis将其可视化的最小示例。

import gravis as gv
import networkx as nx

g = nx.DiGraph()
g.add_edges_from([(1, 2), (2, 3), (2, 4), (4, 5), (4, 7), (5, 6), (1, 6), (6, 7)])
gv.d3(g)
ippsafx7

ippsafx73#

是的,我同意注解解决方案并不是那么有效。这对你想做的事情有用吗: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

gg58donl

gg58donl4#

根据@Aspire的回答,示例中有边/箭头配置和结果图像:

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=[10, 10, 10, 10]),
    marker_size=20, # Node size
)

# Edges
x0 = [1, 2]
y0 = [3, 3]
x1 = [2, 1]
y1 = [4, 4]

fig = go.Figure(
    data=[trace],
    layout=go.Layout(
        height=700, #height of image in pixels.
        width=1000, #Width of image in pixels.
        annotations = [
            dict(
                ax=x0[i], 
                ay=y0[i], 
                axref='x', 
                ayref='y',
                x=x1[i], 
                y=y1[i], 
                xref='x', 
                yref='y',
                arrowwidth=5, # Width of arrow.
                arrowcolor="red",
                arrowsize=0.8, # (1 gives head 3 times as wide as arrow line)
                showarrow=True, 
                arrowhead=1,) for i in range(0, len(x0))
        ]
    )
) 
py.plot(fig)

产量:x1c 0d1x

相关问题