Grid plot and Label with CairoMakie

Hi everyone,
I want to make a plot like this one (illustration from http://dx.doi.org/10.1118/1.4947485) with CairoMakie.jl:

S nothing crazy. However, after several attempts (see code below), I am unable to obtain satisfactory results. The images are always tiny, and there are large borders on the sides.

For instance:


using CairoMakie
function plot_images_grid(mat1_vec, mat2_vec;
                             row_names,
                             col_names)

    @assert length(mat1_vec) == length(mat2_vec) "mat1_vec and mat2_vec must have the same length"
    n = length(mat1_vec)
    n == 0 && error("materials list is empty")

    fig = Figure(backgroundcolor = :black)

    # Row 1: column titles
    material_names_grid = fig[1, 2] = GridLayout()

    Label(material_names_grid[1, 1], col_names[1], color = :white, halign = :center)
    Label(material_names_grid[1, 2], col_names[2], color = :white, halign = :center)

    # Row 2: image grid
    images_grid = fig[2, 2] = GridLayout()
    reg_names_grid = fig[2, 1] = GridLayout()

    for i in 1:n
        Label(reg_names_grid[i, 1], row_names[i], color = :white, halign = :right, rotation = pi/2)

        ax1 = Axis(images_grid[i, 1], aspect = DataAspect())
        heatmap!(ax1, mat1_vec[i], colormap = :grays)

        ax2 = Axis(images_grid[i, 2], aspect = DataAspect())
        heatmap!(ax2, mat2_vec[i], colormap = :grays)
    end

    #colgap!(images_grid, 5)
    #rowgap!(images_grid, 50)
    # after images_grid = fig[2,2] = GridLayout()
    #colsize!(images_grid, 1, Relative(4))
    #colsize!(images_grid, 2, Relative(4))
    return fig
end


mat1_vec = [10*rand(100, 100) for _ in 1:3]
mat2_vec = [15*rand(100, 100) for _ in 1:3]
row_names = ["Region 1", "Region 2", "Region 3"]
col_names = ("Material 1", "Material 2")
fig = plot_images_grid(mat1_vec, mat2_vec;
                       row_names=row_names,
                       col_names=col_names)
display(fig)

give me:

Thanks for your help!
fdekerm

You need to use tellwidth=false for the label.


using GLMakie
function plot_images_grid(mat1_vec, mat2_vec;
                             row_names,
                             col_names)

    @assert length(mat1_vec) == length(mat2_vec) "mat1_vec and mat2_vec must have the same length"
    n = length(mat1_vec)
    n == 0 && error("materials list is empty")

    fig = Figure(backgroundcolor = :black)

    # Row 1: column titles
    material_names_grid = fig[1, 2] = GridLayout()

    Label(material_names_grid[1, 1], col_names[1], color = :white, halign = :center)
    Label(material_names_grid[1, 2], col_names[2], color = :white, halign = :center)
    # Row 2: image grid
    images_grid = fig[2, 2] = GridLayout()
    reg_names_grid = fig[2, 1] = GridLayout()

    for i in 1:n
        Label(reg_names_grid[i, 1], row_names[i], color = :white, tellwidth = false, halign = :right, rotation = pi/2)

        ax1 = Axis(images_grid[i, 1], aspect = DataAspect())
        heatmap!(ax1, mat1_vec[i], colormap = :grays)
        hidedecorations!(ax1)

        ax2 = Axis(images_grid[i, 2], aspect = DataAspect())
        heatmap!(ax2, mat2_vec[i], colormap = :grays)
        hidedecorations!(ax2)
    end

    colgap!(images_grid, 0)
    rowgap!(images_grid, 0)
    return fig
end


mat1_vec = [10*rand(100, 100) for _ in 1:3]
mat2_vec = [15*rand(100, 100) for _ in 1:3]
row_names = ["Region 1", "Region 2", "Region 3"]
col_names = ("Material 1", "Material 2")
fig = plot_images_grid(mat1_vec, mat2_vec;
                       row_names=row_names,
                       col_names=col_names)
display(fig)

Because of aspect=DataAspect(), you also need to give the figure the correct dimensions to fit the whole window.

1 Like

Sorry, that wasn’t entirely right, here is a better solution:


using GLMakie
function plot_images_grid(mat1_vec, mat2_vec;
                             row_names,
                             col_names)

    @assert length(mat1_vec) == length(mat2_vec) "mat1_vec and mat2_vec must have the same length"
    n = length(mat1_vec)
    n == 0 && error("materials list is empty")

    fig = Figure(backgroundcolor = :black)
    Label(fig[0, 1], col_names[1], color=:white, halign=:center, tellwidth=false)
    Label(fig[0, 2], col_names[2], color=:white, halign=:center, tellwidth=false)

    for i in 1:n
        Label(fig[i, 0], row_names[i], color=:white, tellheight=false, halign=:right, rotation=pi / 2)
        ax1 = Axis(fig[i, 1], aspect = DataAspect())
        heatmap!(ax1, mat1_vec[i], colormap = :grays)
        hidedecorations!(ax1)
        ax2 = Axis(fig[i, 2], aspect = DataAspect())
        heatmap!(ax2, mat2_vec[i], colormap = :grays)
        hidedecorations!(ax2)
    end
    colgap!(fig.layout, 0)
    rowgap!(fig.layout, 0)
    return fig
end


mat1_vec = [10*rand(100, 100) for _ in 1:3]
mat2_vec = [15*rand(100, 100) for _ in 1:3]
row_names = ["Region 1", "Region 2", "Region 3"]
col_names = ("Material 1", "Material 2")
fig = plot_images_grid(mat1_vec, mat2_vec;
                       row_names=row_names,
                       col_names=col_names)
display(fig)

The plots + labels should be in the same grid, to align them nicely.

1 Like