Merge pull request #2469 from JuliaPlots/bbs/remove-defaults
remove default recipes
This commit is contained in:
commit
8eac99a389
32
src/Plots.jl
32
src/Plots.jl
@ -18,13 +18,31 @@ using Base.Meta
|
|||||||
import Showoff
|
import Showoff
|
||||||
import StatsBase
|
import StatsBase
|
||||||
import JSON
|
import JSON
|
||||||
import RecipePipeline: _process_userrecipe, _process_plotrecipe,
|
import RecipePipeline:
|
||||||
_process_seriesrecipe, _preprocess_args,
|
_process_userrecipe,
|
||||||
preprocessArgs!, is_st_supported,
|
_process_plotrecipe,
|
||||||
finalize_subplot!, recipe_pipeline!,
|
_process_seriesrecipe,
|
||||||
_recipe_init!, _recipe_after_user!,
|
_preprocess_args,
|
||||||
_recipe_after_plot!, _recipe_before_series!,
|
preprocessArgs!,
|
||||||
_recipe_finish!, is_st_supported
|
is_st_supported,
|
||||||
|
finalize_subplot!,
|
||||||
|
recipe_pipeline!,
|
||||||
|
_recipe_init!,
|
||||||
|
_recipe_after_user!,
|
||||||
|
_recipe_after_plot!,
|
||||||
|
_recipe_before_series!,
|
||||||
|
_recipe_finish!,
|
||||||
|
is_st_supported,
|
||||||
|
Formatted,
|
||||||
|
SliceIt,
|
||||||
|
FuncOrFuncs,
|
||||||
|
MaybeNumber,
|
||||||
|
MaybeString,
|
||||||
|
DataPoint,
|
||||||
|
trueOrAllTrue,
|
||||||
|
Surface,
|
||||||
|
AbstractSurface,
|
||||||
|
Volume
|
||||||
|
|
||||||
using Requires
|
using Requires
|
||||||
|
|
||||||
|
|||||||
@ -650,23 +650,6 @@ end
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
abstract type AbstractSurface end
|
|
||||||
|
|
||||||
"represents a contour or surface mesh"
|
|
||||||
struct Surface{M<:AMat} <: AbstractSurface
|
|
||||||
surf::M
|
|
||||||
end
|
|
||||||
|
|
||||||
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for yi in y, xi in x])
|
|
||||||
|
|
||||||
Base.Array(surf::Surface) = surf.surf
|
|
||||||
|
|
||||||
for f in (:length, :size)
|
|
||||||
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
|
|
||||||
end
|
|
||||||
Base.copy(surf::Surface) = Surface(copy(surf.surf))
|
|
||||||
Base.eltype(surf::Surface{T}) where {T} = eltype(T)
|
|
||||||
|
|
||||||
function expand_extrema!(a::Axis, surf::Surface)
|
function expand_extrema!(a::Axis, surf::Surface)
|
||||||
ex = a[:extrema]
|
ex = a[:extrema]
|
||||||
for vi in surf.surf
|
for vi in surf.surf
|
||||||
@ -686,30 +669,6 @@ end
|
|||||||
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
||||||
# ..(a::T, b::T) = (a,b)
|
# ..(a::T, b::T) = (a,b)
|
||||||
|
|
||||||
struct Volume{T}
|
|
||||||
v::Array{T,3}
|
|
||||||
x_extents::Tuple{T,T}
|
|
||||||
y_extents::Tuple{T,T}
|
|
||||||
z_extents::Tuple{T,T}
|
|
||||||
end
|
|
||||||
|
|
||||||
default_extents(::Type{T}) where {T} = (zero(T), one(T))
|
|
||||||
|
|
||||||
function Volume(v::Array{T,3},
|
|
||||||
x_extents = default_extents(T),
|
|
||||||
y_extents = default_extents(T),
|
|
||||||
z_extents = default_extents(T)) where T
|
|
||||||
Volume(v, x_extents, y_extents, z_extents)
|
|
||||||
end
|
|
||||||
|
|
||||||
Base.Array(vol::Volume) = vol.v
|
|
||||||
for f in (:length, :size)
|
|
||||||
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
|
|
||||||
end
|
|
||||||
Base.copy(vol::Volume{T}) where {T} = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
|
|
||||||
Base.eltype(vol::Volume{T}) where {T} = T
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
# style is :open or :closed (for now)
|
# style is :open or :closed (for now)
|
||||||
struct Arrow
|
struct Arrow
|
||||||
@ -771,13 +730,6 @@ function add_arrows(func::Function, x::AVec, y::AVec)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
"Represents data values with formatting that should apply to the tick labels."
|
|
||||||
struct Formatted{T}
|
|
||||||
data::T
|
|
||||||
formatter::Function
|
|
||||||
end
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
"create a BezierCurve for plotting"
|
"create a BezierCurve for plotting"
|
||||||
|
|||||||
132
src/series.jl
132
src/series.jl
@ -1,71 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
|
||||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
|
||||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
|
||||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
|
||||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
|
||||||
|
|
||||||
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
|
|
||||||
const MaybeNumber = Union{Number, Missing}
|
|
||||||
const MaybeString = Union{AbstractString, Missing}
|
|
||||||
const DataPoint = Union{MaybeNumber, MaybeString}
|
|
||||||
|
|
||||||
prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
|
|
||||||
prepareSeriesData(::Nothing) = nothing
|
|
||||||
prepareSeriesData(t::Tuple{T, T}) where {T<:Number} = t
|
|
||||||
prepareSeriesData(f::Function) = f
|
|
||||||
prepareSeriesData(a::AbstractArray{<:MaybeNumber}) = replace!(
|
|
||||||
x -> ismissing(x) || isinf(x) ? NaN : x,
|
|
||||||
map(float,a))
|
|
||||||
prepareSeriesData(a::AbstractArray{<:MaybeString}) = replace(x -> ismissing(x) ? "" : x, a)
|
|
||||||
prepareSeriesData(s::Surface{<:AMat{<:MaybeNumber}}) = Surface(prepareSeriesData(s.surf))
|
|
||||||
prepareSeriesData(s::Surface) = s # non-numeric Surface, such as an image
|
|
||||||
prepareSeriesData(v::Volume) = Volume(prepareSeriesData(v.v), v.x_extents, v.y_extents, v.z_extents)
|
|
||||||
|
|
||||||
# default: assume x represents a single series
|
|
||||||
convertToAnyVector(x, plotattributes) = Any[prepareSeriesData(x)]
|
|
||||||
|
|
||||||
# fixed number of blank series
|
|
||||||
convertToAnyVector(n::Integer, plotattributes) = Any[zeros(0) for i in 1:n]
|
|
||||||
|
|
||||||
# vector of data points is a single series
|
|
||||||
convertToAnyVector(v::AVec{<:DataPoint}, plotattributes) = Any[prepareSeriesData(v)]
|
|
||||||
|
|
||||||
# list of things (maybe other vectors, functions, or something else)
|
|
||||||
function convertToAnyVector(v::AVec, plotattributes)
|
|
||||||
if all(x -> x isa MaybeNumber, v)
|
|
||||||
convertToAnyVector(Vector{MaybeNumber}(v), plotattributes)
|
|
||||||
elseif all(x -> x isa MaybeString, v)
|
|
||||||
convertToAnyVector(Vector{MaybeString}(v), plotattributes)
|
|
||||||
else
|
|
||||||
vcat((convertToAnyVector(vi, plotattributes) for vi in v)...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Matrix is split into columns
|
|
||||||
function convertToAnyVector(v::AMat{<:DataPoint}, plotattributes)
|
|
||||||
if all3D(plotattributes)
|
|
||||||
Any[prepareSeriesData(Surface(v))]
|
|
||||||
else
|
|
||||||
Any[prepareSeriesData(v[:, i]) for i in axes(v, 2)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
# Fillranges & ribbons
|
|
||||||
|
|
||||||
|
|
||||||
process_fillrange(range::Number, plotattributes) = [range]
|
|
||||||
process_fillrange(range, plotattributes) = convertToAnyVector(range, plotattributes)
|
|
||||||
|
|
||||||
process_ribbon(ribbon::Number, plotattributes) = [ribbon]
|
|
||||||
process_ribbon(ribbon, plotattributes) = convertToAnyVector(ribbon, plotattributes)
|
|
||||||
# ribbon as a tuple: (lower_ribbons, upper_ribbons)
|
|
||||||
process_ribbon(ribbon::Tuple{Any,Any}, plotattributes) = collect(zip(convertToAnyVector(ribbon[1], plotattributes),
|
|
||||||
convertToAnyVector(ribbon[2], plotattributes)))
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
||||||
@ -107,70 +40,6 @@ 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
|
||||||
|
|
||||||
# ensure we dispatch to the slicer
|
|
||||||
struct SliceIt end
|
|
||||||
|
|
||||||
# the catch-all recipes
|
|
||||||
@recipe function f(::Type{SliceIt}, x, y, z)
|
|
||||||
|
|
||||||
# handle data with formatting attached
|
|
||||||
if typeof(x) <: Formatted
|
|
||||||
xformatter := x.formatter
|
|
||||||
x = x.data
|
|
||||||
end
|
|
||||||
if typeof(y) <: Formatted
|
|
||||||
yformatter := y.formatter
|
|
||||||
y = y.data
|
|
||||||
end
|
|
||||||
if typeof(z) <: Formatted
|
|
||||||
zformatter := z.formatter
|
|
||||||
z = z.data
|
|
||||||
end
|
|
||||||
|
|
||||||
xs = convertToAnyVector(x, plotattributes)
|
|
||||||
ys = convertToAnyVector(y, plotattributes)
|
|
||||||
zs = convertToAnyVector(z, plotattributes)
|
|
||||||
|
|
||||||
|
|
||||||
fr = pop!(plotattributes, :fillrange, nothing)
|
|
||||||
fillranges = process_fillrange(fr, plotattributes)
|
|
||||||
mf = length(fillranges)
|
|
||||||
|
|
||||||
rib = pop!(plotattributes, :ribbon, nothing)
|
|
||||||
ribbons = process_ribbon(rib, plotattributes)
|
|
||||||
mr = length(ribbons)
|
|
||||||
|
|
||||||
# @show zs
|
|
||||||
|
|
||||||
mx = length(xs)
|
|
||||||
my = length(ys)
|
|
||||||
mz = length(zs)
|
|
||||||
if mx > 0 && my > 0 && mz > 0
|
|
||||||
for i in 1:max(mx, my, mz)
|
|
||||||
# add a new series
|
|
||||||
di = copy(plotattributes)
|
|
||||||
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
|
|
||||||
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
|
|
||||||
|
|
||||||
# handle fillrange
|
|
||||||
fr = fillranges[mod1(i,mf)]
|
|
||||||
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
|
||||||
|
|
||||||
# handle ribbons
|
|
||||||
rib = ribbons[mod1(i,mr)]
|
|
||||||
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
|
||||||
|
|
||||||
push!(series_list, RecipeData(di, ()))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nothing # don't add a series for the main block
|
|
||||||
end
|
|
||||||
|
|
||||||
# this is the default "type recipe"... just pass the object through
|
|
||||||
@recipe f(::Type{T}, v::T) where {T<:Any} = v
|
|
||||||
|
|
||||||
# this should catch unhandled "series recipes" and error with a nice message
|
|
||||||
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
|
|
||||||
|
|
||||||
_apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1]
|
_apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1]
|
||||||
|
|
||||||
@ -278,7 +147,6 @@ end
|
|||||||
|
|
||||||
@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))
|
|
||||||
|
|
||||||
# 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{T}) where T<:Union{Integer,AbstractFloat,Missing}
|
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat,Missing}
|
||||||
|
|||||||
@ -717,9 +717,6 @@ makekw(; kw...) = KW(kw)
|
|||||||
wraptuple(x::Tuple) = x
|
wraptuple(x::Tuple) = x
|
||||||
wraptuple(x) = (x,)
|
wraptuple(x) = (x,)
|
||||||
|
|
||||||
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
|
|
||||||
trueOrAllTrue(f::Function, x) = f(x)
|
|
||||||
|
|
||||||
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||||
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||||
allShapes(arg) = trueOrAllTrue(a -> is_marker_supported(get(_markerAliases, a, a)), arg) ||
|
allShapes(arg) = trueOrAllTrue(a -> is_marker_supported(get(_markerAliases, a, a)), arg) ||
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user