rename some functions
This commit is contained in:
parent
6e3c218d89
commit
f86b324200
@ -44,7 +44,7 @@ PlotThemes = "1"
|
|||||||
PlotUtils = "0.6.5"
|
PlotUtils = "0.6.5"
|
||||||
RecipesBase = "0.8"
|
RecipesBase = "0.8"
|
||||||
Reexport = "0.2"
|
Reexport = "0.2"
|
||||||
Requires = "0.5, 1.0"
|
Requires = "0.5, 1"
|
||||||
Showoff = "0.3.1"
|
Showoff = "0.3.1"
|
||||||
StatsBase = "0.32"
|
StatsBase = "0.32"
|
||||||
julia = "1"
|
julia = "1"
|
||||||
|
|||||||
@ -222,7 +222,7 @@ end
|
|||||||
|
|
||||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||||
|
|
||||||
include("precompile.jl")
|
# include("precompile.jl")
|
||||||
_precompile_()
|
# _precompile_()
|
||||||
|
|
||||||
end # module
|
end # module
|
||||||
|
|||||||
22
src/args.jl
22
src/args.jl
@ -682,7 +682,7 @@ end
|
|||||||
|
|
||||||
function default(; kw...)
|
function default(; kw...)
|
||||||
kw = KW(kw)
|
kw = KW(kw)
|
||||||
preprocessArgs!(kw)
|
preprocess_attributes!(kw)
|
||||||
for (k,v) in kw
|
for (k,v) in kw
|
||||||
default(k, v)
|
default(k, v)
|
||||||
end
|
end
|
||||||
@ -935,7 +935,7 @@ function _add_markershape(plotattributes::AKW)
|
|||||||
end
|
end
|
||||||
|
|
||||||
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
|
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
|
||||||
function preprocessArgs!(plotattributes::AKW)
|
function preprocess_attributes!(plotattributes::AKW)
|
||||||
replaceAliases!(plotattributes, _keyAliases)
|
replaceAliases!(plotattributes, _keyAliases)
|
||||||
|
|
||||||
# handle axis args common to all axis
|
# handle axis args common to all axis
|
||||||
@ -1122,7 +1122,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
# this is when given a vector-type of values to group by
|
# this is when given a vector-type of values to group by
|
||||||
function extractGroupArgs(v::AVec, args...; legendEntry = string)
|
function _extract_group_attributes(v::AVec, args...; legendEntry = string)
|
||||||
groupLabels = sort(collect(unique(v)))
|
groupLabels = sort(collect(unique(v)))
|
||||||
n = length(groupLabels)
|
n = length(groupLabels)
|
||||||
if n > 100
|
if n > 100
|
||||||
@ -1135,24 +1135,24 @@ end
|
|||||||
legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
|
legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
|
||||||
|
|
||||||
# this is when given a tuple of vectors of values to group by
|
# this is when given a tuple of vectors of values to group by
|
||||||
function extractGroupArgs(vs::Tuple, args...)
|
function _extract_group_attributes(vs::Tuple, args...)
|
||||||
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
|
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
|
||||||
v = map(tuple, vs...)
|
v = map(tuple, vs...)
|
||||||
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
|
_extract_group_attributes(v, args...; legendEntry = legendEntryFromTuple)
|
||||||
end
|
end
|
||||||
|
|
||||||
# allow passing NamedTuples for a named legend entry
|
# allow passing NamedTuples for a named legend entry
|
||||||
legendEntryFromTuple(ns::NamedTuple) =
|
legendEntryFromTuple(ns::NamedTuple) =
|
||||||
join(["$k = $v" for (k, v) in pairs(ns)], ", ")
|
join(["$k = $v" for (k, v) in pairs(ns)], ", ")
|
||||||
|
|
||||||
function extractGroupArgs(vs::NamedTuple, args...)
|
function _extract_group_attributes(vs::NamedTuple, args...)
|
||||||
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
|
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
|
||||||
v = map(NamedTuple{keys(vs)}∘tuple, values(vs)...)
|
v = map(NamedTuple{keys(vs)}∘tuple, values(vs)...)
|
||||||
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
|
_extract_group_attributes(v, args...; legendEntry = legendEntryFromTuple)
|
||||||
end
|
end
|
||||||
|
|
||||||
# expecting a mapping of "group label" to "group indices"
|
# expecting a mapping of "group label" to "group indices"
|
||||||
function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
|
function _extract_group_attributes(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
|
||||||
groupLabels = sortedkeys(idxmap)
|
groupLabels = sortedkeys(idxmap)
|
||||||
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
|
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
|
||||||
GroupBy(groupLabels, groupIds)
|
GroupBy(groupLabels, groupIds)
|
||||||
@ -1180,7 +1180,7 @@ end
|
|||||||
const _already_warned = Dict{Symbol,Set{Symbol}}()
|
const _already_warned = Dict{Symbol,Set{Symbol}}()
|
||||||
const _to_warn = Set{Symbol}()
|
const _to_warn = Set{Symbol}()
|
||||||
|
|
||||||
function warnOnUnsupported_args(pkg::AbstractBackend, plotattributes)
|
function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes)
|
||||||
empty!(_to_warn)
|
empty!(_to_warn)
|
||||||
bend = backend_name(pkg)
|
bend = backend_name(pkg)
|
||||||
already_warned = get!(_already_warned, bend, Set{Symbol}())
|
already_warned = get!(_already_warned, bend, Set{Symbol}())
|
||||||
@ -1204,7 +1204,7 @@ end
|
|||||||
# _markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
|
# _markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
|
||||||
# _markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
# _markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||||
|
|
||||||
function warnOnUnsupported(pkg::AbstractBackend, plotattributes)
|
function warn_on_unsupported(pkg::AbstractBackend, plotattributes)
|
||||||
if !is_seriestype_supported(pkg, plotattributes[:seriestype])
|
if !is_seriestype_supported(pkg, plotattributes[:seriestype])
|
||||||
@warn("seriestype $(plotattributes[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
|
@warn("seriestype $(plotattributes[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
|
||||||
end
|
end
|
||||||
@ -1216,7 +1216,7 @@ function warnOnUnsupported(pkg::AbstractBackend, plotattributes)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function warnOnUnsupported_scales(pkg::AbstractBackend, plotattributes::AKW)
|
function warn_on_unsupported_scales(pkg::AbstractBackend, plotattributes::AKW)
|
||||||
for k in (:xscale, :yscale, :zscale, :scale)
|
for k in (:xscale, :yscale, :zscale, :scale)
|
||||||
if haskey(plotattributes, k)
|
if haskey(plotattributes, k)
|
||||||
v = plotattributes[k]
|
v = plotattributes[k]
|
||||||
|
|||||||
@ -85,7 +85,7 @@ function attr!(axis::Axis, args...; kw...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# then preprocess keyword arguments
|
# then preprocess keyword arguments
|
||||||
preprocessArgs!(KW(kw))
|
preprocess_attributes!(KW(kw))
|
||||||
|
|
||||||
# then override for any keywords... only those keywords that already exists in plotattributes
|
# then override for any keywords... only those keywords that already exists in plotattributes
|
||||||
for (k,v) in kw
|
for (k,v) in kw
|
||||||
|
|||||||
131
src/pipeline.jl
131
src/pipeline.jl
@ -38,7 +38,7 @@ function _expand_seriestype_array(plotattributes::AKW, args)
|
|||||||
rd = Vector{RecipeData}(undef, size(sts, 1))
|
rd = Vector{RecipeData}(undef, size(sts, 1))
|
||||||
for r in axes(sts, 1)
|
for r in axes(sts, 1)
|
||||||
dc = copy(plotattributes)
|
dc = copy(plotattributes)
|
||||||
dc[:seriestype] = sts[r:r,:]
|
dc[:seriestype] = sts[r:r, :]
|
||||||
rd[r] = RecipeData(dc, args)
|
rd[r] = RecipeData(dc, args)
|
||||||
end
|
end
|
||||||
rd
|
rd
|
||||||
@ -52,7 +52,7 @@ function _preprocess_args(plotattributes::AKW, args, still_to_process::Vector{Re
|
|||||||
# we simply add the GroupBy object to the front of the args list to allow
|
# we simply add the GroupBy object to the front of the args list to allow
|
||||||
# the recipe to be applied
|
# the recipe to be applied
|
||||||
if haskey(plotattributes, :group)
|
if haskey(plotattributes, :group)
|
||||||
args = (extractGroupArgs(plotattributes[:group], args...), args...)
|
args = (_extract_group_attributes(plotattributes[:group], args...), args...)
|
||||||
end
|
end
|
||||||
|
|
||||||
# if we were passed a vector/matrix of seriestypes and there's more than one row,
|
# if we were passed a vector/matrix of seriestypes and there's more than one row,
|
||||||
@ -61,9 +61,10 @@ function _preprocess_args(plotattributes::AKW, args, still_to_process::Vector{Re
|
|||||||
append!(still_to_process, _expand_seriestype_array(plotattributes, args))
|
append!(still_to_process, _expand_seriestype_array(plotattributes, args))
|
||||||
end
|
end
|
||||||
|
|
||||||
# remove subplot and axis args from plotattributes... they will be passed through in the kw_list
|
# remove subplot and axis args from plotattributes...
|
||||||
|
# they will be passed through in the kw_list
|
||||||
if !isempty(args)
|
if !isempty(args)
|
||||||
for (k,v) in plotattributes
|
for (k, v) in plotattributes
|
||||||
if k in _all_subplot_args || k in _all_axis_args
|
if k in _all_subplot_args || k in _all_axis_args
|
||||||
reset_kw!(plotattributes, k)
|
reset_kw!(plotattributes, k)
|
||||||
end
|
end
|
||||||
@ -90,22 +91,21 @@ function _process_userrecipes(plt::Plot, plotattributes::AKW, args)
|
|||||||
kw_list = KW[]
|
kw_list = KW[]
|
||||||
while !isempty(still_to_process)
|
while !isempty(still_to_process)
|
||||||
# grab the first in line to be processed and either add it to the kw_list or
|
# grab the first in line to be processed and either add it to the kw_list or
|
||||||
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
|
# pass it through apply_recipe to generate a list of RecipeData objects
|
||||||
# for further processing.
|
# (data + attributes) for further processing.
|
||||||
next_series = popfirst!(still_to_process)
|
next_series = popfirst!(still_to_process)
|
||||||
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
|
# recipedata should be of type RecipeData.
|
||||||
|
# if it's not then the inputs must not have been fully processed by recipes
|
||||||
if !(typeof(next_series) <: RecipeData)
|
if !(typeof(next_series) <: RecipeData)
|
||||||
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
|
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
|
||||||
end
|
end
|
||||||
if isempty(next_series.args)
|
if isempty(next_series.args)
|
||||||
_process_userrecipe(plt, kw_list, next_series)
|
_process_userrecipe(plt, kw_list, next_series)
|
||||||
else
|
else
|
||||||
rd_list = RecipesBase.apply_recipe(
|
rd_list =
|
||||||
next_series.plotattributes,
|
RecipesBase.apply_recipe(next_series.plotattributes, next_series.args...)
|
||||||
next_series.args...
|
|
||||||
)
|
|
||||||
warn_on_recipe_aliases!(rd_list, :user, next_series.args...)
|
warn_on_recipe_aliases!(rd_list, :user, next_series.args...)
|
||||||
prepend!(still_to_process,rd_list)
|
prepend!(still_to_process, rd_list)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -118,9 +118,9 @@ function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeD
|
|||||||
# when the arg tuple is empty, that means there's nothing left to recursively
|
# when the arg tuple is empty, that means there's nothing left to recursively
|
||||||
# process... finish up and add to the kw_list
|
# process... finish up and add to the kw_list
|
||||||
kw = recipedata.plotattributes
|
kw = recipedata.plotattributes
|
||||||
preprocessArgs!(kw)
|
preprocess_attributes!(kw)
|
||||||
_preprocess_userrecipe(kw)
|
_preprocess_userrecipe(kw)
|
||||||
warnOnUnsupported_scales(plt.backend, kw)
|
warn_on_unsupported_scales(plt.backend, kw)
|
||||||
|
|
||||||
# add the plot index
|
# add the plot index
|
||||||
plt.n += 1
|
plt.n += 1
|
||||||
@ -141,12 +141,14 @@ function _preprocess_userrecipe(kw::AKW)
|
|||||||
# map marker_z if it's a Function
|
# map marker_z if it's a Function
|
||||||
if isa(get(kw, :marker_z, nothing), Function)
|
if isa(get(kw, :marker_z, nothing), Function)
|
||||||
# TODO: should this take y and/or z as arguments?
|
# TODO: should this take y and/or z as arguments?
|
||||||
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) :
|
||||||
|
map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
|
||||||
end
|
end
|
||||||
|
|
||||||
# map line_z if it's a Function
|
# map line_z if it's a Function
|
||||||
if isa(get(kw, :line_z, nothing), Function)
|
if isa(get(kw, :line_z, nothing), Function)
|
||||||
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) :
|
||||||
|
map(kw[:line_z], kw[:x], kw[:y], kw[:z])
|
||||||
end
|
end
|
||||||
|
|
||||||
# convert a ribbon into a fillrange
|
# convert a ribbon into a fillrange
|
||||||
@ -178,14 +180,20 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW)
|
|||||||
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
|
||||||
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
|
||||||
sy = β .* sx .+ α
|
sy = β .* sx .+ α
|
||||||
push!(kw_list, merge(copy(kw), KW(
|
push!(
|
||||||
:seriestype => :path,
|
kw_list,
|
||||||
:x => sx,
|
merge(
|
||||||
:y => sy,
|
copy(kw),
|
||||||
:fillrange => nothing,
|
KW(
|
||||||
:label => "",
|
:seriestype => :path,
|
||||||
:primary => false,
|
:x => sx,
|
||||||
)))
|
:y => sy,
|
||||||
|
:fillrange => nothing,
|
||||||
|
:label => "",
|
||||||
|
:primary => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -196,7 +204,12 @@ end
|
|||||||
# to generate a list of RecipeData objects (data + attributes).
|
# to generate a list of RecipeData objects (data + attributes).
|
||||||
# If we applied a "plot recipe" without error, then add the returned datalist's KWs,
|
# If we applied a "plot recipe" without error, then add the returned datalist's KWs,
|
||||||
# otherwise we just add the original KW.
|
# otherwise we just add the original KW.
|
||||||
function _process_plotrecipe(plt::Plot, kw::AKW, kw_list::Vector{KW}, still_to_process::Vector{KW})
|
function _process_plotrecipe(
|
||||||
|
plt::Plot,
|
||||||
|
kw::AKW,
|
||||||
|
kw_list::Vector{KW},
|
||||||
|
still_to_process::Vector{KW},
|
||||||
|
)
|
||||||
if !isa(get(kw, :seriestype, nothing), Symbol)
|
if !isa(get(kw, :seriestype, nothing), Symbol)
|
||||||
# seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
|
# seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
|
||||||
push!(kw_list, kw)
|
push!(kw_list, kw)
|
||||||
@ -208,7 +221,7 @@ function _process_plotrecipe(plt::Plot, kw::AKW, kw_list::Vector{KW}, still_to_p
|
|||||||
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
|
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
|
||||||
warn_on_recipe_aliases!(datalist, :plot, st)
|
warn_on_recipe_aliases!(datalist, :plot, st)
|
||||||
for data in datalist
|
for data in datalist
|
||||||
preprocessArgs!(data.plotattributes)
|
preprocess_attributes!(data.plotattributes)
|
||||||
if data.plotattributes[:seriestype] == st
|
if data.plotattributes[:seriestype] == st
|
||||||
error("Plot recipe $st returned the same seriestype: $(data.plotattributes)")
|
error("Plot recipe $st returned the same seriestype: $(data.plotattributes)")
|
||||||
end
|
end
|
||||||
@ -230,7 +243,7 @@ end
|
|||||||
|
|
||||||
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
||||||
# merge in anything meant for the Plot
|
# merge in anything meant for the Plot
|
||||||
for kw in kw_list, (k,v) in kw
|
for kw in kw_list, (k, v) in kw
|
||||||
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -241,7 +254,7 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
|||||||
|
|
||||||
# create the layout and subplots from the inputs
|
# create the layout and subplots from the inputs
|
||||||
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
|
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
|
||||||
for (idx,sp) in enumerate(plt.subplots)
|
for (idx, sp) in enumerate(plt.subplots)
|
||||||
sp.plt = plt
|
sp.plt = plt
|
||||||
sp.attr[:subplot_index] = idx
|
sp.attr[:subplot_index] = idx
|
||||||
end
|
end
|
||||||
@ -266,7 +279,7 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
|||||||
else
|
else
|
||||||
parent = plt.layout
|
parent = plt.layout
|
||||||
end
|
end
|
||||||
sp = Subplot(backend(), parent=parent)
|
sp = Subplot(backend(), parent = parent)
|
||||||
sp.plt = plt
|
sp.plt = plt
|
||||||
push!(plt.subplots, sp)
|
push!(plt.subplots, sp)
|
||||||
push!(plt.inset_subplots, sp)
|
push!(plt.inset_subplots, sp)
|
||||||
@ -282,28 +295,34 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
|||||||
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
# Subplot/Axis attributes set by a user/series recipe apply only to the
|
||||||
# Subplot object which they belong to.
|
# Subplot object which they belong to.
|
||||||
# TODO: allow matrices to still apply to all subplots
|
# TODO: allow matrices to still apply to all subplots
|
||||||
sp_attrs = Dict{Subplot,Any}()
|
sp_attrs = Dict{Subplot, Any}()
|
||||||
for kw in kw_list
|
for kw in kw_list
|
||||||
# get the Subplot object to which the series belongs.
|
# get the Subplot object to which the series belongs.
|
||||||
sps = get(kw, :subplot, :auto)
|
sps = get(kw, :subplot, :auto)
|
||||||
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], series_idx(kw_list,kw)))
|
sp = get_subplot(
|
||||||
|
plt,
|
||||||
|
_cycle(
|
||||||
|
sps == :auto ? plt.subplots : plt.subplots[sps],
|
||||||
|
series_idx(kw_list, kw),
|
||||||
|
),
|
||||||
|
)
|
||||||
kw[:subplot] = sp
|
kw[:subplot] = sp
|
||||||
|
|
||||||
# extract subplot/axis attributes from kw and add to sp_attr
|
# extract subplot/axis attributes from kw and add to sp_attr
|
||||||
attr = KW()
|
attr = KW()
|
||||||
for (k,v) in collect(kw)
|
for (k, v) in collect(kw)
|
||||||
if is_subplot_attr(k) || is_axis_attr(k)
|
if is_subplot_attr(k) || is_axis_attr(k)
|
||||||
attr[k] = pop!(kw, k)
|
attr[k] = pop!(kw, k)
|
||||||
end
|
end
|
||||||
if is_axis_attr_noletter(k)
|
if is_axis_attr_noletter(k)
|
||||||
v = pop!(kw, k)
|
v = pop!(kw, k)
|
||||||
for letter in (:x,:y,:z)
|
for letter in (:x, :y, :z)
|
||||||
attr[Symbol(letter,k)] = v
|
attr[Symbol(letter, k)] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for k in (:scale,), letter in (:x,:y,:z)
|
for k in (:scale,), letter in (:x, :y, :z)
|
||||||
# Series recipes may need access to this information
|
# Series recipes may need access to this information
|
||||||
lk = Symbol(letter,k)
|
lk = Symbol(letter, k)
|
||||||
if haskey(attr, lk)
|
if haskey(attr, lk)
|
||||||
kw[lk] = attr[lk]
|
kw[lk] = attr[lk]
|
||||||
end
|
end
|
||||||
@ -313,7 +332,7 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
|
|||||||
end
|
end
|
||||||
|
|
||||||
# override subplot/axis args. `sp_attrs` take precendence
|
# override subplot/axis args. `sp_attrs` take precendence
|
||||||
for (idx,sp) in enumerate(plt.subplots)
|
for (idx, sp) in enumerate(plt.subplots)
|
||||||
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
|
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
|
||||||
merge(plotattributes, get(sp_attrs, sp, KW()))
|
merge(plotattributes, get(sp_attrs, sp, KW()))
|
||||||
else
|
else
|
||||||
@ -328,7 +347,7 @@ end
|
|||||||
|
|
||||||
# getting ready to add the series... last update to subplot from anything
|
# getting ready to add the series... last update to subplot from anything
|
||||||
# that might have been added during series recipes
|
# that might have been added during series recipes
|
||||||
function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where T
|
function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T}
|
||||||
st::Symbol = plotattributes[:seriestype]
|
st::Symbol = plotattributes[:seriestype]
|
||||||
sp::Subplot{T} = plotattributes[:subplot]
|
sp::Subplot{T} = plotattributes[:subplot]
|
||||||
sp_idx = get_subplot_index(plt, sp)
|
sp_idx = get_subplot_index(plt, sp)
|
||||||
@ -354,9 +373,10 @@ end
|
|||||||
|
|
||||||
function _override_seriestype_check(plotattributes::AKW, st::Symbol)
|
function _override_seriestype_check(plotattributes::AKW, st::Symbol)
|
||||||
# do we want to override the series type?
|
# do we want to override the series type?
|
||||||
if !is3d(st) && !(st in (:contour,:contour3d))
|
if !is3d(st) && !(st in (:contour, :contour3d))
|
||||||
z = plotattributes[:z]
|
z = plotattributes[:z]
|
||||||
if !isa(z, Nothing) && (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
|
if !isa(z, Nothing) &&
|
||||||
|
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
|
||||||
st = (st == :scatter ? :scatter3d : :path3d)
|
st = (st == :scatter ? :scatter3d : :path3d)
|
||||||
plotattributes[:seriestype] = st
|
plotattributes[:seriestype] = st
|
||||||
end
|
end
|
||||||
@ -364,27 +384,11 @@ function _override_seriestype_check(plotattributes::AKW, st::Symbol)
|
|||||||
st
|
st
|
||||||
end
|
end
|
||||||
|
|
||||||
function _prepare_annotations(sp::Subplot, plotattributes::AKW)
|
|
||||||
# strip out series annotations (those which are based on series x/y coords)
|
|
||||||
# and add them to the subplot attr
|
|
||||||
sp_anns = annotations(sp[:annotations])
|
|
||||||
# series_anns = annotations(pop!(plotattributes, :series_annotations, []))
|
|
||||||
# if isa(series_anns, SeriesAnnotations)
|
|
||||||
# series_anns.x = plotattributes[:x]
|
|
||||||
# series_anns.y = plotattributes[:y]
|
|
||||||
# elseif length(series_anns) > 0
|
|
||||||
# x, y = plotattributes[:x], plotattributes[:y]
|
|
||||||
# nx, ny, na = map(length, (x,y,series_anns))
|
|
||||||
# n = max(nx, ny, na)
|
|
||||||
# series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
|
||||||
# end
|
|
||||||
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
|
||||||
end
|
|
||||||
|
|
||||||
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
|
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
|
||||||
# adjust extrema and discrete info
|
# adjust extrema and discrete info
|
||||||
if st == :image
|
if st == :image
|
||||||
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
|
xmin, xmax = ignorenan_extrema(plotattributes[:x])
|
||||||
|
ymin, ymax = ignorenan_extrema(plotattributes[:y])
|
||||||
expand_extrema!(sp[:xaxis], (xmin, xmax))
|
expand_extrema!(sp[:xaxis], (xmin, xmax))
|
||||||
expand_extrema!(sp[:yaxis], (ymin, ymax))
|
expand_extrema!(sp[:yaxis], (ymin, ymax))
|
||||||
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
|
||||||
@ -398,8 +402,8 @@ function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function _add_the_series(plt, sp, plotattributes)
|
function _add_the_series(plt, sp, plotattributes)
|
||||||
warnOnUnsupported_args(plt.backend, plotattributes)
|
warn_on_unsupported_args(plt.backend, plotattributes)
|
||||||
warnOnUnsupported(plt.backend, plotattributes)
|
warn_on_unsupported(plt.backend, plotattributes)
|
||||||
series = Series(plotattributes)
|
series = Series(plotattributes)
|
||||||
push!(plt.series_list, series)
|
push!(plt.series_list, series)
|
||||||
push!(sp.series_list, series)
|
push!(sp.series_list, series)
|
||||||
@ -411,7 +415,6 @@ end
|
|||||||
# this method recursively applies series recipes when the seriestype is not supported
|
# this method recursively applies series recipes when the seriestype is not supported
|
||||||
# natively by the backend
|
# natively by the backend
|
||||||
function _process_seriesrecipe(plt::Plot, plotattributes::AKW)
|
function _process_seriesrecipe(plt::Plot, plotattributes::AKW)
|
||||||
#println("process $(typeof(plotattributes))")
|
|
||||||
# replace seriestype aliases
|
# replace seriestype aliases
|
||||||
st = Symbol(plotattributes[:seriestype])
|
st = Symbol(plotattributes[:seriestype])
|
||||||
st = plotattributes[:seriestype] = get(_typeAliases, st, st)
|
st = plotattributes[:seriestype] = get(_typeAliases, st, st)
|
||||||
@ -421,10 +424,10 @@ function _process_seriesrecipe(plt::Plot, plotattributes::AKW)
|
|||||||
plotattributes[:fillrange] = nothing
|
plotattributes[:fillrange] = nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
|
# if it's natively supported, finalize processing and pass along to the backend,
|
||||||
|
# otherwise recurse
|
||||||
if is_seriestype_supported(st)
|
if is_seriestype_supported(st)
|
||||||
sp = _prepare_subplot(plt, plotattributes)
|
sp = _prepare_subplot(plt, plotattributes)
|
||||||
_prepare_annotations(sp, plotattributes)
|
|
||||||
_expand_subplot_extrema(sp, plotattributes, st)
|
_expand_subplot_extrema(sp, plotattributes, st)
|
||||||
_update_series_attributes!(plotattributes, plt, sp)
|
_update_series_attributes!(plotattributes, plt, sp)
|
||||||
_add_the_series(plt, sp, plotattributes)
|
_add_the_series(plt, sp, plotattributes)
|
||||||
@ -438,7 +441,7 @@ function _process_seriesrecipe(plt::Plot, plotattributes::AKW)
|
|||||||
# assuming there was no error, recursively apply the series recipes
|
# assuming there was no error, recursively apply the series recipes
|
||||||
for data in datalist
|
for data in datalist
|
||||||
if isa(data, RecipeData)
|
if isa(data, RecipeData)
|
||||||
preprocessArgs!(data.plotattributes)
|
preprocess_attributes!(data.plotattributes)
|
||||||
if data.plotattributes[:seriestype] == st
|
if data.plotattributes[:seriestype] == st
|
||||||
error("The seriestype didn't change in series recipe $st. This will cause a StackOverflow.")
|
error("The seriestype didn't change in series recipe $st. This will cause a StackOverflow.")
|
||||||
end
|
end
|
||||||
|
|||||||
@ -49,7 +49,7 @@ as a String to look up its docstring; e.g. `plotattr("seriestype")`.
|
|||||||
function plot(args...; kw...)
|
function plot(args...; kw...)
|
||||||
# this creates a new plot with args/kw and sets it to be the current plot
|
# this creates a new plot with args/kw and sets it to be the current plot
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocess_attributes!(plotattributes)
|
||||||
|
|
||||||
# create an empty Plot then process
|
# create an empty Plot then process
|
||||||
plt = Plot()
|
plt = Plot()
|
||||||
@ -61,7 +61,7 @@ end
|
|||||||
# note: we split into plt1 and plts_tail so we can dispatch correctly
|
# note: we split into plt1 and plts_tail so we can dispatch correctly
|
||||||
function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocess_attributes!(plotattributes)
|
||||||
|
|
||||||
# build our plot vector from the args
|
# build our plot vector from the args
|
||||||
n = length(plts_tail) + 1
|
n = length(plts_tail) + 1
|
||||||
@ -153,7 +153,7 @@ end
|
|||||||
# this adds to a specific plot... most plot commands will flow through here
|
# this adds to a specific plot... most plot commands will flow through here
|
||||||
function plot!(plt::Plot, args...; kw...)
|
function plot!(plt::Plot, args...; kw...)
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocess_attributes!(plotattributes)
|
||||||
# merge!(plt.user_attr, plotattributes)
|
# merge!(plt.user_attr, plotattributes)
|
||||||
_plot!(plt, plotattributes, args)
|
_plot!(plt, plotattributes, args)
|
||||||
end
|
end
|
||||||
|
|||||||
206
src/series.jl
206
src/series.jl
@ -11,29 +11,32 @@ const MaybeNumber = Union{Number, Missing}
|
|||||||
const MaybeString = Union{AbstractString, Missing}
|
const MaybeString = Union{AbstractString, Missing}
|
||||||
const DataPoint = Union{MaybeNumber, MaybeString}
|
const DataPoint = Union{MaybeNumber, MaybeString}
|
||||||
|
|
||||||
prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
|
prepare_series_data(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
|
||||||
prepareSeriesData(::Nothing) = nothing
|
prepare_series_data(::Nothing) = nothing
|
||||||
prepareSeriesData(t::Tuple{T, T}) where {T<:Number} = t
|
prepare_series_data(t::Tuple{T, T}) where {T <: Number} = t
|
||||||
prepareSeriesData(f::Function) = f
|
prepare_series_data(f::Function) = f
|
||||||
prepareSeriesData(ar::AbstractRange{<:Number}) = ar
|
prepare_series_data(ar::AbstractRange{<:Number}) = ar
|
||||||
function prepareSeriesData(a::AbstractArray{<:MaybeNumber})
|
function prepare_series_data(a::AbstractArray{<:MaybeNumber})
|
||||||
f = isimmutable(a) ? replace : replace!
|
f = isimmutable(a) ? replace : replace!
|
||||||
a = f(x -> ismissing(x) || isinf(x) ? NaN : x, map(float, a))
|
a = f(x -> ismissing(x) || isinf(x) ? NaN : x, map(float, a))
|
||||||
end
|
end
|
||||||
prepareSeriesData(a::AbstractArray{<:Missing}) = fill(NaN, axes(a))
|
prepare_series_data(a::AbstractArray{<:Missing}) = fill(NaN, axes(a))
|
||||||
prepareSeriesData(a::AbstractArray{<:MaybeString}) = replace(x -> ismissing(x) ? "" : x, a)
|
prepare_series_data(a::AbstractArray{<:MaybeString}) =
|
||||||
prepareSeriesData(s::Surface{<:AMat{<:MaybeNumber}}) = Surface(prepareSeriesData(s.surf))
|
replace(x -> ismissing(x) ? "" : x, a)
|
||||||
prepareSeriesData(s::Surface) = s # non-numeric Surface, such as an image
|
prepare_series_data(s::Surface{<:AMat{<:MaybeNumber}}) =
|
||||||
prepareSeriesData(v::Volume) = Volume(prepareSeriesData(v.v), v.x_extents, v.y_extents, v.z_extents)
|
Surface(prepare_series_data(s.surf))
|
||||||
|
prepare_series_data(s::Surface) = s # non-numeric Surface, such as an image
|
||||||
|
prepare_series_data(v::Volume) =
|
||||||
|
Volume(prepare_series_data(v.v), v.x_extents, v.y_extents, v.z_extents)
|
||||||
|
|
||||||
# default: assume x represents a single series
|
# default: assume x represents a single series
|
||||||
series_vector(x, plotattributes) = [prepareSeriesData(x)]
|
series_vector(x, plotattributes) = [prepare_series_data(x)]
|
||||||
|
|
||||||
# fixed number of blank series
|
# fixed number of blank series
|
||||||
series_vector(n::Integer, plotattributes) = [zeros(0) for i in 1:n]
|
series_vector(n::Integer, plotattributes) = [zeros(0) for i in 1:n]
|
||||||
|
|
||||||
# vector of data points is a single series
|
# vector of data points is a single series
|
||||||
series_vector(v::AVec{<:DataPoint}, plotattributes) = [prepareSeriesData(v)]
|
series_vector(v::AVec{<:DataPoint}, plotattributes) = [prepare_series_data(v)]
|
||||||
|
|
||||||
# list of things (maybe other vectors, functions, or something else)
|
# list of things (maybe other vectors, functions, or something else)
|
||||||
function series_vector(v::AVec, plotattributes)
|
function series_vector(v::AVec, plotattributes)
|
||||||
@ -49,9 +52,9 @@ end
|
|||||||
# Matrix is split into columns
|
# Matrix is split into columns
|
||||||
function series_vector(v::AMat{<:DataPoint}, plotattributes)
|
function series_vector(v::AMat{<:DataPoint}, plotattributes)
|
||||||
if all3D(plotattributes)
|
if all3D(plotattributes)
|
||||||
[prepareSeriesData(Surface(v))]
|
[prepare_series_data(Surface(v))]
|
||||||
else
|
else
|
||||||
[prepareSeriesData(v[:, i]) for i in axes(v, 2)]
|
[prepare_series_data(v[:, i]) for i in axes(v, 2)]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -73,35 +76,37 @@ process_ribbon(ribbon::Tuple{S, T}, plotattributes) where {S, T} = collect(zip(
|
|||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
compute_x(x::Nothing, y::Nothing, z) = axes(z,1)
|
compute_x(x::Nothing, y::Nothing, z) = axes(z, 1)
|
||||||
compute_x(x::Nothing, y, z) = axes(y,1)
|
compute_x(x::Nothing, y, z) = axes(y, 1)
|
||||||
compute_x(x::Function, y, z) = map(x, y)
|
compute_x(x::Function, y, z) = map(x, y)
|
||||||
compute_x(x, y, z) = x
|
compute_x(x, y, z) = x
|
||||||
|
|
||||||
compute_y(x::Nothing, y::Nothing, z) = axes(z,2)
|
compute_y(x::Nothing, y::Nothing, z) = axes(z, 2)
|
||||||
compute_y(x, y::Function, z) = map(y, x)
|
compute_y(x, y::Function, z) = map(y, x)
|
||||||
compute_y(x, y, z) = y
|
compute_y(x, y, z) = y
|
||||||
|
|
||||||
compute_z(x, y, z::Function) = map(z, x, y)
|
compute_z(x, y, z::Function) = map(z, x, y)
|
||||||
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
||||||
compute_z(x, y, z::Nothing) = nothing
|
compute_z(x, y, z::Nothing) = nothing
|
||||||
compute_z(x, y, z) = z
|
compute_z(x, y, z) = z
|
||||||
|
|
||||||
nobigs(v::AVec{BigFloat}) = map(Float64, v)
|
nobigs(v::AVec{BigFloat}) = map(Float64, v)
|
||||||
nobigs(v::AVec{BigInt}) = map(Int64, v)
|
nobigs(v::AVec{BigInt}) = map(Int64, v)
|
||||||
nobigs(v) = v
|
nobigs(v) = v
|
||||||
|
|
||||||
@noinline function compute_xyz(x, y, z)
|
@noinline function compute_xyz(x, y, z)
|
||||||
x = compute_x(x,y,z)
|
x = compute_x(x, y, z)
|
||||||
y = compute_y(x,y,z)
|
y = compute_y(x, y, z)
|
||||||
z = compute_z(x,y,z)
|
z = compute_z(x, y, z)
|
||||||
nobigs(x), nobigs(y), nobigs(z)
|
nobigs(x), nobigs(y), nobigs(z)
|
||||||
end
|
end
|
||||||
|
|
||||||
# not allowed
|
# not allowed
|
||||||
compute_xyz(x::Nothing, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
|
compute_xyz(x::Nothing, y::FuncOrFuncs{F}, z) where {F <: Function} =
|
||||||
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
|
error("If you want to plot the function `$y`, you need to define the x values!")
|
||||||
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
|
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs{F}) where {F <: Function} =
|
||||||
|
error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||||
|
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
@ -153,15 +158,15 @@ struct SliceIt end
|
|||||||
for i in 1:max(mx, my, mz)
|
for i in 1:max(mx, my, mz)
|
||||||
# add a new series
|
# add a new series
|
||||||
di = copy(plotattributes)
|
di = copy(plotattributes)
|
||||||
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
|
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)
|
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
|
||||||
|
|
||||||
# handle fillrange
|
# handle fillrange
|
||||||
fr = fillranges[mod1(i,mf)]
|
fr = fillranges[mod1(i, mf)]
|
||||||
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
|
||||||
|
|
||||||
# handle ribbons
|
# handle ribbons
|
||||||
rib = ribbons[mod1(i,mr)]
|
rib = ribbons[mod1(i, mr)]
|
||||||
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
di[:ribbon] = isa(rib, Function) ? map(rib, di[:x]) : rib
|
||||||
|
|
||||||
push!(series_list, RecipeData(di, ()))
|
push!(series_list, RecipeData(di, ()))
|
||||||
@ -176,10 +181,11 @@ end
|
|||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
# 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 = v
|
@recipe f(::Type{T}, v::T) where {T} = v
|
||||||
|
|
||||||
# this should catch unhandled "series recipes" and error with a nice message
|
# 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.")
|
@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.")
|
||||||
|
|
||||||
function _apply_type_recipe(plotattributes, v, letter)
|
function _apply_type_recipe(plotattributes, v, letter)
|
||||||
_preprocess_axis_args!(plotattributes, letter)
|
_preprocess_axis_args!(plotattributes, letter)
|
||||||
@ -206,9 +212,9 @@ function _apply_type_recipe(plotattributes, v::AbstractArray, letter)
|
|||||||
_postprocess_axis_args!(plotattributes, letter)
|
_postprocess_axis_args!(plotattributes, letter)
|
||||||
if length(args) == 2 && all(arg -> arg isa Function, args)
|
if length(args) == 2 && all(arg -> arg isa Function, args)
|
||||||
numfunc, formatter = args
|
numfunc, formatter = args
|
||||||
return Formatted(map(numfunc, v), formatter)
|
return Formatted(map(numfunc, v), formatter)
|
||||||
else
|
else
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
_postprocess_axis_args!(plotattributes, letter)
|
_postprocess_axis_args!(plotattributes, letter)
|
||||||
@ -309,13 +315,16 @@ end
|
|||||||
# so we'll apply_type_recipe to all of them
|
# so we'll apply_type_recipe to all of them
|
||||||
@recipe function f(v1, v2, v3, v4, vrest...)
|
@recipe function f(v1, v2, v3, v4, vrest...)
|
||||||
did_replace = false
|
did_replace = false
|
||||||
newargs = map(v -> begin
|
newargs = map(
|
||||||
newv = _apply_type_recipe(plotattributes, v, :unknown)
|
v -> begin
|
||||||
if newv !== v
|
newv = _apply_type_recipe(plotattributes, v, :unknown)
|
||||||
did_replace = true
|
if newv !== v
|
||||||
end
|
did_replace = true
|
||||||
newv
|
end
|
||||||
end, (v1, v2, v3, v4, vrest...))
|
newv
|
||||||
|
end,
|
||||||
|
(v1, v2, v3, v4, vrest...),
|
||||||
|
)
|
||||||
if !did_replace
|
if !did_replace
|
||||||
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
|
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
|
||||||
end
|
end
|
||||||
@ -344,7 +353,8 @@ end
|
|||||||
# 1 argument
|
# 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(
|
all3D(plotattributes) = trueOrAllTrue(
|
||||||
st -> st in (
|
st -> st in (
|
||||||
@ -408,13 +418,13 @@ end
|
|||||||
yflip --> true
|
yflip --> true
|
||||||
cbar --> false
|
cbar --> false
|
||||||
fillcolor --> ColorGradient([:black, :white])
|
fillcolor --> ColorGradient([:black, :white])
|
||||||
SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
|
SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0.0, 1.0))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# images - colors
|
# images - colors
|
||||||
@recipe function f(mat::AMat{T}) where T<:Colorant
|
@recipe function f(mat::AMat{T}) where {T <: Colorant}
|
||||||
n, m = axes(mat)
|
n, m = axes(mat)
|
||||||
|
|
||||||
if is_seriestype_supported(:image)
|
if is_seriestype_supported(:image)
|
||||||
seriestype := :image
|
seriestype := :image
|
||||||
@ -444,8 +454,8 @@ end
|
|||||||
|
|
||||||
@recipe function f(shapes::AMat{Shape})
|
@recipe function f(shapes::AMat{Shape})
|
||||||
seriestype --> :shape
|
seriestype --> :shape
|
||||||
for j in axes(shapes,2)
|
for j in axes(shapes, 2)
|
||||||
@series coords(vec(shapes[:,j]))
|
@series coords(vec(shapes[:, j]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -455,7 +465,7 @@ end
|
|||||||
|
|
||||||
# function without range... use the current range of the x-axis
|
# function without range... use the current range of the x-axis
|
||||||
|
|
||||||
@recipe function f(f::FuncOrFuncs{F}) where F<:Function
|
@recipe function f(f::FuncOrFuncs{F}) where {F <: Function}
|
||||||
plt = plotattributes[:plot_object]
|
plt = plotattributes[:plot_object]
|
||||||
xmin, xmax = if haskey(plotattributes, :xlims)
|
xmin, xmax = if haskey(plotattributes, :xlims)
|
||||||
plotattributes[:xlims]
|
plotattributes[:xlims]
|
||||||
@ -464,8 +474,8 @@ end
|
|||||||
axis_limits(plt[1], :x)
|
axis_limits(plt[1], :x)
|
||||||
catch
|
catch
|
||||||
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
|
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
|
||||||
xm = PlotUtils.tryrange(f, xinv.([-5,-1,0,0.01]))
|
xm = PlotUtils.tryrange(f, xinv.([-5, -1, 0, 0.01]))
|
||||||
xm, PlotUtils.tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01])))
|
xm, PlotUtils.tryrange(f, filter(x -> x > xm, xinv.([5, 1, 0.99, 0, -0.01])))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -480,7 +490,7 @@ end
|
|||||||
# 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)
|
||||||
|
|
||||||
@recipe function f(f::FuncOrFuncs{F}, x) where F<:Function
|
@recipe function f(f::FuncOrFuncs{F}, x) where {F <: Function}
|
||||||
F2 = typeof(x)
|
F2 = typeof(x)
|
||||||
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
|
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
|
||||||
x, f
|
x, f
|
||||||
@ -505,7 +515,7 @@ end
|
|||||||
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
|
||||||
yflip --> true
|
yflip --> true
|
||||||
@ -520,7 +530,7 @@ 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
|
||||||
yflip --> true
|
yflip --> true
|
||||||
@ -541,27 +551,49 @@ end
|
|||||||
|
|
||||||
# special handling... xmin/xmax with parametric function(s)
|
# special handling... xmin/xmax with parametric function(s)
|
||||||
@recipe function f(f::Function, xmin::Number, xmax::Number)
|
@recipe function f(f::Function, xmin::Number, xmax::Number)
|
||||||
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
|
xscale, yscale = [get(plotattributes, sym, :identity) for sym in (:xscale, :yscale)]
|
||||||
_scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
_scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
||||||
end
|
end
|
||||||
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
|
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where {F <: Function}
|
||||||
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
|
xscale, yscale = [get(plotattributes, sym, :identity) for sym in (:xscale, :yscale)]
|
||||||
unzip(_scaled_adapted_grid.(fs, xscale, yscale, xmin, xmax))
|
unzip(_scaled_adapted_grid.(fs, xscale, yscale, xmin, xmax))
|
||||||
end
|
end
|
||||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
@recipe f(
|
||||||
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
|
fx::FuncOrFuncs{F},
|
||||||
|
fy::FuncOrFuncs{G},
|
||||||
|
u::AVec,
|
||||||
|
) where {F <: Function, G <: Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
|
||||||
|
@recipe f(
|
||||||
|
fx::FuncOrFuncs{F},
|
||||||
|
fy::FuncOrFuncs{G},
|
||||||
|
umin::Number,
|
||||||
|
umax::Number,
|
||||||
|
n = 200,
|
||||||
|
) where {F <: Function, G <: Function} = fx, fy, range(umin, stop = umax, length = n)
|
||||||
|
|
||||||
function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
|
||||||
(xf, xinv), (yf, yinv) = ((scalefunc(s),invscalefunc(s)) for s in (xscale,yscale))
|
(xf, xinv), (yf, yinv) = ((scalefunc(s), invscalefunc(s)) for s in (xscale, yscale))
|
||||||
xs, ys = adapted_grid(yf∘f∘xinv, xf.((xmin, xmax)))
|
xs, ys = adapted_grid(yf ∘ f ∘ xinv, xf.((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)
|
||||||
end
|
end
|
||||||
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
|
@recipe function f(
|
||||||
|
fx::FuncOrFuncs{F},
|
||||||
|
fy::FuncOrFuncs{G},
|
||||||
|
fz::FuncOrFuncs{H},
|
||||||
|
umin::Number,
|
||||||
|
umax::Number,
|
||||||
|
numPoints = 200,
|
||||||
|
) where {F <: Function, G <: Function, H <: Function}
|
||||||
fx, fy, fz, range(umin, stop = umax, length = numPoints)
|
fx, fy, fz, range(umin, stop = umax, length = numPoints)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -570,13 +602,15 @@ 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]
|
||||||
@recipe f(p::GeometryTypes.Point) = [p]
|
@recipe f(p::GeometryTypes.Point) = [p]
|
||||||
|
|
||||||
# Special case for 4-tuples in :ohlc series
|
# Special case for 4-tuples in :ohlc series
|
||||||
@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
|
@recipe f(xyuv::AVec{<:Tuple{R1, R2, R3, R4}}) where {R1, R2, R3, R4} =
|
||||||
|
get(plotattributes, :seriestype, :path) == :ohlc ? OHLC[OHLC(t...) for t in xyuv] :
|
||||||
|
unzip(xyuv)
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
@ -584,11 +618,13 @@ end
|
|||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
splittable_kw(key, val, lengthGroup) = false
|
splittable_kw(key, val, lengthGroup) = false
|
||||||
splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && length(axes(val,1)) == lengthGroup
|
splittable_kw(key, val::AbstractArray, lengthGroup) =
|
||||||
|
!(key in (:group, :color_palette)) && length(axes(val, 1)) == lengthGroup
|
||||||
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
|
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
|
||||||
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
|
splittable_kw(key, val::SeriesAnnotations, lengthGroup) =
|
||||||
|
splittable_kw(key, val.strs, lengthGroup)
|
||||||
|
|
||||||
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val)-1)...]
|
split_kw(key, val::AbstractArray, indices) = val[indices, fill(Colon(), ndims(val) - 1)...]
|
||||||
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
|
split_kw(key, val::Tuple, indices) = Tuple(split_kw(key, v, indices) for v in val)
|
||||||
function split_kw(key, val::SeriesAnnotations, indices)
|
function split_kw(key, val::SeriesAnnotations, indices)
|
||||||
split_strs = split_kw(key, val.strs, indices)
|
split_strs = split_kw(key, val.strs, indices)
|
||||||
@ -596,7 +632,11 @@ function split_kw(key, val::SeriesAnnotations, indices)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
||||||
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(undef, length(keys(x_ind)), length(groupby.groupLabels))
|
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(
|
||||||
|
undef,
|
||||||
|
length(keys(x_ind)),
|
||||||
|
length(groupby.groupLabels),
|
||||||
|
)
|
||||||
fill!(y_mat, def_val)
|
fill!(y_mat, def_val)
|
||||||
for i in eachindex(groupby.groupLabels)
|
for i in eachindex(groupby.groupLabels)
|
||||||
xi = x[groupby.groupIds[i]]
|
xi = x[groupby.groupIds[i]]
|
||||||
@ -606,7 +646,8 @@ function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
|
|||||||
return y_mat
|
return y_mat
|
||||||
end
|
end
|
||||||
|
|
||||||
groupedvec2mat(x_ind, x, y::Tuple, groupby) = Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
|
groupedvec2mat(x_ind, x, y::Tuple, groupby) =
|
||||||
|
Tuple(groupedvec2mat(x_ind, x, v, groupby) for v in y)
|
||||||
|
|
||||||
group_as_matrix(t) = false
|
group_as_matrix(t) = false
|
||||||
|
|
||||||
@ -614,11 +655,11 @@ group_as_matrix(t) = false
|
|||||||
@recipe function f(groupby::GroupBy, args...)
|
@recipe function f(groupby::GroupBy, args...)
|
||||||
lengthGroup = maximum(union(groupby.groupIds...))
|
lengthGroup = maximum(union(groupby.groupIds...))
|
||||||
if !(group_as_matrix(args[1]))
|
if !(group_as_matrix(args[1]))
|
||||||
for (i,glab) in enumerate(groupby.groupLabels)
|
for (i, glab) in enumerate(groupby.groupLabels)
|
||||||
@series begin
|
@series begin
|
||||||
label --> string(glab)
|
label --> string(glab)
|
||||||
idxfilter --> groupby.groupIds[i]
|
idxfilter --> groupby.groupIds[i]
|
||||||
for (key,val) in plotattributes
|
for (key, val) in plotattributes
|
||||||
if splittable_kw(key, val, lengthGroup)
|
if splittable_kw(key, val, lengthGroup)
|
||||||
:($key) := split_kw(key, val, groupby.groupIds[i])
|
:($key) := split_kw(key, val, groupby.groupIds[i])
|
||||||
end
|
end
|
||||||
@ -640,12 +681,15 @@ group_as_matrix(t) = false
|
|||||||
end
|
end
|
||||||
x_u = unique(sort(x))
|
x_u = unique(sort(x))
|
||||||
x_ind = Dict(zip(x_u, eachindex(x_u)))
|
x_ind = Dict(zip(x_u, eachindex(x_u)))
|
||||||
for (key,val) in plotattributes
|
for (key, val) in plotattributes
|
||||||
if splittable_kw(key, val, lengthGroup)
|
if splittable_kw(key, val, lengthGroup)
|
||||||
:($key) := groupedvec2mat(x_ind, x, val, groupby)
|
:($key) := groupedvec2mat(x_ind, x, val, groupby)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
label --> reshape(groupby.groupLabels, 1, :)
|
label --> reshape(groupby.groupLabels, 1, :)
|
||||||
typeof(g)((x_u, (groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...))
|
typeof(g)((
|
||||||
|
x_u,
|
||||||
|
(groupedvec2mat(x_ind, x, arg, groupby, NaN) for arg in last_args)...,
|
||||||
|
))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -838,7 +838,7 @@ end
|
|||||||
|
|
||||||
function attr!(series::Series; kw...)
|
function attr!(series::Series; kw...)
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocess_attributes!(plotattributes)
|
||||||
for (k,v) in plotattributes
|
for (k,v) in plotattributes
|
||||||
if haskey(_series_defaults, k)
|
if haskey(_series_defaults, k)
|
||||||
series[k] = v
|
series[k] = v
|
||||||
@ -852,7 +852,7 @@ end
|
|||||||
|
|
||||||
function attr!(sp::Subplot; kw...)
|
function attr!(sp::Subplot; kw...)
|
||||||
plotattributes = KW(kw)
|
plotattributes = KW(kw)
|
||||||
preprocessArgs!(plotattributes)
|
preprocess_attributes!(plotattributes)
|
||||||
for (k,v) in plotattributes
|
for (k,v) in plotattributes
|
||||||
if haskey(_subplot_defaults, k)
|
if haskey(_subplot_defaults, k)
|
||||||
sp[k] = v
|
sp[k] = v
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user