Функции построения графиков

Построение стандартных графиков с использованием шаблона

Функциональность построения графиков реализуется за счет шаблонов в Plots.jl. Для построения графиков решений достаточно вызвать plot(type) после импорта Plots.jl, и построитель сгенерирует соответствующие графики.

#]add Plots # Перед первым использованием пакета Plots.jl его необходимо установить!
using Plots
plot(sol) # Строит график решения

Многие типы, определенные в экосистеме DiffEq, такие как ODESolution, ConvergenceSimulation, WorkPrecision и т. д., имеют шаблоны графиков для поддержки различных способов построения графиков. Для настройки графиков можно использовать все именованные аргументы, доступные в Plots.jl. Например, можно изменить бэкенд построения графиков на пакет GR и добавить к графику заголовок:

gr()
plot(sol, title = "I Love DiffEqs!")

Затем, чтобы сохранить график, используйте функцию savefig, например:

savefig("myplot.png")

Плотность

Если задача была решена с параметром dense=true, то параметр denseplot определяет, следует ли использовать функцию dense для создания графика, а plotdensity — это количество равномерно распределенных (во времени) точек для построения. Например:

plot(sol, denseplot = false)

означает «строить только точки, которые вычислил решатель», а:

plot(sol, plotdensity = 1000)

означает «строить 1000 точек с помощью функции dense» (так как по умолчанию denseplot=true).

Выбор переменных

В команде plot можно выбрать переменные, которые будут отрисованы на каждом графике. Главная форма имеет следующий вид:

idxs = [(f1, 0, 1), (f2, 1, 3), (f3, 4, 5)]

Ее можно использовать для построения кривых функций f1(var₀, var₁), f2(var₁, var₃) и f3(var₄, var₅) на одном графике (0 считается временем или независимой переменной). Функции f1, f2 и f3 должны принимать скалярные значения и возвращать кортеж. Если функция не передана, например:

idxs = [(0, 1), (1, 3), (4, 5)]

это означает «построить кривую var₁(t) в зависимости от t (времени), кривую var₃(var₁) в зависимости от var₁ и кривую var₅(var₄) в зависимости от var₄ на одном графике, поместив независимые переменные (t, var₁ и var₄) на оси x». Хотя такая форма универсальна, для удобства приняты следующие правила:

  • Если в какой либо позиции кортежа находится просто целое число, строится кривая соответствующей переменной как функции от времени. Например, приведенный выше список эквивалентен следующему:

idxs = [1, (1, 3), (4, 5)]

и

idxs = [1, 3, 4]

является самым лаконичным способом построения кривых переменных 1, 3 и 4 как функций от времени.

  • Если требуется только один график, список можно опустить: (2,3) и 4 эквивалентно [(2,3)] и [(0,4)] соответственно.

  • Кортеж, содержащий один или несколько списков, раскрывается путем связывания соответствующих элементов списков друг с другом:

idxs = ([1, 2, 3], [4, 5, 6])

эквивалентно

idxs = [(1, 4), (2, 5), (3, 6)]

а выражение

idxs = (1, [2, 3, 4])

эквивалентно

idxs = [(1, 2), (1, 3), (1, 4)]
  • Вместо целых чисел можно использовать символы из ParameterizedFunction. Например, в выражении idxs=(:x,:y) символы заменяются целочисленными значениями для компонентов :x и :y.

  • Допускаются n-мерные группы. Например, (1,2,3,4,5) представляет 5-мерный график связанных переменных.

Комплексные числа и высокоразмерные графики

Для дополнительных возможностей работы с числами высокой размерности (комплексными числами) и другими графиками высокой размерности предоставляется библиотека шаблонов DimensionalPlotRecipes.jl. Дополнительные сведения о доступных параметрах см. в файле сведений.

Временной диапазон

Временной диапазон графика можно выбрать с помощью аргумента tspan функции plot. Например:

plot(sol, tspan = (0.0, 40.0))

строит график от t=0.0 до t=40.0. Если denseplot=true, эти границы соблюдаются в точности. В противном случае строятся первая и последняя точка внутри интервала, то есть точки вне интервала не строятся.

Пример

using DifferentialEquations, Plots
function lorenz(du, u, p, t)
    du[1] = p[1] * (u[2] - u[1])
    du[2] = u[1] * (p[2] - u[3]) - u[2]
    du[3] = u[1] * u[2] - p[3] * u[3]
end

u0 = [1.0, 5.0, 10.0]
tspan = (0.0, 100.0)
p = (10.0, 28.0, 8 / 3)
prob = ODEProblem(lorenz, u0, tspan, p)
sol = solve(prob)
xyzt = plot(sol, plotdensity = 10000, lw = 1.5)
xy = plot(sol, plotdensity = 10000, idxs = (1, 2))
xz = plot(sol, plotdensity = 10000, idxs = (1, 3))
yz = plot(sol, plotdensity = 10000, idxs = (2, 3))
xyz = plot(sol, plotdensity = 10000, idxs = (1, 2, 3))
plot(plot(xyzt, xyz), plot(xy, xz, yz, layout = (1, 3), w = 1), layout = (2, 1))

Пример использования функций:

f(x, y, z) = (sqrt(x^2 + y^2 + z^2), x)
plot(sol, idxs = (f, 1, 2, 3))

Нормализация по времени:

f(t, x, y, z) = (t, sqrt(x^2 + y^2 + z^2))
plot(sol, idxs = (f, 0, 1, 2, 3))

Анимация

Используя интерфейс итератора по решениям, можно генерировать анимации с помощью команды animate(sol). Вы можете выбрать имя файла (filename), в котором будет сохранена анимация, посредством вызова animate(sol,filename). С помощью именованных аргументов можно также задать число кадров в секунду (fps) и плотность шагов (every). Остальные аргументы передаются непосредственно в шаблон графика для обработки обычным способом. Например, можно анимировать решение с большей толщиной линии и сохранением каждого 4-го кадра:

#]add ImageMagick # Перед первым использованием пакета ImageMagick.jl его может потребоваться установить!
#using ImageMagick # В некоторых системах для получения качественных анимаций требуется оператор using ImageMagick
animate(sol, lw = 3, every = 4)

Дополнительные сведения о доступных атрибутах см. в документации по Plots.jl.

Построение графиков без шаблона

Что если вы не хотите использовать Plots.jl? Странное решение, но можно и так! Если дифференциальное уравнение описано вектором значений, то объект решения представляет собой матрицу AbstractMatrix элементов sol[i,j] для i-й переменной в точке времени j. Это можно использовать для построения графиков решений. Например, в PyPlot, Gadfly, GR и т. д. для построения графиков временных рядов можно использовать следующее выражение:

plot(sol.t, sol')

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

plot(sol[i, :], sol[j, :], sol[k, :])

это трехмерный фазовый график переменных i, j и k.

Обратите внимание, что интерполяция при этом не применяется. Если шаблон графика не используется, интерполяция должна осуществляться вручную. Например:

n = 101 #число временных точек
ts = range(0, stop = 1, length = n)
plot(sol(ts, idxs = i), sol(ts, idxs = j), sol(ts, idxs = k))

это фазовое пространство со значениями, разделенными во времени на 0.01.