Входные данные

Частью преимуществ Plots является использование множества комбинаций допустимых входных данных. Не стоит тратить время на преобразование и приведение данных к определенному формату. Plots сделает это за вас.

Необходимо запомнить несколько правил, и вы быстро станете опытным пользователем.

Входными данными являются аргументы, а не ключевые слова

Функция plot имеет несколько методов. plot(y): рассматривает входные данные как значения по оси y и выдает единичный диапазон в виде x-значений. plot(x, y): создает двухмерный график plot(x, y, z): создает трехмерный график

Причина заключается в гибкости множественной диспетчеризации Julia, когда любая комбинация входных типов при желании может иметь уникальное поведение.

Столбцы являются рядами

В большинстве случаев передача матрицы (n × m) значений (чисел и т. п.) создает m рядов, каждый из которых содержит n точек данных. Это следует из согласованного правила: векторы применяются к одному ряду, матрицы — ко многим рядам. Это правило распространяется и на именованные аргументы. scatter(rand(10,4), markershape = [:circle, :rect]) создаст 4 ряда, каждому из которых будет присвоен вектор формы маркера [:circle,:rect]. Однако scatter(rand(10,4), markershape = [:circle :rect]) создаст 4 ряда, причем в рядах 1 и 3 маркеры будут иметь форму :circle, а в рядах 2 и 4 — форму :rect (т. е. в виде квадратов). Разница в том, что в первом примере это вектор-столбец длины 2, а во втором — вектор-строка (1 × 2) (матрица).

Гибкость и эффективность создания рядов можно проиллюстрировать следующим фрагментом кода:

using Plots

# 10 точек данных в 4 рядах
xs = range(0, 2π, length = 10)
data = [sin.(xs) cos.(xs) 2sin.(xs) 2cos.(xs)]

# Помещаем надписи в вектор-строку: применяется к каждому ряду
labels = ["Apples" "Oranges" "Hats" "Shoes"]

# Формы маркеров в векторе-столбце: применяется к точкам данных
markershapes = [:circle, :star5]

# Цвета маркеров в матрице: применяется к рядам и точкам данных
markercolors = [
    :green :orange :black :purple
    :red   :yellow :brown :white
]

plot(
    xs,
    data,
    label = labels,
    shape = markershapes,
    color = markercolors,
    markersize = 10
)

В этом примере показано построение четырех рядов с различными надписями, формами маркеров и цветами маркеров путем комбинирования векторов строк и столбцов для оформления данных.

В следующем примере показано, как Plots.jl обрабатывает массив матриц, массив массивов массивов и массив кортежей массивов.

x1, x2 = [1, 0],  [2, 3]    # векторы
y1, y2 = [4, 5],  [6, 7]    # векторы
m1, m2 = [x1 y1], [x2 y2]   # матрицы 2x2

plot([m1, m2])              # массив матриц -> 4 ряда, строит каждый столбец матрицы, x принимается за кол-во целых чисел
plot([[x1,y1], [x2,y2]])    # массив массивов -> 4 ряда, строит каждый отдельный массив, x принимается за кол-во целых чисел
plot([(x1,y1), (x2,y2)])    # массив кортежей массивов -> 2 ряда, строит каждый кортеж в виде нового ряда

Несвязанные данные в одних и тех же группах

Как показано в примерах, построить один многоугольник можно с помощью одного вызова plot с использованием типа линии :path. Для построения нескольких многоугольников можно использовать несколько вызовов plot.

Допустим, вы строите n многоугольников, объединенных в g групп, где n > g. Хотя можно использовать plot для построения отдельных многоугольников при каждом вызове, нельзя сгруппировать два отдельных графика в одну группу. В результате в условных обозначениях появится n групп, а не g.

Для решения этой проблемы можно использовать NaN в качестве разделителя путей. При вызове plot будет построен один путь с непересекающимися линиями. Следующий код строит прямоугольники n=4 в группах g=2.

using Plots
plotlyjs()

function rectangle_from_coords(xb,yb,xt,yt)
    [
        xb  yb
        xt  yb
        xt  yt
        xb  yt
        xb  yb
        NaN NaN
    ]
end

some_rects=[
    rectangle_from_coords(1, 1, 5, 5)
    rectangle_from_coords(10, 10, 15, 15)
]
other_rects=[
    rectangle_from_coords(1, 10, 5, 15)
    rectangle_from_coords(10, 1, 15, 5)
]

plot(some_rects[:,1], some_rects[:,2], label = "some group")
plot!(other_rects[:,1], other_rects[:,2], label = "other group")
png("input_data_1") # скрыть
"input_data_1.png"
input data 1

Поддержка DataFrames

Используя пакет расширения StatsPlots, вы можете передавать DataFrame в качестве первого аргумента (аналогично Gadfly или ggplot2 в R). Для полей данных или определенных атрибутов (например, group) символ будет заменен соответствующими столбцами DataFrame. Кроме того, имя столбца может использоваться в качестве Пример:

using StatsPlots, RDatasets
gr()
iris = dataset("datasets", "iris")
@df iris scatter(
    :SepalLength,
    :SepalWidth,
    group = :Species,
    m = (0.5, [:+ :h :star7], 12),
    bg = RGB(0.2, 0.2, 0.2)
)

