Engee documentation
Notebook

Creating complex graph layouts using Makie

This example demonstrates the tools of the Makie library for creating professional scientific visualizations by combining graphs of various types (scatter plots, contour plots, 3D models, and time series) into a single complex layout using nested GridLayout, linked axes, custom legends, and color scales, as well as advanced element positioning and space management techniques to create informative and colorful illustrations.

1. Package installation and data preparation
In [ ]:
Pkg.add("Makie")
Pkg.add("CairoMakie")

Preparing data for the first chart:

In [ ]:
seconds = 0:0.1:2
measurements = [8.2, 8.4, 6.3, 9.5, 9.1, 10.5, 8.6, 8.2, 10.5, 8.5, 7.2,
                8.8, 9.7, 10.8, 12.5, 11.6, 12.1, 12.1, 15.1, 14.7, 13.1]

using CairoMakie
2. Creating a basic schedule

Let's start with a simple visualization of experimental data and an exponential model.
Main components:

  • Figure() creates a container for graphs
  • Axis() defines a coordinate system with captions
  • scatter!() adds measurement points
  • lines!() draws the model line
  • axislegend() creates a legend

Displaying a graph with experimental data and an exponential model:

In [ ]:
f = Figure()
ax = Axis(f[1, 1],
    title = "Experimental data and exponential fit",
    xlabel = "Time (seconds)",
    ylabel = "Value",
)
CairoMakie.scatter!(
    ax,
    seconds,
    measurements,
    color = :tomato,
    label = "Measurements"
)
lines!(
    ax,
    seconds,
    exp.(seconds) .+ 7,
    color = :tomato,
    linestyle = :dash,
    label = "f(x) = exp(x) + 7",
)
# Добавление легенды в правый нижний угол
axislegend(position = :rb)

# Отображение фигуры
f
Out[0]:
No description has been provided for this image
3. Forming a complex layout

Creating a complex graphic object (shape) with several areas for plotting:

  1. We use GridLayout for organizing nested grids
  2. We define 4 main areas (A, B, C, D)
  3. Adjust the background and shape size
  4. We connect the axes to synchronize the scales
In [ ]:
using CairoMakie
using Makie.FileIO  # Для работы с файлами

# Активация бэкенда и создание фигуры
CairoMakie.activate!()
f = Figure(
    backgroundcolor = RGBf(0.98, 0.98, 0.98),
    size = (1000, 700)
)

# Создание вложенных сеток
ga = f[1, 1] = GridLayout()  # Область A
gb = f[2, 1] = GridLayout()  # Область B
gcd = f[1:2, 2] = GridLayout()  # Контейнер для C и D
gc = gcd[1, 1] = GridLayout()  # Область C (3D мозг)
gd = gcd[2, 1] = GridLayout()  # Область D (EEG сигналы)

# Создание связанных осей для Область A
axtop = Axis(ga[1, 1])        # Верхнее распределение
axmain = Axis(ga[2, 1],       # Основной график
    xlabel = "before", 
    ylabel = "after")
axright = Axis(ga[2, 2])      # Правое распределение

# Связывание осей для синхронизации
linkyaxes!(axmain, axright)  # Общая шкала Y
linkxaxes!(axmain, axtop)    # Общая шкала X

f
Out[0]:
No description has been provided for this image
4. Area A: Scattering and distribution diagrams

Area A demonstrates:

  • Grouping of data through color coding
  • Related axes with common scales
  • Distributions at the edges of the main graph
  • Automatic legend placement
  • Fine-tune the margins between the elements
In [ ]:
# Генерация тестовых данных для трех групп
labels = ["treatment", "placebo", "control"]
data = randn(3, 100, 2) .+ [1, 3, 5]  # 3 группы × 100 точек × 2 измерения

# Визуализация каждой группы
for (label, col) in zip(labels, eachslice(data, dims = 1))
    CairoMakie.scatter!(axmain, col, label = label)
    CairoMakie.density!(axtop, col[:, 1])  # Распределение сверху
    CairoMakie.density!(axright, col[:, 2], direction = :y)  # Распределение справа
end

# Настройка границ осей
CairoMakie.ylims!(axtop, low = 0)
CairoMakie.xlims!(axright, low = 0)

# Установка меток на осях
axmain.xticks = 0:3:9
axtop.xticks = 0:3:9

# Добавление легенды и скрытие лишних элементов
leg = Legend(ga[1, 2], axmain)
hidedecorations!(axtop, grid = false)
hidedecorations!(axright, grid = false)
leg.tellheight = true  # Фиксируем высоту легенды

# Добавление заголовка области
Label(ga[1, 1:2, Top()], "Stimulus ratings", valign = :bottom,
    font = :bold,
    padding = (0, 0, 5, 0))

# Настройка расстояний между элементами
colgap!(ga, 10)
rowgap!(ga, 10)

f
Out[0]:
No description has been provided for this image
5. Area B: Contour plots

Area B shows:

  • Contour graphs for visualization of 2D data
  • Graph hierarchy: contourf+ contour
  • Custom color scale with bin marking
  • Alignment of elements via Mixed alignmode
  • Precise control over the distances between the graphs
