matplotlib子图的常见xlabel/ylabel

jol*_*dbe 110 python matplotlib

我有以下情节:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
Run Code Online (Sandbox Code Playgroud)

现在我想给这个图绘制常见的x轴标签和y轴标签.对于"常见",我的意思是在整个子图网格下面应该有一个大的x轴标签,在右边有一个大的y轴标签.我在文档中找不到任何关于此的内容plt.subplots,而且我的谷歌搜索建议我需要开始做一个大的plt.subplot(111)- 但是我如何将我的5*2子图用于使用plt.subplots

div*_*nex 176

这看起来像你真正想要的.它对您的具体案例采用与此答案相同的方法:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6))

fig.text(0.5, 0.04, 'common X', ha='center')
fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical')
Run Code Online (Sandbox Code Playgroud)

带有公共轴标签的多个图

  • 请注意,x标签的x坐标的0.5不会将标签放在中心子图的中心.你需要略大于那个来计算yticklabels. (4认同)
  • 看看[this answer](http://stackoverflow.com/a/36542971/2550114),了解一种不使用`plt.text`的方法。您创建了子图,但是添加了一个位图,使其不可见,并标记了其x和y。 (2认同)
  • 使用`tight_layout`替换`0.04`和@ 0`的@ serv-inc似乎有效. (2认同)
  • 使用`fig.text`不是一个好主意。这弄乱了诸如`plt.tight_layout()`之类的东西 (2认同)

Pio*_*dal 34

没有sharex=True, sharey=True你得到:

在此输入图像描述

有了它你应该更好:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))

plt.tight_layout()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,如果要添加其他标签,则只应将它们添加到边缘图中:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))
        if i == len(axes2d) - 1:
            cell.set_xlabel("noise column: {0:d}".format(j + 1))
        if j == 0:
            cell.set_ylabel("noise row: {0:d}".format(i + 1))

plt.tight_layout()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

为每个绘图添加标签会破坏它(可能有一种方法可以自动检测重复的标签,但我不知道一个).


Ore*_*ren 31

Matplotlib v3.4 中的新功能( pip install matplotlib --upgrade)

supxlabelsupylabel

    fig.supxlabel('common_x')
    fig.supylabel('common_y')
Run Code Online (Sandbox Code Playgroud)

见示例:

import matplotlib.pyplot as plt

for tl, cl in zip([True, False, False], [False, False, True]):
    fig = plt.figure(constrained_layout=cl, tight_layout=tl)

    gs = fig.add_gridspec(2, 3)

    ax = dict()

    ax['A'] = fig.add_subplot(gs[0, 0:2])
    ax['B'] = fig.add_subplot(gs[1, 0:2])
    ax['C'] = fig.add_subplot(gs[:, 2])

    ax['C'].set_xlabel('Booger')
    ax['B'].set_xlabel('Booger')
    ax['A'].set_ylabel('Booger Y')
    fig.suptitle(f'TEST: tight_layout={tl} constrained_layout={cl}')
    fig.supxlabel('XLAgg')
    fig.supylabel('YLAgg')
    
    plt.show()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

查看更多

  • 整洁,但似乎 plt.tight_layout() 有问题,其中事物重叠。当我尝试更改 f.supxlabel() 的 x 参数时,它也会弄乱边距。 (2认同)
  • 确保使用 Python 3.7 或更高版本,以便能够安装 `matplotlib` v 3.4 (2认同)
  • 如果事物与“tight_layout”重叠,请尝试提供“rect”参数,例如增加左边距:“fig.tight_layout(rect=(0.025,0,1,1))” (2认同)
  • 这是最好的规范解决方案。 (2认同)

bli*_*bli 29

由于我认为它相关且足够优雅(不需要指定坐标来放置文本),我复制(略微改编)对另一个相关问题的答案.

import matplotlib.pyplot as plt
fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15))
# add a big axis, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")
Run Code Online (Sandbox Code Playgroud)

这导致以下结果(使用matplotlib 2.2.0版):

5行和2列子图,具有常见的x和y轴标签

  • 由于简单,这应该是公认的答案。非常简单。仍然与matplotlib v3.x相关。 (3认同)
  • 该解决方案的唯一问题是,当使用“constrained_layout=True”时它不起作用,因为它会创建重叠的标签。在这种情况下,您必须手动调整子图的边界。 (3认同)
  • 仅供参考:现在人们在 StackOverflow 中使用深色主题,标签几乎无法阅读,因此最好导出带有白色背景的 png (2认同)

Mar*_*ius 14

由于命令:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
Run Code Online (Sandbox Code Playgroud)

你用返回一个元组由图形和轴实例列表中,这已经是足够的做这样的事情(记住,我已经改变fig,axfig,axes):

fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

for ax in axes:
    ax.set_xlabel('Common x-label')
    ax.set_ylabel('Common y-label')
Run Code Online (Sandbox Code Playgroud)

如果你碰巧要改变一个特定的次要情节的一些细节,你可以通过访问它axes[i]在那里i遍历您的次要情节.

包含一个可能也非常有帮助

fig.tight_layout()
Run Code Online (Sandbox Code Playgroud)

在文件的末尾,之前plt.show(),以避免重叠标签.

  • 对不起我上面有点不清楚.对于"常见",我的意思是在所有图表下面都有一个单独的x标签,在图表的左边有一个单独的y标签,我已经更新了问题以反映这一点. (5认同)
  • @JohanLindberg:关于你在这里及以上的评论:确实`plt.subplots()`将创建一个新的数字实例.如果你想坚持使用这个命令,你可以轻松添加一个`big_ax = fig.add_subplot(111)`,因为你已经有了一个数字并且可以添加另一个轴.之后,您可以按照Hooked链接中显示的方式操作`big_ax`. (2认同)
  • @JohanLindberg,你说得对,我没有检查过.但你可以通过这样做来轻松地将大轴的背景颜色设置为"无":`big_ax.set_axis_bgcolor('none')`你还应该使labelcolor为'none`(与Hooked链接的例子相反): big_ax.tick_params(labelcolor ='none',top ='off',bottom ='off',left ='off',right ='off')` (2认同)
  • 我收到一个错误:`AttributeError:'numpy.ndarray'对象在语句`ax.set_xlabel('Common x-label')`中没有属性'set_xlabel'.你能搞清楚吗? (2认同)

EL_*_*DON 8

如果您通过为左下角的子图制作不可见标签来为公共标签保留空间,效果会更好。从 rcParams 传入字体大小也很好。这样,公共标签将随着您的 rc 设置而改变大小,并且轴也将被调整为公共标签留出空间。

fig_size = [8, 6]
fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size)
# Reserve space for axis labels
ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0))
ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0))
# Make common axis labels
fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize'])
fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize'])
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明 在此处输入图片说明


