Skip to content

Commit

Permalink
more bypass
Browse files Browse the repository at this point in the history
  • Loading branch information
t-bltg committed Nov 22, 2022
1 parent 91ed03d commit c68bddf
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 90 deletions.
29 changes: 16 additions & 13 deletions src/axes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
amin, amax = alims

# scale the limits
sf = RecipesPipeline.scale_func(scale)
sf, invsf, noop = scale_inverse_scale_func(scale)

# If the axis input was a Date or DateTime use a special logic to find
# "round" Date(Time)s as ticks
Expand All @@ -135,7 +135,8 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
# or DateTime) is chosen based on the time span between amin and amax
# rather than on the input format
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
if ticks === nothing && scale === :identity

if ticks === nothing && noop
if formatter == RecipesPipeline.dateformatter
# optimize_datetime_ticks returns ticks and labels(!) based on
# integers/floats corresponding to the DateTime type. Thus, the axes
Expand All @@ -159,7 +160,7 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
sf(amax);
k_min = scale _logScales ? 2 : 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
scale = scale,
scale,
) |> first
elseif typeof(ticks) <: Int
optimize_ticks(
Expand All @@ -171,12 +172,12 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
scale = scale,
scale,
) |> first
else
map(sf, filter(t -> amin t amax, ticks))
end
unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks)
unscaled_ticks = noop ? scaled_ticks : map(invsf, scaled_ticks)

labels::Vector{String} = if any(isfinite, unscaled_ticks)
if formatter in (:auto, :plain, :scientific, :engineering)
Expand Down Expand Up @@ -520,9 +521,14 @@ function scale_lims(from, to, factor)
mid .+ (-span, span) .* factor
end

function scale_lims(from, to, factor, scale)
f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale)
_scale_lims(::Val{true}, ::Function, ::Function, from, to, factor) =
scale_lims(from, to, factor)
_scale_lims(::Val{false}, f::Function, invf::Function, from, to, factor) =
invf.(scale_lims(f(from), f(to), factor))

function scale_lims(from, to, factor, scale)
f, invf, noop = scale_inverse_scale_func(scale)
_scale_lims(Val(noop), f, invf, from, to, factor)
end

"""
Expand All @@ -534,9 +540,8 @@ If `letter` is omitted, all axes are affected.
"""
function scale_lims!(sp::Subplot, letter, factor)
axis = Plots.get_axis(sp, letter)
scale = axis[:scale]
from, to = Plots.get_sp_lims(sp, letter)
axis[:lims] = scale_lims(from, to, factor, scale)
axis[:lims] = scale_lims(from, to, factor, axis[:scale])
end
function scale_lims!(plt::Plot, letter, factor)
foreach(sp -> scale_lims!(sp, letter, factor), plt.subplots)
Expand Down Expand Up @@ -770,8 +775,7 @@ function add_major_or_minor_segments_2d(
)
ticks === nothing && return
if cond
f = RecipesPipeline.scale_func(oax[:scale])
invf = RecipesPipeline.inverse_scale_func(oax[:scale])
f, invf = scale_inverse_scale_func(oax[:scale])
tick_start, tick_stop = if sp[:framestyle] === :origin
oamin, oamax = oamM
t = invf(f(0) + factor * (f(oamax) - f(oamin)))
Expand Down Expand Up @@ -904,8 +908,7 @@ function add_major_or_minor_segments_3d(
)
ticks === nothing && return
if cond
f = RecipesPipeline.scale_func(nax[:scale])
invf = RecipesPipeline.inverse_scale_func(nax[:scale])
f, invf = scale_inverse_scale_func(nax[:scale])
tick_start, tick_stop = if sp[:framestyle] === :origin
namin, namax = namM
t = invf(f(0) + factor * (f(namax) - f(namin)))
Expand Down
161 changes: 84 additions & 77 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,29 @@ replaceAlias!(plotattributes::AKW, k::Symbol, aliases::Dict{Symbol,Symbol}) =
replaceAliases!(plotattributes::AKW, aliases::Dict{Symbol,Symbol}) =
foreach(k -> replaceAlias!(plotattributes, k, aliases), collect(keys(plotattributes)))