Функции

Функции, как правило, могут использоваться вместо входных данных, и они будут сопоставляться по мере необходимости. Также можно строить двух- и трехмерные параметрические графики, а диапазоны можно задавать в виде векторов или минимальных и максимальных значений. Например, вот альтернативные методы построения одного и того же графика.

using Plots
tmin = 0
tmax = 4π
tvec = range(tmin, tmax, length = 100)

plot(sin.(tvec), cos.(tvec))

plot(sin, cos, tvec)

plot(sin, cos, tmin, tmax)

Разрешены также векторы функций (один ряд на функцию).

Изображения

Изображения можно добавлять в графики напрямую с помощью библиотеки Images.jl. Например, можно импортировать растровое изображение и построить его в Plots с помощью команд:

using Plots, Images
img = load("image.png")
plot(img)

Графику в формате PDF также можно добавить в графики Plots.jl с помощью load("image.pdf"). Обратите внимание, что для Images.jl требуется, чтобы цветовая схема PDF была RGB.

Фигуры

Спасти Готэм

using Plots

function make_batman()
    p = [(0, 0), (0.5, 0.2), (1, 0), (1, 2),  (0.3, 1.2), (0.2, 2), (0, 1.7)]
    s = [(0.2, 1), (0.4, 1), (2, 0), (0.5, -0.6), (0, 0), (0, -0.15)]
    m = [(p[i] .+ p[i + 1]) ./ 2 .+ s[i] for i in 1:length(p) - 1]

    pts = similar(m, 0)
    for (i, mi) in enumerate(m)
        append!(
            pts,
            map(BezierCurve([p[i], m[i], p[i + 1]]), range(0, 1, length = 30))
        )
    end
    x, y = Plots.unzip(Tuple.(pts))
    Shape(vcat(x, -reverse(x)), vcat(y, reverse(y)))
end

# фон и ограничения
plt = plot(
    bg = :black,
    xlim = (0.1, 0.9),
    ylim = (0.2, 1.5),
    framestyle = :none,
    size = (400, 400),
    legend = false,
)

# создает эллипс в небе
pts = Plots.partialcircle(0, 2π, 100, 0.1)
x, y = Plots.unzip(pts)
x = 1.5x .+ 0.7
y .+= 1.3
pts = collect(zip(x, y))

# луч
beam = Shape([(0.3, 0.0), pts[95], pts[50], (0.3, 0.0)])
plot!(beam, fillcolor = plot_color(:yellow, 0.3))

# направленный свет
plot!(Shape(x, y), c = :yellow)

# здания
rect(w, h, x, y) = Shape(x .+ [0, w, w, 0, 0], y .+ [0, 0, h, h, 0])
gray(pct) = RGB(pct, pct, pct)
function windowrange(dim, denom)
    range(0, 1, length = max(3, round(Int, dim/denom)))[2:end - 1]
end

for k in 1:50
    local w, h, x, y = 0.1rand() + 0.05, 0.8rand() + 0.3, rand(), 0.0
    shape = rect(w, h, x, y)
    graypct = 0.3rand() + 0.3
    plot!(shape, c = gray(graypct))

    # окна
    I = windowrange(w, 0.015)
    J = windowrange(h, 0.04)
    local pts = vec([(Float64(x + w * i), Float64(y + h * j)) for i in I, j in J])
    windowcolors = Symbol[rand() < 0.2 ? :yellow : :black for i in 1:length(pts)]
    scatter!(pts, marker = (stroke(0), :rect, windowcolors))
end
plt

# Построение фигуры Бэтмена
batman = Plots.scale(make_batman(), 0.07, 0.07, (0, 0))
batman = translate(batman, 0.7, 1.23)
plot!(batman, fillcolor = :black)

Дополнительные ключевые слова

Существуют некоторые возможности, которые очень специфичны для определенного бэкенда или еще не реализованы в Plots. В этих случаях можно передать дополнительные ключевые слова в бэкенд. Тогда каждое ключевое слово, не являющееся ключевым словом Plots, будет занесено в словарь extra_kwargs.

Этот словарь имеет три уровня: :plot, :subplot и :series (по умолчанию). Уровень, на котором собираются ключевые слова, можно указать с помощью ключевого слова extra_kwargs. Если в одном вызове аргументы должны передаваться на несколько уровней или ключевое слово уже является допустимым ключевым словом Plots, словарь extra_kwargs должен быть построен в месте вызова.

plot(1:5, series_keyword = 5)
# приводит к extra_kwargs = Dict( :series => Dict( series_keyword => 5 ) )
plot(1:5, colormap_width = 6, extra_kwargs = :subplot)
# приводит к extra_kwargs = Dict( :subplot => Dict( colormap_width = 6 ) )
plot(1:5, extra_kwargs = Dict( :series => Dict( series_keyword => 5 ), :subplot => Dict( colormap_width => 6 ) ) )

Чтобы узнать, для каких бэкендов реализована эта возможность, обратитесь на страницу отслеживания проблем. Какие дополнительные ключевые слова на самом деле обрабатывает бэкенд, должно быть указано в документации по бэкенду.

Использование механизма дополнительных ключевых слов сделает ваш код зависимым от бэкенда. Применяйте его только для окончательной доработки. Использовать его в шаблонах не следует.