Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvements to heatmap path #4549

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/args.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const _allTypes = vcat(
_3dTypes,
)

const _z_colored_series = [:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin]
const _z_colored_series = Dict([:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin] .=> true)

const _typeAliases = Dict{Symbol,Symbol}(
:n => :none,
Expand Down Expand Up @@ -2027,11 +2027,13 @@ has_black_border_for_default(st::Function) =
has_black_border_for_default(st::Symbol) =
like_histogram(st) || st in (:hexbin, :bar, :shape)

default_cgrad() = PlotUtils.DEFAULT_COLOR_GRADIENT[] # MOVE TO PLOTUTILS

# converts a symbol or string into a Colorant or ColorGradient
# and assigns a color automatically
get_series_color(c, sp::Subplot, n::Int, seriestype) =
if c === :auto
like_surface(seriestype) ? cgrad() : _cycle(sp[:color_palette], n)
like_surface(seriestype) ? default_cgrad() : _cycle(sp[:color_palette], n)
elseif isa(c, Int)
_cycle(sp[:color_palette], c)
else
Expand Down
102 changes: 70 additions & 32 deletions src/axes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,39 @@ function reset_extrema!(sp::Subplot)
end
end

finitemin(x::Real, y::Real) = min(promote(x, y)...)
finitemax(x::Real, y::Real) = max(promote(x, y)...)

finitemin(x::T, y::T) where {T<:AbstractFloat} = ifelse((y < x) | (signbit(y) > signbit(x)),
ifelse(isfinite(y), y, x),
ifelse(isfinite(x), x, y))
finitemax(x::T, y::T) where {T<:AbstractFloat} = ifelse((y > x) | (signbit(y) < signbit(x)),
ifelse(isfinite(y), y, x),
ifelse(isfinite(x), x, y))

function finite_extrema(v::AbstractArray)
emin, emax = Inf, -Inf
for x in v
emin = finitemin(emin, x)
emax = finitemax(emax, x)
end
emin, emax
end

finite_extrema(v) = extrema(v)

finite_minimum(v::AbstractArray) = reduce(finitemin, v)
finite_maximum(v::AbstractArray) = reduce(finitemax, v)

function expand_extrema!(ex::Extrema, v::Number)
ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin
ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax
ex.emin = finitemin(v, ex.emin)
ex.emax = finitemax(v, ex.emax)
ex
end

function expand_extrema!(ex::Extrema, v::Extrema)
ex.emin = finitemin(v.emin, ex.emin)
ex.emax = finitemax(v.emax, ex.emax)
ex
end

Expand All @@ -415,16 +445,22 @@ expand_extrema!(axis::Axis, v::Number) = expand_extrema!(axis[:extrema], v)
expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]

function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
function expand_extrema!(axis::Axis, v::Tuple{<:Number, <:Number})
ex = axis[:extrema]::Extrema
ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin
ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax
ex.emin = finitemin(v[1], ex.emin)
ex.emax = finitemax(v[2], ex.emax)
ex
end
function expand_extrema!(axis::Axis, v::AVec{N}) where {N<:Number}
ex = axis[:extrema]::Extrema
foreach(vi -> expand_extrema!(ex, vi), v)
ex
function expand_extrema!(axis::Axis, v::AbstractArray{<:Number})
vex = if length(v) > 1024
vex = finite_extrema(@view v[1:1000])
stride = length(v) ÷ 1024 + 1
vex2 = finite_extrema(@view v[1001:stride:end])
finitemin(vex[1], vex2[1]), finitemax(vex[2], vex2[2])
else
finite_extrema(v)
end
expand_extrema!(axis, vex)
end

function expand_extrema!(sp::Subplot, plotattributes::AKW)
Expand Down Expand Up @@ -468,6 +504,31 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
expand_extrema!(axis, plotattributes[letter])
end
end

# expand for bar_width
if plotattributes[:seriestype] === :bar
dsym = vert ? :x : :y
data = plotattributes[dsym]

if (bw = plotattributes[:bar_width]) === nothing
pos = filter(>(0), diff(sort(data)))
plotattributes[:bar_width] = bw = _bar_width * finite_minimum(pos)
end
axis = sp.attr[get_attr_symbol(dsym, :axis)]
ex = finite_extrema(data)
expand_extrema!(axis, ex[1] + 0.5maximum(bw))
expand_extrema!(axis, ex[2] - 0.5minimum(bw))
elseif plotattributes[:seriestype] === :heatmap
for letter in (:x, :y)
data = plotattributes[letter]
axis = sp[get_attr_symbol(letter, :axis)]
scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity)
ex = scale === :identity ?
heatmap_extrema(data) :
heatmap_extrema(data, scale)
expand_extrema!(axis, ex)
end
end

