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

Рисунки

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

Объект Figure содержит Scene верхнего уровня и GridLayout, а также список блоков, которые были помещены в него, например Axis, Colorbar, Slider, Legend и т. д.

Создание рисунка

Вы можете явным образом создать рисунок с помощью функции Figure() и задать атрибуты базовой сцены. Самым важным из них является size.

f = Figure()
f = Figure(size = (600, 400))

Рисунок также создается неявно при использовании простых не изменяющих команд построения графиков, таких как plot(), scatter(), lines() и т. д. Так как эти команды также создают ось, на которой будет располагаться график, и сам график, они возвращают составной объект FigureAxisPlot, в котором просто хранятся эти три компонента. Для доступа к рисунку можно либо разбить этот объект на три части, либо обратиться к полю рисунка напрямую.

figureaxisplot = scatter(rand(100, 2))
figure = figureaxisplot.figure

# синтаксис разбиения
figure, axis, plot = scatter(rand(100, 2))

# можно также игнорировать компоненты
figure, = scatter(rand(100, 2))

Аргументы созданного рисунка можно передать в объекте наподобие словаря через специальный именованный аргумент figure:

scatter(rand(100, 2), figure = (size = (600, 400),))

Размещение блоков в рисунке

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

f = Figure()
ax = f[1, 1] = Axis(f)
sl = f[2, 1] = Slider(f)

GridPosition и GridSubposition

Синтаксис индексирования Figure реализован так, чтобы можно было легко работать с макетом. При обращении к рисунку по индексу создается объект GridPosition, в котором хранится созданная операция индексирования. Этот объект можно использовать для построения новой оси в определенной позиции макета на рисунке, например, так:

using CairoMakie
f = Figure()
pos = f[1, 1]
scatter(pos, rand(100, 2))

pos2 = f[1, 2]
lines(pos2, cumsum(randn(100)))

# разумеется, вам не нужно сначала сохранять позицию в переменной
heatmap(f[1, 3], randn(10, 10))

f
1cffa50

Можно также далее обратиться по индексу к GridPosition, в результате чего будет создан объект GridSubposition. С помощью GridSubposition можно описывать позиции в произвольно вложенных сеточных макетах. Зачастую требуемый макет графика можно получить только путем вложения, и многократное индексирование упрощает эту задачу.

using CairoMakie
f = Figure()

f[1, 1] = Axis(f, title = "I'm not nested")
f[1, 2][1, 1] = Axis(f, title = "I'm nested")

# также возможно построение графиков во вложенных позициях
heatmap(f[1, 2][2, 1], randn(20, 20))

f
c29c561

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

Note Объекты GridLayout, которые создаются неявно при использовании GridSubpositions, недоступны напрямую в возвращаемом значении для дальнейшей обработки. Вместо этого их можно извлечь впоследствии с помощью функции content, например как описано в следующем разделе.

Внутренние отступы рисунка

Вы можете изменить размер пустого пространства (поля) вокруг содержимого рисунка с помощью именованного аргумента figure_padding. Он принимает либо число для всех четырех сторон, либо кортеж из четырех чисел для левой, правой, нижней и верхней сторон. Для этой настройки также можно задать тему, например, так: set_theme!(figure_padding = 30).

using CairoMakie
f = Figure(figure_padding = 1, backgroundcolor = :gray80)

Axis(f[1, 1])
scatter!(1:10)

f
e02da88

Извлечение объектов из рисунка

Иногда пользователи удивляются, что при обращении по индексу к рисунку не извлекается объект, находящийся в этой позиции. Связано это с тем, что объект GridPosition необходим для построения графика, а возврат объектов содержимого напрямую лишит такой возможности. Кроме того, GridLayout может содержать несколько объектов в одной позиции или иметь частично перекрывающееся содержимое, поэтому не совсем ясно, что именно должно возвращаться по определенному индексу.

Для извлечения объектов из рисунка можно вместо этого использовать индексирование и функцию contents или content. Функция contents возвращает вектор всех объектов, найденных в заданной позиции GridPosition. С помощью именованного аргумента exact = true можно указать, что позиция должна точно совпадать; в противном случае будут также возвращены объекты в этой позиции.

f = Figure()
box = f[1:3, 1:2] = Box(f)
ax = f[1, 1] = Axis(f)

contents(f[1, 1]) == [ax]
contents(f[1:3, 1:2]) == [box, ax]
contents(f[1:3, 1:2], exact = true) == [box]

При использовании contents применительно к GridSubposition именованный аргумент exact относится только к сеточному макету самого нижнего уровня; все верхние уровни должны точно совпадать.

f = Figure()
ax = f[1, 1][2, 3] = Axis(f)

contents(f[1, 1][2, 3]) == [ax]
contents(f[1:2, 1:2][2, 3]) == [] # верхний уровень должен точно совпадать

Часто бывает так, что в определенной позиции ожидается только один объект и вы хотите работать с ним напрямую, не извлекая его из вектора, возвращаемого функцией contents. В этом случаеиспользуйте вместо этого функцию content. Она работает аналогично only(contents(pos, exact = true)), поэтому выдает ошибку, если не может вернуть ровно один объект из заданной позиции.

f = Figure()
ax = f[1, 1] = Axis(f)

contents(f[1, 1]) == [ax]
content(f[1, 1]) == ax

Размер и разрешение рисунка

