Skip to content

Commit 642ec0b

Browse files
authored
Add Makie Extension, introduce plotvalues_layout (#158)
* Start Makie extension * Add QuasiPlot for matrices * plotgrid for banded * _grid -> grid_layout, plotvalues_layout * v0.15 * Update plotting.jl * Add tests * increase cov * Update plotting.jl
1 parent 734c408 commit 642ec0b

10 files changed

+148
-75
lines changed

Project.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ContinuumArrays"
22
uuid = "7ae1f121-cc2c-504b-ac30-9b923412ae5c"
3-
version = "0.14.2"
3+
version = "0.15"
44

55
[deps]
66
AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c"
@@ -18,10 +18,12 @@ QuasiArrays = "c4ea9172-b204-11e9-377d-29865faadc5c"
1818
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1919

2020
[weakdeps]
21+
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
2122
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
2223

2324
[extensions]
2425
ContinuumArraysRecipesBaseExt = "RecipesBase"
26+
ContinuumArraysMakieExt = "Makie"
2527

2628
[compat]
2729
AbstractFFTs = "1.0"
@@ -35,16 +37,18 @@ InfiniteArrays = "0.12, 0.13"
3537
Infinities = "0.1"
3638
IntervalSets = "0.7"
3739
LazyArrays = "1.0"
38-
QuasiArrays = "0.11"
40+
Makie = "0.19"
41+
QuasiArrays = "0.11.1"
3942
RecipesBase = "1.0"
4043
StaticArrays = "1.0"
4144
julia = "1.9"
4245

4346
[extras]
4447
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
4548
FastTransforms = "057dd010-8810-581a-b7be-e3fc3b93f78c"
49+
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
4650
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
4751
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
4852

4953
[targets]
50-
test = ["Base64", "FastTransforms", "RecipesBase", "Test"]
54+
test = ["Base64", "FastTransforms", "RecipesBase", "Makie", "Test"]

ext/ContinuumArraysMakieExt.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module ContinuumArraysMakieExt
2+
3+
using ContinuumArrays, Makie
4+
using ContinuumArrays: plotgridvalues, AbstractQuasiArray, AbstractQuasiMatrix, AbstractQuasiVector, _split_svec
5+
import Makie: convert_arguments, plot!
6+
7+
8+
function Makie.convert_arguments(p::PointBased, g::AbstractQuasiVector)
9+
x,v = plotgridvalues(g)
10+
convert_arguments(p, _split_svec(x)..., v)
11+
end
12+
13+
14+
@recipe(QuasiPlot, P) do scene
15+
Theme(
16+
)
17+
end
18+
19+
Makie.plottype(a::AbstractQuasiVector) = Lines
20+
Makie.plottype(a::AbstractQuasiMatrix) = QuasiPlot
21+
22+
function Makie.plot!(sc::QuasiPlot)
23+
x,v = plotgridvalues(sc[:P][])
24+
x2 = _split_svec(x)
25+
for j in axes(v,2)
26+
lines!(sc, x, v[:,j])
27+
end
28+
sc
29+
end
30+
31+
32+
33+
34+
end # module

ext/ContinuumArraysRecipesBaseExt.jl

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
module ContinuumArraysRecipesBaseExt
22

3-
using ContinuumArrays, RecipesBase, StaticArrays
4-
using ContinuumArrays: plotgridvalues, AbstractQuasiArray
5-
6-
_split_svec(x) = (x,)
7-
_split_svec(x::AbstractArray{<:StaticVector{2}}) = (map(first,x), map(last,x))
8-
3+
using ContinuumArrays, RecipesBase
4+
using ContinuumArrays: plotgridvalues, AbstractQuasiArray, _split_svec
95

106
@recipe function f(g::AbstractQuasiArray)
117
x,v = plotgridvalues(g)

src/ContinuumArrays.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclu
1818
QuasiDiagonal, MulQuasiArray, MulQuasiMatrix, MulQuasiVector, QuasiMatMulMat, QuasiArrayLayout,
1919
ApplyQuasiArray, ApplyQuasiMatrix, LazyQuasiArrayApplyStyle, AbstractQuasiArrayApplyStyle, AbstractQuasiLazyLayout,
2020
LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle, _factorize, _cutdim,
21-
AbstractQuasiFill, UnionDomain, sum_size, sum_layout, _cumsum, cumsum_layout, applylayout, _equals, layout_broadcasted, PolynomialLayout, dot_size,
21+
AbstractQuasiFill, UnionDomain, sum_size, sum_layout, _cumsum, cumsum_layout, applylayout, equals_layout, layout_broadcasted, PolynomialLayout, dot_size,
2222
diff_layout, diff_size
2323
import InfiniteArrays: Infinity, InfAxes
2424
import AbstractFFTs: Plan

src/bases/bases.jl

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ ApplyStyle(::typeof(pinv), ::Type{<:Basis}) = LazyQuasiArrayApplyStyle()
4949
pinv(J::Basis) = apply(pinv,J)
5050

5151

52-
function _equals(::AbstractBasisLayout, ::AbstractBasisLayout, A, B)
52+
function equals_layout(::AbstractBasisLayout, ::AbstractBasisLayout, A, B)
5353
axes(A) == axes(B) && throw(ArgumentError("Override == to compare bases of type $(typeof(A)) and $(typeof(B))"))
5454
false
5555
end
5656

57-
_equals(::SubBasisLayouts, ::SubBasisLayouts, A::SubQuasiArray, B::SubQuasiArray) = parentindices(A) == parentindices(B) && parent(A) == parent(B)
58-
_equals(::MappedBasisLayouts, ::MappedBasisLayouts, A::SubQuasiArray, B::SubQuasiArray) = parentindices(A) == parentindices(B) && demap(A) == demap(B)
59-
_equals(::AbstractWeightedBasisLayout, ::AbstractWeightedBasisLayout, A, B) = weight(A) == weight(B) && unweighted(A) == unweighted(B)
57+
equals_layout(::SubBasisLayouts, ::SubBasisLayouts, A::SubQuasiArray, B::SubQuasiArray) = parentindices(A) == parentindices(B) && parent(A) == parent(B)
58+
equals_layout(::MappedBasisLayouts, ::MappedBasisLayouts, A::SubQuasiArray, B::SubQuasiArray) = parentindices(A) == parentindices(B) && demap(A) == demap(B)
59+
equals_layout(::AbstractWeightedBasisLayout, ::AbstractWeightedBasisLayout, A, B) = weight(A) == weight(B) && unweighted(A) == unweighted(B)
6060

6161
@inline copy(L::Ldiv{<:AbstractBasisLayout,BroadcastLayout{typeof(+)}}) = +(broadcast(\,Ref(L.A),arguments(L.B))...)
6262
@inline copy(L::Ldiv{<:AbstractBasisLayout,BroadcastLayout{typeof(+)},<:Any,<:AbstractQuasiVector}) =
@@ -154,12 +154,12 @@ copy(L::Ldiv{<:MappedBasisLayouts,BroadcastLayout{typeof(*)},<:Any,<:AbstractQua
154154

155155

156156
# expansion
157-
_grid(_, P, n...) = error("Overload Grid")
157+
grid_layout(_, P, n...) = error("Overload Grid")
158158

159-
_grid(::MappedBasisLayout, P, n...) = invmap(parentindices(P)[1])[grid(demap(P), n...)]
160-
_grid(::SubBasisLayout, P::AbstractQuasiMatrix, n) = grid(parent(P), maximum(parentindices(P)[2][n]))
161-
_grid(::SubBasisLayout, P::AbstractQuasiMatrix) = grid(parent(P), maximum(parentindices(P)[2]))
162-
_grid(::WeightedBasisLayouts, P, n...) = grid(unweighted(P), n...)
159+
grid_layout(::MappedBasisLayout, P, n...) = invmap(parentindices(P)[1])[grid(demap(P), n...)]
160+
grid_layout(::SubBasisLayout, P::AbstractQuasiMatrix, n) = grid(parent(P), maximum(parentindices(P)[2][n]))
161+
grid_layout(::SubBasisLayout, P::AbstractQuasiMatrix) = grid(parent(P), maximum(parentindices(P)[2]))
162+
grid_layout(::WeightedBasisLayouts, P, n...) = grid(unweighted(P), n...)
163163

164164

165165
"""
@@ -170,7 +170,7 @@ be sufficient number of points to determine `size(P,2)`
170170
coefficients. Otherwise its enough points to determine `n`
171171
coefficients.
172172
"""
173-
grid(P, n...) = _grid(MemoryLayout(P), P, n...)
173+
grid(P, n...) = grid_layout(MemoryLayout(P), P, n...)
174174

175175

176176
# values(f) =
@@ -363,7 +363,7 @@ copy(L::Ldiv{Bas,<:ExpansionLayout}) where Bas<:AbstractBasisLayout = copy(Ldiv{
363363
copy(L::Mul{<:ExpansionLayout,Lay}) where Lay = copy(Mul{ApplyLayout{typeof(*)},Lay}(L.A, L.B))
364364
copy(L::Mul{<:ExpansionLayout,Lay}) where Lay<:AbstractLazyLayout = copy(Mul{ApplyLayout{typeof(*)},Lay}(L.A, L.B))
365365

366-
function _broadcastbasis(::typeof(+), _, _, a, b)
366+
function broadcastbasis_layout(::typeof(+), _, _, a, b)
367367
try
368368
a b && error("Overload broadcastbasis(::typeof(+), ::$(typeof(a)), ::$(typeof(b)))")
369369
catch
@@ -372,17 +372,17 @@ function _broadcastbasis(::typeof(+), _, _, a, b)
372372
a
373373
end
374374

375-
_broadcastbasis(::typeof(+), ::MappedBasisLayouts, ::MappedBasisLayouts, a, b) = broadcastbasis(+, demap(a), demap(b))[basismap(a), :]
376-
function _broadcastbasis(::typeof(+), ::SubBasisLayout, ::SubBasisLayout, a, b)
375+
broadcastbasis_layout(::typeof(+), ::MappedBasisLayouts, ::MappedBasisLayouts, a, b) = broadcastbasis(+, demap(a), demap(b))[basismap(a), :]
376+
function broadcastbasis_layout(::typeof(+), ::SubBasisLayout, ::SubBasisLayout, a, b)
377377
kr_a,jr_a = parentindices(a)
378378
kr_b,jr_b = parentindices(b)
379379
@assert kr_a == kr_b # frist axes must match
380380
view(broadcastbasis(+, parent(a), parent(b)), kr_a, union(jr_a,jr_b))
381381
end
382-
_broadcastbasis(::typeof(+), ::SubBasisLayout, _, a, b) = broadcastbasis(+, parent(a), b)
383-
_broadcastbasis(::typeof(+), _, ::SubBasisLayout, a, b) = broadcastbasis(+, a, parent(b))
382+
broadcastbasis_layout(::typeof(+), ::SubBasisLayout, _, a, b) = broadcastbasis(+, parent(a), b)
383+
broadcastbasis_layout(::typeof(+), _, ::SubBasisLayout, a, b) = broadcastbasis(+, a, parent(b))
384384

385-
broadcastbasis(::typeof(+), a, b) = _broadcastbasis(+, MemoryLayout(a), MemoryLayout(b), a, b)
385+
broadcastbasis(::typeof(+), a, b) = broadcastbasis_layout(+, MemoryLayout(a), MemoryLayout(b), a, b)
386386
broadcastbasis(::typeof(+), a, b, c...) = broadcastbasis(+, broadcastbasis(+, a, b), c...)
387387

388388
broadcastbasis(::typeof(-), a, b) = broadcastbasis(+, a, b)
@@ -426,7 +426,7 @@ end
426426
# end
427427

428428

429-
function _equals(::ExpansionLayout, ::ExpansionLayout, f, g)
429+
function equals_layout(::ExpansionLayout, ::ExpansionLayout, f, g)
430430
S,c = arguments(f)
431431
T,d = arguments(g)
432432
ST = broadcastbasis(+, S, T)

src/maps.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ end
117117
AffineMap(domain::AbstractQuasiVector{T}, range::AbstractQuasiVector{V}) where {T,V} =
118118
AffineMap{promote_type(T,V), typeof(domain),typeof(range)}(domain,range)
119119

120+
union(d::AffineMap) = d.range
120121
measure(x::Inclusion{<:Any,<:AbstractInterval}) = last(x)-first(x)
121122

122123
function getproperty(A::AffineMap, d::Symbol)

src/plotting.jl

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,37 @@ the number of coefficients.
1212

1313
plotgrid(P, n...) = plotgrid_layout(MemoryLayout(P), P, n...)
1414

15-
plotgrid_layout(lay, P, n=size(P,2)) = grid(P, min(n,MAX_PLOT_POINTS))
16-
15+
plotgrid_layout(lay, P, n...) = plotgrid_size(size(P), P, n...)
16+
plotgrid_size(::Tuple{InfiniteCardinal{1}}, P, n...) = plotgrid(expand(P), n...)
17+
plotgrid_size(sz, P, n=size(P,2)) = grid(P, min(n,MAX_PLOT_POINTS))
1718
plotgrid_layout(::WeightedBasisLayouts, wP, n...) = plotgrid(unweighted(wP), n...)
1819
plotgrid_layout(::MappedBasisLayout, P, n...) = invmap(parentindices(P)[1])[plotgrid(demap(P), n...)]
1920
plotgrid_layout(::SubBasisLayout, P::AbstractQuasiMatrix, n) = plotgrid(parent(P), maximum(parentindices(P)[2][n]))
2021
plotgrid_layout(::SubBasisLayout, P::AbstractQuasiMatrix) = plotgrid(parent(P), maximum(parentindices(P)[2]))
2122

22-
const _plotgrid = plotgrid_layout # TODO: remove
23-
2423

2524
_mul_plotgrid(_, args) = plotgrid_layout(UnknownLayout(), first(args))
26-
_mul_plotgrid(::Tuple{Any,PaddedLayout}, (P,c)) = plotgrid(P, maximum(colsupport(c)))
25+
_mul_plotgrid(::Tuple{Any,PaddedLayout}, (P,c)) = plotgrid(P, last(colsupport(c)))
2726

2827
function plotgrid_layout(lay::ExpansionLayout, P)
2928
args = arguments(lay,P)
3029
_mul_plotgrid(map(MemoryLayout,args), args)
3130
end
3231

33-
plotvalues(g::AbstractQuasiVector, x) = g[x]
34-
plotvalues(g::AbstractQuasiMatrix, x) = g[x,:]
35-
plotvalues(g::AbstractQuasiArray) = plotvalues(g, plotgrid(g))
32+
plotvalues_size(::Tuple{InfiniteCardinal{1}}, g, x=plotgrid(g)) = g[x]
33+
plotvalues_size(::Tuple{InfiniteCardinal{1},Int}, g, x=plotgrid(g)) = g[x,:]
34+
plotvalues_layout(lay, g, x...) = plotvalues_size(size(g), g, x...)
35+
# plotvalues_layout(::WeightedBasisLayouts, wP, n...) = plotvalues(unweighted(wP), n...)
36+
plotvalues_layout(::ExpansionLayout{MappedBasisLayout}, g, x...) = plotvalues(demap(g))
37+
# plotvalues_layout(::SubBasisLayout, P::AbstractQuasiMatrix, n) = plotvalues(parent(P), maximum(parentindices(P)[2][n]))
38+
# plotvalues_layout(::SubBasisLayout, P::AbstractQuasiMatrix) = plotvalues(parent(P), maximum(parentindices(P)[2]))
39+
40+
plotvalues(g::AbstractQuasiArray, x...) = plotvalues_layout(MemoryLayout(g), g, x...)
3641

3742
function plotgridvalues(g)
3843
x = plotgrid(g)
3944
x, plotvalues(g,x)
4045
end
46+
47+
_split_svec(x) = (x,)
48+
_split_svec(x::AbstractArray{<:StaticVector{2}}) = (map(first,x), map(last,x))

test/runtests.jl

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
using ContinuumArrays, QuasiArrays, IntervalSets, DomainSets, FillArrays, LinearAlgebra, BandedMatrices, InfiniteArrays, Test, Base64, RecipesBase
1+
using ContinuumArrays, QuasiArrays, IntervalSets, DomainSets, FillArrays, LinearAlgebra, BandedMatrices, InfiniteArrays, Test, Base64
22
import ContinuumArrays: ℵ₁, materialize, AffineQuasiVector, BasisLayout, AdjointBasisLayout, SubBasisLayout, ℵ₁,
33
MappedBasisLayout, AdjointMappedBasisLayouts, MappedWeightedBasisLayout, TransformFactorization, Weight, WeightedBasisLayout, SubWeightedBasisLayout, WeightLayout,
4-
basis, invmap, Map, checkpoints, plotgrid_layout, mul, plotvalues
4+
basis, invmap, Map, checkpoints, plotgrid, plotgrid_layout, mul, plotvalues
55
import QuasiArrays: SubQuasiArray, MulQuasiMatrix, Vec, Inclusion, QuasiDiagonal, LazyQuasiArrayApplyStyle, LazyQuasiArrayStyle
66
import LazyArrays: MemoryLayout, ApplyStyle, Applied, colsupport, arguments, ApplyLayout, LdivStyle, MulStyle
77

@@ -85,44 +85,16 @@ include("test_splines.jl")
8585
include("test_chebyshev.jl")
8686
include("test_basisconcat.jl")
8787

88-
@testset "Plotting" begin
89-
L = LinearSpline(0:5)
90-
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), L)
91-
@test rep[1].args == (L.points,L[L.points,:])
92-
93-
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), L[:,1:3])
94-
@test rep[1].args == (L.points,L[L.points,1:3])
95-
96-
@test plotgrid(L[:,1:3],3) == grid(L[:,1:3]) == grid(L[:,1:3],3) == L.points
97-
98-
99-
u = L*randn(6)
100-
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
101-
@test rep[1].args == (L.points,u[L.points])
88+
@testset "Grids/values" begin
89+
L = LinearSpline(1:5)
90+
c = randn(5)
91+
u = L*c
10292
@test plotvalues(u) == u[plotgrid(u)]
10393

104-
@testset "padded" begin
105-
u = L * Vcat(rand(3), Zeros(3))
106-
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
107-
@test rep[1].args == (L.points,u[L.points])
108-
end
109-
110-
@testset "Chebyshev and weighted Chebyshev" begin
111-
T = Chebyshev(10)
112-
w = ChebyshevWeight()
113-
wT = w .* T
114-
x = axes(T, 1)
115-
116-
u = T * Vcat(rand(3), Zeros(7))
117-
v = wT * Vcat(rand(3), Zeros(7))
118-
119-
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
120-
@test rep[1].args == (grid(T), u[grid(T)])
121-
wrep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), v)
122-
@test wrep[1].args == (grid(wT), v[grid(wT)])
123-
124-
@test plotgrid(v) == plotgrid(u) == grid(T) == grid(wT) == plotgrid_layout(MemoryLayout(v), v) == plotgrid_layout(MemoryLayout(u), u)
125-
y = affine(0..1, x)
126-
@test plotgrid(T[y,:]) == (plotgrid(T) .+ 1)/2
127-
end
94+
a = affine(0..1, 1..5)
95+
v = L[a,:] * c
96+
@test plotvalues(v) == v[plotgrid(v)]
12897
end
98+
99+
include("test_recipesbaseext.jl")
100+
include("test_makieext.jl")

