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

Cоздание сложных компоновок графиков с помощью Makie

В данном примере демонстрируются инструменты библиотеки Makie для создания профессиональных научных визуализаций через объединение графиков разных типов (диаграммы рассеяния, контурные графики, 3D-модели и временные ряды) в единую сложную компоновку с использованием вложенных GridLayout, связанных осей, пользовательских легенд и цветовых шкал, а также продвинутых техник позиционирования элементов и управления пространством для создания информативных и красочных иллюстраций.

1. Установка пакетов и подготовка данных

In [ ]:
Pkg.add("Makie")
Pkg.add("CairoMakie")

Подготовка данных для первого графика:

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. Создание базового графика

Начнем с простой визуализации экспериментальных данных и экспоненциальной модели.
Основные компоненты:

  • Figure() создает контейнер для графиков
  • Axis() определяет систему координат с подписями
  • scatter!() добавляет точки измерений
  • lines!() рисует линию модели
  • axislegend() создает легенду

Отображение графика с экспериментальными данными и экспоненциальной моделью:

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. Формирование сложной компоновки

Создаем сложный графический объект (фигуру) с несколькими областями для построения графиков:

  1. Используем GridLayout для организации вложенных сеток
  2. Определяем 4 основные области (A, B, C, D)
  3. Настраиваем фон и размер фигуры
  4. Связываем оси для синхронизации масштабов
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. Область A: Диаграммы рассеяния и распределения

Область A демонстрирует:

  • Группировку данных через цветовое кодирование
  • Связанные оси с общими масштабами
  • Распределения на краях основного графика
  • Автоматическое размещение легенды
  • Точную настройку отступов между элементами
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. Область B: Контурные графики

Область B показывает:

  • Контурные графики для визуализации 2D данных
  • Иерархию графиков: contourf + contour
  • Кастомную цветовую шкалу с биновой маркировкой
  • Выравнивание элементов через Mixed alignmode
  • Точный контроль над расстояниями между графиками
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. Область C: 3D визуализация мозга

Область C демонстрирует:

  • Загрузку и визуализацию 3D моделей (формат STL)
  • Использование Axis3 для 3D графиков
  • Цветовое кодирование на основе координат Y
  • Инвертированную цветовую карту для лучшего восприятия
  • Интеграцию 3D визуализации в общую компоновку
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. Область D: ЭЭГ сигналы

Область D показывает:

  • Массивы осей для группировки графиков
  • Генерацию искусственных ЭЭГ сигналов
  • Динамическое масштабирование осей по количеству точек
  • Повёрнутые метки для экономии пространства
  • Автоматическое выравнивание размеров колонок
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. Финальные настройки и метки

Дополнительные настройки:

  • Добавление меток A/B/C/D
  • Точная настройка пропорций колонок
  • Балансировка высоты строк
  • Оптимизация общего расположения элементов
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