Документация Engee

Соотношения сторон и автоматические размеры фигур

Страница в процессе перевода.

Весьма распространенной проблемой при построении графиков является работа с соотношениями сторон и другими способами точного управления фигурами.

Например, для многих графиков нужны квадратные оси. Если вы изучали документацию по Axis, возможно, вы знаете, что у этого блока есть атрибут aspect, который может управлять соотношением сторон осевого прямоугольника. Это соотношение не зависит от ограничений данных, оно касается только относительной визуальной длины осей.

Рассмотрим один из распространенных примеров — квадратную ось с панелью цветов рядом с ней.

using CairoMakie
set_theme!(backgroundcolor = :gray90)

f = Figure(size = (800, 500))
ax = Axis(f[1, 1], aspect = 1)
Colorbar(f[1, 2])
f
e2e38fc

Как видите, эта ось квадратная, но между ней и панелью цветов есть большой промежуток. Почему это так?

Мы можем визуализировать причину, добавив прямоугольник в ту же ячейку, где находится ось.

Box(f[1, 1], color = (:red, 0.2), strokewidth = 0)
f
d9c1747

Красная область прямоугольника выходит за пределы белого пространства, оставленного осью. Так мы видим, что на самом деле делает ключевое слово aspect. Оно уменьшает размер оси таким образом, чтобы мы получили выбранное соотношение сторон. Оно не указывает макету, в котором находится ось, сделать так, чтобы эта ячейка соответствовала этому соотношению сторон. Что касается макета, ось имеет неопределенный размер, поэтому ее ячейка макета может иметь любой размер, который макет сочтет правильным с учетом всего остального содержимого макета и размера фигуры.

Поэтому использование aspect всегда будет приводить к появлению промежутков, если только у ячейки макета, в которой находится ось, случайно нет точно такого же соотношения сторон. Это означает, что aspect следует использовать только в том случае, если вызванные им промежутки не имеют большого значения.

Для всех остальных ситуаций существует другой подход.

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

По умолчанию каждая строка и столбец GridLayout имеют размер типа Auto(). Это означает, что размер может зависеть от содержимого фиксированного размера, если таковое имеется, в противном случае он расширяется, чтобы заполнить все доступное пространство. Если у ячейки должно быть соотношение сторон, нужно задать Aspect в качестве соответствующего размера строки или столбца.

Давайте попробуем повторить пример выше, но на этот раз у столбца будет соотношение сторон 1,0 относительно строки оси, которая является строкой 1.

f = Figure(size = (800, 500))
ax = Axis(f[1, 1])
Colorbar(f[1, 2])
colsize!(f.layout, 1, Aspect(1, 1.0))
f
eb7f71f

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

Box(f[1, 1], color = (:red, 0.2), strokewidth = 0)
f
bd6ab05

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

ax.aspect = 0.5
f
d065017

Теперь снова изменим соотношение столбца, чтобы убрать этот промежуток.

colsize!(f.layout, 1, Aspect(1, 0.5))
f
55a3a0c

Вернемся к предыдущему состоянию с квадратной осью.

f = Figure(size = (800, 500))
ax = Axis(f[1, 1])
Colorbar(f[1, 2])
colsize!(f.layout, 1, Aspect(1, 1.0))
f
f24e727

Теперь может показаться, что между осью и панелью цветов больше нет пространства, но слева и справа его достаточно. Почему макет не может решить эту проблему?

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

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

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

Попробуем сделать это.

resize_to_layout!(f)
f
7f1bac0

Как видите, пространство по бокам было обрезано. (Если масштаб выглядит меньше или больше, это связано с отображением на этом сайте, а не с размером основного рисунка.)

Такой метод полезен во всех ситуациях, когда определять размер фигуры должно содержимое, а не наоборот.

Допустим, у нас есть фасетный график с 25 квадратными осями размером 150 на 150. Мы можем просто создать эти оси с фиксированными шириной и высотой. Столбцы и строки стандартного макета размером типа Auto воспринимают эти измерения и настраиваются соответствующим образом.

Конечно, размер рисунка по умолчанию не будет соответствовать такому расположению, и содержимое будет обрезаться.

f = Figure()
for i in 1:5, j in 1:5
    Axis(f[i, j], width = 150, height = 150)
end
f
31313bc

Но, как и раньше, можно вызвать функцию resize_to_layout!, и размер будет скорректирован так, что обрезки не будет.

resize_to_layout!(f)
f
6d7c02a