Figure 27: First Layout.

    这看起来已经不错了,但能变得更好。可以使用以下关键字和方法来解决图的间距问题:

    • figure_padding=(left, right, bottom, top)
    • padding=(left, right, bottom, top)

    改变 LegendColorbar 实际大小的方法为:

    可以使用以下方法指定行和列的间距:

    • colgap!(fig.layout, col, separation)
    • rowgap!(fig.layout, row, separation)

    列间距colgap!),如果给定了 col,那么间距将只应用在指定的列。 行间距rowgap!),如果给定了 row,那么间距将只应用在指定的行。

    接下来将学习如何将内容放进 突出部分(protrusion),即为 标题 xy,或 ticks 以及 label 保留的空间。 实现方法是将位置索引改为 fig[i, j, protrusion], 其中 protrusion 可以是 Left()Right()Bottom()Top(),或者是四个角 TopLeft()TopRight()BottomRight()BottomLeft()。 这些选项将在如下的例子中使用:

    1. function first_layout_fixed()
    2. seed!(123)
    3. x, y, z = randn(6), randn(6), randn(6)
    4. fig = Figure(figure_padding=(0, 3, 5, 2), resolution=(600, 400),
    5. backgroundcolor=:grey90, font="CMU Serif")
    6. ax = Axis(fig[1, 1], xlabel=L"x", ylabel=L"y",
    7. title="Layout example", backgroundcolor=:white)
    8. pltobj = scatter!(ax, x, y; color=z, label="scatters")
    9. lines!(ax, x, 1.1y, label="line")
    10. Legend(fig[2, 1:2], ax, "Labels", orientation=:horizontal,
    11. tellheight=true, titleposition=:left)
    12. Colorbar(fig[1, 2], pltobj, label="colorbar")
    13. # additional aesthetics
    14. Box(fig[1, 1, Right()], color=(:slateblue1, 0.35))
    15. Label(fig[1, 1, Right()], "protrusion", textsize=18,
    16. rotation=pi / 2, padding=(3, 3, 3, 3))
    17. Label(fig[1, 1, TopLeft()], "(a)", textsize=18, padding=(0, 3, 8, 0))
    18. colgap!(fig.layout, 5)
    19. rowgap!(fig.layout, 5)
    20. fig
    21. end
    22. first_layout_fixed()

    Figure 28: First Layout Fixed.

    Figure 28: First Layout Fixed.

    这里在 TopLeft()添加标签 (a) 可能是不必要的, 因为标签仅在有两个以上的图时有意义。 在接下来的例子中,我们将继续使用之前的工具和一些新工具,并创建一个更丰富、更复杂的图。

    可以使用以下函数隐藏图的装饰部分和轴线:

    应记住总是可以调用 help 查看能够传递的参数,例如:

    1. help(hidespines!)
    1. hidespines!(la::Axis, spines::Symbol... = (:l, :r, :b, :t)...)
    2. Hide all specified axis spines. Hides all spines by default, otherwise
    3. choose with the symbols :l, :r, :b and :t.
    4. hidespines! has the following function signatures:
    5. (Vector, Vector)
    6. (Vector, Vector, Vector)
    7. (Matrix)
    8. Available attributes for Combined{Makie.MakieLayout.hidespines!} are:

    另外,对于 hidedecorations! 有:

    1. help(hidedecorations!)

    对于 不想隐藏的 元素,仅需要将它们的值设置为 false,即 hideydecorations!(ax; ticks=false, grid=false)

    同步 Axis 的方式如下:

    • linkaxes!linkyaxes!linkxaxes!

    使用以下方式可一次性设定,当然也能单独为每个方向的轴单独设定:

    例子如下:

    1. function complex_layout_double_axis()
    2. seed!(123)
    3. x = LinRange(0, 1, 10)
    4. y = LinRange(0, 1, 10)
    5. z = rand(10, 10)
    6. fig = Figure(resolution=(600, 400), font="CMU Serif", backgroundcolor=:grey90)
    7. ax1 = Axis(fig, xlabel=L"x", ylabel=L"y")
    8. ax2 = Axis(fig, xlabel=L"x")
    9. heatmap!(ax1, x, y, z; colorrange=(0, 1))
    10. hm = scatter!(10x, y; color=z[1, :], label="dots", colorrange=(0, 1))
    11. hideydecorations!(ax2, ticks=false, grid=false)
    12. linkyaxes!(ax1, ax2)
    13. #layout
    14. fig[1, 1] = ax1
    15. fig[1, 2] = ax2
    16. Label(fig[1, 1, TopLeft()], "(a)", textsize=18, padding=(0, 6, 8, 0))
    17. Label(fig[1, 2, TopLeft()], "(b)", textsize=18, padding=(0, 6, 8, 0))
    18. Colorbar(fig[2, 1:2], hm, label="colorbar", vertical=false, flipaxis=false)
    19. Legend(fig[1, 3], ax2, "Legend")
    20. colgap!(fig.layout, 5)
    21. rowgap!(fig.layout, 5)
    22. fig
    23. end
    24. complex_layout_double_axis()

    Figure 29: Complex layout double axis.

    如上所示, Colorbar 的方向已经变为水平且它的标签也处在其下方。 这是因为设定了 vertical=falseflipaxis=false。 另外,也可以将更多的 Axis 添加到 fig 里,甚至可以是 ColorbarLegend,然后再构建布局。

    另一种常见布局是热力图组成的正方网格:

    1. function squares_layout()
    2. seed!(123)
    3. letters = reshape(collect('a':'d'), (2, 2))
    4. fig = Figure(resolution=(600, 400), fontsize=14, font="CMU Serif",
    5. backgroundcolor=:grey90)
    6. axs = [Axis(fig[i, j], aspect=DataAspect()) for i = 1:2, j = 1:2]
    7. hms = [heatmap!(axs[i, j], randn(10, 10), colorrange=(-2, 2))
    8. for i = 1:2, j = 1:2]
    9. Colorbar(fig[1:2, 3], hms[1], label="colorbar")
    10. [Label(fig[i, j, TopLeft()], "($(letters[i, j]))", textsize=16,
    11. padding=(-2, 0, -20, 0)) for i = 1:2, j = 1:2]
    12. colgap!(fig.layout, 5)
    13. rowgap!(fig.layout, 5)
    14. fig
    15. end
    16. squares_layout()

    Figure 30: Squares layout.

    Figure 30: Squares layout.

    上图中每一个标签都位于 突出部分 并且每一个 Axis 都有 AspectData() 率属性。 图中 Colorbar 位于第三列,并从第一行跨到第二行。

    下例将使用称为 Mixed()对齐模式,这在处理 Axis 间的大量空白区域时很有用,而这些空白区域通常是由长标签导致的。 另外,本例还需要使用 Julia 标准库中的 Dates

    1. using Dates
    1. function mixed_mode_layout()
    2. seed!(123)
    3. longlabels = ["$(today() - Day(1))", "$(today())", "$(today() + Day(1))"]
    4. fig = Figure(resolution=(600, 400), fontsize=12,
    5. backgroundcolor=:grey90, font="CMU Serif")
    6. ax1 = Axis(fig[1, 1])
    7. ax2 = Axis(fig[1, 2], xticklabelrotation=pi / 2, alignmode=Mixed(bottom=0),
    8. xticks=([1, 5, 10], longlabels))
    9. ax3 = Axis(fig[2, 1:2])
    10. ax4 = Axis(fig[3, 1:2])
    11. axs = [ax1, ax2, ax3, ax4]
    12. [lines!(ax, 1:10, rand(10)) for ax in axs]
    13. hidexdecorations!(ax3; ticks=false, grid=false)
    14. Box(fig[2:3, 1:2, Right()], color=(:slateblue1, 0.35))
    15. Label(fig[2:3, 1:2, Right()], "protrusion", rotation=pi / 2, textsize=14,
    16. padding=(3, 3, 3, 3))
    17. Label(fig[1, 1:2, Top()], "Mixed alignmode", textsize=16,
    18. padding=(0, 0, 15, 0))
    19. colsize!(fig.layout, 1, Auto(2))
    20. rowsize!(fig.layout, 2, Auto(0.5))
    21. rowsize!(fig.layout, 3, Auto(0.5))
    22. rowgap!(fig.layout, 1, 15)
    23. rowgap!(fig.layout, 2, 0)
    24. colgap!(fig.layout, 5)
    25. fig
    26. end
    27. mixed_mode_layout()

    Figure 31: Mixed mode layout.

    如上,参数 alignmode=Mixed(bottom=0) 将边界框移动到底部,使其与左侧面板保持对齐。

    从上图也可以看到 colsize!rowsize! 如何作用于不同的行和列。 可以向函数传递一个数字而不是 Auto(),但那会固定所有的设置。 另外, 在定义 Axis 时也可以设定 height 或 ,例如 Axis(fig, heigth=50) 将会固定轴的高度。

    精准定义一组 Axis (subplots) 也是可行的, 可以使用一组 Axis 构造具有多行多列的图。 例如,下面展示了一组较复杂的 Axis

    1. function main_figure()
    2. Axis(fig[1, 1])
    3. nested_sub_plot!(fig[1, 2])
    4. nested_sub_plot!(fig[1, 3])
    5. nested_sub_plot!(fig[2, 1:3])
    6. fig
    7. end
    8. main_figure()

    Figure 32: Main figure.

    Figure 32: Main figure.

    注意,这里可以调用不同的子图函数。 另外,每一个 Axis 都是 Figure 的独立部分。 因此,当在进行 rowgap!或者 colsize! 这样的操作时,你需要考虑是对每一个子图单独作用还是对所有的图一起作用。

    对于组合的 Axis (subplots) 可以使用 GridLayout(), 它能用来构造更复杂的 Figure

    可以使用 GridLayout() 组合子图,这种方法能够更自由地构建更复杂的图。 这里再次使用之前的 nested_sub_plot!,它定义了三组子图和一个普通的 Axis

    1. function nested_Grid_Layouts()
    2. fig = Figure(backgroundcolor=RGBf(0.96, 0.96, 0.96))
    3. ga = fig[1, 1] = GridLayout()
    4. gb = fig[1, 2] = GridLayout()
    5. gc = fig[1, 3] = GridLayout()
    6. gd = fig[2, 1:3] = GridLayout()
    7. gA = Axis(ga[1, 1])
    8. nested_sub_plot!(gb)
    9. axsc = nested_sub_plot!(gc)
    10. nested_sub_plot!(gd)
    11. [hidedecorations!(axsc[i], grid=false, ticks=false) for i = 1:length(axsc)]
    12. colgap!(gc, 5)
    13. rowgap!(gc, 5)
    14. rowsize!(fig.layout, 2, Auto(0.5))
    15. colsize!(fig.layout, 1, Auto(0.5))
    16. fig
    17. end
    18. nested_Grid_Layouts()

    Figure 33: Nested Grid Layouts.

    现在,对每一组使用 rowgap!colsize! 将是可行的,并且 rowsize!, colsize! 也能够应用于 GridLayout()

    目前,绘制 inset 是一项棘手的工作。 本节展示两种在初始时通过定义辅助函数实现绘制插图的方法。 第一种是定义 BBox,它存在于整个 Figure 空间:

    1. function add_box_inset(fig; left=100, right=250, bottom=200, top=300,
    2. bgcolor=:grey90)
    3. inset_box = Axis(fig, bbox=BBox(left, right, bottom, top),
    4. xticklabelsize=12, yticklabelsize=12, backgroundcolor=bgcolor)
    5. # bring content upfront
    6. translate!(inset_box.scene, 0, 0, 10)
    7. elements = keys(inset_box.elements)
    8. filtered = filter(ele -> ele != :xaxis && ele != :yaxis, elements)
    9. foreach(ele -> translate!(inset_box.elements[ele], 0, 0, 9), filtered)
    10. return inset_box
    11. end

    然后可以按照如下方式轻松地绘制插图:

    1. function figure_box_inset()
    2. fig = Figure(resolution=(600, 400))
    3. ax = Axis(fig[1, 1], backgroundcolor=:white)
    4. inset_ax1 = add_box_inset(fig; left=100, right=250, bottom=200, top=300,
    5. bgcolor=:grey90)
    6. inset_ax2 = add_box_inset(fig; left=500, right=600, bottom=100, top=200,
    7. bgcolor=(:white, 0.65))
    8. lines!(ax, 1:10)
    9. lines!(inset_ax1, 1:10)
    10. scatter!(inset_ax2, 1:10, color=:black)
    11. fig
    12. end
    13. figure_box_inset()

    Figure 34: Figure box inset.

    Figure 34: Figure box inset.

    其中 Box 的尺寸受到 Figureresolution 参数的约束。 注意,也可以在 Axis 外绘制插图。 另一种绘制插图的方法是,在位置fig[i, j]处定义一个新的 Axis,并且指定 widthheighthalignvalign。 如下面的函数例子所示:

    在下面的例子中,如果总图的大小发生变化,那么将重新缩放灰色背景的 Axis。 同时 插图 要受到 Axis 位置的约束。

    1. function figure_axis_inset()
    2. fig = Figure(resolution=(600, 400))
    3. ax = Axis(fig[1, 1], backgroundcolor=:white)
    4. inset_ax1 = add_axis_inset(; pos=fig[1, 1], halign=0.1, valign=0.65,
    5. width=Relative(0.3), height=Relative(0.3), bgcolor=:grey90)
    6. inset_ax2 = add_axis_inset(; pos=fig[1, 1], halign=1, valign=0.25,
    7. width=Relative(0.25), height=Relative(0.3), bgcolor=(:white, 0.65))
    8. lines!(ax, 1:10)
    9. lines!(inset_ax1, 1:10)
    10. scatter!(inset_ax2, 1:10, color=:black)
    11. fig

    Figure 35: Figure axis inset.

    Jose Storopoli, Rik Huijzer, Lazaro Alonso, 刘贵欣 (中文翻译), 田俊 (中文审校)