我正在使用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)
我想显示这样的东西,每个平行边缘分开绘制:
问题R reciprocal edges in igraph in R似乎处理同样的问题,但解决方案存在于R igraph库,而不是Python库。
有没有一种简单的方法可以使用现有的Python图形可视化库生成这种样式的绘图?如果它可以支持多图,那将是一个奖励。
我愿意接受调用外部程序来生成图像的解决方案。我想生成一系列动画帧,因此解决方案必须自动化。
答案 0 :(得分:23)
Graphviz工具似乎显示不同的边缘。
例如,给出:
digraph G {
A -> B;
A -> B;
A -> B;
B -> C;
B -> A;
C -> B;
}
到dot
会产生:
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
在这里您看到结果:
答案 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()