apply type recipes also for series

This commit is contained in:
Daniel Schwabeneder 2020-04-01 12:08:32 +02:00
parent 945874ca7d
commit d98262bc08

View File

@ -106,10 +106,16 @@ compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all no
# we are going to build recipes to do the processing and splitting of the args # we are going to build recipes to do the processing and splitting of the args
# --------------------------------------------------------------------
# The catch-all SliceIt recipe
# --------------------------------------------------------------------
# ensure we dispatch to the slicer # ensure we dispatch to the slicer
struct SliceIt end struct SliceIt end
# the catch-all recipes # The `SliceIt` recipe finishes user and type recipe processing.
# It splits processed data into individual series data, stores in copied `plotattributes`
# for each series and returns no arguments.
@recipe function f(::Type{SliceIt}, x, y, z) @recipe function f(::Type{SliceIt}, x, y, z)
# handle data with formatting attached # handle data with formatting attached
@ -130,7 +136,6 @@ struct SliceIt end
ys = series_vector(y, plotattributes) ys = series_vector(y, plotattributes)
zs = series_vector(z, plotattributes) zs = series_vector(z, plotattributes)
fr = pop!(plotattributes, :fillrange, nothing) fr = pop!(plotattributes, :fillrange, nothing)
fillranges = process_fillrange(fr, plotattributes) fillranges = process_fillrange(fr, plotattributes)
mf = length(fillranges) mf = length(fillranges)
@ -139,8 +144,6 @@ struct SliceIt end
ribbons = process_ribbon(rib, plotattributes) ribbons = process_ribbon(rib, plotattributes)
mr = length(ribbons) mr = length(ribbons)
# @show zs
mx = length(xs) mx = length(xs)
my = length(ys) my = length(ys)
mz = length(zs) mz = length(zs)
@ -165,6 +168,11 @@ struct SliceIt end
nothing # don't add a series for the main block nothing # don't add a series for the main block
end end
# --------------------------------------------------------------------
# Apply type recipes
# --------------------------------------------------------------------
# this is the default "type recipe"... just pass the object through # this is the default "type recipe"... just pass the object through
@recipe f(::Type{T}, v::T) where {T<:Any} = v @recipe f(::Type{T}, v::T) where {T<:Any} = v
@ -216,8 +224,9 @@ function _apply_type_recipe(plotattributes, v::Surface)
end end
end end
# don't do anything for ints or floats # don't do anything for datapoints or nothing
_apply_type_recipe(plotattributes, v::AbstractArray{<:DataPoint}, letter) = v _apply_type_recipe(plotattributes, v::AbstractArray{<:DataPoint}, letter) = v
_apply_type_recipe(plotattributes, v::Nothing, leter) = v
# axis args before type recipes should still be mapped to all axes # axis args before type recipes should still be mapped to all axes
function _preprocess_axis_args!(plotattributes) function _preprocess_axis_args!(plotattributes)
@ -250,8 +259,14 @@ function _postprocess_axis_args!(plotattributes, letter)
end end
end end
# --------------------------------------------------------------------
# Fallback user recipes calling type recipes
# --------------------------------------------------------------------
# handle "type recipes" by converting inputs, and then either re-calling or slicing # handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z) @recipe function f(x, y, z)
wrap_surfaces!(plotattributes, x, y, z)
did_replace = false did_replace = false
newx = _apply_type_recipe(plotattributes, x, :x) newx = _apply_type_recipe(plotattributes, x, :x)
x === newx || (did_replace = true) x === newx || (did_replace = true)
@ -266,6 +281,7 @@ end
end end
end end
@recipe function f(x, y) @recipe function f(x, y)
wrap_surfaces!(plotattributes, x, y)
did_replace = false did_replace = false
newx = _apply_type_recipe(plotattributes, x, :x) newx = _apply_type_recipe(plotattributes, x, :x)
x === newx || (did_replace = true) x === newx || (did_replace = true)
@ -278,6 +294,7 @@ end
end end
end end
@recipe function f(y) @recipe function f(y)
wrap_surfaces!(plotattribute, y)
newy = _apply_type_recipe(plotattributes, y, :y) newy = _apply_type_recipe(plotattributes, y, :y)
if y !== newy if y !== newy
newy newy
@ -304,12 +321,14 @@ end
end end
# --------------------------------------------------------------------
# 1 argument
# --------------------------------------------------------------------
# helper function to ensure relevant attributes are wrapped by Surface # helper function to ensure relevant attributes are wrapped by Surface
function wrap_surfaces(plotattributes::AKW) function wrap_surfaces!(plotattributes, args...) end
wrap_surfaces!(plotattributes, x::AMat, y::AMat, z::AMat) = wrap_surfaces!(plotattributes)
wrap_surfaces!(plotattributes, x::AVec, y::AVec, z::AMat) = wrap_surfaces!(plotattributes)
function wrap_surfaces!(plotattributes, x::AVec, y::AVec, z::Surface)
wrap_surfaces!(plotattributes)
end
function wrap_surfaces!(plotattributes)
if haskey(plotattributes, :fill_z) if haskey(plotattributes, :fill_z)
v = plotattributes[:fill_z] v = plotattributes[:fill_z]
if !isa(v, Surface) if !isa(v, Surface)
@ -318,18 +337,34 @@ function wrap_surfaces(plotattributes::AKW)
end end
end end
# --------------------------------------------------------------------
# 1 argument
# --------------------------------------------------------------------
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing) @recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
all3D(plotattributes) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none)) all3D(plotattributes) = all(
st -> st in (
:contour,
:contourf,
:heatmap,
:surface,
:wireframe,
:contour3d,
:image,
:plots_heatmap,
),
get(plotattributes, :seriestype, :none),
)
# return a surface if this is a 3d plot, otherwise let it be sliced up # return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f(mat::AMat{<:MaybeNumber}) @recipe function f(mat::AMat)
if all3D(plotattributes) if all3D(plotattributes)
n, m = axes(mat) n, m = axes(mat)
wrap_surfaces(plotattributes) m, n, Surface(mat)
SliceIt, m, n, Surface(mat)
else else
SliceIt, nothing, mat, nothing nothing, mat, nothing
end end
end end
@ -338,15 +373,14 @@ end
if all3D(plotattributes) if all3D(plotattributes)
mat = fmt.data mat = fmt.data
n, m = axes(mat) n, m = axes(mat)
wrap_surfaces(plotattributes) m, n, Formatted(Surface(mat), fmt.formatter)
SliceIt, m, n, Formatted(Surface(mat), fmt.formatter)
else else
SliceIt, nothing, fmt, nothing nothing, fmt, nothing
end end
end end
# assume this is a Volume, so construct one # assume this is a Volume, so construct one
@recipe function f(vol::AbstractArray{T, 3}, args...) where T<:Union{Number,Missing} @recipe function f(vol::AbstractArray{<:MaybeNumber, 3}, args...)
seriestype := :volume seriestype := :volume
SliceIt, nothing, Volume(vol, args...), nothing SliceIt, nothing, Volume(vol, args...), nothing
end end
@ -394,7 +428,6 @@ end
end end
end end
# plotting arbitrary shapes/polygons # plotting arbitrary shapes/polygons
@recipe function f(shape::Shape) @recipe function f(shape::Shape)
@ -456,11 +489,11 @@ function tryrange(F, vec)
error("$F is not a Function, or is not defined at any of the values $vec") error("$F is not a Function, or is not defined at any of the values $vec")
end end
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# 2 arguments # 2 arguments
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# if functions come first, just swap the order (not to be confused with parametric # if functions come first, just swap the order (not to be confused with parametric
# functions... as there would be more than one function passed in) # functions... as there would be more than one function passed in)
@ -475,39 +508,20 @@ end
# 3 arguments # 3 arguments
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# 3d line or scatter
@recipe function f(x::AVec, y::AVec, z::AVec)
SliceIt, x, y, z
end
@recipe function f(x::AMat, y::AMat, z::AMat)
wrap_surfaces(plotattributes)
SliceIt, x, y, z
end
# surface-like... function # surface-like... function
@recipe function f(x::AVec, y::AVec, zf::Function) @recipe function f(x::AVec, y::AVec, zf::Function)
wrap_surfaces(plotattributes) x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
end end
# surface-like... matrix grid # surface-like... matrix grid
@recipe function f(x::AVec, y::AVec, z::AMat) @recipe function f(x::AVec, y::AVec, z::AMat)
if !like_surface(get(plotattributes, :seriestype, :none)) if !like_surface(get(plotattributes, :seriestype, :none))
plotattributes[:seriestype] = :contour plotattributes[:seriestype] = :contour
end end
wrap_surfaces(plotattributes) x, y, Surface(z)
SliceIt, x, y, Surface(z)
end end
# images - grays # images - grays
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Gray @recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Gray
if is_seriestype_supported(:image) if is_seriestype_supported(:image)
seriestype := :image seriestype := :image
@ -523,7 +537,6 @@ end
end end
# images - colors # images - colors
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Colorant @recipe function f(x::AVec, y::AVec, mat::AMat{T}) where T<:Colorant
if is_seriestype_supported(:image) if is_seriestype_supported(:image)
seriestype := :image seriestype := :image
@ -567,7 +580,6 @@ function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
xinv.(xs), yinv.(ys) xinv.(xs), yinv.(ys)
end end
# special handling... 3D parametric function(s) # special handling... 3D parametric function(s)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function} @recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u) mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
@ -577,12 +589,10 @@ end
end end
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Lists of tuples and GeometryTypes.Points # Lists of tuples and GeometryTypes.Points
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@recipe f(v::AVec{<:Tuple}) = unzip(v) @recipe f(v::AVec{<:Tuple}) = unzip(v)
@recipe f(v::AVec{<:GeometryTypes.Point}) = unzip(v) @recipe f(v::AVec{<:GeometryTypes.Point}) = unzip(v)
@recipe f(tup::Tuple) = [tup] @recipe f(tup::Tuple) = [tup]