Общие меткой х/ylabel для библиотек matplotlib сюжетных линий
у меня есть следующий сюжет:
fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
а теперь я хотел бы дать этот участок общей оси X и y оси. С помощью "common" я имею в виду, что под всей сеткой подзаголовков должна быть одна большая метка оси x и одна большая метка оси y справа. Я не могу найти ничего об этом в документации plt.subplots, и мои гуглинги предполагают, что мне нужно сделать большой plt.subplot(111) для начала - но как мне тогда поместить мои 5*2 подзаголовки в это с помощью plt.subplots?
6 ответов:
Это похоже на то, что вы на самом деле хотите. Он применяет тот же подход ответ к вашему конкретному случаю:
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')
без
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()
но если вы хотите добавить дополнительные метки, Вы должны добавить их только к краевым участкам:
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()
добавление метки для каждого участка испортило бы его (возможно, есть способ автоматически обнаруживать повторяющиеся метки, но я не знаю об этом).
С помощью команды:
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(), для того, чтобы избежать дублирования меток.
я столкнулся с подобной проблемой при построении сетки графиков. Графики состоял из двух частей (верхней и нижней). Y-метка должна была быть сосредоточена на обеих частях.
Я не хотел использовать решение, которое зависит от знания положения на внешней фигуре (например, рис.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()минусы:
горизонтальное расстояние до участка основано на верхней части, нижние тики могут распространяться на метку.
формула не учитывает расстояние между частями.
выдает исключение, когда высота верхней части будет 0.
вероятно, существует общее решение, которое учитывает заполнение между фигурами.
я обнаружил более надежный метод:
если вы знаете
bottomиtopкварги, которые вошли вGridSpecинициализация, или вы иначе знаете положение ребер ваших осей вFigureкоординаты, вы также можете указать позицию ylabel в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!')...и вы должны видеть, что метка по-прежнему соответствующим образом регулирует влево-вправо сохранить от перекрытие с ticklabels, как обычно - но теперь он будет корректировать, чтобы быть всегда между нужные сюжетных линий.
кроме того, если вы даже не используете
set_position, ylabel будет отображаться по умолчанию ровно на полпути вверх по фигуре. Я предполагаю, что это потому, что когда метка наконец-то,matplotlibиспользует 0,5 дляy-координата без проверки того, изменилось ли базовое преобразование координат.
это будет выглядеть лучше, если вы зарезервируете место для общих меток, сделав невидимые метки для подзаголовка в нижнем левом углу. Это также хорошо, чтобы пройти в кегль от 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'])






Comments