Skip to content

Commit c14d246

Browse files
authored
Merge pull request #166 from control-toolbox/165-feature-plot-current
Add plot! on current and update docstrings
2 parents e4ea0f4 + a3412c0 commit c14d246

File tree

12 files changed

+198
-198
lines changed

12 files changed

+198
-198
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "CTModels"
22
uuid = "34c4fa32-2049-4079-8329-de33c2a22e2d"
33
authors = ["Olivier Cots <olivier.cots@toulouse-inp.fr>"]
4-
version = "0.5.2"
4+
version = "0.5.3"
55

66
[deps]
77
CTBase = "54762871-cc72-4466-b8e8-f6c8b58076cd"

ext/CTModelsJLD.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ allowing it to be reloaded later.
2121
2222
# Example
2323
```julia-repl
24+
julia> using JLD2
2425
julia> export_ocp_solution(JLD2Tag(), sol; filename="mysolution")
2526
# → creates "mysolution.jld2"
2627
```
@@ -51,6 +52,7 @@ This function loads a previously saved `CTModels.Solution` from disk.
5152
5253
# Example
5354
```julia-repl
55+
julia> using JLD2
5456
julia> sol = import_ocp_solution(JLD2Tag(), model; filename="mysolution")
5557
```
5658
"""

ext/CTModelsJSON.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The exported JSON includes the time grid, state, control, costate, objective, so
2525
2626
# Example
2727
```julia-repl
28+
julia> using JSON3
2829
julia> export_ocp_solution(JSON3Tag(), sol; filename="mysolution")
2930
# → creates "mysolution.json"
3031
```
@@ -91,6 +92,7 @@ Handles both vector and matrix encodings of signals. If dual fields are missing
9192
9293
# Example
9394
```julia-repl
95+
julia> using JSON3
9496
julia> sol = import_ocp_solution(JSON3Tag(), model; filename="mysolution")
9597
```
9698
"""

