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::Bool) = val ? :best : :none
convertLegendValue(val::Nothing) = :none convertLegendValue(val::Nothing) = :none
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v 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) 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) gr_update_viewport_ratio!(viewport_plotarea, sp)
leg = gr_get_legend_geometry(viewport_plotarea, sp) leg = gr_get_legend_geometry(viewport_plotarea, sp)
gr_update_viewport_legend!(viewport_plotarea, sp, leg) gr_update_viewport_legend!(viewport_plotarea, sp, leg)
# fill in the plot area background # fill in the plot area background
gr_fill_plotarea(sp, viewport_plotarea) gr_fill_plotarea(sp, viewport_plotarea)
@ -1047,7 +1047,24 @@ end
function gr_legend_pos(sp::Subplot, leg, viewport_plotarea) function gr_legend_pos(sp::Subplot, leg, viewport_plotarea)
s = sp[:legend] 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) str = string(s)
if str == "best" if str == "best"
str = "topright" str = "topright"
@ -1098,6 +1115,55 @@ function gr_legend_pos(v::Tuple{S,T}, viewport_plotarea) where {S<:Real, T<:Real
(xpos,ypos) (xpos,ypos)
end 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) function gr_get_legend_geometry(viewport_plotarea, sp)
legendn = 0 legendn = 0
legendw = 0 legendw = 0
@ -1154,12 +1220,28 @@ end
## Viewport, window and scale ## Viewport, window and scale
function gr_update_viewport_legend!(viewport_plotarea, sp, leg) function gr_update_viewport_legend!(viewport_plotarea, sp, leg)
leg_str = string(sp[:legend]) s = sp[:legend]
xaxis, yaxis = sp[:xaxis], sp[:yaxis] xaxis, yaxis = sp[:xaxis], sp[:yaxis]
xmirror = xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) xmirror = xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
ymirror = yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[: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("outer", leg_str)
if occursin("right", leg_str) if occursin("right", leg_str)
viewport_plotarea[2] -= leg.leftw + leg.textw + leg.rightw + leg.xoffset 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]) viewport_plotarea[3] += leg.h + leg.dy + leg.yoffset + !xmirror * gr_axis_height(sp, sp[:xaxis])
end end
end end
if sp[:legend] == :inline if s === :inline
if sp[:yaxis][:mirror] if sp[:yaxis][:mirror]
viewport_plotarea[1] += leg.w viewport_plotarea[1] += leg.w
else else
@ -1464,10 +1546,10 @@ function gr_label_axis_3d(sp, letter)
if ax[:guide] != "" if ax[:guide] != ""
near_letter = letter in (:x, :z) ? :y : :x near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x far_letter = letter in (:x, :y) ? :z : :x
nax = sp[Symbol(near_letter, :axis)] nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)] fax = sp[Symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter) amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter) namin, namax = axis_limits(sp, near_letter)
famin, famax = axis_limits(sp, far_letter) famin, famax = axis_limits(sp, far_letter)
@ -1732,7 +1814,7 @@ function gr_draw_contour(series, x, y, z, clims)
end end
function gr_draw_surface(series, x, y, z, clims) function gr_draw_surface(series, x, y, z, clims)
if series[:seriestype] === :surface if series[:seriestype] === :surface
fillalpha = get_fillalpha(series) fillalpha = get_fillalpha(series)
fillcolor = get_fillcolor(series) fillcolor = get_fillcolor(series)