29

我正在使用 Python 来模拟在有向图上发生的过程。我想制作这个过程的动画。

我遇到的问题是大多数 Python 图形可视化库将成对的有向边组合成一条边。例如,NetworkX在显示下图时仅绘制两条边,而我想分别显示四个边中的每一条:

import networkx as nx
import matplotlib.pyplot as plt 

G = nx.MultiDiGraph()

G.add_edges_from([
    (1, 2),
    (2, 3),
    (3, 2),
    (2, 1),
])

plt.figure(figsize=(8,8))
nx.draw(G)

NetworkX 的输出; 平行边是重叠的,所以只显示两条线

我想显示这样的东西,每个平行边分别绘制:

所需的输出格式; 平行边分别绘制

问题R reciprocal edges in igraph in R似乎解决了同样的问题,但解决方案是针对 R igraph 库,而不是 Python 库。

有没有一种简单的方法可以使用现有的 Python 图形可视化库来生成这种风格的绘图?如果它可以支持多图,那将是一个奖励。

我对调用外部程序来生成图像的解决方案持开放态度。我想生成一系列动画帧,所以解决方案必须是自动化的。

4

4 回答 4

31

Graphviz工具似乎显示了不同的边缘。

例如,给出这个:

digraph G {
  A -> B;
  A -> B;
  A -> B;
  B -> C;

  B -> A;
  C -> B;
}

产生dot

示例图

Graphviz 的输入语言非常简单,因此您可以自己生成它,尽管搜索“python graphviz”确实会出现几个库,包括graphvizPyPI 上的一个模块

graphviz这是使用模块生成上述图表的python :

from graphviz import Digraph

dot = Digraph()
dot.node('A', 'A')
dot.node('B', 'B')
dot.node('C', 'C')
dot.edges(['AB', 'AB', 'AB', 'BC', 'BA', 'CB'])

print(dot.source)
dot.render(view=True)
于 2012-05-02T18:33:58.767 回答
13

使用 NetworkX,避免文件 I/O 并通过 pydot 使用 dot 进行布局的可能解决方法是:

import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from io import BytesIO

g = nx.dodecahedral_graph()
d = nx.drawing.nx_pydot.to_pydot(g)
    # `d` is a `pydot` graph object,
    # `dot` options can be easily set
    # attributes get converted from `networkx`,
    # use set methods to control
    # `dot` attributes after creation
png_str = d.create_png()
sio = BytesIO() # file-like string, appropriate for imread below
sio.write(png_str)
sio.seek(0)
img = mpimg.imread(sio)
imgplot = plt.imshow(img)
plt.show()  # added to make the script wait before exiting

为什么seek(0)需要,请参阅如何从 python 中的字符串创建图像

如果在 IPython (qt) 控制台中,则上述内容将内联打印,更直接的方法是:

import networkx as nx
from IPython.display import Image

g = nx.dodecahedral_graph()
d = nx.drawing.nx_pydot.to_pydot(g)

png_str = d.create_png()
Image(data=png_str)
于 2013-07-24T00:10:34.693 回答
13

也许我有点晚了,但我找到了另一个解决你问题的方法。我发布它是为了如果有人遇到同样的问题,它会有所帮助。

通过将参数传递给函数,可以networkx使用 using以边缘单独出现的方式绘制有向图:matplotlibconnectionstylenetworkx.drawing.nx_pylab.draw

import matplotlib.pyplot as plt
import networkx as nx


# create a directed multi-graph
G = nx.MultiDiGraph()
G.add_edges_from([
    (1, 2),
    (2, 3),
    (3, 2),
    (2, 1),
])
# plot the graph
plt.figure(figsize=(8,8))
nx.draw(G, connectionstyle='arc3, rad = 0.1')
plt.show()  # pause before exiting

在这里你可以看到结果:

结果

另请参阅about the argument的文档matplotlib.patches.ConnectionStyleconnectionstyle

于 2020-01-26T09:59:15.093 回答
3

您可以通过使用 matplotlib 接口来做到这一点:

G=nx.MultiGraph ([(1, 2),
   (2, 3),
   (3, 2),
   (2, 1)])
pos = {1: (0.4,0.5), 2: (0.5,0.5), 3: (0.6,0.5)}
nx.draw_networkx_nodes(G, pos, node_color = 'k', node_size = 100, alpha = 1)
ax = plt.gca()
for e in G.edges:
    ax.annotate("",
                xy=pos[e[0]], xycoords='data',
                xytext=pos[e[1]], textcoords='data',
                arrowprops=dict(arrowstyle="->", color="0.5",
                                shrinkA=5, shrinkB=5,
                                patchA=None, patchB=None,
                                connectionstyle="arc3,rad=rrr".replace('rrr',str(2*(e[2]-0.5))
                                ),
                                ),
                )
plt.axis('off')
plt.show()

在此处输入图像描述

于 2020-04-30T13:26:13.953 回答