使用subplot时,networkx绘制的节点部分超出了坐标轴框架

3
当我在子图中绘制一个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不适合该框架中。
Minimal example

你使用的是哪个版本的 networkxmatplotlib?我在 2.2 版本的 networkx 和 3.0.2 版本的 matplotlib 上尝试了你的代码,但无论如何都无法复现你的图形。同样的情况也出现在 networkx 2.4 和 matplotlib 3.1.3 上。 - Sparky05
@Sparky05 我正在使用 networkx 2.4 和 matplotlib 3.2.1。 - chasmani
在我第二个环境(nx 2.4)中升级了matplotlib之后,我现在可以复现你的错误。你的问题可能是由于版本3.2.0引入的matplotlib不同的自动缩放引起的。 - Sparky05
3个回答

5

背景

您遇到的问题似乎是由于在matplotlib 3.2.0中引入的新的自适应缩放算法引起的。链接中指出,旧算法会对Axes.scatter做出以下处理:

对于Axes.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()

2
只需要调整图形大小就可以解决问题。尝试通过子图的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')

enter image description here


您还可以查看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')

enter image description here


1
由于其他答案需要用户手动调整一些参数进行迭代过程,因此我想添加自己的答案。它是自动的,但是当前实现仅在所有节点大小相等时有效。
节点大小以点为单位,因此它们不随图像缩放而变化。虽然此答案在程序上可以工作,但如果您交互式更改图形的窗口大小,则无法正常工作。`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()

样例结果


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接