Python matplotlib 子图的通用 xlabel/ylabel

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16150819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:53:00  来源:igfitidea点击:

Common xlabel/ylabel for matplotlib subplots

pythonmatplotlib

提问by jolindbe

I have the following plot:

我有以下情节:

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

and now I would like to give this plot common x-axis labels and y-axis labels. With "common", I mean that there should be one big x-axis label below the whole grid of subplots, and one big y-axis label to the right. I can't find anything about this in the documentation for plt.subplots, and my googlings suggest that I need to make a big plt.subplot(111)to start with - but how do I then put my 5*2 subplots into that using plt.subplots?

现在我想给这个图提供通用的 x 轴标签和 y 轴标签。对于“common”,我的意思是在整个子图网格下方应该有一个大的 x 轴标签,右侧应该有一个大的 y 轴标签。我在 的文档中找不到任何关于此的内容plt.subplots,我的谷歌搜索表明我需要从大plt.subplot(111)开始 - 但是我如何使用 将我的 5*2 子图放入其中plt.subplots

采纳答案by divenex

This looks like what you actually want. It applies the same approach of this answerto your specific case:

这看起来像你真正想要的。它将此答案的相同方法应用于您的特定案例:

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')

Multiple plots with common axes label

具有公共轴标签的多个图

回答by Marius

Since the command:

由于命令:

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

you used returns a tuple consisting of the figure and a list of the axes instances, it is already sufficient to do something like (mind that I've changed fig,axto fig,axes):

您使用返回一个由图形和轴实例列表组成的元组,执行类似的操作已经足够了(请注意,我已更改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')

If you happen to want to change some details on a specific subplot, you can access it via axes[i]where iiterates over your subplots.

如果您碰巧想要更改特定子图的一些细节,您可以通过axes[i]wherei迭代您的子图来访问它。

It might also be very helpful to include a

包括一个

fig.tight_layout()

at the end of the file, before the plt.show(), in order to avoid overlapping labels.

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

回答by Piotr Migdal

Without sharex=True, sharey=Trueyou get:

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

enter image description here

在此处输入图片说明

With it you should get it nicer:

有了它,你应该会变得更好:

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()

enter image description here

在此处输入图片说明

But if you want to add additional labels, you should add them only to the edge plots:

但是如果你想添加额外的标签,你应该只将它们添加到边缘图中:

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()

enter image description here

在此处输入图片说明

Adding label for each plot would spoil it (maybe there is a way to automatically detect repeated labels, but I am not aware of one).

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

回答by CPe

I ran into a similar problem while plotting a grid of graphs. The graphs consisted of two parts (top and bottom). The y-label was supposed to be centered over both parts.

我在绘制图形网格时遇到了类似的问题。图表由两部分组成(顶部和底部)。y 标签应该以两个部分为中心。

I did not want to use a solution that depends on knowing the position in the outer figure (like fig.text()), so I manipulated the y-position of the set_ylabel() function. It is usually 0.5, the middle of the plot it is added to. As the padding between the parts (hspace) in my code was zero, I could calculate the middle of the two parts relative to the upper part.

我不想使用依赖于知道外部图形中的位置的解决方案(如 fig.text()),所以我操纵了 set_ylabel() 函数的 y 位置。它通常是 0.5,它被添加到绘图的中间。由于我的代码中部分 (hspace) 之间的填充为零,我可以计算相对于上部的两个部分的中间部分。

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
               subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)

# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])

# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)

# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)

plt.show()

picture

图片

Downsides:

缺点:

  • The horizontal distance to the plot is based on the top part, the bottom ticks might extend into the label.

  • The formula does not take space between the parts into account.

  • Throws an exception when the height of the top part is 0.

  • 到绘图的水平距离基于顶部,底部刻度可能会延伸到标签中。

  • 该公式不考虑部件之间的空间。

  • 当顶部的高度为 0 时抛出异常。

There is probably a general solution that takes padding between figures into account.

可能有一个通用的解决方案,它考虑了数字之间的填充。

回答by Luke Davis

Update:

更新:

This feature is now part of the proplot matplotlib packagethat I recently released on pypi. By default, when you make figures, the labels are "shared" between axes.

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



Original answer:

原答案:

I discovered a more robust method:

我发现了一个更强大的方法:

If you know the bottomand topkwargs that went into a GridSpecinitialization, or you otherwise know the edges positions of your axes in Figurecoordinates, you can also specify the ylabel position in Figurecoordinates with some fancy "transform" magic. For example:

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

import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
       mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
       )) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')

...and you should see that the label still appropriately adjusts left-rightto keep from overlapping with ticklabels, just like normal -- but now it will adjust to be always exactly betweenthe desired subplots.

...并且您应该看到标签仍然适当地左右调整以防止与刻度标签重叠,就像正常一样 - 但现在它将调整为始终完全在所需的子图之间

Furthermore, if you don't even use set_position, the ylabel will show up by default exactly halfway up the figure. I'm guessing this is because when the label is finally drawn, matplotlibuses 0.5 for the y-coordinate without checking whether the underlying coordinate transform has changed.

此外,如果您甚至不使用set_position,默认情况下 ylabel 将显示在图的正中间。我猜这是因为当最终绘制标签时,matplotlib使用 0.5 作为y-coordinate 而不检查底层坐标变换是否已更改。

回答by EL_DON

It will look better if you reserve space for the common labels by making invisible labels for the subplot in the bottom left corner. It is also good to pass in the fontsize from rcParams. This way, the common labels will change size with your rc setup, and the axes will also be adjusted to leave space for the common labels.

如果您通过为左下角的子图制作不可见标签来为公共标签保留空间,效果会更好。从 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'])

enter image description hereenter image description here

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

回答by bli

Since I consider it relevant and elegant enough (no need to specify coordinates to place text), I copy (with a slight adaptation) an answer to another related question.

由于我认为它足够相关和优雅(无需指定坐标来放置文本),我复制(稍作修改)另一个相关问题的答案

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")

This results in the following (with matplotlib version 2.2.0):

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

5 rows and 2 columns subplots with common x and y axis labels

具有通用 x 和 y 轴标签的 5 行 2 列子图