Improve data preprocessing for bar and histogram plots

Fixes broken bar-plots with non-numeric a-axes
This commit is contained in:
Oliver Schulz 2017-05-06 15:00:31 +02:00
parent a523903c15
commit 67b4157e25

View File

@ -323,7 +323,7 @@ end
# create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
procx, procy, xscale, yscale, baseline, wautolims = _preprocess_barlike(d, x, y)
nx, ny = length(procx), length(procy)
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=procx]
@ -380,6 +380,7 @@ end
x := xseg.pts
y := yseg.pts
seriestype := :shape
ylims --> wautolims
()
end
@deps bar shape
@ -402,39 +403,64 @@ function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector,
end
end
function _hist_ylim_lo{T<:Real}(ymin::T, yscale::Symbol)
if (yscale in _logScales)
ymin / T(_logScaleBases[yscale]^log10(2))
function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else
zero(T)
end
end
function _hist_ylim_hi{T<:Real}(ymax::T, yscale::Symbol)
if (yscale in _logScales)
ymax * T(_logScaleBases[yscale]^log10(2))
function _binbarlike_autolims{T<:Real}(min_value::T, max_value::T, scale::Symbol)
lo = if (scale in _logScales)
_binbarlike_baseline(min_value, scale)
else
ymax * T(1.1)
end
min(min_value * T(1.1), zero(T))
end::T
hi = if !isnan(max_value)
if (scale in _logScales)
max_value * T(_logScaleBases[scale]^log10(2))
else
max(max_value * T(1.1), zero(T))
end
else
one(T)
end::T
(lo, hi)
end
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol)
w_adj = _scale_adjusted_values(T, w, wscale)
w_min = minimum(w_adj)
w_max = maximum(w_adj)
baseline = _binbarlike_baseline(w_min, wscale)
autolims = _binbarlike_autolims(w_min, w_max,wscale)
w_adj, baseline, autolims
end
function _preprocess_barlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
weights, baseline, wautolims = _preprocess_binbarlike_weights(float(eltype(y)), y, yscale)
x, weights, xscale, yscale, baseline, wautolims
end
function _preprocess_binlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
T = float(promote_type(eltype(x), eltype(y)))
edge = map(T, x)
weights = _scale_adjusted_values(T, y, yscale)
w_min = minimum(weights)
baseline = _hist_ylim_lo(isnan(w_min) ? one(T) : w_min, yscale)
edge, weights, xscale, yscale, baseline
edge = T.(x)
weights, baseline, wautolims = _preprocess_binbarlike_weights(T, y, yscale)
edge, weights, xscale, yscale, baseline, wautolims
end
@recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline, wautolims = _preprocess_binlike(d, x, y)
if (d[:bar_width] == nothing)
bar_width := diff(edge)
end
@ -447,7 +473,7 @@ end
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline, wautolims = _preprocess_binlike(d, x, y)
xerror := diff(edge)/2
x := _bin_centers(edge)
y := weights
@ -512,7 +538,7 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights, xscale, yscale, baseline, wautolims = _preprocess_binlike(d, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(d)
@ -539,7 +565,7 @@ end
y := ypts
seriestype := :path
ylims --> [baseline, _hist_ylim_hi(maximum(weights), yscale)]
ylims --> wautolims
()
end
Plots.@deps stepbins path
@ -639,7 +665,7 @@ end
if d[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
edge, weights, xscale, yscale, baseline, wautolims = _preprocess_binlike(d, h.edges[1], h.weights)
xerror --> diff(h.edges[1])/2
seriestype := :scatter
(Plots._bin_centers(edge), weights)