From d6a72a5df5d01b024237ef1fbc4bebfd513541bc Mon Sep 17 00:00:00 2001 From: David Gustavsson Date: Tue, 2 Mar 2021 10:19:26 +0100 Subject: [PATCH] Add legend angle to pyplot --- src/backends/pyplot.jl | 63 +++++++++++++++--------------------------- src/legend.jl | 35 ++++++++++++++++++++++- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 83899620..d89ac3aa 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -492,11 +492,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) y[rng], x[rng], z[rng] else y[rng], x[rng] - end + end else if RecipesPipeline.is3d(sp) x[rng], y[rng], z[rng] - else + else x[rng], y[rng] end end @@ -1305,44 +1305,26 @@ end # ----------------------------------------------------------------- -py_legend_pos(pos::Symbol) = get( - ( - right = "right", - left = "center left", - top = "upper center", - bottom = "lower center", - bottomleft = "lower left", - bottomright = "lower right", - topright = "upper right", - topleft = "upper left", - outerright = "center left", - outerleft = "right", - outertop = "lower center", - outerbottom = "upper center", - outerbottomleft = "lower right", - outerbottomright = "lower left", - outertopright = "upper left", - outertopleft = "upper right", - ), - pos, - "best", -) -py_legend_pos(pos) = "lower left" +py_legend_pos(pos::Tuple{S,T}) where {S<:Real,T<:Real} = "lower left" + +function py_legend_pos(pos::Tuple{<:Real,Symbol}) + (s,c) = sincosd(pos[1]) + if pos[2] === :outer + s = -s + c = -c + end + yanchors = ["lower","center","upper"] + xanchors = ["left","center","right"] + return join([yanchors[legend_anchor_index(s)], xanchors[legend_anchor_index(c)]], ' ') +end + +function py_legend_bbox(pos::Tuple{T,Symbol}) where T<:Real + if pos[2] === :outer + return legend_pos_from_angle(pos[1],-0.15,0.5,1.0,-0.15,0.5,1.0) + end + legend_pos_from_angle(pos[1],0.0,0.5,1.0,0.0,0.5,1.0) +end -py_legend_bbox(pos::Symbol) = get( - ( - outerright = (1.0, 0.5, 0.0, 0.0), - outerleft = (-0.15, 0.5, 0.0, 0.0), - outertop = (0.5, 1.0, 0.0, 0.0), - outerbottom = (0.5, -0.15, 0.0, 0.0), - outerbottomleft = (-0.15, 0.0, 0.0, 0.0), - outerbottomright = (1.0, 0.0, 0.0, 0.0), - outertopright = (1.0, 1.0, 0.0, 0.0), - outertopleft = (-0.15, 1.0, 0.0, 0.0), - ), - pos, - (0.0, 0.0, 1.0, 1.0), -) py_legend_bbox(pos) = pos function py_add_legend(plt::Plot, sp::Subplot, ax) @@ -1388,6 +1370,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) # if anything was added, call ax.legend and set the colors if !isempty(handles) + leg = legend_angle(leg) leg = ax."legend"(handles, labels, loc = py_legend_pos(leg), @@ -1398,7 +1381,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) edgecolor = py_color(sp[:foreground_color_legend]), framealpha = alpha(plot_color(sp[:background_color_legend])), fancybox = false, # makes the legend box square - borderpad=0.8 # to match GR legendbox + borderpad = 0.8 # to match GR legendbox ) frame = leg."get_frame"() frame."set_linewidth"(py_thickness_scale(plt, 1)) diff --git a/src/legend.jl b/src/legend.jl index bb1e0a46..0b996619 100644 --- a/src/legend.jl +++ b/src/legend.jl @@ -17,10 +17,43 @@ end """ -Split continuous range `[-1,1]` into an integer `[1,2,3]` +Split continuous range `[-1,1]` evenly into an integer `[1,2,3]` """ function legend_anchor_index(x) x<-1//3 && return 1 x<1//3 && return 2 return 3 end + +""" +Turn legend argument into a (theta, :inner) or (theta, :outer) tuple. +For backends where legend position is given in normal coordinates (0,0) -- (1,1), +so :topleft exactly corresponds to (45, :inner) etc. + +If `leg` is a (::Real,::Real) tuple, keep it as is. +""" +legend_angle(leg::Real) = (leg,:inner) +legend_angle(leg::Tuple{S,T}) where {S<:Real,T<:Real} = leg +legend_angle(leg::Tuple{S,Symbol}) where S<:Real = leg +legend_angle(leg::Symbol) = get( + ( + topleft = (135,:inner), + top = (90, :inner), + topright = (45, :inner), + left = (180,:inner), + right = (0, :inner), + bottomleft = (225,:inner), + bottom = (270,:inner), + bottomright = (315,:inner), + outertopleft = (135,:outer), + outertop = (90, :outer), + outertopright = (45, :outer), + outerleft = (180,:outer), + outerright = (0, :outer), + outerbottomleft = (225,:outer), + outerbottom = (270,:outer), + outerbottomright = (315,:outer), + ), + leg, + (45, :inner) + )