format file

This commit is contained in:
Simon Christ 2020-03-03 23:03:46 +01:00
parent 16b8d01b88
commit d1dbb1bf2a

View File

@ -44,7 +44,7 @@ end
# ---------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------
num_series(x::AMat) = size(x,2) num_series(x::AMat) = size(x, 2)
num_series(x) = 1 num_series(x) = 1
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T")) RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
@ -55,13 +55,26 @@ RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) wher
# for seriestype `line`, need to sort by x values # for seriestype `line`, need to sort by x values
const POTENTIAL_VECTOR_ARGUMENTS = [ const POTENTIAL_VECTOR_ARGUMENTS = [
:seriescolor, :seriesalpha, :seriescolor,
:linecolor, :linealpha, :linewidth, :linestyle, :line_z, :seriesalpha,
:fillcolor, :fillalpha, :fill_z, :linecolor,
:markercolor, :markeralpha, :markershape, :marker_z, :linealpha,
:markerstrokecolor, :markerstrokealpha, :linewidth,
:yerror, :yerror, :linestyle,
:series_annotations, :fillrange :line_z,
:fillcolor,
:fillalpha,
:fill_z,
:markercolor,
:markeralpha,
:markershape,
:marker_z,
:markerstrokecolor,
:markerstrokealpha,
:yerror,
:yerror,
:series_annotations,
:fillrange,
] ]
@recipe function f(::Type{Val{:line}}, x, y, z) @recipe function f(::Type{Val{:line}}, x, y, z)
@ -99,7 +112,7 @@ end
@recipe function f(::Type{Val{:hline}}, x, y, z) @recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y) n = length(y)
newx = repeat(Float64[-1, 1, NaN], n) newx = repeat(Float64[-1, 1, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y]) newy = vec(Float64[yi for i = 1:3, yi in y])
x := newx x := newx
y := newy y := newy
seriestype := :straightline seriestype := :straightline
@ -109,7 +122,7 @@ end
@recipe function f(::Type{Val{:vline}}, x, y, z) @recipe function f(::Type{Val{:vline}}, x, y, z)
n = length(y) n = length(y)
newx = vec(Float64[yi for i=1:3,yi=y]) newx = vec(Float64[yi for i = 1:3, yi in y])
newy = repeat(Float64[-1, 1, NaN], n) newy = repeat(Float64[-1, 1, NaN], n)
x := newx x := newx
y := newy y := newy
@ -121,7 +134,7 @@ end
@recipe function f(::Type{Val{:hspan}}, x, y, z) @recipe function f(::Type{Val{:hspan}}, x, y, z)
n = div(length(y), 2) n = div(length(y), 2)
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n) newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
newy = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...) newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
linewidth --> 0 linewidth --> 0
x := newx x := newx
y := newy y := newy
@ -132,7 +145,7 @@ end
@recipe function f(::Type{Val{:vspan}}, x, y, z) @recipe function f(::Type{Val{:vspan}}, x, y, z)
n = div(length(y), 2) n = div(length(y), 2)
newx = vcat([[y[2i-1], y[2i-1], y[2i], y[2i], NaN] for i in 1:n]...) newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n) newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
linewidth --> 0 linewidth --> 0
x := newx x := newx
@ -156,7 +169,7 @@ end
primary := false primary := false
() ()
end end
() ()
end end
@deps scatterpath path scatter @deps scatterpath path scatter
@ -169,7 +182,7 @@ function make_steps(x::AbstractArray, st)
n = length(x) n = length(x)
n == 0 && return zeros(0) n == 0 && return zeros(0)
newx = zeros(2n - 1) newx = zeros(2n - 1)
for i in 1:n for i = 1:n
idx = 2i - 1 idx = 2i - 1
newx[idx] = x[i] newx[idx] = x[i]
if i > 1 if i > 1
@ -249,10 +262,10 @@ end
end end
end end
newx, newy = zeros(3n), zeros(3n) newx, newy = zeros(3n), zeros(3n)
for i=1:n for i = 1:n
rng = 3i-2:3i rng = (3i - 2):(3i)
newx[rng] = [x[i], x[i], NaN] newx[rng] = [x[i], x[i], NaN]
newy[rng] = [_cycle(fr,i), y[i], NaN] newy[rng] = [_cycle(fr, i), y[i], NaN]
end end
x := newx x := newx
y := newy y := newy
@ -282,16 +295,16 @@ end
# get the value of the curve point at position t # get the value of the curve point at position t
function bezier_value(pts::AVec, t::Real) function bezier_value(pts::AVec, t::Real)
val = 0.0 val = 0.0
n = length(pts)-1 n = length(pts) - 1
for (i,p) in enumerate(pts) for (i, p) in enumerate(pts)
val += p * binomial(n, i-1) * (1-t)^(n-i+1) * t^(i-1) val += p * binomial(n, i - 1) * (1 - t)^(n - i + 1) * t^(i - 1)
end end
val val
end end
# create segmented bezier curves in place of line segments # create segmented bezier curves in place of line segments
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30) @recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30)
args = z !== nothing ? (x,y,z) : (x,y) args = z !== nothing ? (x, y, z) : (x, y)
newx, newy = zeros(0), zeros(0) newx, newy = zeros(0), zeros(0)
fr = plotattributes[:fillrange] fr = plotattributes[:fillrange]
newfr = fr !== nothing ? zeros(0) : nothing newfr = fr !== nothing ? zeros(0) : nothing
@ -304,13 +317,13 @@ end
for rng in iter_segments(args...) for rng in iter_segments(args...)
length(rng) < 2 && continue length(rng) < 2 && continue
ts = range(0, stop = 1, length = npoints) ts = range(0, stop = 1, length = npoints)
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts)) nanappend!(newx, map(t -> bezier_value(_cycle(x, rng), t), ts))
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts)) nanappend!(newy, map(t -> bezier_value(_cycle(y, rng), t), ts))
if z !== nothing if z !== nothing
nanappend!(newz, map(t -> bezier_value(_cycle(z,rng), t), ts)) nanappend!(newz, map(t -> bezier_value(_cycle(z, rng), t), ts))
end end
if fr !== nothing if fr !== nothing
nanappend!(newfr, map(t -> bezier_value(_cycle(fr,rng), t), ts)) nanappend!(newfr, map(t -> bezier_value(_cycle(fr, rng), t), ts))
end end
# if lz !== nothing # if lz !== nothing
# lzrng = _cycle(lz, rng) # the line_z's for this segment # lzrng = _cycle(lz, rng) # the line_z's for this segment
@ -343,14 +356,15 @@ end
# create a bar plot as a filled step function # create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z) @recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y) procx, procy, xscale, yscale, baseline =
_preprocess_barlike(plotattributes, x, y)
nx, ny = length(procx), length(procy) nx, ny = length(procx), length(procy)
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis] axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=procx] cv = [discrete_value!(axis, xi)[1] for xi in procx]
procx = if nx == ny procx = if nx == ny
cv cv
elseif nx == ny + 1 elseif nx == ny + 1
0.5diff(cv) + cv[1:end-1] 0.5 * diff(cv) + cv[1:(end - 1)]
else else
error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))") error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
end end
@ -359,12 +373,12 @@ end
bw = plotattributes[:bar_width] bw = plotattributes[:bar_width]
hw = if bw === nothing hw = if bw === nothing
if nx > 1 if nx > 1
0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx))) 0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(procx)))
else else
0.5 * _bar_width 0.5 * _bar_width
end end
else else
Float64[0.5_cycle(bw,i) for i=eachindex(procx)] Float64[0.5 * _cycle(bw, i) for i in eachindex(procx)]
end end
# make fillto a vector... default fills to 0 # make fillto a vector... default fills to 0
@ -378,13 +392,20 @@ end
# create the bar shapes by adding x/y segments # create the bar shapes by adding x/y segments
xseg, yseg = Segments(), Segments() xseg, yseg = Segments(), Segments()
for i=1:ny for i = 1:ny
yi = procy[i] yi = procy[i]
if !isnan(yi) if !isnan(yi)
center = procx[i] center = procx[i]
hwi = _cycle(hw,i) hwi = _cycle(hw, i)
fi = _cycle(fillto,i) fi = _cycle(fillto, i)
push!(xseg, center-hwi, center-hwi, center+hwi, center+hwi, center-hwi) push!(
xseg,
center - hwi,
center - hwi,
center + hwi,
center + hwi,
center - hwi,
)
push!(yseg, yi, fi, fi, yi, yi) push!(yseg, yi, fi, fi, yi, yi)
end end
end end
@ -415,8 +436,8 @@ end
m, n = size(z.surf) m, n = size(z.surf)
x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n) x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n)
fz = zeros(m * n) fz = zeros(m * n)
for i in 1:m # y for i = 1:m # y
for j in 1:n # x for j = 1:n # x
k = (j - 1) * m + i k = (j - 1) * m + i
inds = (6 * (k - 1) + 1):(6 * k - 1) inds = (6 * (k - 1) + 1):(6 * k - 1)
x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]] x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]]
@ -440,13 +461,17 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Histograms # Histograms
_bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2 _bin_centers(v::AVec) = (v[1:(end - 1)] + v[2:end]) / 2
_is_positive(x) = (x > 0) && !(x 0) _is_positive(x) = (x > 0) && !(x 0)
_positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN) _positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) where T<:AbstractFloat function _scale_adjusted_values(
::Type{T},
V::AbstractVector,
scale::Symbol,
) where {T<:AbstractFloat}
if scale in _logScales if scale in _logScales
[_positive_else_nan(T, x) for x in V] [_positive_else_nan(T, x) for x in V]
else else
@ -455,7 +480,7 @@ function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) whe
end end
function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real}
if (scale in _logScales) if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3) !isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else else
@ -464,7 +489,11 @@ function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
end end
function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:AbstractFloat function _preprocess_binbarlike_weights(
::Type{T},
w,
wscale::Symbol,
) where {T<:AbstractFloat}
w_adj = _scale_adjusted_values(T, w, wscale) w_adj = _scale_adjusted_values(T, w, wscale)
w_min = ignorenan_minimum(w_adj) w_min = ignorenan_minimum(w_adj)
w_max = ignorenan_maximum(w_adj) w_max = ignorenan_maximum(w_adj)
@ -490,7 +519,8 @@ end
@recipe function f(::Type{Val{:barbins}}, x, y, z) @recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y)
if (plotattributes[:bar_width] === nothing) if (plotattributes[:bar_width] === nothing)
bar_width := diff(edge) bar_width := diff(edge)
end end
@ -503,8 +533,9 @@ end
@recipe function f(::Type{Val{:scatterbins}}, x, y, z) @recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) edge, weights, xscale, yscale, baseline =
xerror := diff(edge)/2 _preprocess_binlike(plotattributes, x, y)
xerror := diff(edge) / 2
x := _bin_centers(edge) x := _bin_centers(edge)
y := weights y := weights
seriestype := :scatter seriestype := :scatter
@ -513,7 +544,13 @@ end
@deps scatterbins scatter @deps scatterbins scatter
function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::Symbol) function _stepbins_path(
edge,
weights,
baseline::Real,
xscale::Symbol,
yscale::Symbol,
)
log_scale_x = xscale in _logScales log_scale_x = xscale in _logScales
log_scale_y = yscale in _logScales log_scale_y = yscale in _logScales
@ -538,7 +575,7 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
w, it_state_w = it_tuple_w w, it_state_w = it_tuple_w
if (log_scale_x && a 0) if (log_scale_x && a 0)
a = oftype(a, b/_logScaleBases[xscale]^3) a = oftype(a, b / _logScaleBases[xscale]^3)
end end
if isnan(w) if isnan(w)
@ -575,9 +612,11 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z) @recipe function f(::Type{Val{:stepbins}}, x, y, z)
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis] axis =
plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale) xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(plotattributes) if !isvertical(plotattributes)
@ -607,9 +646,19 @@ end
end end
Plots.@deps stepbins path Plots.@deps stepbins path
wand_edges(x...) = (@warn("Load the StatsPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto) wand_edges(x...) = (
@warn(
"Load the StatsPlots package in order to use :wand bins. Defaulting to :auto",
once = true
);
:auto
)
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N function _auto_binning_nbins(
vs::NTuple{N,AbstractVector},
dim::Integer;
mode::Symbol = :auto,
) where {N}
max_bins = 10_000 max_bins = 10_000
_cl(x) = min(ceil(Int, max(x, one(x))), max_bins) _cl(x) = min(ceil(Int, max(x, one(x))), max_bins)
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1)) _iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
@ -618,8 +667,13 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
n_samples = length(LinearIndices(first(vs))) n_samples = length(LinearIndices(first(vs)))
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation # The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
nd = n_samples^(1/(2+N)) nd = n_samples^(1 / (2 + N))
nd = N == 2 ? min(n_samples^(1/(2+N)), nd / (1-cor(first(vs), last(vs))^2)^(3//8)) : nd # the >2-dimensional case does not have a nice solution to correlations nd = N == 2 ?
min(
n_samples^(1 / (2 + N)),
nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8),
) :
nd # the >2-dimensional case does not have a nice solution to correlations
v = vs[dim] v = vs[dim]
@ -644,32 +698,52 @@ function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::S
end end
end end
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} = StatsBase.histrange(vs[dim], binning, :left) _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} =
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning)) StatsBase.histrange(vs[dim], binning, :left)
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} =
_hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge(
vs::NTuple{N,AbstractVector},
dim::Integer,
binning::AbstractVector,
) where {N} = binning
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N, Any}) where {N} = _hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N,Any}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,)) map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} = _hist_edges(
map(dim -> _hist_edge(vs, dim, binning), (1:N...,)) vs::NTuple{N,AbstractVector},
binning::Union{Integer,Symbol,AbstractVector},
) where {N} = map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
_hist_norm_mode(mode::Symbol) = mode _hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none _hist_norm_mode(mode::Bool) = mode ? :pdf : :none
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs) _filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
function _filternans(vs::NTuple{N,AbstractVector}) where N function _filternans(vs::NTuple{N,AbstractVector}) where {N}
_invertedindex(v, not) = [j for (i,j) in enumerate(v) if !(i not)] _invertedindex(v, not) = [j for (i, j) in enumerate(v) if !(i not)]
nots = union(Set.(findall.(!isfinite, vs))...) nots = union(Set.(findall.(!isfinite, vs))...)
_invertedindex.(vs, Ref(nots)) _invertedindex.(vs, Ref(nots))
end end
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N function _make_hist(
vs::NTuple{N,AbstractVector},
binning;
normed = false,
weights = nothing,
) where {N}
localvs = _filternans(vs) localvs = _filternans(vs)
edges = _hist_edges(localvs, binning) edges = _hist_edges(localvs, binning)
h = float( weights === nothing ? h = float(
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) : weights === nothing ?
StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left) StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
StatsBase.fit(
StatsBase.Histogram,
localvs,
StatsBase.Weights(weights),
edges,
closed = :left,
),
) )
normalize!(h, mode = _hist_norm_mode(normed)) normalize!(h, mode = _hist_norm_mode(normed))
end end
@ -682,7 +756,12 @@ end
@deps histogram barhist @deps histogram barhist
@recipe function f(::Type{Val{:barhist}}, x, y, z) @recipe function f(::Type{Val{:barhist}}, x, y, z)
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights]) h = _make_hist(
(y,),
plotattributes[:bins],
normed = plotattributes[:normalize],
weights = plotattributes[:weights],
)
x := h.edges[1] x := h.edges[1]
y := h.weights y := h.weights
seriestype := :barbins seriestype := :barbins
@ -691,7 +770,12 @@ end
@deps barhist barbins @deps barhist barbins
@recipe function f(::Type{Val{:stephist}}, x, y, z) @recipe function f(::Type{Val{:stephist}}, x, y, z)
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights]) h = _make_hist(
(y,),
plotattributes[:bins],
normed = plotattributes[:normalize],
weights = plotattributes[:weights],
)
x := h.edges[1] x := h.edges[1]
y := h.weights y := h.weights
seriestype := :stepbins seriestype := :stepbins
@ -700,7 +784,12 @@ end
@deps stephist stepbins @deps stephist stepbins
@recipe function f(::Type{Val{:scatterhist}}, x, y, z) @recipe function f(::Type{Val{:scatterhist}}, x, y, z)
h = _make_hist((y,), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights]) h = _make_hist(
(y,),
plotattributes[:bins],
normed = plotattributes[:normalize],
weights = plotattributes[:weights],
)
x := h.edges[1] x := h.edges[1]
y := h.weights y := h.weights
seriestype := :scatterbins seriestype := :scatterbins
@ -709,19 +798,23 @@ end
@deps scatterhist scatterbins @deps scatterhist scatterbins
@recipe function f(h::StatsBase.Histogram{T, 1, E}) where {T, E} @recipe function f(h::StatsBase.Histogram{T,1,E}) where {T,E}
seriestype --> :barbins seriestype --> :barbins
st_map = Dict( st_map = Dict(
:bar => :barbins, :scatter => :scatterbins, :step => :stepbins, :bar => :barbins,
:steppost => :stepbins # :step can be mapped to :steppost in pre-processing :scatter => :scatterbins,
:step => :stepbins,
:steppost => :stepbins, # :step can be mapped to :steppost in pre-processing
) )
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype]) seriestype :=
get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
if plotattributes[:seriestype] == :scatterbins if plotattributes[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins # Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, h.edges[1], h.weights) edge, weights, xscale, yscale, baseline =
xerror --> diff(h.edges[1])/2 _preprocess_binlike(plotattributes, h.edges[1], h.weights)
xerror --> diff(h.edges[1]) / 2
seriestype := :scatter seriestype := :scatter
(Plots._bin_centers(edge), weights) (Plots._bin_centers(edge), weights)
else else
@ -730,7 +823,7 @@ end
end end
@recipe function f(hv::AbstractVector{H}) where H <: StatsBase.Histogram @recipe function f(hv::AbstractVector{H}) where {H<:StatsBase.Histogram}
for h in hv for h in hv
@series begin @series begin
h h
@ -769,7 +862,12 @@ Plots.@deps bins2d heatmap
@recipe function f(::Type{Val{:histogram2d}}, x, y, z) @recipe function f(::Type{Val{:histogram2d}}, x, y, z)
h = _make_hist((x, y), plotattributes[:bins], normed = plotattributes[:normalize], weights = plotattributes[:weights]) h = _make_hist(
(x, y),
plotattributes[:bins],
normed = plotattributes[:normalize],
weights = plotattributes[:weights],
)
x := h.edges[1] x := h.edges[1]
y := h.edges[2] y := h.edges[2]
z := Surface(h.weights) z := Surface(h.weights)
@ -779,7 +877,7 @@ end
@deps histogram2d bins2d @deps histogram2d bins2d
@recipe function f(h::StatsBase.Histogram{T, 2, E}) where {T, E} @recipe function f(h::StatsBase.Histogram{T,2,E}) where {T,E}
seriestype --> :bins2d seriestype --> :bins2d
(h.edges[1], h.edges[2], Surface(h.weights)) (h.edges[1], h.edges[2], Surface(h.weights))
end end
@ -855,7 +953,11 @@ end
@recipe function f(::Type{Val{:yerror}}, x, y, z) @recipe function f(::Type{Val{:yerror}}, x, y, z)
error_style!(plotattributes) error_style!(plotattributes)
markershape := :hline markershape := :hline
plotattributes[:x], plotattributes[:y] = error_coords(plotattributes[:x], plotattributes[:y], error_zipit(plotattributes[:yerror])) plotattributes[:x], plotattributes[:y] = error_coords(
plotattributes[:x],
plotattributes[:y],
error_zipit(plotattributes[:yerror]),
)
() ()
end end
@deps yerror path @deps yerror path
@ -863,7 +965,11 @@ end
@recipe function f(::Type{Val{:xerror}}, x, y, z) @recipe function f(::Type{Val{:xerror}}, x, y, z)
error_style!(plotattributes) error_style!(plotattributes)
markershape := :vline markershape := :vline
plotattributes[:y], plotattributes[:x] = error_coords(plotattributes[:y], plotattributes[:x], error_zipit(plotattributes[:xerror])) plotattributes[:y], plotattributes[:x] = error_coords(
plotattributes[:y],
plotattributes[:x],
error_zipit(plotattributes[:xerror]),
)
() ()
end end
@deps xerror path @deps xerror path
@ -898,15 +1004,15 @@ function quiver_using_arrows(plotattributes::AKW)
first(vi), last(vi) first(vi), last(vi)
elseif isscalar(vi) elseif isscalar(vi)
vi, vi vi, vi
elseif isa(vi,Function) elseif isa(vi, Function)
vi(xi, yi) vi(xi, yi)
else else
error("unexpected vi type $(typeof(vi)) for quiver: $vi") error("unexpected vi type $(typeof(vi)) for quiver: $vi")
end end
# add the points # add the points
nanappend!(x, [xi, xi+vx, NaN]) nanappend!(x, [xi, xi + vx, NaN])
nanappend!(y, [yi, yi+vy, NaN]) nanappend!(y, [yi, yi + vy, NaN])
end end
plotattributes[:x], plotattributes[:y] = x, y plotattributes[:x], plotattributes[:y] = x, y
@ -936,7 +1042,7 @@ function quiver_using_hack(plotattributes::AKW)
first(vi), last(vi) first(vi), last(vi)
elseif isscalar(vi) elseif isscalar(vi)
vi, vi vi, vi
elseif isa(vi,Function) elseif isa(vi, Function)
vi(xi, yi) vi(xi, yi)
else else
error("unexpected vi type $(typeof(vi)) for quiver: $vi") error("unexpected vi type $(typeof(vi)) for quiver: $vi")
@ -951,8 +1057,11 @@ function quiver_using_hack(plotattributes::AKW)
U1 *= arrow_h U1 *= arrow_h
U2 *= arrow_w U2 *= arrow_w
ppv = p+v ppv = p + v
nanappend!(pts, P2[p, ppv-U1, ppv-U1+U2, ppv, ppv-U1-U2, ppv-U1]) nanappend!(
pts,
P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1],
)
end end
plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end]) plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end])
@ -977,32 +1086,28 @@ end
"Represent Open High Low Close data (used in finance)" "Represent Open High Low Close data (used in finance)"
mutable struct OHLC{T<:Real} mutable struct OHLC{T<:Real}
open::T open::T
high::T high::T
low::T low::T
close::T close::T
end end
Base.convert(::Type{OHLC}, tup::Tuple) = OHLC(tup...) Base.convert(::Type{OHLC}, tup::Tuple) = OHLC(tup...)
# Base.tuple(ohlc::OHLC) = (ohlc.open, ohlc.high, ohlc.low, ohlc.close) # Base.tuple(ohlc::OHLC) = (ohlc.open, ohlc.high, ohlc.low, ohlc.close)
# get one OHLC path # get one OHLC path
function get_xy(o::OHLC, x, xdiff) function get_xy(o::OHLC, x, xdiff)
xl, xm, xr = x-xdiff, x, x+xdiff xl, xm, xr = x - xdiff, x, x + xdiff
ox = [xl, xm, NaN, ox = [xl, xm, NaN, xm, xm, NaN, xm, xr]
xm, xm, NaN, oy = [o.open, o.open, NaN, o.low, o.high, NaN, o.close, o.close]
xm, xr]
oy = [o.open, o.open, NaN,
o.low, o.high, NaN,
o.close, o.close]
ox, oy ox, oy
end end
# get the joined vector # get the joined vector
function get_xy(v::AVec{OHLC}, x = eachindex(v)) function get_xy(v::AVec{OHLC}, x = eachindex(v))
xdiff = 0.3ignorenan_mean(abs.(diff(x))) xdiff = 0.3 * ignorenan_mean(abs.(diff(x)))
x_out, y_out = zeros(0), zeros(0) x_out, y_out = zeros(0), zeros(0)
for (i,ohlc) in enumerate(v) for (i, ohlc) in enumerate(v)
ox,oy = get_xy(ohlc, x[i], xdiff) ox, oy = get_xy(ohlc, x[i], xdiff)
nanappend!(x_out, ox) nanappend!(x_out, ox)
nanappend!(y_out, oy) nanappend!(y_out, oy)
end end
@ -1015,10 +1120,17 @@ end
# to squash ambiguity warnings... # to squash ambiguity warnings...
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error() @recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
@recipe f(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error() @recipe f(
x::AVec{Function},
v::AVec{Tuple{R1,R2,R3,R4}},
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
# this must be OHLC? # this must be OHLC?
@recipe f(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc] @recipe f(
x::AVec,
ohlc::AVec{Tuple{R1,R2,R3,R4}},
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} =
x, OHLC[OHLC(t...) for t in ohlc]
@recipe function f(x::AVec, v::AVec{OHLC}) @recipe function f(x::AVec, v::AVec{OHLC})
seriestype := :path seriestype := :path
@ -1056,11 +1168,11 @@ end
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix @assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
seriestype := :spy seriestype := :spy
mat = g.args[1] mat = g.args[1]
n,m = axes(mat) n, m = axes(mat)
Plots.SliceIt, m, n, Surface(mat) Plots.SliceIt, m, n, Surface(mat)
end end
@recipe function f(::Type{Val{:spy}}, x,y,z) @recipe function f(::Type{Val{:spy}}, x, y, z)
yflip := true yflip := true
aspect_ratio := 1 aspect_ratio := 1
rs, cs, zs = findnz(z.surf) rs, cs, zs = findnz(z.surf)
@ -1086,7 +1198,8 @@ end
# ------------------------------------------------- # -------------------------------------------------
"Adds ax+b... straight line over the current plot, without changing the axis limits" "Adds ax+b... straight line over the current plot, without changing the axis limits"
abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...) abline!(plt::Plot, a, b; kw...) =
plot!(plt, [0, 1], [b, b + a]; seriestype = :straightline, kw...)
abline!(args...; kw...) = abline!(current(), args...; kw...) abline!(args...; kw...) = abline!(current(), args...; kw...)
@ -1099,9 +1212,11 @@ datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t))) timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
@recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter) @recipe f(::Type{Date}, dt::Date) = (dt -> Dates.value(dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> Dates.value(dt), datetimeformatter) @recipe f(::Type{DateTime}, dt::DateTime) =
(dt -> Dates.value(dt), datetimeformatter)
@recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter) @recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter)
@recipe f(::Type{P}, t::P) where P <: Dates.Period = (t -> Dates.value(t), t -> string(P(t))) @recipe f(::Type{P}, t::P) where {P<:Dates.Period} =
(t -> Dates.value(t), t -> string(P(t)))
# ------------------------------------------------- # -------------------------------------------------
# Characters # Characters
@ -1111,7 +1226,7 @@ timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t)))
# ------------------------------------------------- # -------------------------------------------------
# Complex Numbers # Complex Numbers
@recipe function f(A::Array{Complex{T}}) where T<:Number @recipe function f(A::Array{Complex{T}}) where {T<:Number}
xguide --> "Re(x)" xguide --> "Re(x)"
yguide --> "Im(x)" yguide --> "Im(x)"
real.(A), imag.(A) real.(A), imag.(A)
@ -1120,10 +1235,10 @@ end
# Splits a complex matrix to its real and complex parts # Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed # Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing # Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f(x::AbstractArray{T},y::Array{Complex{T2}}) where {T<:Real,T2} @recipe function f(x::AbstractArray{T}, y::Array{Complex{T2}}) where {T<:Real,T2}
ylabel --> "Re(y)" ylabel --> "Re(y)"
zlabel --> "Im(y)" zlabel --> "Im(y)"
x,real.(y),imag.(y) x, real.(y), imag.(y)
end end
@ -1137,7 +1252,7 @@ end
end end
library = PlotUtils.color_libraries[cl.args[1]] library = PlotUtils.color_libraries[cl.args[1]]
z = sqrt.((1:15)*reshape(1:20,1,:)) z = sqrt.((1:15) * reshape(1:20, 1, :))
seriestype := :heatmap seriestype := :heatmap
ticks := nothing ticks := nothing
@ -1161,7 +1276,7 @@ end
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol)) if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
error("showgradient takes the name of a color gradient as a Symbol") error("showgradient takes the name of a color gradient as a Symbol")
end end
z = sqrt.((1:15)*reshape(1:20,1,:)) z = sqrt.((1:15) * reshape(1:20, 1, :))
seriestype := :heatmap seriestype := :heatmap
ticks := nothing ticks := nothing
legend := false legend := false
@ -1184,9 +1299,9 @@ end
weights = cumsum(weights, dims = 2) weights = cumsum(weights, dims = 2)
seriestype := :shape seriestype := :shape
# create a filled polygon for each item # create a filled polygon for each item
for c=axes(weights,2) for c in axes(weights, 2)
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1])) sx = vcat(weights[:, c], c == 1 ? zeros(n) : reverse(weights[:, c - 1]))
sy = vcat(returns, reverse(returns)) sy = vcat(returns, reverse(returns))
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx) @series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
end end
@ -1205,13 +1320,13 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
@userplot AreaPlot @userplot AreaPlot
@recipe function f(a::AreaPlot) @recipe function f(a::AreaPlot)
data = cumsum(a.args[end], dims=2) data = cumsum(a.args[end], dims = 2)
x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1] x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1]
seriestype := :line seriestype := :line
for i in axes(data, 2) for i in axes(data, 2)
@series begin @series begin
fillrange := i > 1 ? data[:,i-1] : 0 fillrange := i > 1 ? data[:, i - 1] : 0
x, data[:,i] x, data[:, i]
end end
end end
end end