Я пытаюсь создать Gridspec с этим макетом: Планировка выглядит так, как и должно быть
Нижний левый график должен иметь одинаковое соотношение сторон. К сожалению, мне пришлось изменить размер окна, чтобы получить это изображение. Для других размеров верхний или правый графики не совпадают с нижним левым графиком.
Планировка с участками, не совмещенными
Мой код выглядит следующим образом:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8,8))
gs = gridspec.GridSpec(3, 3, width_ratios=[1, 1/4, 1/32], height_ratios=[1/32, 1/4, 1])
ax = plt.subplot(gs[2, 0])
ax.set_aspect('equal')
ax_histx = plt.subplot(gs[1, 0], sharex=ax)
ax_histy = plt.subplot(gs[2, 1], sharey=ax)
cax = plt.subplot(gs[2, 2])
cax2 = plt.subplot(gs[0, 0])
plt.show()
Подсюжеты идеально совпадают, если я не устанавливаю соотношение сторон. Но кажется, что у меня не может быть одновременно выравнивания и равного соотношения сторон.
Кроме того, нижняя левая фигура не всегда должна быть квадратом. Например, если я установлю разные пределы для x и y
ax.set_xlim(0,10)
ax.set_ylim(0,5)
это должен быть прямоугольник с шириной = 2*высотой, чтобы все ячейки на графике были квадратами.
На самом деле, я вижу, что если я нарисую что-нибудь в ax
, то эта ось действительно сместится.
Вы довольны возможностью вручную устанавливать пределы оси? Если да, то пока вы сохраняете свой набор figsize
таким, чтобы у вас была квадратная фигура, вы можете удалить ax.set_aspect('equal')
и просто оставить, например, ax.set_xlim([0, 1])
и ax.set_ylim([0, 1])
.
Я попробовал это, но это не исправляет соотношение сторон.
Установка аспекта оси приведет к изменению размера оси, но не фигуры. Я не вижу другого способа, кроме как правильно установить размер фигуры с помощью математики.
В вашем случае, к счастью, это довольно просто, поскольку подойдет любой размер квадратной фигуры. На самом деле важен не размер фигуры, а размер прямоугольника, содержащего все подграфики внутри фигуры.
Загвоздка в том, что поля по умолчанию между экстентом фигуры и экстентом подграфика делают экстент подграфика не квадратным, когда размер фигуры равен.
(Этот параметр figure.subplot.left/right/bottom/top
установлен на 0.125/0.9/0.11/0.88
в rcParams по умолчанию ).
Подводя итог, укажите размер квадратной фигуры и исправьте аргументы left
/right
/bottom
/top
для GridSpec
, и все готово:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8, 8))
gs = gridspec.GridSpec(
nrows=3,
ncols=3,
width_ratios=[1, 1 / 4, 1 / 32],
height_ratios=[1 / 32, 1 / 4, 1],
bottom=0.1,
top=0.9,
left=0.1,
right=0.9,
# wspace=0,
# hspace=0,
)
ax = plt.subplot(gs[2, 0])
ax.set_aspect("equal")
ax_histx = plt.subplot(gs[1, 0], sharex=ax)
ax_histy = plt.subplot(gs[2, 1], sharey=ax)
cax = plt.subplot(gs[2, 2])
cax2 = plt.subplot(gs[0, 0])
plt.show()
Спасибо за отличный ответ. К сожалению, я не могу понять, как это сделать, если нижний левый график представляет собой не квадрат, а прямоугольник (см. редактирование исходного вопроса). Есть ли у вас какие-нибудь идеи на этот счет?
Кроме того, если я перемещаю границы окна, оно все равно не выравнивается. Но это второстепенная мысль, поскольку сюжет сохраняется идеально согласованным с файлом.
Да, сложнее, когда это не квадрат. По сути, вам нужно самостоятельно вычислить соотношение сторон экстента подзаголовка. И это должно учитывать wspace. Вариант другого ответа с inset_axes
, кажется, больше подходит для этой работы, но, я думаю, нужно еще добавить некоторые изменения для размера фигуры.
Вы можете рассмотреть возможность использования метода inset_axes для размещения осей вместо GridSpec
. Здесь у меня жестко запрограммированы позиции для каждой вставленной оси, но вы можете сделать их функцией ограничений ваших основных осей.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig, ax = plt.subplots(figsize=(8,8), layout='compressed')
ax.set_aspect('equal')
ax_histx = ax.inset_axes([0, 1.2, 1, 0.25], sharex=ax)
ax_histy = ax.inset_axes([1.1, 0, 0.25, 1], sharey=ax)
cax = ax.inset_axes([0, 1.65, 1, 0.125])
cax2 = ax.inset_axes([1.45, 0, 0.125, 1])
ax.set_xlim(0,10)
ax.set_ylim(0,5)
plt.show()
Спасибо, кажется, это работает. Это не имеет ничего общего с исходным вопросом, но знаете ли вы, смогу ли я выровнять метки для осей? fig.align_labels(), похоже, ничего не делает при таком подходе.
@RaphBilder, возможно, лучше открыть новый вопрос о выравнивании меток. ax.align_labels не будет работать со вставленными осями.
Ваш код создает для меня правильно выглядящий график с включенным
ax.set_aspect('equal')
. Какую версию matplotlib вы используете? Я использовал версию 3.8.2.