子图中的 networkx 正在绘制部分位于轴框架之外的节点

networkx in a subplot is drawing nodes partially outside of axes frame

当我在子图中绘制 networkx 图时,一些节点在轴的框架中被部分切断。我已经用所有不同类型的图形和布局尝试过这个,它总是一个问题。它总是切断我的节点。就好像 networkx 在比实际更大的轴上绘制图形。

这是一个最小的例子

plt.subplot(2, 1, 1)
plt.scatter(range(10), range(10))

plt.subplot(2, 1, 2)
G = nx.erdos_renyi_graph(20, p=0.1)
nx.draw_networkx(G)
plt.show()

这就是我从中得到的。如您所见,节点 0 和节点 7 不适合框架。

只需调整一下数字大小就可以了。尝试通过子图的 figsize 参数设置更大的图形尺寸:

f, axs = plt.subplots(2,1,figsize=(15,15))
axs[0].scatter(range(10), range(10))
G = nx.erdos_renyi_graph(20, p=0.1)
nx.draw_networkx(G, ax=axs[1], node_color='lightgreen')


您还可以查看 networkX 的布局,例如 spring_layout,它允许将节点封装在由 scale 参数指定的给定框大小内。这是一个例子:

f, axs = plt.subplots(2,1,figsize=(15,15))
axs[0].scatter(range(10), range(10))
G = nx.erdos_renyi_graph(20, p=0.05)
pos = nx.spring_layout(G, k=0.7, scale=0.05)
nx.draw_networkx(G, pos=pos, ax=axs[1], node_color='lightgreen')

背景

您的问题似乎是由 matplotlib 3.2.0 引入的新 autoscaling 算法引起的。在 link 它指出,旧算法确实

for Axes.scatter it would make the limits large enough to not clip any markers in the scatter.

因此,新算法已停止执行此操作,从而导致出现可爱的节点。

如何解决您的问题

您可以简单地增加轴的长度:

import networkx as nx
import matplotlib.pylab as plt

figure = plt.subplot(2, 1, 1)
plt.scatter(range(10), range(10))

plt.subplot(2, 1, 2)
G = nx.erdos_renyi_graph(20, p=0.1)
nx.draw_networkx(G)
axis = plt.gca()
# maybe smaller factors work as well, but 1.1 works fine for this minimal example
axis.set_xlim([1.1*x for x in axis.get_xlim()])
axis.set_ylim([1.1*y for y in axis.get_ylim()])
plt.show()

由于其他答案需要用户在迭代过程中手动调整一些参数,所以我想添加自己的答案。它是自动的,但当前的实现仅在所有节点大小都相等时才有效。

节点大小以磅为单位,因此它们不随图像缩放。尽管此答案以编程方式工作,但如果您以交互方式更改图的 window 大小,则它不起作用。 fix_graph_scale 函数的前半部分根据未来的 x 和 y 比例计算节点半径。后半部分设置轴比例,使其包括所有节点位置加上节点大小的一半。

get_ax_size 函数来自 unutbu's answer,稍作修改。

import matplotlib.pyplot as plt
import networkx as nx

def get_ax_size(ax):
    bbox = ax.get_window_extent().transformed(ax.figure.dpi_scale_trans.inverted())
    width, height = bbox.width, bbox.height
    width *= 72
    height *= 72
    return width, height

def fix_graph_scale(ax,pos,node_size = 300):

    node_radius = (node_size / 3.14159265359)**0.5

    min_x = min(i_pos[0] for i_pos in pos.values())
    max_x = max(i_pos[0] for i_pos in pos.values())
    min_y = min(i_pos[1] for i_pos in pos.values())
    max_y = max(i_pos[1] for i_pos in pos.values())

    ax_size_x, ax_size_y = get_ax_size(ax)
    points_to_x_axis = (max_x - min_x)/(ax_size_x-node_radius*2)
    points_to_y_axis = (max_y - min_y)/(ax_size_y-node_radius*2)
    node_radius_in_x_axis = node_radius * points_to_x_axis
    node_radius_in_y_axis = node_radius * points_to_y_axis

    ax_min_x = min_x - node_radius_in_x_axis
    ax_max_x = max_x + node_radius_in_x_axis
    ax_min_y = min_y - node_radius_in_y_axis
    ax_max_y = max_y + node_radius_in_y_axis

    ax.set_xlim([ax_min_x, ax_max_x])
    ax.set_ylim([ax_min_y, ax_max_y])

fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.scatter(range(10), range(10))

G = nx.erdos_renyi_graph(20, p=0.1)
pos = nx.drawing.spring_layout(G)
nx.draw_networkx(G,pos,ax=ax2)

default_node_size = 300
fix_graph_scale(ax2,pos,node_size = default_node_size)
plt.show()

Sample result