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

Синтаксис шаблонов

Синтаксис в макросе @recipe лучше всего пояснить на примере. Предположим, у нас есть пользовательский тип, хранящий результаты моделирования x и y и меру ε для максимальной погрешности в y.

struct Result
    x::Vector{Float64}
    y::Vector{Float64}
    ε::Vector{Float64}
end

Чтобы построить график значений x и y такого результата с полосой погрешности, заданной ε, можно выполнить что-то вроде следующего

res = Result(1:10, cumsum(rand(10)), cumsum(rand(10)) / 5)

using Plots

# строит полосу погрешностей в виде невидимой строки с диапазоном заполнения
plot(
    res.x,
    res.y .+ res.ε,
    xlabel = "x",
    ylabel = "y",
    fill = (res.y .- res.ε, :lightgray, 0.5),
    linecolor = nothing,
    primary = false, # без записи условных обозначений
)

# добавляет данные на графики
plot!(res.x, res.y, marker = :diamond)

Вместо постоянного ввода этой команды для получения различных результатов можно определить пользовательский шаблон, чтобы указать Plots, что делать с входными данными типа Result. Приведем пример такого пользовательского шаблона с дополнительной функцией выделения точек данных, где максимальная погрешность превышает определенный порог ε_max.

@recipe function f(r::Result; ε_max = 0.5)
    # задает значение по умолчанию для атрибута с помощью `-->`
    xlabel --> "x"
    yguide --> "y"
    markershape --> :diamond
    # добавляет ряд для полосы погрешностей
    @series begin
        # применяет аргумент с помощью `:=`
        seriestype := :path
        # игнорирует ряды в условных обозначениях и изменении палитры цветов
        primary := false
        linecolor := nothing
        fillcolor := :lightgray
        fillalpha := 0.5
        fillrange := r.y .- r.ε
        # гарантирует, что для полосы погрешностей не отображаются маркеры
        markershape := :none
        # возвращает данные ряда
        r.x, r.y .+ r.ε
    end
    # получает цвет ряда, указанный пользователем
    c = get(plotattributes, :seriescolor, :auto)
    # выделяет значительные погрешности, в противном случае использует определяемый пользователем цвет
    markercolor := ifelse.(r.ε .> ε_max, :red, c)
    # возвращает данные
    r.x, r.y
end

Разберем этот шаблон пошагово. Сначала сигнатура функции в определении шаблона определяет тип шаблона, в данном случае — пользовательский шаблон. Имя функции f является несущественным и может быть заменено любым другим именем функции. @recipe не использует его. В теле шаблона можно задать значения по умолчанию для атрибутов Plots.

attr --> val

При этом attr будет задано val, если в команде plot пользователь не укажет иное.

plot(args...; kw..., attr = otherval)

Аналогичным образом можно принудительно задать значение атрибута с помощью :=.

attr := val

Будет перезаписано все, что пользователь передал в plot для attr, и задано val.

Настоятельно рекомендуется не использовать псевдонимы атрибутов в шаблонах, так как в некоторых случаях это может привести к неожиданному поведению. В приведенном выше шаблоне xlabel используется как псевдоним для xguide. При использовании шаблона Plots будет выдавать предупреждение и подсказку для имени атрибута по умолчанию. Их также можно найти в таблицах атрибутов по адресу: https://docs.juliaplots.org/latest/attributes/.

С помощью макроса @series мы добавляем на график новый ряд для полосы погрешностей. Внутри блока @series можно использовать тот же синтаксис, что и выше, для принудительной установки или задания значений по умолчанию для атрибутов.

В @recipe у нас есть доступ к plotattributes. Это словарь (AbstractDict), хранящий атрибуты, которые уже были обработаны на текущем этапе конвейера Plots. Для пользовательских шаблонов, которые вызываются на ранних этапах конвейера, здесь в основном содержатся именованные аргументы, указанные пользователем в команде plot. В нашем примере мы хотим выделить точки данных с погрешностью выше определенного порога, изменив цвет маркера. Для всех остальных точек данных мы задаем цвет маркера, который используется по умолчанию или был указан в качестве именованного аргумента. Это можно сделать, получив seriescolor из plotattributes и установив по умолчанию auto, если он не был указан пользователем.

Наконец, в обоих блоках @recipe и @series мы возвращаем данные, которые хотим передать Plots (или в следующий шаблон).

Совместимость: 1.0

В RecipesBase 1.0 в макросах @recipe и @series разрешен оператор return.

С помощью приведенного выше шаблона мы можем построить график Result, используя только

plot(res)

или

scatter(res, ε_max = 0.7, color = :green, marker = :star)