Matplotlib Gridspec с соотношением сторон

Я пытаюсь создать 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.set_aspect('equal'). Какую версию matplotlib вы используете? Я использовал версию 3.8.2.

Matt Pitkin 04.09.2024 10:21

На самом деле, я вижу, что если я нарисую что-нибудь в ax, то эта ось действительно сместится.

Matt Pitkin 04.09.2024 10:25

Вы довольны возможностью вручную устанавливать пределы оси? Если да, то пока вы сохраняете свой набор figsize таким, чтобы у вас была квадратная фигура, вы можете удалить ax.set_aspect('equal') и просто оставить, например, ax.set_xlim([0, 1]) и ax.set_ylim([0, 1]).

Matt Pitkin 04.09.2024 10:31

Я попробовал это, но это не исправляет соотношение сторон.

RaphBilder 04.09.2024 11:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Установка аспекта оси приведет к изменению размера оси, но не фигуры. Я не вижу другого способа, кроме как правильно установить размер фигуры с помощью математики.

В вашем случае, к счастью, это довольно просто, поскольку подойдет любой размер квадратной фигуры. На самом деле важен не размер фигуры, а размер прямоугольника, содержащего все подграфики внутри фигуры.

Загвоздка в том, что поля по умолчанию между экстентом фигуры и экстентом подграфика делают экстент подграфика не квадратным, когда размер фигуры равен. (Этот параметр 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()

Спасибо за отличный ответ. К сожалению, я не могу понять, как это сделать, если нижний левый график представляет собой не квадрат, а прямоугольник (см. редактирование исходного вопроса). Есть ли у вас какие-нибудь идеи на этот счет?

RaphBilder 04.09.2024 10:59

Кроме того, если я перемещаю границы окна, оно все равно не выравнивается. Но это второстепенная мысль, поскольку сюжет сохраняется идеально согласованным с файлом.

RaphBilder 04.09.2024 11:02

Да, сложнее, когда это не квадрат. По сути, вам нужно самостоятельно вычислить соотношение сторон экстента подзаголовка. И это должно учитывать wspace. Вариант другого ответа с inset_axes, кажется, больше подходит для этой работы, но, я думаю, нужно еще добавить некоторые изменения для размера фигуры.

paime 04.09.2024 13:07
Ответ принят как подходящий

Вы можете рассмотреть возможность использования метода 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 04.09.2024 13:09

@RaphBilder, возможно, лучше открыть новый вопрос о выравнивании меток. ax.align_labels не будет работать со вставленными осями.

Jody Klymak 05.09.2024 00:57

Другие вопросы по теме