Skip to content

Commit ba325c3

Browse files
InfiniteChait-bltg
andauthored
add specialisation for vector of vectors (#5103)
Co-authored-by: t-bltg <tf.bltg@gmail.com>
1 parent 8882291 commit ba325c3

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

RecipesPipeline/src/type_recipe.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,52 @@ function _apply_type_recipe(plotattributes, v::AbstractArray, letter)
5454
w
5555
end
5656

57+
# Specialisation to apply type recipes on a vector of vectors. The type recipe can either
58+
# apply to the vector of elements or the elements themselves
59+
function _apply_type_recipe(plotattributes, v::AVec{<:AVec}, letter)
60+
plt = plotattributes[:plot_object]
61+
preprocess_axis_attrs!(plt, plotattributes, letter)
62+
# First we attempt on the vector of vector type recipe across everything.
63+
w = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1]
64+
warn_on_recipe_aliases!(plt, plotattributes, :type, v)
65+
if typeof(v) != typeof(w)
66+
postprocess_axis_attrs!(plt, plotattributes, letter)
67+
return w
68+
end
69+
# Next we attempt the array type recipe and if any of the vector elements applies,
70+
# we will stop there. Note we use the same type equivalency test as for a general array
71+
# to check if changes applied
72+
did_replace = false
73+
w = map(v) do u
74+
newu = RecipesBase.apply_recipe(plotattributes, typeof(u), u)[1].args[1]
75+
warn_on_recipe_aliases!(plt, plotattributes, :type, u)
76+
did_replace |= typeof(u) !== typeof(newu)
77+
newu
78+
end
79+
80+
# if nothing changed, then we attempt it at a piecewise level
81+
if !did_replace
82+
if (smv = skipmissing(Base.Iterators.flatten(v))) |> isempty
83+
postprocess_axis_attrs!(plt, plotattributes, letter)
84+
# We'll just leave it untampered with if there are no elements
85+
return v
86+
end
87+
x = first(smv)
88+
args = RecipesBase.apply_recipe(plotattributes, typeof(x), x)[1].args
89+
warn_on_recipe_aliases!(plt, plotattributes, :type, x)
90+
postprocess_axis_attrs!(plt, plotattributes, letter)
91+
return if length(args) == 2 && all(arg -> arg isa Function, args)
92+
numfunc, formatter = args
93+
Formatted(map(u -> map(numfunc, u), v), formatter)
94+
else
95+
v
96+
end
97+
end
98+
99+
postprocess_axis_attrs!(plt, plotattributes, letter)
100+
w
101+
end
102+
57103
# special handling for Surface... need to properly unwrap and re-wrap
58104
_apply_type_recipe(
59105
plotattributes,

RecipesPipeline/test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[deps]
22
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
3+
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
34
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
45
RecipesPipeline = "01d81517-befc-4cb6-b9ec-a95719d0359c"
56
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"

RecipesPipeline/test/runtests.jl

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ using BenchmarkTools
33
using StableRNGs
44
using Test
55

6-
import RecipesPipeline: _prepare_series_data
6+
import Dates
7+
import RecipesPipeline: _prepare_series_data, _apply_type_recipe
78
import RecipesBase
9+
import RecipesBase: @recipe
810

911
@testset "DefaultsDict" begin
1012
dd = DefaultsDict(Dict(:foo => 1, :bar => missing), Dict(:foo => nothing, :baz => 'x'))
@@ -82,6 +84,41 @@ end
8284
@test RecipesBase.is_key_supported("key")
8385
end
8486

87+
@testset "_apply_type_recipe" begin
88+
plt = nothing
89+
plotattributes = Dict{Symbol,Any}(:plot_object => plt)
90+
@test _apply_type_recipe(plotattributes, [1, 2, 3], :x) == [1, 2, 3]
91+
@test _apply_type_recipe(plotattributes, [[1, 2], [3, 4]], :x) == [[1, 2], [3, 4]]
92+
res = _apply_type_recipe(plotattributes, [Dates.Date(2001)], :x)
93+
@test typeof(res) <: Formatted
94+
@test res.data == [Dates.value(Dates.Date(2001))]
95+
@test res.formatter(Dates.value(Dates.Date(2001))) == "2001-01-01"
96+
97+
res = _apply_type_recipe(plotattributes, [[Dates.Date(2001)]], :x)
98+
@test typeof(res) <: Formatted
99+
@test res.data == [[Dates.value(Dates.Date(2001))]]
100+
@test res.formatter(Dates.value(Dates.Date(2001))) == "2001-01-01"
101+
102+
struct Test1 <: Number
103+
val::Float64
104+
end
105+
106+
@recipe f(::Type{T}, v::T) where {T<:AbstractVector{<:Test1}} = map(x -> x.val + 1, v)
107+
108+
@test _apply_type_recipe(plotattributes, Test1.([1, 2, 3]), :x) == [2.0, 3.0, 4.0]
109+
@test _apply_type_recipe(plotattributes, [Test1.([1, 2, 3])], :x) == [[2.0, 3.0, 4.0]]
110+
111+
struct Test2 <: Number
112+
val::Float64
113+
end
114+
115+
@recipe f(::Type{T}, v::T) where {T<:AbstractVector{<:AbstractVector{<:Test2}}} =
116+
map(x -> map(y -> y.val + 2, x), v)
117+
118+
@test _apply_type_recipe(plotattributes, Test2.([1, 2, 3]), :x) == Test2.([1, 2, 3])
119+
@test _apply_type_recipe(plotattributes, [Test2.([1, 2, 3])], :x) == [[3.0, 4.0, 5.0]]
120+
end
121+
85122
@testset "_prepare_series_data" begin
86123
@test_throws ErrorException _prepare_series_data(:test)
87124
@test _prepare_series_data(nothing) nothing

0 commit comments

Comments
 (0)