In [ ]:
# Подготовка данных для контурных графиков
xs = LinRange(0.5, 6, 50)
ys = LinRange(0.5, 6, 50)
data1 = [sin(x^1.5) * cos(y^0.5) for x in xs, y in ys] .+ 0.1 .* randn.()
data2 = [sin(x^0.8) * cos(y^1.5) for x in xs, y in ys] .+ 0.1 .* randn.()

# Построение контурных графиков
ax1, hm = CairoMakie.contourf(gb[1, 1], xs, ys, data1, levels = 6)
ax1.title = "Histological analysis"
CairoMakie.contour!(ax1, xs, ys, data1, levels = 5, color = :black)
hidexdecorations!(ax1)  # Скрываем метки на оси X

ax2, hm2 = CairoMakie.contourf(gb[2, 1], xs, ys, data2, levels = 6)
CairoMakie.contour!(ax2, xs, ys, data2, levels = 5, color = :black)

# Настройка цветовой шкалы
cb = CairoMakie.Colorbar(gb[1:2, 2], hm, label = "cell group")
low, high = CairoMakie.extrema(data1)
edges = range(low, high, length = 7)
centers = (edges[1:6] .+ edges[2:7]) .* 0.5
cb.ticks = (centers, string.(1:6))  # Кастомные метки

# Оптимизация выравнивания
cb.alignmode = Mixed(right = 0)

# Настройка расстояний
colgap!(gb, 10)
rowgap!(gb, 10)

f
Out[0]:
No description has been provided for this image
6. Area C: 3D visualization of the brain

Area C demonstrates:

  • Download and visualization of 3D models (STL format)
  • Use Axis3 for 3D graphs
  • Color coding based on Y coordinates
  • Inverted color map for better perception
  • Integration of 3D visualization into the overall layout
In [ ]:
# Загрузка и визуализация 3D модели мозга
brain = load(assetpath("brain.stl"))

ax3d = Axis3(gc[1, 1], title = "Brain activation")
m = mesh!(
    ax3d,
    brain,
    color = [tri[1][2] for tri in brain for i in 1:3],
    colormap = Reverse(:magma),  # Инвертированная цветовая карта
)
Colorbar(gc[1, 2], m, label = "BOLD level")  # Цветовая шкала

f
Out[0]:
No description has been provided for this image
7. Area D: EEG signals

Area D shows:

  • Arrays of axes for grouping graphs
  • Generation of artificial EEG signals
  • Dynamic scaling of axes by the number of points
  • Rotated labels to save space
  • Automatic alignment of column sizes
In [ ]:
# Создание сетки осей для сигналов ЭЭГ
axs = [Axis(gd[row, col]) for row in 1:3, col in 1:2]
hidedecorations!.(axs, grid = false, label = false)  # Упрощаем оформление

# Генерация и визуализация ЭЭГ сигналов
for row in 1:3, col in 1:2
    xrange = col == 1 ? (0:0.1:6pi) : (0:0.1:10pi)  # Разные диапазоны
    eeg = [sum(sin(pi * rand() + k * x) / k for k in 1:10)
           for x in xrange] .+ 0.1 .* randn.()
    lines!(axs[row, col], eeg, color = (:black, 0.5))  # Полупрозрачные линии
end

# Подписи осей и заголовок
axs[3, 1].xlabel = "Day 1"
axs[3, 2].xlabel = "Day 2"
Label(gd[1, :, Top()], "EEG traces", valign = :bottom,
    font = :bold,
    padding = (0, 0, 5, 0))

# Добавление повернутых меток
for (i, label) in enumerate(["sleep", "awake", "test"])
    Box(gd[i, 3], color = :gray90)  # Фон метки
    Label(gd[i, 3], label, rotation = pi/2, tellheight = false)  # Вертикальный текст
end

# Автомасштабирование по количеству точек
n_day_1 = length(0:0.1:6pi)
n_day_2 = length(0:0.1:10pi)
colsize!(gd, 1, Auto(n_day_1))
colsize!(gd, 2, Auto(n_day_2))

# Настройка расстояний
rowgap!(gd, 10)
colgap!(gd, 10)
colgap!(gd, 2, 0)  # Убираем отступ у колонки с метками

f
Out[0]:
No description has been provided for this image
8. Final settings and labels

Additional settings:

  • Adding A/B/C/D labels
  • Fine-tune the column proportions
  • Row height balancing
  • Optimization of the overall arrangement of the elements
In [ ]:
# Добавление меток областей
for (label, layout) in zip(["A", "B", "C", "D"], [ga, gb, gc, gd])
    Label(layout[1, 1, TopLeft()], label,
        fontsize = 26,
        font = :bold,
        padding = (0, 5, 5, 0),
        halign = :right)
end

# Настройка пропорций
colsize!(f.layout, 1, Auto(0.5))  # Уменьшаем ширину первой колонки
rowsize!(gcd, 1, Auto(1.5))       # Увеличиваем высоту 3D визуализации

# Отображение финального результата
f
Out[0]:
No description has been provided for this image