Общая xlabel/ylabel для подзаголовков matplotlib
У меня есть следующий график:
fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
и теперь я хотел бы дать этому графику общие метки оси x и метки оси Y. С "общим" я имею в виду, что должна быть одна большая метка оси x под всей сеткой подзаголовков, а одна большая метка оси Y справа. Я не могу найти ничего об этом в документации для plt.subplots
, и мои googlings предполагают, что мне нужно сделать большой plt.subplot(111)
для начала, но как я тогда помещаю свои подстроки 5 * 2 в это, используя plt.subplots
?
Ответы
Ответ 1
Это похоже на то, что вы на самом деле хотите. Он применяет тот же подход этого ответа к вашему конкретному случаю:
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]()
Ответ 2
Без sharex=True, sharey=True
вы получите:
![enter image description here]()
С ним вы должны получить его лучше:
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]()
Но если вы хотите добавить дополнительные метки, вы должны добавить их только к граничным графикам:
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]()
Добавление метки для каждого графика испортит ее (возможно, есть способ автоматически обнаруживать повторяющиеся метки, но я не знаю об этом).
Ответ 3
Так как команда:
fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
который вы использовали, возвращает кортеж, состоящий из фигуры и списка экземпляров осей, уже достаточно сделать что-то вроде (помните, что я изменил fig,ax
на fig,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')
Если вам захочется изменить некоторые детали на конкретном подзаголовке, вы можете получить к нему доступ через axes[i]
, где i
выполняет итерацию по вашим подзаголовкам.
Также может быть очень полезно включить
fig.tight_layout()
в конце файла перед plt.show()
, чтобы избежать перекрытия меток.
Ответ 4
У меня возникла аналогичная проблема при построении сетки графиков. Графики состояли из двух частей (сверху и снизу). Предполагалось, что y-метка будет центрирована по обеим частям.
Я не хотел использовать решение, которое зависит от знания положения на внешней фигуре (например, fig.text()), поэтому я манипулировал y-позицией функции set_ylabel(). Это обычно 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()
картинка
Downsides:
-
Горизонтальное расстояние до графика основано на верхней части, нижние тики могут распространяться на метку.
-
Формула не учитывает пробел между частями.
-
Выдает исключение, если высота верхней части равна 0.
Возможно, существует общее решение, которое учитывает отступы между фигурами.
Ответ 5
Я обнаружил альтернативный метод; если вы знаете bottom
и top
kwargs, которые вошли в инициализацию GridSpec
, или вы иначе знаете положения краев ваших осей в координатах Figure
, вы также можете указать ярлык положение в координатах Figure
с некоторой фантастической магией "преобразования". Например:
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!')
... и вы должны увидеть, что метка по-прежнему соответствующим образом регулирует влево-вправо, чтобы не перекрывать метки с метками, как обычно, но теперь она будет регулироваться всегда точно между желаемыми подзаголовками.
Кроме того, если вы даже не используете set_position
, ylabel будет отображаться по умолчанию точно на полпути вверх по фигуре. Я предполагаю, что это происходит потому, что, когда ярлык окончательно нарисован, matplotlib
использует 0,5 для y
-координата, не проверяя, изменилось ли базовое преобразование координат.