Um canvas/layout completo é definido por Figure
, que pode ser preenchido com conteúdo após ser criado. Começaremos com um arranjo simples de um Axis
, uma Legend
e uma Colorbar
. Para esta tarefa, podemos pensar no canvas como um arranjo de rows
e columns
na indexação de uma Figure
bem como um Array
/Matrix
regular. O conteúdo do Axis
estará na linha 1, coluna 1, por exemplo fig[1, 1]
, a Colorbar
na linha 1, coluna 2, ou seja, fig[1, 2]
. E a Legend
na linha 2 e nas colunas 1 e 2, ou seja, fig[2, 1:2]
.
function first_layout()
seed!(123)
x, y, z = randn(6), randn(6), randn(6)
fig = Figure(resolution=(600, 400), backgroundcolor=:grey90)
ax = Axis(fig[1, 1], backgroundcolor=:white)
pltobj = scatter!(ax, x, y; color=z, label="scatters")
lines!(ax, x, 1.1y; label="line")
Legend(fig[2, 1:2], ax, "labels", orientation=:horizontal)
Colorbar(fig[1, 2], pltobj, label="colorbar")
fig
end
first_layout()
Isso já parece bom, mas poderia ser melhor. Podemos corrigir problemas de espaçamento usando as seguintes palavras-chave e métodos:
figure_padding=(left, right, bottom, top)
padding=(left, right, bottom, top)
Levar em consideração o tamanho real de uma Legend
ou Colorbar
é feito por:
tellheight=true
oufalse
tellwidth=true
oufalse
Definir como
true
levará em consideração o tamanho real (altura ou largura) para umaLegend
ouColorbar
. Consequentemente, as coisas serão redimensionadas de acordo.
O espaço entre colunas e linhas é especificado como:
colgap!(fig.layout, col, separation)
rowgap!(fig.layout, row, separation)
Column gap (
colgap!
), secol
for fornecido, a lacuna será aplicada a essa coluna específica. Row gap (rowgap!
) , se alinha
for fornecido, a lacuna será aplicada a essa linha específica.
Além disso, veremos como colocar conteúdo nas protrusões, i.e. o espaço reservado para título: x
e y
; ou ticks
ou label
. Fazemos isso plotando em fig[i, j, protrusion]
onde protrusion
pode ser Left()
, Right()
, Bottom()
e Top()
, ou para cada canto TopLeft()
, TopRight()
, BottomRight()
, BottomLeft()
. Veja abaixo como essas opções estão sendo utilizadas:
function first_layout_fixed()
seed!(123)
x, y, z = randn(6), randn(6), randn(6)
fig = Figure(figure_padding=(0, 3, 5, 2), resolution=(600, 400),
backgroundcolor=:grey90, font="CMU Serif")
ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"y",
title="Layout example", backgroundcolor=:white)
pltobj = scatter!(ax, x, y; color=z, label="scatters")
lines!(ax, x, 1.1y, label="line")
Legend(fig[2, 1:2], ax, "Labels", orientation=:horizontal,
tellheight=true, titleposition=:left)
Colorbar(fig[1, 2], pltobj, label="colorbar")
# additional aesthetics
Box(fig[1, 1, Right()], color=(:slateblue1, 0.35))
Label(fig[1, 1, Right()], "protrusion", textsize=18,
rotation=pi / 2, padding=(3, 3, 3, 3))
Label(fig[1, 1, TopLeft()], "(a)", textsize=18, padding=(0, 3, 8, 0))
colgap!(fig.layout, 5)
rowgap!(fig.layout, 5)
fig
end
first_layout_fixed()
Aqui, ter o rótulo (a)
no TopLeft()
provavelmente não é necessário, isso só fará sentido para mais de dois plots. Para o nosso próximo exemplo vamos continuar usando as ferramentas anteriores e mais algumas para criar uma figura mais rica e complexa.
Você pode ocultar decorações e espinhas de eixos com:
hidedecorations!(ax; kwargs...)
hidexdecorations!(ax; kwargs...)
hideydecorations!(ax; kwargs...)
hidespines!(ax; kwargs...)
Lembre-se, sempre podemos pedir ajuda para ver que tipo de argumentos podemos usar, por exemplo,
help(hidespines!)
hidespines!(la::Axis, spines::Symbol... = (:l, :r, :b, :t)...)
Hide all specified axis spines. Hides all spines by default, otherwise
choose with the symbols :l, :r, :b and :t.
hidespines! has the following function signatures:
(Vector, Vector)
(Vector, Vector, Vector)
(Matrix)
Available attributes for Combined{Makie.MakieLayout.hidespines!} are:
Alternativamente, para decorações:
help(hidedecorations!)
hidedecorations!(la::Axis)
Hide decorations of both x and y-axis: label, ticklabels, ticks and grid.
hidedecorations! has the following function signatures:
(Vector, Vector)
(Vector, Vector, Vector)
(Matrix)
Available attributes for Combined{Makie.MakieLayout.hidedecorations!} are:
Para elementos que você não deseja ocultar, apenas passe-os com false
, ou seja, hideydecorations!(ax; ticks=false, grid=false)
.
A sincronização do seu Axis
é feita via:
linkaxes!
,linkyaxes!
elinkxaxes!
Isso pode ser útil quando eixos compartilhados são desejados. Outra maneira de obter eixos compartilhados será definindo
limites!
.
Definir limites de uma vez ou independentemente para cada eixo é feito chamando
limits!(ax; l, r, b, t)
, ondel
é esquerda,r
direita,b
inferior et
superior.Você também pode fazer
ylims!(low, high)
ouxlims!(low, high)
, e até mesmo abrir fazendoylims!(low=0)
ouxlims!(high=1)
.
Agora, o exemplo:
function complex_layout_double_axis()
seed!(123)
x = LinRange(0, 1, 10)
y = LinRange(0, 1, 10)
z = rand(10, 10)
fig = Figure(resolution=(600, 400), font="CMU Serif", backgroundcolor=:grey90)
ax1 = Axis(fig, xlabel=L"x", ylabel=L"y")
ax2 = Axis(fig, xlabel=L"x")
heatmap!(ax1, x, y, z; colorrange=(0, 1))
series!(ax2, abs.(z[1:4, :]); labels=["lab $i" for i = 1:4], color=:Set1_4)
hm = scatter!(10x, y; color=z[1, :], label="dots", colorrange=(0, 1))
hideydecorations!(ax2, ticks=false, grid=false)
linkyaxes!(ax1, ax2)
#layout
fig[1, 1] = ax1
fig[1, 2] = ax2
Label(fig[1, 1, TopLeft()], "(a)", textsize=18, padding=(0, 6, 8, 0))
Label(fig[1, 2, TopLeft()], "(b)", textsize=18, padding=(0, 6, 8, 0))
Colorbar(fig[2, 1:2], hm, label="colorbar", vertical=false, flipaxis=false)
Legend(fig[1, 3], ax2, "Legend")
colgap!(fig.layout, 5)
rowgap!(fig.layout, 5)
fig
end
complex_layout_double_axis()
Então, agora nosso Colorbar
precisa ser horizontal e as marcações da barra precisam estar na parte inferior. Isso é feito configurando vertical=false
e flipaxis=false
. Além disso, observe que podemos chamar muitos Axis
em fig
, ou mesmo Colorbar
e Legend
, e depois construir o layout.
Outro layout comum é uma grade de quadrados para mapas de calor:
function squares_layout()
seed!(123)
letters = reshape(collect('a':'d'), (2, 2))
fig = Figure(resolution=(600, 400), fontsize=14, font="CMU Serif",
backgroundcolor=:grey90)
axs = [Axis(fig[i, j], aspect=DataAspect()) for i = 1:2, j = 1:2]
hms = [heatmap!(axs[i, j], randn(10, 10), colorrange=(-2, 2))
for i = 1:2, j = 1:2]
Colorbar(fig[1:2, 3], hms[1], label="colorbar")
[Label(fig[i, j, TopLeft()], "($(letters[i, j]))", textsize=16,
padding=(-2, 0, -20, 0)) for i = 1:2, j = 1:2]
colgap!(fig.layout, 5)
rowgap!(fig.layout, 5)
fig
end
squares_layout()
onde todos os rótulos estão em protrusões e cada Axis
tem uma razão AspectData()
. A Colorbar
está localizada na terceira coluna e se expande da linha 1 até a linha 2.
O próximo caso usa o chamado modo de alinhamento Mixed()
, o que é especialmente útil ao lidar com grandes espaços vazios entre Axis
devido a tiques longos. Ainda, o módulo Dates
da biblioteca padrão de Julia será necessário para esse exemplo.
using Dates
function mixed_mode_layout()
seed!(123)
longlabels = ["$(today() - Day(1))", "$(today())", "$(today() + Day(1))"]
fig = Figure(resolution=(600, 400), fontsize=12,
backgroundcolor=:grey90, font="CMU Serif")
ax1 = Axis(fig[1, 1])
ax2 = Axis(fig[1, 2], xticklabelrotation=pi / 2, alignmode=Mixed(bottom=0),
xticks=([1, 5, 10], longlabels))
ax3 = Axis(fig[2, 1:2])
ax4 = Axis(fig[3, 1:2])
axs = [ax1, ax2, ax3, ax4]
[lines!(ax, 1:10, rand(10)) for ax in axs]
hidexdecorations!(ax3; ticks=false, grid=false)
Box(fig[2:3, 1:2, Right()], color=(:slateblue1, 0.35))
Label(fig[2:3, 1:2, Right()], "protrusion", rotation=pi / 2, textsize=14,
padding=(3, 3, 3, 3))
Label(fig[1, 1:2, Top()], "Mixed alignmode", textsize=16,
padding=(0, 0, 15, 0))
colsize!(fig.layout, 1, Auto(2))
rowsize!(fig.layout, 2, Auto(0.5))
rowsize!(fig.layout, 3, Auto(0.5))
rowgap!(fig.layout, 1, 15)
rowgap!(fig.layout, 2, 0)
colgap!(fig.layout, 5)
fig
end
mixed_mode_layout()
Aqui, o argumento alignmode=Mixed(bottom=0)
desloca a caixa delimitadora para a parte inferior, de forma a alinhar com o painel à esquerda preenchendo o espaço.
Também, veja como colsize!
e rowsize!
estão sendo usados para diferentes colunas e linhas. Você também pode colocar um número ao invés de Auto()
mas então tudo vai ser corrigido. E, além disso, pode-se também dar um height
ou width
ao definir o Axis
, como em Axis(fig, heigth=50)
que será corrigido também.
Axis
aninhado (subplots)Também é possível definir um conjunto de Axis
(subplots) explicitamente e use-o para construir uma figura principal com várias linhas e colunas. Por exemplo, o seguinte é um arranjo “complicado” de Axis
:
function nested_sub_plot!(fig)
color = rand(RGBf)
ax1 = Axis(fig[1, 1], backgroundcolor=(color, 0.25))
ax2 = Axis(fig[1, 2], backgroundcolor=(color, 0.25))
ax3 = Axis(fig[2, 1:2], backgroundcolor=(color, 0.25))
ax4 = Axis(fig[1:2, 3], backgroundcolor=(color, 0.25))
return (ax1, ax2, ax3, ax4)
end
que, quando usado para construir uma figura mais complexa fazendo várias chamadas, obtemos:
function main_figure()
fig = Figure()
Axis(fig[1, 1])
nested_sub_plot!(fig[1, 2])
nested_sub_plot!(fig[1, 3])
nested_sub_plot!(fig[2, 1:3])
fig
end
main_figure()
Observe que diferentes funções de subplot podem ser chamadas aqui. Também, cada Axis
aqui é uma parte independente de Figure
. Então, se você precisar fazer alguma operação rowgap!
ou colsize!
, você precisará fazê-lo em cada um deles de forma independente ou em todos eles juntos.
Para Axis
(subplots) agrupados podemos usar GridLayout()
que, então, poderia ser usado para compor um Figure
.
Ao usar o GridLayout()
podemos agrupar subplots, permitindo mais liberdade na construção de figuras complexas. Aqui, usando nosso nested_sub_plot!
anterior, definimos três subgrupos e um Axis
normal:
function nested_Grid_Layouts()
fig = Figure(backgroundcolor=RGBf(0.96, 0.96, 0.96))
ga = fig[1, 1] = GridLayout()
gb = fig[1, 2] = GridLayout()
gc = fig[1, 3] = GridLayout()
gd = fig[2, 1:3] = GridLayout()
gA = Axis(ga[1, 1])
nested_sub_plot!(gb)
axsc = nested_sub_plot!(gc)
nested_sub_plot!(gd)
[hidedecorations!(axsc[i], grid=false, ticks=false) for i = 1:length(axsc)]
colgap!(gc, 5)
rowgap!(gc, 5)
rowsize!(fig.layout, 2, Auto(0.5))
colsize!(fig.layout, 1, Auto(0.5))
fig
end
nested_Grid_Layouts()
Agora, usando rowgap!
ou colsize!
sobre cada grupo é possível rowsize!, colsize!
também pode ser aplicado ao conjunto de GridLayout()
.
inset
Atualmente, fazer gráficos inset
é um pouco complicado. Aqui, mostramos duas maneiras possíveis de fazer isso definindo inicialmente as funções auxiliares. A primeira é fazendo um BBox
, que fica em todo o espaço Figure
:
function add_box_inset(fig; left=100, right=250, bottom=200, top=300,
bgcolor=:grey90)
inset_box = Axis(fig, bbox=BBox(left, right, bottom, top),
xticklabelsize=12, yticklabelsize=12, backgroundcolor=bgcolor)
# bring content upfront
translate!(inset_box.scene, 0, 0, 10)
elements = keys(inset_box.elements)
filtered = filter(ele -> ele != :xaxis && ele != :yaxis, elements)
foreach(ele -> translate!(inset_box.elements[ele], 0, 0, 9), filtered)
return inset_box
end
Então, o inset
é feito facilmente, como em:
function figure_box_inset()
fig = Figure(resolution=(600, 400))
ax = Axis(fig[1, 1], backgroundcolor=:white)
inset_ax1 = add_box_inset(fig; left=100, right=250, bottom=200, top=300,
bgcolor=:grey90)
inset_ax2 = add_box_inset(fig; left=500, right=600, bottom=100, top=200,
bgcolor=(:white, 0.65))
lines!(ax, 1:10)
lines!(inset_ax1, 1:10)
scatter!(inset_ax2, 1:10, color=:black)
fig
end
figure_box_inset()
onde as dimensões Box
estão vinculadas ao resolution
Figure
. Observe que um inset também pode estar fora do Axis
. A outra abordagem é definir um novo Axis
em uma posição fig[i, j]
especificando seu width
, height
, halign
and valign
. Fazemos isso na seguinte função:
function add_axis_inset(; pos=fig[1, 1], halign=0.1, valign=0.5,
width=Relative(0.5), height=Relative(0.35), bgcolor=:lightgray)
inset_box = Axis(pos, width=width, height=height,
halign=halign, valign=valign, xticklabelsize=12, yticklabelsize=12,
backgroundcolor=bgcolor)
# bring content upfront
translate!(inset_box.scene, 0, 0, 10)
elements = keys(inset_box.elements)
filtered = filter(ele -> ele != :xaxis && ele != :yaxis, elements)
foreach(ele -> translate!(inset_box.elements[ele], 0, 0, 9), filtered)
return inset_box
end
Veja que no exemplo a seguir o Axis
com fundo cinza será redimensionado se o tamanho total da figura for alterado. Os insets são limitados pelo posicionamento do Axis
.
function figure_axis_inset()
fig = Figure(resolution=(600, 400))
ax = Axis(fig[1, 1], backgroundcolor=:white)
inset_ax1 = add_axis_inset(; pos=fig[1, 1], halign=0.1, valign=0.65,
width=Relative(0.3), height=Relative(0.3), bgcolor=:grey90)
inset_ax2 = add_axis_inset(; pos=fig[1, 1], halign=1, valign=0.25,
width=Relative(0.25), height=Relative(0.3), bgcolor=(:white, 0.65))
lines!(ax, 1:10)
lines!(inset_ax1, 1:10)
scatter!(inset_ax2, 1:10, color=:black)
fig
end
figure_axis_inset()
E isso deve cobrir os casos mais usados para layout com Makie. Agora, vamos fazer alguns bons exemplos 3D com GLMakie.jl
.