function _heatmap_edges(v::AVec, isedges::Bool, ispolar::Bool)
length(v) == 1 && return v[1] .+ [ispolar ? max(-v[1], -0.5) : -0.5, 0.5]
scale_inverse_scale_func(scale::Symbol) = (
RecipesPipeline.scale_func(scale),
RecipesPipeline.inverse_scale_func(scale),
scale === :identity,
)

function __heatmap_edges(v::AVec, isedges::Bool, ispolar::Bool)
(n = length(v)) == 1 && return v[1] .+ [ispolar ? max(-v[1], -0.5) : -0.5, 0.5]
isedges && return v
# `isedges = true` means that v is a vector which already describes edges
# and does not need to be extended.
vmin, vmax = ignorenan_extrema(v)
extra_min = ispolar ? min(v[1], 0.5(v[2] - v[1])) : 0.5(v[2] - v[1])
extra_max = 0.5(v[end] - v[end - 1])
vcat(vmin - extra_min, 0.5(v[1:(end - 1)] + v[2:end]), vmax + extra_max)
extra_max = 0.5(v[n] - v[n - 1])
vcat(vmin - extra_min, 0.5(v[1:(n - 1)] + v[2:n]), vmax + extra_max)
end

_heatmap_edges(::Val{true}, v::AVec, ::Symbol, isedges::Bool, ispolar::Bool) =
_heatmap_edges(v, isedges, ispolar)
__heatmap_edges(v, isedges, ispolar)

function _heatmap_edges(::Val{false}, v::AVec, scale::Symbol, isedges::Bool, ispolar::Bool)
f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale)
map(invf, _heatmap_edges(map(f, v), isedges, ispolar))
f, invf = scale_inverse_scale_func(scale)
invf.(__heatmap_edges(f.(v), isedges, ispolar))
end

"create an (n+1) list of the outsides of heatmap rectangles"
Expand Down Expand Up @@ -942,45 +948,7 @@ function convert_sci_unicode(label::AbstractString)
label
end

function straightline_data(series, expansion_factor = 1)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))

# handle axes scales
xscale = sp[:xaxis][:scale]
xf = RecipesPipeline.scale_func(xscale)
xinvf = RecipesPipeline.inverse_scale_func(xscale)
yscale = sp[:yaxis][:scale]
yf = RecipesPipeline.scale_func(yscale)
yinvf = RecipesPipeline.inverse_scale_func(yscale)

xl, yl = xf.(xl), yf.(yl)
x, y = xf.(series[:x]), yf.(series[:y])
n = length(x)

xdata, ydata = if n == 2
straightline_data(xl, yl, x, y, expansion_factor)
else
k, r = divrem(n, 3)
if r == 0
xdata, ydata = fill(NaN, n), fill(NaN, n)
for i in 1:k
inds = (3 * i - 2):(3 * i - 1)
xdata[inds], ydata[inds] =
straightline_data(xl, yl, x[inds], y[inds], expansion_factor)
end
xdata, ydata
else
error(
"Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n",
)
end
end

xinvf.(xdata), yinvf.(ydata)
end

function straightline_data(xl, yl, x, y, expansion_factor = 1)
function ___straightline_data(xl, yl, x, y, exp_fact)
x_vals, y_vals = if y[1] == y[2]
if x[1] == x[2]
error("Two identical points cannot be used to describe a straight line.")
Expand All @@ -1004,28 +972,85 @@ function straightline_data(xl, yl, x, y, expansion_factor = 1)
end
# expand the data outside the axis limits, by a certain factor too improve
# plotly(js) and interactive behaviour
x_vals = x_vals .+ (x_vals[2] - x_vals[1]) .* expansion_factor .* [-1, 1]
y_vals = y_vals .+ (y_vals[2] - y_vals[1]) .* expansion_factor .* [-1, 1]
x_vals, y_vals
(
x_vals .+ (x_vals[2] - x_vals[1]) .* exp_fact,
y_vals .+ (y_vals[2] - y_vals[1]) .* exp_fact,
)
end