test/test_makieext.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using ContinuumArrays, Test
2+
import Makie
3+
import Makie: Point
4+
5+
@testset "Plotting" begin
6+
L = LinearSpline(0:5)
7+
u = L*(2:7)
8+
9+
fig = Makie.lines(u);
10+
@test fig.plot.positions[] == Point.(0:5, 2:7)
11+
fig = Makie.plot(u);
12+
@test fig.plot.positions[] == Point.(0:5, 2:7)
13+
fig = Makie.plot(L);
14+
@test fig.plot.P[] == L
15+
end

test/test_recipesbaseext.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using ContinuumArrays, Test
2+
import RecipesBase
3+
4+
@testset "Plotting" begin
5+
L = LinearSpline(0:5)
6+
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), L)
7+
@test rep[1].args == (L.points,L[L.points,:])
8+
9+
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), L[:,1:3])
10+
@test rep[1].args == (L.points,L[L.points,1:3])
11+
12+
@test plotgrid(L[:,1:3],3) == grid(L[:,1:3]) == grid(L[:,1:3],3) == L.points
13+
14+
15+
u = L*randn(6)
16+
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
17+
@test rep[1].args == (L.points,u[L.points])
18+
19+
@testset "padded" begin
20+
u = L * Vcat(rand(3), Zeros(3))
21+
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
22+
@test rep[1].args == (L.points,u[L.points])
23+
end
24+
25+
@testset "Chebyshev and weighted Chebyshev" begin
26+
T = Chebyshev(10)
27+
w = ChebyshevWeight()
28+
wT = w .* T
29+
x = axes(T, 1)
30+
31+
u = T * Vcat(rand(3), Zeros(7))
32+
v = wT * Vcat(rand(3), Zeros(7))
33+
34+
rep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), u)
35+
@test rep[1].args == (grid(T), u[grid(T)])
36+
wrep = RecipesBase.apply_recipe(Dict{Symbol, Any}(), v)
37+
@test wrep[1].args == (grid(wT), v[grid(wT)])
38+
39+
@test plotgrid(v) == plotgrid(u) == grid(T) == grid(wT) == plotgrid_layout(MemoryLayout(v), v) == plotgrid_layout(MemoryLayout(u), u)
40+
y = affine(0..1, x)
41+
@test plotgrid(T[y,:]) == (plotgrid(T) .+ 1)/2
42+
end
43+
end

0 commit comments

Comments
 (0)