Add polar legend position

This commit is contained in:
David Gustavsson 2021-02-25 15:08:33 +01:00
parent 6193519b1f
commit 2cee039dbc
2 changed files with 91 additions and 7 deletions

View File

@ -1262,6 +1262,8 @@ end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Nothing) = :none
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::Tuple{<:Real,Symbol}) = v
convertLegendValue(v::Real) = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# -----------------------------------------------------------------------------

View File

@ -911,7 +911,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_update_viewport_ratio!(viewport_plotarea, sp)
leg = gr_get_legend_geometry(viewport_plotarea, sp)
gr_update_viewport_legend!(viewport_plotarea, sp, leg)
# fill in the plot area background
gr_fill_plotarea(sp, viewport_plotarea)
@ -1047,7 +1047,24 @@ end
function gr_legend_pos(sp::Subplot, leg, viewport_plotarea)
s = sp[:legend]
typeof(s) <: Symbol || return gr_legend_pos(s, viewport_plotarea)
s isa Real && return gr_legend_pos(s, leg, viewport_plotarea)
if s isa Tuple{<:Real,Symbol}
if s[2] !== :outer
return gr_legend_pos(s[1], leg, viewport_plotarea)
end
xaxis, yaxis = sp[:xaxis], sp[:yaxis]
xmirror = xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
ymirror = yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true)
axisclearance = [
!ymirror*gr_axis_width(sp, sp[:yaxis]),
ymirror*gr_axis_width(sp,sp[:yaxis]),
!xmirror*gr_axis_height(sp,sp[:xaxis]),
xmirror*gr_axis_height(sp,sp[:xaxis]),
]
return gr_legend_pos(s[1], leg, viewport_plotarea; axisclearance)
end
s isa Symbol || return gr_legend_pos(s, viewport_plotarea)
str = string(s)
if str == "best"
str = "topright"
@ -1098,6 +1115,55 @@ function gr_legend_pos(v::Tuple{S,T}, viewport_plotarea) where {S<:Real, T<:Real
(xpos,ypos)
end
function gr_legend_pos(theta::Real, leg, viewport_plotarea; axisclearance=nothing)
xmean = +(viewport_plotarea[1:2]...)/2
ymean = +(viewport_plotarea[3:4]...)/2
(s,c) = sincosd(theta)
if isnothing(axisclearance)
# Inner
# rectangle relative to midpoint where the anchor can legally be
rect = viewport_plotarea .+ [
- xmean + leg.xoffset + leg.leftw,
- xmean - leg.xoffset - leg.rightw - leg.textw,
- ymean + leg.yoffset + leg.h,
- ymean - leg.yoffset - leg.dy,
]
x = c < 0 ? rect[1]/c : rect[2]/c
y = s < 0 ? rect[3]/s : rect[4]/s
A = min(x,y) # Biggest A that places (Acos(theta),Asin(theta)) inside rectangle
else
# Outer
# rectangle relative to midpoint where the anchor is forbidden
rect = viewport_plotarea .+ [
- xmean - leg.xoffset - leg.rightw - leg.textw - axisclearance[1],
- xmean + leg.xoffset + leg.leftw + axisclearance[2],
- ymean - leg.yoffset - leg.dy - axisclearance[3],
- ymean + leg.yoffset + leg.h + axisclearance[4],
]
t = tand(theta)
if c < 0
if t < rect[4]/rect[1]
A = rect[4]/s
elseif t < rect[3]/rect[1]
A = rect[1]/c
else
A = rect[3]/s
end
else
if t < rect[3]/rect[2]
A = rect[3]/s
elseif t <rect[4]/rect[2]
A = rect[2]/c
else
A = rect[4]/s
end
end
end
return xmean + A*c, ymean + A*s
end
function gr_get_legend_geometry(viewport_plotarea, sp)
legendn = 0
legendw = 0
@ -1154,12 +1220,28 @@ end
## Viewport, window and scale
function gr_update_viewport_legend!(viewport_plotarea, sp, leg)
leg_str = string(sp[:legend])
s = sp[:legend]
xaxis, yaxis = sp[:xaxis], sp[:yaxis]
xmirror = xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
ymirror = yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true)
if s isa Tuple{<:Real,Symbol}
if s[2] === :outer
(x,y) = gr_legend_pos(sp, leg, viewport_plotarea) # Dry run, to figure out
if x < viewport_plotarea[1]
viewport_plotarea[1] += leg.leftw + leg.textw + leg.rightw + leg.xoffset + !ymirror * gr_axis_width(sp, sp[:yaxis])
elseif x > viewport_plotarea[2]
viewport_plotarea[2] -= leg.leftw + leg.textw + leg.rightw + leg.xoffset
end
if y < viewport_plotarea[3]
viewport_plotarea[3] += leg.h + leg.dy + leg.yoffset + !xmirror * gr_axis_height(sp, sp[:xaxis])
elseif y > viewport_plotarea[4]
viewport_plotarea[4] -= leg.h + leg.dy + leg.yoffset
end
end
end
leg_str = string(s)
if occursin("outer", leg_str)
if occursin("right", leg_str)
viewport_plotarea[2] -= leg.leftw + leg.textw + leg.rightw + leg.xoffset
@ -1171,7 +1253,7 @@ function gr_update_viewport_legend!(viewport_plotarea, sp, leg)
viewport_plotarea[3] += leg.h + leg.dy + leg.yoffset + !xmirror * gr_axis_height(sp, sp[:xaxis])
end
end
if sp[:legend] == :inline
if s === :inline
if sp[:yaxis][:mirror]
viewport_plotarea[1] += leg.w
else
@ -1464,10 +1546,10 @@ function gr_label_axis_3d(sp, letter)
if ax[:guide] != ""
near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
famin, famax = axis_limits(sp, far_letter)
@ -1732,7 +1814,7 @@ function gr_draw_contour(series, x, y, z, clims)
end
function gr_draw_surface(series, x, y, z, clims)
if series[:seriestype] === :surface
fillalpha = get_fillalpha(series)
fillcolor = get_fillcolor(series)