From 10a852080566bab4b773ab475caab4ef8ed554fe Mon Sep 17 00:00:00 2001 From: Andrew Palugniok Date: Sun, 31 Dec 2017 09:56:57 -0800 Subject: [PATCH] Add subplot labeling via annotations. --- src/args.jl | 8 +++---- src/backends/gr.jl | 2 +- src/backends/pgfplots.jl | 2 +- src/backends/plotly.jl | 5 +++-- src/backends/pyplot.jl | 2 +- src/components.jl | 48 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/args.jl b/src/args.jl index e2586610..63b90848 100644 --- a/src/args.jl +++ b/src/args.jl @@ -1294,11 +1294,9 @@ end function _update_subplot_periphery(sp::Subplot, anns::AVec) # extend annotations, and ensure we always have a (x,y,PlotText) tuple - newanns = vcat(anns, sp[:annotations]) - for (i,ann) in enumerate(newanns) - x,y,tmp = ann - ptxt = isa(tmp, PlotText) ? tmp : text(tmp) - newanns[i] = (x,y,ptxt) + newanns = [] + for ann in vcat(anns, sp[:annotations]) + append!(newanns, process_annotation(sp, ann...)) end sp.attr[:annotations] = newanns diff --git a/src/backends/gr.jl b/src/backends/gr.jl index c499a8ad..144880cd 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -1330,7 +1330,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end end for ann in sp[:annotations] - x, y, val = ann + x, y, val = locate_annotation(sp, ann...) x, y = if is3d(sp) # GR.wc3towc(x, y, z) else diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index db4e8b26..1956f1b3 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -465,7 +465,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) # add the annotations for ann in sp[:annotations] - pgf_add_annotation!(o,ann...) + pgf_add_annotation!(o, locate_annotation(sp, ann...)...) end diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 5b4dcd8d..92a25809 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -385,8 +385,9 @@ function plotly_layout(plt::Plot) end # annotations - append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]]) - + for ann in sp[:annotations] + append!(d_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$spidx", yref = "y$spidx")]) + end # series_annotations for series in series_list(sp) anns = series[:series_annotations] diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index d2566d44..8630c931 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -969,7 +969,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) # add the annotations for ann in sp[:annotations] - py_add_annotations(sp, ann...) + py_add_annotations(sp, locate_annotation(sp, ann...)...) end # title diff --git a/src/components.jl b/src/components.jl index 7f452b97..20acffc5 100644 --- a/src/components.jl +++ b/src/components.jl @@ -348,6 +348,7 @@ PlotText(str) = PlotText(string(str), font()) Create a PlotText object wrapping a string with font info, for plot annotations """ text(t::PlotText) = t +text(t::PlotText, font::Font) = PlotText(t.str, font) text(str::AbstractString, f::Font) = PlotText(str, f) function text(str, args...) PlotText(string(str), font(args...)) @@ -535,6 +536,53 @@ annotations(anns::AVec) = anns annotations(anns) = Any[anns] annotations(sa::SeriesAnnotations) = sa +# Expand arrays of coordinates, positions and labels into induvidual annotations +# and make sure labels are of type PlotText +function process_annotation(sp::Subplot, xs, ys, labs, font = font()) + anns = [] + labs = makevec(labs) + for i in 1:max(length(xs), length(ys), length(labs)) + x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i) + if lab == :auto + alphabet = "abcdefghijklmnopqrstuvwxyz" + push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font))) + else + push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font))) + end + end + anns +end +function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font()) + anns = [] + positions, labs = makevec(positions), makevec(labs) + for i in 1:max(length(positions), length(labs)) + pos, lab = _cycle(positions, i), _cycle(labs, i) + if lab == :auto + alphabet = "abcdefghijklmnopqrstuvwxyz" + push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font))) + else + push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font))) + end + end + anns +end + +# Give each annotation coordinates based on specified position +function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText) + position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}( + :top_left => (0.1, 0.9), + :top_center => (0.5, 0.9), + :top_right => (0.9, 0.9), + :bottom_right => (0.9, 0.1), + :bottom_left => (0.1, 0.9), + :bottom_center => (0.5,0.1), + ) + xmin, xmax = ignorenan_extrema(sp[:xaxis]) + ymin, ymax = ignorenan_extrema(sp[:yaxis]) + x, y = (xmin, ymin).+ position_multiplier[pos].* (xmax - xmin, ymax - ymin) + (x, y, lab) +end +locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label) # ----------------------------------------------------------------------- "type which represents z-values for colors and sizes (and anything else that might come up)"