function _shape_data!(::Val{false}, x, xl, xf::Function, xinvf::Function, expansion_factor)
__straightline_data(xl, yl, x, y, exp_fact) =
if (n = length(x)) == 2
___straightline_data(xl, yl, x, y, exp_fact)
else
k, r = divrem(n, 3)
@assert r == 0 "Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n"
xdata, ydata = fill(NaN, n), fill(NaN, n)
for i in 1:k
inds = (3i - 2):(3i - 1)
xdata[inds], ydata[inds] =
___straightline_data(xl, yl, x[inds], y[inds], exp_fact)
end
xdata, ydata
end

_straightline_data(::Val{true}, ::Function, ::Function, ::Function, ::Function, args...) =
__straightline_data(args...)

function _straightline_data(
::Val{false},
xf::Function,
xinvf::Function,
yf::Function,
yinvf::Function,
xl,
yl,
x,
y,
exp_fact,
)
xdata, ydata = __straightline_data(xf.(xl), yf.(yl), xf.(x), yf.(y), exp_fact)
xinvf.(xdata), yinvf.(ydata)
end

function straightline_data(series, expansion_factor = 1)
sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))

# handle axes scales
xf, xinvf, xnoop = scale_inverse_scale_func(sp[:xaxis][:scale])
yf, yinvf, ynoop = scale_inverse_scale_func(sp[:yaxis][:scale])

_straightline_data(
Val(xnoop && ynoop),
xf,
xinvf,
yf,
yinvf,
xl,
yl,
series[:x],
series[:y],
[-expansion_factor, +expansion_factor],
)
end

function _shape_data!(::Val{false}, xf::Function, xinvf::Function, x, xl, exp_fact)
@inbounds for i in eachindex(x)
if x[i] == -Inf
x[i] = xinvf(xf(xl[1]) - expansion_factor * (xf(xl[2]) - xf(xl[1])))
x[i] = xinvf(xf(xl[1]) - exp_fact * (xf(xl[2]) - xf(xl[1])))
elseif x[i] == +Inf
x[i] = xinvf(xf(xl[2]) + expansion_factor * (xf(xl[2]) - xf(xl[1])))
x[i] = xinvf(xf(xl[2]) + exp_fact * (xf(xl[2]) - xf(xl[1])))
end
end
x
end

function _shape_data!(::Val{true}, x, xl, ::Function, ::Function, expansion_factor)
function _shape_data!(::Val{true}, ::Function, ::Function, x, xl, exp_fact)
@inbounds for i in eachindex(x)
if x[i] == -Inf
x[i] = xl[1] - expansion_factor * (xl[2] - xl[1])
x[i] = xl[1] - exp_fact * (xl[2] - xl[1])
elseif x[i] == +Inf
x[i] = xl[2] + expansion_factor * (xl[2] - xl[1])
x[i] = xl[2] + exp_fact * (xl[2] - xl[1])
end
end
x
Expand All @@ -1036,30 +1061,12 @@ function shape_data(series, expansion_factor = 1)
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))

# handle axes scales
xscale = sp[:xaxis][:scale]
xf, xinvf =
RecipesPipeline.scale_func(xscale), RecipesPipeline.inverse_scale_func(xscale)
yscale = sp[:yaxis][:scale]
yf, yinvf =
RecipesPipeline.scale_func(yscale), RecipesPipeline.inverse_scale_func(yscale)
xf, xinvf, xnoop = scale_inverse_scale_func(sp[:xaxis][:scale])
yf, yinvf, ynoop = scale_inverse_scale_func(sp[:yaxis][:scale])

(
_shape_data!(
Val(xscale === :identity),
copy(series[:x]),
xl,
xf,
xinvf,
expansion_factor,
),
_shape_data!(
Val(yscale === :identity),
copy(series[:y]),
yl,
yf,
yinvf,
expansion_factor,
),
_shape_data!(Val(xnoop), xf, xinvf, copy(series[:x]), xl, expansion_factor),
_shape_data!(Val(ynoop), yf, yinvf, copy(series[:y]), yl, expansion_factor),
)
end

Expand Down

0 comments on commit c68bddf

Please sign in to comment.