Luk*_*vis 6

更新:

这个功能现在是我最近在 pypi 上发布的proplot matplotlib 包的一部分。默认情况下,当您制作图形时,标签在子图之间“共享”。


原答案:

我发现了一个更稳健的方法:

如果您知道进入初始化的bottom和kwargs ,或者知道坐标轴中轴的边缘位置,您还可以使用一些奇特的“变换”魔法指定坐标中的 ylabel 位置。topGridSpecFigureFigure

例如:

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
bottom, top = 0.1, 0.9
fig, axs = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = 0.5 * (bottom + top)
transform = mtransforms.blended_transform_factory(mtransforms.IdentityTransform(), fig.transFigure)  # specify x, y transform
axs[0].yaxis.label.set_transform(transform)  # changed from default blend (IdentityTransform(), axs[0].transAxes)
axs[0].yaxis.label.set_position((0, avepos))
axs[0].set_ylabel('Hello, world!')
Run Code Online (Sandbox Code Playgroud)

...您应该看到标签仍然适当地左右调整,以防止与标签重叠,就像正常一样,但也会将其自身精确地定位在所需的子图之间。

值得注意的是,如果省略调用set_position,ylabel 将恰好显示在图的中间位置。我猜测这是因为当最终绘制标签时,matplotlib使用 0.5 作为y- 坐标,而不检查底层坐标变换是否已更改。