ChatGPT解决这个技术问题 Extra ChatGPT

使用 matplotlib 中的许多子图改进子图大小/间距

this question 非常相似,但不同之处在于我的图可以根据需要变大。

我需要在 matplotlib 中生成一大堆垂直堆叠的图。结果将使用 figsave 保存并在网页上查看,所以我不在乎最终图像的高度,只要子图之间有间距,它们不会重叠。

无论我允许这个数字有多大,子图似乎总是重叠。

我的代码目前看起来像

import matplotlib.pyplot as plt
import my_other_module

titles, x_lists, y_lists = my_other_module.get_data()

fig = plt.figure(figsize=(10,60))
for i, y_list in enumerate(y_lists):
    plt.subplot(len(titles), 1, i)
    plt.xlabel("Some X label")
    plt.ylabel("Some Y label")
    plt.title(titles[i])
    plt.plot(x_lists[i],y_list)
fig.savefig('out.png', dpi=100)
此问题也适用于带有子图的 pandas.DataFrame.plot,以及 seaborn 轴级图(带有 ax 参数的图):sns.lineplot(..., ax=ax)

T
Trenton McKinney

尝试使用 plt.tight_layout

举个简单的例子:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=4, ncols=4)
fig.tight_layout() # Or equivalently,  "plt.tight_layout()"

plt.show()

没有紧凑的布局

https://i.stack.imgur.com/roV9q.png

https://i.stack.imgur.com/ouSJi.png


值得一提的是,这必须在 添加重叠方面后应用。我的 x 和 y 标签与相邻的图重叠,直到我移动 fig.tight_layout() 之后。可以把这个功能想象成“我的图形布局太紧了,请重新调整”
这对我来说似乎是一个糟糕的默认值。有人想知道为什么必须调用它而不是自动完成是否有合理的理由?
B
Brian Burns

您可以使用 plt.subplots_adjust 更改子图之间的间距 (source)

调用签名:

subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

参数含义(和建议的默认值)是:

left  = 0.125  # the left side of the subplots of the figure
right = 0.9    # the right side of the subplots of the figure
bottom = 0.1   # the bottom of the subplots of the figure
top = 0.9      # the top of the subplots of the figure
wspace = 0.2   # the amount of width reserved for blank space between subplots
hspace = 0.2   # the amount of height reserved for white space between subplots

实际的默认值由 rc 文件控制


我试过弄乱hspace,但增加它似乎只会使所有的图变小而没有解决重叠问题。我也尝试过使用其他参数,但我不知道 left、right、bottom 和 top 在那里实际指定了什么。
@mcstrother 如果您在显示绘图后单击“调整”按钮,则可以交互地更改所有 6 个参数,然后在找到有效的方法后将它们复制到代码中。
我没有看到调整按钮。虽然我在 Jupyter 笔记本中。我尝试了 %matplotlib inline 和 %matplotlib 笔记本。
@MattKleinsmith:调整按钮具有悬停文本“配置子图”,并出现在 Matplotlib 的常规非笔记本用途中。它是此处“软盘”保存按钮左侧的按钮:pythonspot-9329.kxcdn.com/wp-content/uploads/2016/07/… - 请注意,根据您使用的窗口系统,该按钮看起来会有所不同,但它始终位于保存按钮的左侧。
@JohnZwinck,您评论中的链接现在已失效。
A
Alexa Halford

我发现 subplots_adjust(hspace = 0.001) 最终对我有用。当我使用 space = None 时,每个图之间仍然有空白。然而,将其设置为非常接近于零的值似乎会迫使他们排队。我在这里上传的不是最优雅的一段代码,但你可以看到 hspace 是如何工作的。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tic

fig = plt.figure()

x = np.arange(100)
y = 3.*np.sin(x*2.*np.pi/100.)

for i in range(5):
    temp = 510 + i
    ax = plt.subplot(temp)
    plt.plot(x,y)
    plt.subplots_adjust(hspace = .001)
    temp = tic.MaxNLocator(3)
    ax.yaxis.set_major_locator(temp)
    ax.set_xticklabels(())
    ax.title.set_visible(False)

plt.show()

https://i.stack.imgur.com/52ZH1.png


此代码产生错误: ValueError Traceback (most recent call last) in 10 for i in range(5): 11 temp = 510 + i ---> 12 ax = plt .subplot(temp) ValueError: num 必须是 1 <= num <= 5,而不是 0
S
Steven C. Howell

tight_layout 类似,matplotlib 现在(从 2.2 版开始)提供 constrained_layouttight_layout 可以在代码中随时调用以用于单个优化布局,与此相反,constrained_layout 是一个属性,它可能处于活动状态,并且会在每个绘制步骤之前优化布局。

因此,它需要在子图创建之前或期间激活,例如 figure(constrained_layout=True)subplots(constrained_layout=True)

例子:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(4,4, constrained_layout=True)

plt.show()

https://i.stack.imgur.com/HcF1b.png

也可以通过 rcParams 设置 constrained_layout

plt.rcParams['figure.constrained_layout.use'] = True

请参阅 what's new entryConstrained Layout Guide


