Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
MultivariatePolynomials = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

Expand All @@ -26,10 +25,13 @@ julia = "1.6"

[extensions]
LazySetsExt = "LazySets"
RecipesBaseExt = "RecipesBase"

[extras]
LazySets = "b4f0291d-fe17-52bc-9479-3d1a343d9043"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"

[weakdeps]
LazySets = "b4f0291d-fe17-52bc-9479-3d1a343d9043"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
85 changes: 85 additions & 0 deletions ext/RecipesBaseExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
module RecipesBaseExt

using MathematicalSystems: VectorField

using RecipesBase: @recipe

### plot recipe
# arguments:
# - grid_points: pair containing the x and y coordinates of the grid points
# example: the pair `([-1, 0, 1], [2, 3])` represents the grid of points
# `[-1, 2], [0, 2], [1, 2], [-1, 3], [0, 3], [1, 3]`
# - dims: the two dimensions to plot
@recipe function plot(V::VectorField; # COV_EXCL_LINE
grid_points=[range(-3; stop=3, length=21),
range(-3; stop=3, length=21)],
dims=[1, 2])
seriestype := :quiver

x, y, vx, vy = _position_value_list(V, grid_points, dims[1], dims[2])
quiver := (vx, vy)

return (x, y)
end

function _position_value_list(V::VectorField, grid, dimx, dimy)
X, Y = grid
x1 = X[1]
y1 = Y[1]
N_POS = typeof(x1)
N_VAL = typeof(V([x1, y1])[dimx])
m = length(X) * length(Y)

x = Vector{N_POS}(undef, m) # x coordinates of each point
y = similar(x)
vx = Vector{N_VAL}(undef, m)
vy = similar(vx)
k = 1
max_entry = N_VAL(-Inf)
for xi in X
for yj in Y
x[k] = xi
y[k] = yj
val = V([xi, yj])
vx_k = val[dimx]
vy_k = val[dimy]
max_entry = max(max_entry, abs(vx_k), abs(vy_k))
vx[k] = vx_k
vy[k] = vy_k
k += 1
end
end

# normalize
if max_entry > zero(N_VAL)
step_x = (maximum(X) - minimum(X)) / length(X)
step_y = (maximum(Y) - minimum(Y)) / length(Y)
max_entry_x = max_entry / step_x
max_entry_y = max_entry / step_y
max_entry = max(max_entry_x, max_entry_y)
for k in 1:m
vx[k] /= max_entry
vy[k] /= max_entry
end
end

# filter out (0, 0) entries
for k in m:-1:1
if vx[k] == vy[k] == zero(N_VAL)
deleteat!(x, k)
deleteat!(y, k)
deleteat!(vx, k)
deleteat!(vy, k)
end
end

# center arrows in the grid points
for k in eachindex(x)
x[k] -= vx[k] / 2
y[k] -= vy[k] / 2
end

return x, y, vx, vy
end

end # module
1 change: 0 additions & 1 deletion src/MathematicalSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ using Base: /
using LinearAlgebra: LinearAlgebra, Adjoint, Diagonal, I, Transpose,
UniformScaling, checksquare, rank
using SparseArrays: sparsevec, spzeros
using RecipesBase: @recipe
using Espresso: matchex
using MacroTools: @capture
using InteractiveUtils: subtypes
Expand Down
1 change: 1 addition & 0 deletions src/init.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ end
@static if !isdefined(Base, :get_extension)
function __init__()
@require LazySets = "b4f0291d-fe17-52bc-9479-3d1a343d9043" include("../ext/LazySetsExt.jl")
@require RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" include("../ext/RecipesBaseExt.jl")
end
end
78 changes: 0 additions & 78 deletions src/vector_field.jl
Original file line number Diff line number Diff line change
Expand Up @@ -168,81 +168,3 @@ function VectorField(sys::AbstractContinuousSystem)
end
return VectorField(field)
end

function _position_value_list(V::VectorField, grid, dimx, dimy)
X, Y = grid
x1 = X[1]
y1 = Y[1]
N_POS = typeof(x1)
N_VAL = typeof(V([x1, y1])[dimx])
m = length(X) * length(Y)

x = Vector{N_POS}(undef, m) # x coordinates of each point
y = similar(x)
vx = Vector{N_VAL}(undef, m)
vy = similar(vx)
k = 1
max_entry = N_VAL(-Inf)
for xi in X
for yj in Y
x[k] = xi
y[k] = yj
val = V([xi, yj])
vx_k = val[dimx]
vy_k = val[dimy]
max_entry = max(max_entry, abs(vx_k), abs(vy_k))
vx[k] = vx_k
vy[k] = vy_k
k += 1
end
end

# normalize
if max_entry > zero(N_VAL)
step_x = (maximum(X) - minimum(X)) / length(X)
step_y = (maximum(Y) - minimum(Y)) / length(Y)
max_entry_x = max_entry / step_x
max_entry_y = max_entry / step_y
max_entry = max(max_entry_x, max_entry_y)
for k in 1:m
vx[k] /= max_entry
vy[k] /= max_entry
end
end

# filter out (0, 0) entries
for k in m:-1:1
if vx[k] == vy[k] == zero(N_VAL)
deleteat!(x, k)
deleteat!(y, k)
deleteat!(vx, k)
deleteat!(vy, k)
end
end

# center arrows in the grid points
for k in eachindex(x)
x[k] -= vx[k] / 2
y[k] -= vy[k] / 2
end

return x, y, vx, vy
end

### plot recipe
# arguments:
# - grid_points: pair containing the x and y coordinates of the grid points
# example: the pair `([-1, 0, 1], [2, 3])` represents the grid of points
# `[-1, 2], [0, 2], [1, 2], [-1, 3], [0, 3], [1, 3]`
# - dims: the two dimensions to plot
@recipe function plot(V::VectorField; # COV_EXCL_LINE
grid_points=[range(-3; stop=3, length=21),
range(-3; stop=3, length=21)],
dims=[1, 2])
seriestype := :quiver

x, y, vx, vy = _position_value_list(V, grid_points, dims[1], dims[2])
quiver := (vx, vy)

return (x, y)
end
2 changes: 1 addition & 1 deletion test/quality_assurance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ using MathematicalSystems, Test
import Aqua, ExplicitImports

@testset "ExplicitImports tests" begin
ignores = (:checksquare,)
ignores = (:VectorField, :checksquare)
@test isnothing(ExplicitImports.check_all_explicit_imports_are_public(MathematicalSystems;
ignore=ignores))
@test isnothing(ExplicitImports.check_all_explicit_imports_via_owners(MathematicalSystems))
Expand Down
Loading