В Makie размер объекта Figure не имеет единиц измерения. Это связано с тем, что объекты Figure можно отрисовывать как изображения или векторную графику либо отображать в интерактивных окнах. Фактический физический размер результата зависит от множества факторов, таких как размеры экранов, которые Makie зачастую не контролирует, поэтому мы не можем обещать точный размер результата при любых обстоятельствах для гипотетического объекта Figure(size = (4cm, 5cm)).

Атрибут size объекта Figure в первую очередь указывает, сколько места есть для объектов Axis и другого содержимого. Например, fontsize или Axis(width = ..., height = ...) также не имеет единиц измерения, но их можно интерпретировать относительно размера рисунка. Если в Figure недостаточно места, можно либо увеличить size, либо уменьшить размер содержимого (например, уменьшив размер шрифта). Однако атрибут size объекта Figure интересует нас не только относительно размеров содержимого. Он также имеет значение, когда мы решаем, насколько большим будет выглядеть объект Figure при отображении на всех возможных устройствах вывода.

Хотя в Makie для указания размера рисунка используются числа без единиц измерения, по умолчанию эти числа можно рассматривать как пиксели CSS. Мы выбрали такое соглашение, чтобы упростить использование Makie в контексте веб-приложений, включая браузерные инструменты, такие как Pluto, записные книжки Jupyter или редакторы, например VSCode. Все они используют CSS для управления внешним видом объектов.

При настройках по умолчанию объект Figure размером (600, 450) будет отображаться в веб-приложениях размером 600 x 450 пикселей CSS (если отрисовка в Makie осуществляется с использованием типа MIME text/html или image/svg+xml). Это справедливо независимо от разрешения, то есть количества пикселей в выходном растровом изображении. Изображение будет снабжено аннотацией width = "600px" height = "450px", сообщающей браузерам его предполагаемый размер.

Пиксель CSS — это физическая единица (1 пиксель == 1/96 дюйма), но, разумеется, браузеры отображают содержимое на различных экранах с разными уровнями масштабирования, поэтому не стоит ожидать, что элемент шириной 96 пикселей всегда будет иметь ширину ровно 1 дюйм. Но даже если неизвестно, какой физический размер будут иметь графики на экранах, нужно, чтобы они хорошо сочетались с другим содержимым и текстом, поэтому они должны соответствовать размерам, традиционно используемым в современных системах. Например, распространенным размером шрифта является 12 pt, что эквивалентно 16 px (1 пиксель == 3/4 пункта).

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

В то время как векторная графика всегда отображается четко при заданном уровне масштабирования, для растровых изображений фактическое количество пикселей определяет то, при каком уровне масштабирования или на каком расстоянии просмотра они будут выглядеть четкими или размытыми. Этот фактор четкости часто указывается в dpi (или точках на дюйм). Опять же, не следует ожидать, что дюйм здесь всегда будет соответствовать реальному физическому дюйму (как во времена печати на бумаге) из-за масштабирования на экранах цифровых устройств. Но, если, согласно соглашению, размеры описываются в пикселях CSS, мы также можем использовать dpi и будем знать, какой четкости следует ожидать на типичных устройствах и при типичных уровнях масштабирования.

Подводя итог, можно сказать, что на результат отрисовки объекта Makie Figure влияют два фактора: его размер, который определяет доступное для содержимого пространство и отображаемый размер при интерпретации в таких единицах измерения, как пиксели CSS, и разрешение или четкость в виде плотности пикселей или dpi. В случае с векторной графикой нас интересует только фактор размера (если только мы не встраиваем в нее растровые изображения).

Фактор px_per_unit

При отображении Figure(size = (600, 450)) в веб-приложениях согласно соглашению Makie изображение снабжается аннотацией width = "600px" height = "450px". Но сколько пикселей будет содержать фактическое растровое изображение, то есть насколько четким оно будет?

Это определяется параметром px_per_unit при отрисовке рисунка в виде растрового изображения или сохранении его с помощью save. По умолчанию при отрисовке растровых изображений он имеет значение 2, так как на многих современных экранах (например, на дисплеях Retina от Apple) область 2 x 2 пикселя экрана сопоставляется с областью 1 x 1 пиксель CSS. Чтобы при увеличении масштаба сохранялось хорошее разрешение, необходимо увеличить значение px_per_unit, чтобы изображения содержали еще больше пикселей.

Ниже приведены два изображения, которые показывают, как size и px_per_unit влияют на внешний вид графиков. Следует помнить два простых правила:

При увеличении значения size вы получаете больше места для содержимого и более крупное растровое изображение. При масштабировании до того же размера в контексте вывода (например, в документе PDF) содержимое рисунка с большим значением size будет выглядеть меньше.

figure size

При увеличении значения px_per_unit место для содержимого остается прежним, но размер растрового изображения увеличивается за счет более высокого разрешения. При масштабировании до того же размера в контексте вывода (например, в документе PDF) содержимое рисунка с большим значением px_per_unit будет выглядеть так же, но четче.

px per unit

Существует также коэффициент pt_per_unit, с помощью которого можно увеличивать или уменьшать масштаб выходной векторной графики. Однако, если придерживаться соглашения о том, что числа без единиц измерения в Makie на самом деле представляют пиксели CSS, можно оставить значение pt_per_unit по умолчанию, равное 0,75, и автоматически получать растровые изображения и векторную графику соответствующего размера.