ext/plot.jl

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -464,13 +464,11 @@ constraints, and duals based on the provided `layout` and `description`.
464464
Includes options such as:
465465
- `layout`, `control`, `time`
466466
- `state_style`, `control_style`, `costate_style`, etc.
467-
- `solution_label`: Label to annotate the plotted solution.
468467
"""
469468
function __plot!(
470469
p::Plots.Plot,
471470
sol::CTModels.Solution,
472471
description::Symbol...;
473-
solution_label::String,
474472
model::Union{CTModels.Model,Nothing},
475473
time::Symbol,
476474
control::Symbol,
@@ -511,11 +509,6 @@ function __plot!(
511509
path_bounds_style=path_bounds_style,
512510
)
513511

514-
# add an empty space to the label if the label is not empty
515-
if solution_label != ""
516-
@warn "Deprecated: `solution_label` keyword argument is replaced by `label`."
517-
end
518-
519512
#
520513
n = CTModels.state_dimension(sol)
521514
m = CTModels.control_dimension(sol)
@@ -1018,7 +1011,6 @@ Use this to obtain a standalone plot.
10181011
function __plot(
10191012
sol::CTModels.Solution,
10201013
description::Symbol...;
1021-
solution_label::String,
10221014
model::Union{CTModels.Model,Nothing},
10231015
time::Symbol,
10241016
control::Symbol,
@@ -1068,7 +1060,6 @@ function __plot(
10681060
layout=layout,
10691061
control=control,
10701062
time=time,
1071-
solution_label=solution_label,
10721063
state_style=state_style,
10731064
control_style=control_style,
10741065
costate_style=costate_style,
@@ -1088,9 +1079,9 @@ end
10881079
"""
10891080
$(TYPEDSIGNATURES)
10901081
1091-
Update an existing plot `p` with the optimal control `Solution`.
1082+
Modify Plot `p` with the optimal control solution `sol`.
10921083
1093-
See `__plot!` for full behavior and keyword arguments.
1084+
See [`plot`](@ref plot(::CTModels.Solution)) for full behavior and keyword arguments.
10941085
"""
10951086
function Plots.plot!(
10961087
p::Plots.Plot,
@@ -1099,7 +1090,6 @@ function Plots.plot!(
10991090
layout::Symbol=__plot_layout(),
11001091
control::Symbol=__control_layout(),
11011092
time::Symbol=__time_normalization(),
1102-
solution_label::String=__plot_label_suffix(),
11031093
state_style::Union{NamedTuple,Symbol}=__plot_style(),
11041094
state_bounds_style::Union{NamedTuple,Symbol}=__plot_style(),
11051095
control_style::Union{NamedTuple,Symbol}=__plot_style(),
@@ -1158,7 +1148,6 @@ function Plots.plot!(
11581148
layout=layout,
11591149
control=control,
11601150
time=time,
1161-
solution_label=solution_label,
11621151
state_style=state_style,
11631152
control_style=control_style,
11641153
costate_style=costate_style,
@@ -1176,9 +1165,53 @@ end
11761165
"""
11771166
$(TYPEDSIGNATURES)
11781167
1168+
Modify Plot `current()` with the optimal control solution `sol`.
1169+
1170+
See [`plot`](@ref plot(::CTModels.Solution)) for full behavior and keyword arguments.
1171+
"""
1172+
function Plots.plot!(
1173+
sol::CTModels.Solution,
1174+
description::Symbol...;
1175+
layout::Symbol=__plot_layout(),
1176+
control::Symbol=__control_layout(),
1177+
time::Symbol=__time_normalization(),
1178+
state_style::Union{NamedTuple,Symbol}=__plot_style(),
1179+
state_bounds_style::Union{NamedTuple,Symbol}=__plot_style(),
1180+
control_style::Union{NamedTuple,Symbol}=__plot_style(),
1181+
control_bounds_style::Union{NamedTuple,Symbol}=__plot_style(),
1182+
costate_style::Union{NamedTuple,Symbol}=__plot_style(),
1183+
time_style::Union{NamedTuple,Symbol}=__plot_style(),
1184+
path_style::Union{NamedTuple,Symbol}=__plot_style(),
1185+
path_bounds_style::Union{NamedTuple,Symbol}=__plot_style(),
1186+
dual_style::Union{NamedTuple,Symbol}=__plot_style(),
1187+
kwargs...,
1188+
)
1189+
return Plots.plot!(
1190+
Plots.current(),
1191+
sol,
1192+
description...;
1193+
layout,
1194+
control,
1195+
time,
1196+
state_style,
1197+
state_bounds_style,
1198+
control_style,
1199+
control_bounds_style,
1200+
costate_style,
1201+
time_style,
1202+
path_style,
1203+
path_bounds_style,
1204+
dual_style,
1205+
kwargs...,
1206+
)
1207+
end
1208+
1209+
"""
1210+
$(TYPEDSIGNATURES)
1211+
11791212
Plot the components of an optimal control solution.
11801213
1181-
This is the main user-facing function to visualize the solution of an optimal control problem
1214+
This is the main user-facing function to visualise the solution of an optimal control problem
11821215
solved with the control-toolbox ecosystem.
11831216
11841217
It generates a set of subplots showing the evolution of the state, control, costate,
@@ -1211,13 +1244,11 @@ If no symbols are provided, a default set is used based on the problem and style
12111244
- `:default`: Real time scale.
12121245
- `:normalize` or `:normalise`: Normalised to the interval [0, 1].
12131246
1214-
- `solution_label::String = ""`: Label to annotate this solution in the legend. (Deprecated: use `label` instead)
1215-
12161247
## Style Options (Optional)
12171248
12181249
All style-related keyword arguments can be either a `NamedTuple` of plotting attributes or the `Symbol` `:none` referring to not plot the associated element. These allow you to customise color, line style, markers, etc.
12191250
1220-
- `time_style`: Style for vertical lines at initial and final time.
1251+
- `time_style`: Style for vertical lines at initial and final times.
12211252
- `state_style`: Style for state components.
12221253
- `costate_style`: Style for costate components.
12231254
- `control_style`: Style for control components.
@@ -1234,7 +1265,7 @@ Use these options to customise bounds on the plots if applicable and defined in
12341265
12351266
# Returns
12361267
1237-
- A `Plots.Plot` object, which can be displayed, saved, or further customized.
1268+
- A `Plots.Plot` object, which can be displayed, saved, or further customised.
12381269
12391270
# Example
12401271
@@ -1247,7 +1278,7 @@ julia> plot(sol, :state, :control)
12471278
12481279
# customise layout and styles, no costate
12491280
julia> plot(sol;
1250-
layout = :split,
1281+
layout = :group,
12511282
control = :all,
12521283
state_style = (color=:blue, linestyle=:solid),
12531284
control_style = (color=:red, linestyle=:dash),
@@ -1260,7 +1291,6 @@ function Plots.plot(
12601291
layout::Symbol=__plot_layout(),
12611292
control::Symbol=__control_layout(),
12621293
time::Symbol=__time_normalization(),
1263-
solution_label::String=__plot_label_suffix(),
12641294
state_style::Union{NamedTuple,Symbol}=__plot_style(),
12651295
state_bounds_style::Union{NamedTuple,Symbol}=__plot_style(),
12661296
control_style::Union{NamedTuple,Symbol}=__plot_style(),
@@ -1290,7 +1320,6 @@ function Plots.plot(
12901320
layout=layout,
12911321
control=control,
12921322
time=time,
1293-
solution_label=solution_label,
12941323
state_style=state_style,
12951324
control_style=control_style,
12961325
costate_style=costate_style,

src/CTModels.jl

Lines changed: 21 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -130,53 +130,43 @@ JSON tag for export/import functions.
130130
"""
131131
struct JSON3Tag <: AbstractTag end
132132

133-
# to be extended
134-
"""
135-
$(TYPEDSIGNATURES)
133+
# -----------------------------
134+
# to be extended: no docstrings
135+
function RecipesBase.plot(sol::AbstractSolution, description::Symbol...; kwargs...)
136+
throw(CTBase.ExtensionError(:Plots))
137+
end
136138

137-
Export a solution in JLD format.
138-
"""
139139
function export_ocp_solution(::JLD2Tag, ::AbstractSolution; filename::String)
140140
throw(CTBase.ExtensionError(:JLD2))
141141
end
142142

143-
"""
144-
$(TYPEDSIGNATURES)
145-
146-
Import a solution from a JLD file.
147-
"""
148143
function import_ocp_solution(::JLD2Tag, ::AbstractModel; filename::String)
149144
throw(CTBase.ExtensionError(:JLD2))
150145
end
151146

152-
"""
153-
$(TYPEDSIGNATURES)
154-
155-
Export a solution in JSON format.
156-
"""
157147
function export_ocp_solution(::JSON3Tag, ::AbstractSolution; filename::String)
158148
throw(CTBase.ExtensionError(:JSON3))
159149
end
160150

161-
"""
162-
$(TYPEDSIGNATURES)
163-
164-
Import a solution from a JLD file.
165-
"""
166151
function import_ocp_solution(::JSON3Tag, ::AbstractModel; filename::String)
167152
throw(CTBase.ExtensionError(:JSON3))
168153
end
169154

170155
"""
171156
$(TYPEDSIGNATURES)
172157
173-
Export a solution in JLD or JSON formats.
158+
Export a solution in JLD or JSON formats. Redirect to one of the methods:
159+
160+
- [`export_ocp_solution(JLD2Tag(), sol, filename=filename)`](@ref export_ocp_solution(::CTModels.JLD2Tag, ::CTModels.Solution))
161+
- [`export_ocp_solution(JSON3Tag(), sol, filename=filename)`](@ref export_ocp_solution(::CTModels.JSON3Tag, ::CTModels.Solution))
174162
175163
# Examples
176164
177165
```julia-repl
178-
julia> CTModels.export_ocp_solution(sol; filename="solution", format=:JSON)
179-
julia> CTModels.export_ocp_solution(sol; filename="solution", format=:JLD)
166+
julia> using JSON3
167+
julia> export_ocp_solution(sol; filename="solution", format=:JSON)
168+
julia> using JLD2
169+
julia> export_ocp_solution(sol; filename="solution", format=:JLD) # JLD is the default
180170
```
181171
"""
182172
function export_ocp_solution(
@@ -200,13 +190,18 @@ end
200190
"""
201191
$(TYPEDSIGNATURES)
202192
203-
Import a solution from a JLD or JSON file.
193+
Import a solution from a JLD or JSON file. Redirect to one of the methods:
194+
195+
- [`import_ocp_solution(JLD2Tag(), ocp, filename=filename)`](@ref import_ocp_solution(::CTModels.JLD2Tag, ::CTModels.Model))
196+
- [`import_ocp_solution(JSON3Tag(), ocp, filename=filename)`](@ref import_ocp_solution(::CTModels.JSON3Tag, ::CTModels.Model))
204197
205198
# Examples
206199
207200
```julia-repl
208-
julia> sol = CTModels.import_ocp_solution(ocp; filename="solution", format=:JSON)
209-
julia> sol = CTModels.import_ocp_solution(ocp; filename="solution", format=:JLD)
201+
julia> using JSON3
202+
julia> sol = import_ocp_solution(ocp; filename="solution", format=:JSON)
203+
julia> using JLD2
204+
julia> sol = import_ocp_solution(ocp; filename="solution", format=:JLD) # JLD is the default
210205
```
211206
"""
212207
function import_ocp_solution(
@@ -227,38 +222,6 @@ function import_ocp_solution(
227222
end
228223
end
229224

230-
# to be extended
231-
"""
232-
$(TYPEDSIGNATURES)
233-
234-
Plot a solution from an optimal control problem.
235-
236-
This function dispatches on a solution type that inherits from `AbstractSolution`. It is intended to visualize various components of the solution (such as state trajectories, controls, costates, or any other variables defined in the model).
237-
238-
!!! note
239-
This function requires the `Plots.jl` package to be available. If it is not loaded, a `CTBase.ExtensionError(:Plots)` is thrown.
240-
241-
# Arguments
242-
- `sol::AbstractSolution`: A solution object returned by solving a control problem.
243-
- `description::Symbol...`: Optional symbols specifying what to plot (e.g., `:state`, `:control`, `:costate`, etc.). If empty, a default set of components is plotted.
244-
- `kwargs...`: Additional keyword arguments passed to the underlying plotting routines (e.g., `xlabel`, `ylabel`, `legend`, etc.).
245-
246-
# Returns
247-
- A plot object (if `Plots.jl` is available) visualizing the selected components of the solution.
248-
249-
# Example
250-
```julia-repl
251-
julia> using Plots
252-
julia> plot(sol, :state, :control, xlabel = "Time", layout = (2,1))
253-
```
254-
255-
# Throws
256-
- `CTBase.ExtensionError` if the `Plots` package is not available or not loaded.
257-
"""
258-
function RecipesBase.plot(sol::AbstractSolution, description::Symbol...; kwargs...)
259-
throw(CTBase.ExtensionError(:Plots))
260-
end
261-
262225
#
263226
include("init.jl")
264227
include("dual_model.jl")

src/constraints.jl

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -562,9 +562,8 @@ end
562562
$(TYPEDSIGNATURES)
563563
564564
Get a labelled constraint from the model. Returns a tuple of the form
565-
`(type, f, lb, ub)` where `type` is the type of the constraint, `f` is the function
566-
of the constraint, `lb` is the lower bound of the constraint and `ub` is the upper
567-
bound of the constraint.
565+
`(type, f, lb, ub)` where `type` is the type of the constraint, `f` is the function,
566+
`lb` is the lower bound and `ub` is the upper bound.
568567
569568
The function returns an exception if the label is not found in the model.
570569
@@ -576,14 +575,6 @@ The function returns an exception if the label is not found in the model.
576575
## Returns
577576
578577
- `Tuple`: A tuple containing the type, function, lower bound, and upper bound of the constraint.
579-
580-
## Example
581-
582-
```julia-repl
583-
julia> # Example of getting a labelled constraint from the model
584-
julia> model = Model(...)
585-
julia> constraint_info = constraint(model, :my_constraint)
586-
```
587578
"""
588579
function constraint(model::Model, label::Symbol)::Tuple # not type stable
589580

src/dual_model.jl

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ $(TYPEDSIGNATURES)
99
Return the dual variable associated with a constraint identified by its `label`.
1010
1111
Searches through all constraint types (path, boundary, state, control, and variable constraints)
12-
defined in the model and returns the corresponding dual value(s) from the solution. If the label
13-
is found multiple times, a vector of values is returned.
12+
defined in the model and returns the corresponding dual value from the solution.
1413
1514
# Arguments
1615
- `sol::Solution`: Solution object containing dual variables.
@@ -20,12 +19,6 @@ is found multiple times, a vector of values is returned.
2019
# Returns
2120
A function of time `t` for time-dependent constraints, or a scalar/vector for time-invariant duals.
2221
If the label is not found, throws an `IncorrectArgument` exception.
23-
24-
# Examples
25-
```julia-repl
26-
julia> dual_fun = dual(sol, model, :velocity_limit)
27-
julia> dual_value_at_t1 = dual_fun(1.0)
28-
```
2922
"""
3023
function dual(sol::Solution, model::Model, label::Symbol)
3124

0 commit comments

Comments
 (0)