# # expand for fillrange/bar_width
# fillaxis, baraxis = sp.attr[:yaxis], sp.attr[:xaxis]
Expand All @@ -489,29 +550,6 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
end
end

# expand for bar_width
if plotattributes[:seriestype] === :bar
dsym = vert ? :x : :y
data = plotattributes[dsym]

if (bw = plotattributes[:bar_width]) === nothing
pos = filter(>(0), diff(sort(data)))
plotattributes[:bar_width] = bw = _bar_width * ignorenan_minimum(pos)
end
axis = sp.attr[get_attr_symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end

# expand for heatmaps
if plotattributes[:seriestype] === :heatmap
for letter in (:x, :y)
data = plotattributes[letter]
axis = sp[get_attr_symbol(letter, :axis)]
scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
end

function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
Expand Down
1 change: 1 addition & 0 deletions src/backends/gaston.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ function gaston_seriesconf!(
extra_curves = String[]

clims = get_clims(sp, series)
clims = clims.emin, clims.emax
if st ∈ (:scatter, :scatter3d)
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
pt, ps, mc = gaston_mk_ms_mc(series, clims, i)
Expand Down
8 changes: 6 additions & 2 deletions src/backends/gr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,12 @@ remap(x, lo, hi) = (x - lo) / (hi - lo)
get_z_normalized(z, clims...) = isnan(z) ? 256 / 255 : remap(clamp(z, clims...), clims...)

function gr_clims(sp, args...)
sp[:clims] === :auto || return get_clims(sp)
lo, hi = get_clims(sp, args...)
if sp[:clims] !== :auto
lims = get_clims(sp)
return lims.emin, lims.emax
end
lims = get_clims(sp, args...)
lo, hi = lims.emin, lims.emax
if lo == hi
if lo == 0
hi = one(hi)
Expand Down
1 change: 1 addition & 0 deletions src/backends/inspectdr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
(plot = sp.o) === nothing && return

clims = get_clims(sp, series)
clims = clims.emin, clims.emax

_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x, y = if st === :straightline
Expand Down
4 changes: 2 additions & 2 deletions src/backends/pgfplotsx.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
bgc_inside = plot_color(sp[:background_color_inside])
update_clims(sp)
axis_opt = Options(
"point meta max" => get_clims(sp)[2],
"point meta min" => get_clims(sp)[1],
"point meta max" => get_clims(sp).emax,
"point meta min" => get_clims(sp).emin,
"legend cell align" => "left",
"legend columns" => pgfx_legend_col(sp[:legend_column]),
"title" => sp[:title],
Expand Down
4 changes: 3 additions & 1 deletion src/backends/plotly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ as_gradient(grad, α) = cgrad(alpha = α)
function plotly_series(plt::Plot, series::Series)
sp = series[:subplot]
clims = get_clims(sp, series)
clims = clims.emin, clims.emax

(st = series[:seriestype]) === :shape && return plotly_series_shapes(plt, series, clims)

Expand Down Expand Up @@ -953,7 +954,8 @@ end

function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symbol)
plotattributes_out = deepcopy(plotattributes_base)
cmin, cmax = get_clims(series[:subplot])
clims = get_clims(series[:subplot])
cmin, cmax = clims.emin, clims.emax
plotattributes_out[:showlegend] = false
plotattributes_out[:type] = RecipesPipeline.is3d(series) ? :scatter3d : :scatter
plotattributes_out[:hoverinfo] = :none
Expand Down
7 changes: 5 additions & 2 deletions src/backends/pyplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)

# handle zcolor and get c/cmap
needs_colorbar = hascolorbar(sp)
vmin, vmax = clims = get_clims(sp, series)
clims = get_clims(sp, series)
vmin, vmax = clims = clims.emin, clims.emax

# Dict to store extra kwargs
extrakw = if st === :wireframe || st === :hexbin
Expand Down Expand Up @@ -1011,7 +1012,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
elseif any(
colorbar_series[attr] !== nothing for attr in (:line_z, :fill_z, :marker_z)
)
cmin, cmax = get_clims(sp)
clims = get_clims(sp)
cmin, cmax = clims.emin, clims.emax
norm = pycolors."Normalize"(vmin = cmin, vmax = cmax)
f = if colorbar_series[:line_z] !== nothing
py_linecolormap
Expand Down Expand Up @@ -1467,6 +1469,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
should_add_to_legend(series) || continue
nseries += 1
clims = get_clims(sp, series)
clims = clims.emin, clims.emax
# add a line/marker and a label
if series[:seriestype] === :shape || series[:fillrange] !== nothing
lc = get_linecolor(series, clims)
Expand Down
Loading