Как выровнять оси подзаголовка высоты и ширины с помощью gridspec и matplotlib?

Я пытаюсь использовать matplotlib с gridspec, чтобы создать подзаговор так, чтобы оси были расположены чтобы выглядеть как на рисунке ниже; цифра была взята из этого несвязанного вопроса .

Исходное изображение

Моя попытка воссоздать это расположение осей ниже. В частности, моя проблема в том, что оси не выровнены должным образом. Например, объект оси для синей гистограммы выше, чем объект оси для изображения с различными оттенками зеленого; кажется, что оранжевая гистограмма правильно выровнена по ширине, но я считаю это удачей. Как мне правильно выровнять эти оси? В отличие от исходного рисунка, я хотел бы добавить / заполнить дополнительное пустое пространство между осями, чтобы границы не пересекались; обозначение среза в приведенном ниже коде делает это путем добавления пустой строки / столбца. (Чтобы не делать этот пост длиннее, чем он должен быть, я не делал фигуры красивыми, играя с отметками оси и т.п.)

Моя попытка

В отличие от исходного изображения, оси не идеально выровнены. Есть ли способ сделать это без использования ограниченного макета? Под этим я подразумеваю некую производную от fig, ax = plt.subplots(constrained_layout=True)?

Код MWE для воссоздания моей фигуры ниже; обратите внимание, что не было разницы между ax.imshow(...) и ax.matshow(...).

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

## initialize figure and axes
fig = plt.figure()
gs = fig.add_gridspec(6, 6, hspace=0.2, wspace=0.2)
ax_bottom = fig.add_subplot(gs[4:, 2:])
ax_left = fig.add_subplot(gs[:4, :2])
ax_big = fig.add_subplot(gs[:4, 2:])

## generate data
x = np.random.normal(loc=50, scale=10, size=100)
y = np.random.normal(loc=500, scale=50, size=100)

## get singular histograms
x_counts, x_edges = np.histogram(x, bins=np.arange(0, 101, 5))
y_counts, y_edges = np.histogram(y, bins=np.arange(0, 1001, 25))
x_mids = (x_edges[1:] + x_edges[:-1]) / 2
y_mids = (y_edges[1:] + y_edges[:-1]) / 2

## get meshed histogram
sample = np.array([x, y]).T
xy_counts, xy_edges = np.histogramdd(sample, bins=(x_edges, y_edges))

## subplot histogram of x
ax_bottom.bar(x_mids, x_counts,
    width=np.diff(x_edges),
    color='darkorange')
ax_bottom.set_xlim([x_edges[0], x_edges[-1]])
ax_bottom.set_ylim([0, np.max(x_counts)])

## subplot histogram of y
ax_left.bar(y_mids, y_counts,
    width=np.diff(y_edges),
    color='steelblue')
ax_left.set_xlim([y_edges[0], y_edges[-1]])
ax_left.set_ylim([0, np.max(y_counts)])

## subplot histogram of xy-mesh
ax_big.imshow(xy_counts,
    cmap='Greens',
    norm=Normalize(vmin=np.min(xy_counts), vmax=np.max(xy_counts)),
    interpolation='nearest',
    origin='upper')

plt.show()
plt.close(fig)

РЕДАКТИРОВАТЬ:

Можно инициализировать оси, явно задав width_ratios и height_ratios для каждой строки / столбца; это показано ниже. Это не влияет на вывод, но может я неправильно его использую?

## initialize figure and axes
fig = plt.figure()
gs = gridspec.GridSpec(ncols=6, nrows=6, figure=fig, width_ratios=[1]*6, height_ratios=[1]*6)
ax_bottom = fig.add_subplot(gs[4:, 2:])
ax_left = fig.add_subplot(gs[:4, :2])
ax_big = fig.add_subplot(gs[:4, 2:])

person Community    schedule 12.10.2020    source источник
comment
Когда вы создаете свою сетку, вы можете вместо этого использовать соотношение высоты и ширины, а не нарезать сетку 6x6. Gridspec также принимает аргументы pad   -  person Jody Klymak    schedule 12.10.2020


Ответы (1)


Проблема заключается в imshow, который автоматически изменяет размеры осей, чтобы сохранить пропорции квадратных пикселей. Вы можете предотвратить это, позвонив:

ax_big.imshow(..., aspect='auto')
person Diziet Asahi    schedule 12.10.2020