在Python中绘制有向图,以分别显示所有边

时间:2012-04-30 06:33:52

标签: python graph-visualization

我正在使用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)

Output from NetworkX; parallel edges are overlapping, so only two lines are displayed

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

Desired output format; parallel edges are drawn separately

问题R reciprocal edges in igraph in R似乎处理同样的问题,但解决方案存在于R igraph库,而不是Python库。

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

我愿意接受调用外部程序来生成图像的解决方案。我想生成一系列动画帧,因此解决方案必须自动化。

4 个答案:

答案 0 :(得分:23)

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

例如,给出:

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

  B -> A;
  C -> B;
}

dot会产生:

example graph

Graphviz的输入语言非常简单,所以你可以自己生成它,虽然搜索“python graphviz”确实会出现几个库,包括graphviz module on PyPI

这是使用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(file_name, view=True)

答案 1 :(得分:11)

使用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)

为什么需要seek(0),请参阅How to create an image from a string in 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)

答案 2 :(得分:8)

也许我来晚了,但我找到了另一个解决您问题的方法,因此我将其发布,以便在有人遇到相同问题时提供帮助。 这会将connectionstyle参数添加到nx.draw:

net\bytebuddy

在这里您看到结果:

The result

答案 3 :(得分:1)

您可以通过使用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()

enter image description here