Merge pull request #3299 from fhagemann/master

Implement non-uniform polar heatmaps with the GR backend
This commit is contained in:
Daniel Schwabeneder 2021-02-16 21:54:58 +01:00 committed by GitHub
commit e06a51b420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 45 deletions

View File

@ -1578,10 +1578,8 @@ function gr_add_series(sp, series)
GR.gr3.clear()
dmin, dmax = GR.gr3.volume(y.v, 0)
elseif st === :heatmap
if !ispolar(series)
# `z` is already transposed, so we need to reverse before passing its size.
x, y = heatmap_edges(x, xscale, y, yscale, reverse(size(z)))
end
# `z` is already transposed, so we need to reverse before passing its size.
x, y = heatmap_edges(x, xscale, y, yscale, reverse(size(z)), ispolar(series))
gr_draw_heatmap(series, x, y, z, clims)
elseif st === :image
gr_draw_image(series, x, y, z, clims)
@ -1751,42 +1749,33 @@ end
function gr_draw_heatmap(series, x, y, z, clims)
fillgrad = _as_gradient(series[:fillcolor])
if !ispolar(series)
GR.setspace(clims..., 0, 90)
w, h = length(x) - 1, length(y) - 1
if is_uniformly_spaced(x) && is_uniformly_spaced(y)
# For uniformly spaced data use GR.drawimage, which can be
# much faster than GR.nonuniformcellarray, especially for
# pdf output, and also supports alpha values.
# Note that drawimage draws uniformly spaced data correctly
# even on log scales, where it is visually non-uniform.
colors = plot_color.(get(fillgrad, z, clims), series[:fillalpha])
rgba = gr_color.(colors)
GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba)
else
if something(series[:fillalpha], 1) < 1
@warn "GR: transparency not supported in non-uniform heatmaps. Alpha values ignored."
end
z_normalized = get_z_normalized.(z, clims...)
rgba = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized]
GR.nonuniformcellarray(x, y, w, h, rgba)
end
GR.setspace(clims..., 0, 90)
w, h = length(x) - 1, length(y) - 1
if !ispolar(series) && is_uniformly_spaced(x) && is_uniformly_spaced(y)
# For uniformly spaced data use GR.drawimage, which can be
# much faster than GR.nonuniformcellarray, especially for
# pdf output, and also supports alpha values.
# Note that drawimage draws uniformly spaced data correctly
# even on log scales, where it is visually non-uniform.
colors = plot_color.(get(fillgrad, z, clims), series[:fillalpha])
rgba = gr_color.(colors)
GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba)
else
phimin, phimax = 0.0, 360.0 # nonuniform polar array is not yet supported in GR.jl
nx, ny = length(series[:x]), length(series[:y])
xmin, xmax, ymin, ymax = gr_xy_axislims(series[:subplot])
GR.setwindow(-ymax, ymax, -ymax, ymax)
if ymin > 0
@warn "'ymin[1] > 0' (rmin) is not yet supported."
end
if series[:y][end] != ny
@warn "Right now only the maximum value of y (r) is taken into account."
if something(series[:fillalpha], 1) < 1
@warn "GR: transparency not supported in non-uniform heatmaps. Alpha values ignored."
end
z_normalized = get_z_normalized.(z, clims...)
rgba = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized]
GR.polarcellarray(0, 0, phimin, phimax, 0, ymax, nx, ny, rgba)
# Right now only the maximum value of y (r) is taken into account.
# This is certainly not perfect but nonuniform polar array is not yet supported in GR.jl
if !ispolar(series)
GR.nonuniformcellarray(x, y, w, h, rgba)
else
if y[1] < 0
@warn "'y[1] < 0' (rmin) is not yet supported."
end
xmin, xmax, ymin, ymax = gr_xy_axislims(series[:subplot])
GR.setwindow(-ymax, ymax, -ymax, ymax)
GR.nonuniformpolarcellarray(rad2deg.(x), y, w, h, rgba)
end
end
end

View File

@ -1044,8 +1044,10 @@ const _examples = PlotExample[
"Polar heatmaps",
"",
[quote
z = (1:4) .+ (1:8)'
heatmap(z, projection = :polar)
x = range(0, 2π, length=9)
y = 0:4
z = (1:4) .+ (1:8)'
heatmap(x, y, z, projection = :polar)
end]
),
PlotExample( # 50

View File

@ -212,24 +212,24 @@ createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end]
sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes)))
function _heatmap_edges(v::AVec, isedges::Bool = false)
length(v) == 1 && return v[1] .+ [-0.5, 0.5]
function _heatmap_edges(v::AVec, isedges::Bool = false, ispolar::Bool = false)
length(v) == 1 && return v[1] .+ [ispolar ? max(-v[1], -0.5) : -0.5, 0.5]
if isedges return v end
# `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 = (v[2] - v[1]) / 2
extra_min = ispolar ? min(v[1], (v[2] - v[1]) / 2) : (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
end
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false)
function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false, ispolar::Bool = false)
f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale)
map(invf, _heatmap_edges(map(f,v), isedges))
map(invf, _heatmap_edges(map(f,v), isedges, ispolar))
end
function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int})
function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int}, ispolar::Bool = false)
nx, ny = length(x), length(y)
# ismidpoints = z_size == (ny, nx) # This fails some tests, but would actually be
# the correct check, since (4, 3) != (3, 4) and a missleading plot is produced.
@ -241,7 +241,7 @@ function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size:
or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""")
end
x, y = heatmap_edges(x, xscale, isedges),
heatmap_edges(y, yscale, isedges)
heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots
return x, y
end