Python Matplotlib+;NetworkX-在一个图形中绘制两个网络

Python Matplotlib+;NetworkX-在一个图形中绘制两个网络,python,matplotlib,networkx,Python,Matplotlib,Networkx,如果您知道如何使用Matplotlib,您可能可以在不了解NetworkX的情况下回答问题 我有两个网络使用NetworkX绘制,我想在一个图形中并排绘制,显示每个网络的轴。本质上,这是在Matplotlib(NetworkX用于绘制图形的库)中创建2个子图的问题 网络的每个节点的位置分布在[0,area_size]的区域内,但通常没有坐标x=0.0或y=area_size的点。也就是说,点出现在[0,area_size]或更小的区域内。不是更大 每个子图的比例应为0.8 x 1.0,由比例为0

如果您知道如何使用Matplotlib,您可能可以在不了解NetworkX的情况下回答问题

我有两个网络使用NetworkX绘制,我想在一个图形中并排绘制,显示每个网络的轴。本质上,这是在Matplotlib(NetworkX用于绘制图形的库)中创建2个子图的问题

网络的每个节点的位置分布在[0,area_size]的区域内,但通常没有坐标x=0.0或y=area_size的点。也就是说,点出现在[0,area_size]或更小的区域内。不是更大

每个子图的比例应为0.8 x 1.0,由比例为0.16 x 1.0的区域分隔

本质上,它应该是这样的(假设面积_size=100)

然后我必须在两个图之间画线,所以我需要一些方法回到每个图中的位置,以便连接它们

节点位置的生成、存储和分配如下

# generate and store node positions
positions = {}
for node_id in G.nodes():
    pos_x = # generate pos_x in [0.0, area_size]
    pos_y = # generate pos_y in [0.0, area_size]

    positions[node_id]['x'] = pos_x
    positions[node_id]['y'] = pos_y

    G.node[node_id]['x'] = pos_x
    G.node[node_id]['y'] = pos_y
这些位置然后存储在字典
pos={node_id:(x,y),…}
中。NetworkX获取此结构以在正确位置绘制节点
nx。绘制网络(G,pos=positions)

现在,我做以下工作:

  • 计算第一个网络在[0,area_size]上的位置,然后将其拉伸到[0,area_size*0.8]
  • 用同样的方法计算第二个网络的位置
  • 将第二个网络的位置向右移动,将area_size*0.8+area_size*0.16相加到x坐标
  • 设置体形尺寸(以英寸为单位)
    plt.体形(figsize=(h,w),dpi=100)
  • 设置x轴
    plt.xlim(0.0,面积大小*0.8*2+面积大小*0.16)
  • 设置y轴
    plt.ylim(0.0,面积大小)
  • 绘制第一个网络(通过其位置)
  • 绘制第二个网络(通过其位置)
  • 在两个网络之间画线
我得到的绘图具有正确的比例,但轴未显示正确的信息。我应该隐藏轴并绘制虚拟轴吗

我可能需要一些更好的程序来画合适的子图

我还注意到,当我导出到pdf时,我设置的体形大小并不总是得到尊重

NetworkX用于绘制图形的函数是我正在使用的


如果单独的轴太麻烦的话,我真的不介意绘制它们。

我发现要让Matplotlib生成精确的比例需要一些调整。通常需要进行一些简单的计算,以计算出所需的比率(例如,通过测量,您希望每个子地块的高度为其宽度的1.25)

至于PDF不考虑图形大小,可能是因为您指定了DPI。无需指定DPI,因为PDF是以矢量格式保存的。或者您可能正在使用
plt.tight_layout
功能,该功能可能很有用,但会改变图形大小

在子地块之间画线有点像噩梦。首先,必须使用从轴坐标系转换到地物坐标系。然后你可以直接在图上画线。可能会有帮助

下面的代码应该会有所帮助。你需要以各种方式调整它,但希望它能帮助你生成你想要的图形

import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.lines as lines

# Generate some random graphs and positions for demonstrative purposes.
G1 = nx.gnp_random_graph(10, 0.2)
G2 = nx.gnp_random_graph(10, 0.2)
pos1 = nx.spring_layout(G1)
pos2 = nx.spring_layout(G2)

