Plotting

Visualizing trajectories is crucial for understanding the solutions of trajectory optmization problems and NamedTrajectories exports a plot function that contains a lot of functionality that is continually being added to. Makie.jl is used as the plotting framework, and at the moment the default backend is CairoMakie, as it creates high quality vector graphics. The function is called as follows:

MakieCore.plotFunction
plot(traj::NamedTrajectory, comps=traj.names; kwargs...)

Plot a NamedTrajectory using CairoMakie.

Arguments

  • traj::NamedTrajectory: the trajectory to plot
  • comps::Union{Symbol, Vector{Symbol}, Tuple{Vararg{Symbol}}}: the components of the trajectory to plot, e.g., :x, [:x, :u], or (:x, :u).

Keyword Arguments

component specification

  • ignored_labels::Union{Symbol, Vector{Symbol}, Tuple{Vararg{Symbol}}}: the components of the trajectory to ignore. The default is ().
  • ignore_timestep::Bool: whether or not to ignore the timestep component of the trajectory. The default is true.

transformations

  • transformations::OrderedDict{Symbol, <:Union{Function, Vector}}: a dictionary of transformations to apply to the components of the trajectory. The keys of the dictionary are the components of the trajectory to transform, and the values are either a single function or a vector of functions to apply to each column of the component. If a single function is provided, it is applied to each column of the component. If a vector of functions is provided, a separate plot is created for each function. The default is an empty OrderedDict.
  • transformation_labels::Union{Nothing, OrderedDict{Symbol, <:Union{Nothing, <:AbstractString, Vector{<:Union{Nothing, <:AbstractString}}}}}: a dictionary of labels for the transformed components of the trajectory. The keys of the dictionary are the components of the trajectory to transform, and the values are either a single string or a vector of strings that correspond to a vector of transformations. If a single string is provided, it is applied to each transformation of the component. If a vector of strings is provided, a separate label is created for each function. The default is nothing.
  • include_transformation_labels::Union{Bool, Vector{<:Union{Bool, Vector{Bool}}}}: a boolean, vector of booleans, or vector of vectors of booleans, that determines whether or not to include the labels for the transformed components of the trajectory. The default is false.
  • transformation_titles::Union{Nothing, OrderedDict{Symbol, <:Union{<:AbstractString, Vector{String}}}}: a dictionary of titles for the transformed components of the trajectory. The keys of the dictionary are the components of the trajectory to transform, and the values are either a single string or a vector of strings that correspond to a vector of transformations. If a single string is provided, it is applied to each transformation of the component. If a vector of strings is provided, a separate title is created for each function. The default is nothing.

style

  • fig_size::Tuple{Int, Int}: the size of the figure, (width, height). The default is (1200, 800).
  • titlesize::Int: the size of the titles. The default is 25.
  • series_color::Symbol: the color of the series. The default is :glasbey_bw_minc_20_n256. See options here
  • markersize: the size of the markers. The default is 5.

other

source

Basic example

Let's first create a simple trajectory to plot

using NamedTrajectories

# define the number timestamps
T = 100
Δt = 0.1
ts = [0:T-1...] * Δt

# define sinusoidal state trajectories
X = zeros(3, T)
X[1, :] = sin.(3 * 2π * ts / (2 * (T - 1) * Δt))
X[2, :] = -sin.(5 * 2π * ts / (2 * (T - 1) * Δt))
X[3, :] = sin.(9 * 2π * ts / (2 * (T - 1) * Δt))

# define gaussian shaped controls
U = stack(
    [
        exp.(-((ts .- ts[length(ts)÷3]) / 2.0).^2) .* sin.(5.0 * ts),
        exp.(-((ts .- ts[2(length(ts)÷3)]) / 1.5).^2) .* sin.(4.0 * ts)
    ];
    dims=1
)
V = exp.(-((ts .- ts[length(ts)÷2]) ./ 1.5).^2) .* sin.(6.0 * ts)

# create the trajectory
traj = NamedTrajectory(
    (
        x=X,
        u=U,
        v=V
    );
    timestep=Δt,
    controls=(:u, :v)
)

# plot the trajectory
plot(traj)
Example block output

Selectively plotting components

We can selectively plot components of the trajectory by passing a Vector of Symbols to the components keyword argument. For example, if we only wanted to plot the state and the first control we could do the following:

plot(traj, [:x, :u])
Example block output

Playing with transformations

We can also apply transformations to the components of the trajectory. Transformations are performed on columns of the data.

For example, if we wanted to plot absolute values of the states we could do the following:

transformations = OrderedDict(
    :x => x -> abs.(x),
)

plot(traj, [:x]; transformations=transformations)
Example block output

We can also pass multiple transformations to the same component, with selective labels and titles:

# define the transformations
transformations = OrderedDict(
    :x => [
        x -> [x[1] + x[2], x[3] - x[2]],
        x -> [x[1] - x[2], x[3] + x[2]]
    ],
)

# define the labels
transformation_labels = OrderedDict(
    :x => [
        "\\tilde{x}",
        "\\hat{x}"
    ],
)

# define the titles
transformation_titles = OrderedDict(
    :x => [
        L"x_1 + x_2, x_3 - x_2",
        L"x_1 - x_2, x_3 + x_2"
    ],
)

# plot the trajectory, with only the transformation and the `u` control
plot(traj, [:u];
    transformations=transformations,
    transformation_labels=transformation_labels,
    include_transformation_labels=[[true, true]],
    transformation_titles=transformation_titles,
)
Example block output

This page was generated using Literate.jl.