diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 83a5bcc3..227a122f 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -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 diff --git a/src/examples.jl b/src/examples.jl index 498f367f..b81f5789 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -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 diff --git a/src/utils.jl b/src/utils.jl index 7cfc7b3a..fc85923a 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -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