打算试试这个:没见过这个选项 - 并且 tight_layout 不可靠
这听起来很有希望,但没有给我足够的间距(轴标签和标题仍然重叠)并且渲染需要更长的时间。 tight_layout() 效果更好
@craq 正确,通常 contrained_layout 较慢,因为如本答案所示,它在每个绘图步骤之前优化布局
对我来说,这是最有用的答案——对我来说,tight_layout 总是提高垂直间距,为面板标题留出空间,但代价是每次都切断 y 轴标签。相反,这可以完美地工作,谢谢。
@craq,如果您有一个无法正确间隔轴的可重现示例,那么如果您在 github.com/matplotlib/matplotlib 处打开问题将非常有帮助,最新的 Matplotlib (3.4.x) 使用 constrained_layout 更快。
B
Brian Burns
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,60))
plt.subplots_adjust( ... )

plt.subplots_adjust 方法:

def subplots_adjust(*args, **kwargs):
    """
    call signature::

      subplots_adjust(left=None, bottom=None, right=None, top=None,
                      wspace=None, hspace=None)

    Tune the subplot layout via the
    :class:`matplotlib.figure.SubplotParams` mechanism.  The parameter
    meanings (and suggested defaults) are::

      left  = 0.125  # the left side of the subplots of the figure
      right = 0.9    # the right side of the subplots of the figure
      bottom = 0.1   # the bottom of the subplots of the figure
      top = 0.9      # the top of the subplots of the figure
      wspace = 0.2   # the amount of width reserved for blank space between subplots
      hspace = 0.2   # the amount of height reserved for white space between subplots

    The actual defaults are controlled by the rc file
    """
    fig = gcf()
    fig.subplots_adjust(*args, **kwargs)
    draw_if_interactive()

或者

fig = plt.figure(figsize=(10,60))
fig.subplots_adjust( ... )

图片的大小很重要。

“我尝试过弄乱 hspace,但增加它似乎只会使所有图形变小而没有解决重叠问题。”

因此,为了创造更多的空白空间并保持子图大小,总图像需要更大。


图片的大小很重要,更大的图片大小可以解决这个问题!设置 plt.figure(figsize=(10, 7)),图片的大小将是 2000 x 1400 pix
C
CiaranWelsh

你可以试试 subplot_tool()

plt.subplot_tool()

T
Trenton McKinney

使用 pandas.DataFrame.plot 绘制数据框时解决此问题,它使用 matplotlib 作为默认后端。以下适用于指定的 kind=(例如“bar”、“scatter”、“hist”等)

以下适用于指定的 kind=(例如“bar”、“scatter”、“hist”等)

在 python 3.8.12、pandas 1.3.4、matplotlib 3.4.3 中测试

导入和样本数据

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# sinusoidal sample data
sample_length = range(1, 15+1)
rads = np.arange(0, 2*np.pi, 0.01)
data = np.array([np.sin(t*rads) for t in sample_length])
df = pd.DataFrame(data.T, index=pd.Series(rads.tolist(), name='radians'), columns=[f'freq: {i}x' for i in sample_length])

# display(df.head(3))
         freq: 1x  freq: 2x  freq: 3x  freq: 4x  freq: 5x  freq: 6x  freq: 7x  freq: 8x  freq: 9x  freq: 10x  freq: 11x  freq: 12x  freq: 13x  freq: 14x  freq: 15x
radians                                                                                                                                                            
0.00     0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000  0.000000   0.000000   0.000000   0.000000   0.000000   0.000000   0.000000
0.01     0.010000  0.019999  0.029996  0.039989  0.049979  0.059964  0.069943  0.079915  0.089879   0.099833   0.109778   0.119712   0.129634   0.139543   0.149438
0.02     0.019999  0.039989  0.059964  0.079915  0.099833  0.119712  0.139543  0.159318  0.179030   0.198669   0.218230   0.237703   0.257081   0.276356   0.295520

# default plot with subplots; each column is a subplot
axes = df.plot(subplots=True)

https://i.stack.imgur.com/9K9iM.png

调整间距

调整 pandas.DataFrame.plot 中的默认参数 更改 figsize:每个子图的宽度为 5 和高度为 4 是一个很好的起点 更改布局:(行、列)用于子图的布局。 sharey=True 和 sharex=True 因此不会为每个子图上的冗余标签占用空间。

更改 figsize:每个子图的宽度为 5,高度为 4 是一个不错的起点

更改布局:(行、列)用于子图的布局。

sharey=True 和 sharex=True 因此不会为每个子图上的冗余标签占用空间。

.plot 方法返回一个 matplotlib.axes.Axes 的 numpy 数组,应该将其展平以便于使用。

使用 .get_figure() 从其中一个轴中提取 DataFrame.plot 图形对象。

如果需要,请使用 fig.tight_layout()。

axes = df.plot(subplots=True, layout=(3, 5), figsize=(25, 16), sharex=True, sharey=True)

# flatten the axes array to easily access any subplot
axes = axes.flat

# extract the figure object
fig = axes[0].get_figure()

# use tight_layout
fig.tight_layout()

https://i.stack.imgur.com/ncA2i.png