# Set up the figure with two subplots and a figure size of 6.5 by 4 inches.
fig, ax = plt.subplots(1, 2, figsize=(6.5, 4))

# Set the x and y limits for each axis, leaving a 0.2 margin te ensure
# that nodes near the edges of the graph are not clipped.
ax[0].set_xlim([-0.2, 1.2])
ax[0].set_ylim([-0.2, 1.2])
ax[1].set_xlim([-0.2, 1.2])
ax[1].set_ylim([-0.2, 1.2])

# Stretch the subplots up, so that each unit in the y direction appears 1.25
# times taller than the width of each unit in the x direction.
ax[0].set_aspect(1.25)
ax[1].set_aspect(1.25)

# Remove the tick labels from the axes.
ax[0].xaxis.set_visible(False)
ax[0].yaxis.set_visible(False)
ax[1].xaxis.set_visible(False)
ax[1].yaxis.set_visible(False)

# Set the space between the subplots to be 0.2 times their width.
# Also reduce the margins of the figure.
plt.subplots_adjust(wspace=0.2, left=0.05, right=0.95, bottom=0.05, top=0.95)

# Draw the networks in each subplot
nx.draw_networkx(G1, pos1, ax=ax[0], node_color='r')
nx.draw_networkx(G2, pos2, ax=ax[1], node_color='b')

# Now suppose we want to draw a line between nodes 5 in each subplot. First, we need to
# be able to convert from the axes coordinates to the figure coordinates, like so.
# (Read the matplotlib transformations documentation for more detail).
def ax_to_fig(coordinates, axis):
    transFig = fig.transFigure.inverted()
    return transFig.transform((axis.transData.transform((coordinates))))

# Now we can get the figure coordinates for the nodes we want to connect.
line_start = ax_to_fig(pos1[5], ax[0])
line_end = ax_to_fig(pos2[5], ax[1])

# Create the line and draw it on the figure.
line = lines.Line2D((line_start[0], line_end[0]), (line_start[1], line_end[1]), transform=fig.transFigure)
fig.lines = [line]

# Save the figure.
plt.savefig('test_networks.pdf', format='pdf')
编辑

上面的代码似乎没有精确地在相应节点的中心之间绘制轴之间的线。删除
ax.set\u aspect
函数可以解决这个问题,但是现在比例是错误的。为了适应这种情况,您可以手动更改节点的y位置(NetworkX使其变得比应有的困难得多)。接下来,您必须更改
ax.set_ymin
值以获得正确的比例,如下所示:

# Manually rescale the positions of the nodes in the y-direction only.
for node in pos1:
    pos1[node][1] *= 1.35
for node in pos2:
    pos2[node][1] *= 1.35

# Set the x and y limits for each axis, leaving a 0.2 margin te ensure
# that nodes near the edges of the graph are not clipped.
ax[0].set_xlim([-0.2, 1.2])
ax[0].set_ylim([-0.2, 1.55])
ax[1].set_xlim([-0.2, 1.2])
ax[1].set_ylim([-0.2, 1.55])

将要打印到的轴对象作为
ax
kwarg传递到
draw\u networkx
。我对matplotlib很陌生。我可以直接在主绘图上修改轴,但我不明白如何使用
ax
绘制我描述的2个网络。另外,两个网之间也有界线。谢谢。这些图形看起来不错,但是它们之间的线条没有击中节点的确切中心。注释行
ax[…]。设置切面(…)
我看到中心完美连接,而将切面更改为
0.8
会使情况变得更糟。也许有错误?我编辑了这篇文章来解决这个问题。解决方案有点复杂。也许有一种更简单的方式处理事情,但至少它是有效的。谢谢。您可能指的是
1.35
,或者更一般地说是
y_scale
。我还将创建一个
margin
变量来保存
0.2
。但是,此解决方案不允许正确标记轴。也许有办法绕过这个画出假轴?我想在不清除图形的情况下,用正确的轴绘制两个空的子图是可行的。我想我不太清楚你想做什么。也许你可以编辑你的问题来包含你的代码。否则,我认为了解以下几点会有所帮助:1)是否需要显示勾号标签?2) 您是手动生成节点位置,还是让NetworkX为您生成节点位置?以及3)节点的位置是否重要,或者它们是任意的?更新的问题。谢谢你的关注。轴刻度将是很好的。