Merge pull request #3743 from t-bltg/ann
Allow passing collection of tuples to series_annotations
This commit is contained in:
commit
40b5df38f4
@ -996,9 +996,9 @@ function processFontArg!(plotattributes::AKW, fontname::Symbol, arg)
|
||||
elseif arg == :center
|
||||
plotattributes[Symbol(fontname, :halign)] = :hcenter
|
||||
plotattributes[Symbol(fontname, :valign)] = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
elseif arg ∈ _haligns
|
||||
plotattributes[Symbol(fontname, :halign)] = arg
|
||||
elseif arg in (:vcenter, :top, :bottom)
|
||||
elseif arg ∈ _valigns
|
||||
plotattributes[Symbol(fontname, :valign)] = arg
|
||||
elseif T <: Colorant
|
||||
plotattributes[Symbol(fontname, :color)] = arg
|
||||
|
||||
@ -70,6 +70,7 @@ function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
||||
width, height
|
||||
end
|
||||
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||
text_size(lab::PlotText, sz::Number, rot::Number = 0) = text_size(length(lab.str), sz, rot)
|
||||
|
||||
# account for the size/length/rotation of tick labels
|
||||
function tick_padding(sp::Subplot, axis::Axis)
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
const P2 = GeometryBasics.Point2{Float64}
|
||||
const P3 = GeometryBasics.Point3{Float64}
|
||||
|
||||
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
|
||||
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
|
||||
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
|
||||
const _haligns = :hcenter, :left, :right
|
||||
const _valigns = :vcenter, :top, :bottom
|
||||
|
||||
nanpush!(a::AVec{P2}, b) = (push!(a, P2(NaN, NaN)); push!(a, b))
|
||||
nanappend!(a::AVec{P2}, b) = (push!(a, P2(NaN, NaN)); append!(a, b))
|
||||
nanpush!(a::AVec{P3}, b) = (push!(a, P3(NaN, NaN, NaN)); push!(a, b))
|
||||
nanappend!(a::AVec{P3}, b) = (push!(a, P3(NaN, NaN, NaN)); append!(a, b))
|
||||
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
@ -38,9 +41,7 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
|
||||
@deprecate shape_coords coords
|
||||
|
||||
"return the vertex points from a Shape or Segments object"
|
||||
function coords(shape::Shape)
|
||||
shape.x, shape.y
|
||||
end
|
||||
coords(shape::Shape) = shape.x, shape.y
|
||||
|
||||
#coords(shapes::AVec{Shape}) = unzip(map(coords, shapes))
|
||||
function coords(shapes::AVec{<:Shape})
|
||||
@ -51,9 +52,9 @@ function coords(shapes::AVec{<:Shape})
|
||||
end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
[(r*cos(u), r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
|
||||
end
|
||||
partialcircle(start_θ, end_θ, n=20, r=1) = [
|
||||
(r*cos(u), r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)
|
||||
]
|
||||
|
||||
"interleave 2 vectors into each other (like a zipper's teeth)"
|
||||
function weave(x, y; ordering=Vector[x, y])
|
||||
@ -81,10 +82,9 @@ function makestar(n; offset = -0.5, radius = 1.0)
|
||||
end
|
||||
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius))
|
||||
end
|
||||
makeshape(n; offset=-0.5, radius=1.0) = Shape(
|
||||
partialcircle(offset * π, offset * π + 2π, n+1, radius)
|
||||
)
|
||||
|
||||
function makecross(; offset=-0.5, radius=1.0)
|
||||
z2 = offset * π
|
||||
@ -97,11 +97,9 @@ end
|
||||
|
||||
from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
|
||||
|
||||
function makearrowhead(angle; h = 2.0, w = 0.4)
|
||||
tip = from_polar(angle, h)
|
||||
Shape(P2[(0,0), from_polar(angle - 0.5π, w) - tip,
|
||||
from_polar(angle + 0.5π, w) - tip, (0,0)])
|
||||
end
|
||||
makearrowhead(angle; h=2.0, w=0.4, tip=from_polar(angle, h)) = Shape(
|
||||
P2[(0, 0), from_polar(angle - 0.5π, w) - tip, from_polar(angle + 0.5π, w) - tip, (0, 0)]
|
||||
)
|
||||
|
||||
const _shapes = KW(
|
||||
:circle => makeshape(20),
|
||||
@ -121,7 +119,7 @@ const _shapes = KW(
|
||||
:hline => Shape([(1, 0), (-1, 0)]),
|
||||
)
|
||||
|
||||
for n in [4,5,6,7,8]
|
||||
for n in 4:8
|
||||
_shapes[Symbol("star$n")] = makestar(n)
|
||||
end
|
||||
|
||||
@ -129,19 +127,18 @@ Shape(k::Symbol) = deepcopy(_shapes[k])
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
|
||||
"return the centroid of a Shape"
|
||||
function center(shape::Shape)
|
||||
x, y = coords(shape)
|
||||
n = length(x)
|
||||
A, Cx, Cy = 0.0, 0.0, 0.0
|
||||
for i=1:n
|
||||
A, Cx, Cy = 0, 0, 0
|
||||
for i ∈ 1:n
|
||||
ip1 = i == n ? 1 : i+1
|
||||
A += x[i] * y[ip1] - x[ip1] * y[i]
|
||||
end
|
||||
A *= 0.5
|
||||
for i=1:n
|
||||
for i ∈ 1:n
|
||||
ip1 = i == n ? 1 : i+1
|
||||
m = (x[i] * y[ip1] - x[ip1] * y[i])
|
||||
Cx += (x[i] + x[ip1]) * m
|
||||
@ -153,52 +150,46 @@ end
|
||||
function scale!(shape::Shape, x::Real, y::Real=x, c=center(shape))
|
||||
sx, sy = coords(shape)
|
||||
cx, cy = c
|
||||
for i=eachindex(sx)
|
||||
for i ∈ eachindex(sx)
|
||||
sx[i] = (sx[i] - cx) * x + cx
|
||||
sy[i] = (sy[i] - cy) * y + cy
|
||||
end
|
||||
shape
|
||||
end
|
||||
|
||||
function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
|
||||
shapecopy = deepcopy(shape)
|
||||
scale!(shapecopy, x, y, c)
|
||||
end
|
||||
scale(shape::Shape, x::Real, y::Real=x, c=center(shape)) = scale!(deepcopy(shape), x, y, c)
|
||||
|
||||
|
||||
"translate a Shape in space"
|
||||
function translate!(shape::Shape, x::Real, y::Real=x)
|
||||
sx, sy = coords(shape)
|
||||
for i=eachindex(sx)
|
||||
for i ∈ eachindex(sx)
|
||||
sx[i] += x
|
||||
sy[i] += y
|
||||
end
|
||||
shape
|
||||
end
|
||||
|
||||
function translate(shape::Shape, x::Real, y::Real = x)
|
||||
shapecopy = deepcopy(shape)
|
||||
translate!(shapecopy, x, y)
|
||||
end
|
||||
translate(shape::Shape, x::Real, y::Real=x) = translate!(deepcopy(shape), x, y)
|
||||
|
||||
function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
|
||||
rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = (
|
||||
(x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx
|
||||
end
|
||||
)
|
||||
|
||||
function rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
|
||||
rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = (
|
||||
(y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery
|
||||
end
|
||||
)
|
||||
|
||||
function rotate(x::Real, y::Real, θ::Real, c = center(shape))
|
||||
cx, cy = c
|
||||
rotate_x(x, y, Θ, cx, cy), rotate_y(x, y, Θ, cx, cy)
|
||||
end
|
||||
rotate(x::Real, y::Real, θ::Real, c=center(shape)) = (
|
||||
rotate_x(x, y, Θ, c...),
|
||||
rotate_y(x, y, Θ, c...),
|
||||
)
|
||||
|
||||
function rotate!(shape::Shape, Θ::Real, c=center(shape))
|
||||
x, y = coords(shape)
|
||||
cx, cy = c
|
||||
for i=eachindex(x)
|
||||
xi = rotate_x(x[i], y[i], Θ, cx, cy)
|
||||
yi = rotate_y(x[i], y[i], Θ, cx, cy)
|
||||
for i ∈ eachindex(x)
|
||||
xi = rotate_x(x[i], y[i], Θ, c...)
|
||||
yi = rotate_y(x[i], y[i], Θ, c...)
|
||||
x[i], y[i] = xi, yi
|
||||
end
|
||||
shape
|
||||
@ -207,15 +198,13 @@ end
|
||||
"rotate an object in space"
|
||||
function rotate(shape::Shape, θ::Real, c=center(shape))
|
||||
x, y = coords(shape)
|
||||
cx, cy = c
|
||||
x_new = rotate_x.(x, y, θ, cx, cy)
|
||||
y_new = rotate_y.(x, y, θ, cx, cy)
|
||||
x_new = rotate_x.(x, y, θ, c...)
|
||||
y_new = rotate_y.(x, y, θ, c...)
|
||||
Shape(x_new, y_new)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
mutable struct Font
|
||||
family::AbstractString
|
||||
pointsize::Int
|
||||
@ -243,13 +232,12 @@ julia> font(family="serif",halign=:center,rotation=45.0)
|
||||
```
|
||||
"""
|
||||
function font(args...; kw...)
|
||||
|
||||
# defaults
|
||||
family = "sans-serif"
|
||||
pointsize = 14
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
rotation = 0.0
|
||||
rotation = 0
|
||||
color = colorant"black"
|
||||
|
||||
for arg in args
|
||||
@ -265,9 +253,9 @@ function font(args...;kw...)
|
||||
elseif arg == :center
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
elseif arg ∈ _haligns
|
||||
halign = arg
|
||||
elseif arg in (:vcenter, :top, :bottom)
|
||||
elseif arg ∈ _valigns
|
||||
valign = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
@ -282,33 +270,29 @@ function font(args...;kw...)
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
@warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
@warn "Unused font arg: $arg ($(typeof(arg)))"
|
||||
end
|
||||
end
|
||||
|
||||
for symbol in keys(kw)
|
||||
if symbol == :family
|
||||
family = string(kw[:family])
|
||||
elseif symbol == :pointsize
|
||||
pointsize = kw[:pointsize]
|
||||
elseif symbol == :halign
|
||||
halign = kw[:halign]
|
||||
if halign == :center
|
||||
halign = :hcenter
|
||||
end
|
||||
@assert halign in (:hcenter, :left, :right)
|
||||
elseif symbol == :valign
|
||||
valign = kw[:valign]
|
||||
if valign == :center
|
||||
valign = :vcenter
|
||||
end
|
||||
@assert valign in (:vcenter, :top, :bottom)
|
||||
elseif symbol == :rotation
|
||||
rotation = kw[:rotation]
|
||||
elseif symbol == :color
|
||||
color = parse(Colorant, kw[:color])
|
||||
for sym in keys(kw)
|
||||
if sym == :family
|
||||
family = string(kw[sym])
|
||||
elseif sym == :pointsize
|
||||
pointsize = kw[sym]
|
||||
elseif sym == :halign
|
||||
halign = kw[sym]
|
||||
halign == :center && (halign = :hcenter)
|
||||
@assert halign ∈ _haligns
|
||||
elseif sym == :valign
|
||||
valign = kw[sym]
|
||||
valign == :center && (valign = :vcenter)
|
||||
@assert valign ∈ _valigns
|
||||
elseif sym == :rotation
|
||||
rotation = kw[sym]
|
||||
elseif sym == :color
|
||||
color = parse(Colorant, kw[sym])
|
||||
else
|
||||
@warn("Unused font kwarg: $symbol")
|
||||
@warn "Unused font kwarg: $sym"
|
||||
end
|
||||
end
|
||||
|
||||
@ -381,16 +365,12 @@ 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...;kw...)
|
||||
PlotText(string(str), font(args...;kw...))
|
||||
end
|
||||
text(str, args...; kw...) = PlotText(string(str), font(args...; kw...))
|
||||
|
||||
Base.length(t::PlotText) = length(t.str)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
struct Stroke
|
||||
width
|
||||
color
|
||||
@ -426,7 +406,7 @@ function stroke(args...; alpha = nothing)
|
||||
elseif allReals(arg)
|
||||
width = arg
|
||||
else
|
||||
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
@warn "Unused stroke arg: $arg ($(typeof(arg)))"
|
||||
end
|
||||
end
|
||||
|
||||
@ -459,7 +439,7 @@ function brush(args...; alpha = nothing)
|
||||
elseif allReals(arg)
|
||||
size = arg
|
||||
else
|
||||
@warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
@warn "Unused brush arg: $arg ($(typeof(arg)))"
|
||||
end
|
||||
end
|
||||
|
||||
@ -469,33 +449,40 @@ end
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
mutable struct SeriesAnnotations
|
||||
strs::AbstractVector # the labels/names
|
||||
strs::AVec # the labels/names
|
||||
font::Font
|
||||
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
|
||||
baseshape::Union{Shape, AVec{Shape}, Nothing}
|
||||
scalefactor::Tuple
|
||||
end
|
||||
|
||||
_text_label(lab::Tuple, font) = text(lab[1], font, lab[2:end]...)
|
||||
_text_label(lab::PlotText, font) = lab
|
||||
_text_label(lab, font) = text(lab, font)
|
||||
|
||||
series_annotations(anns::AMat) = map(series_annotations, anns)
|
||||
series_annotations(scalar) = series_annotations([scalar])
|
||||
function series_annotations(anns::AMat)
|
||||
map(series_annotations, anns)
|
||||
end
|
||||
function series_annotations(strs::AbstractVector, args...)
|
||||
series_annotations(anns::SeriesAnnotations) = anns
|
||||
series_annotations(::Nothing) = nothing
|
||||
|
||||
function series_annotations(strs::AVec, args...)
|
||||
fnt = font()
|
||||
shp = nothing
|
||||
scalefactor = (1,1)
|
||||
scalefactor = 1, 1
|
||||
for arg in args
|
||||
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
|
||||
if isa(arg, Shape) || (isa(arg, AVec) && eltype(arg) == Shape)
|
||||
shp = arg
|
||||
elseif isa(arg, Font)
|
||||
fnt = arg
|
||||
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||
shp = _shapes[arg]
|
||||
elseif isa(arg, Number)
|
||||
scalefactor = (arg,arg)
|
||||
scalefactor = arg, arg
|
||||
elseif is_2tuple(arg)
|
||||
scalefactor = arg
|
||||
elseif isa(arg, AVec)
|
||||
strs = collect(zip(strs, arg))
|
||||
else
|
||||
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||
@warn "Unused SeriesAnnotations arg: $arg ($(typeof(arg)))"
|
||||
end
|
||||
end
|
||||
# if scalefactor != 1
|
||||
@ -503,16 +490,14 @@ function series_annotations(strs::AbstractVector, args...)
|
||||
# scale!(s, scalefactor, scalefactor, (0, 0))
|
||||
# end
|
||||
# end
|
||||
SeriesAnnotations(strs, fnt, shp, scalefactor)
|
||||
SeriesAnnotations([_text_label(s, fnt) for s ∈ strs], fnt, shp, scalefactor)
|
||||
end
|
||||
series_annotations(anns::SeriesAnnotations) = anns
|
||||
series_annotations(::Nothing) = nothing
|
||||
|
||||
function series_annotations_shapes!(series::Series, scaletype::Symbol=:pixels)
|
||||
anns = series[:series_annotations]
|
||||
# msw, msh = anns.scalefactor
|
||||
# ms = series[:markersize]
|
||||
# msw,msh = if isa(ms, AbstractVector)
|
||||
# msw, msh = if isa(ms, AVec)
|
||||
# 1, 1
|
||||
# elseif is_2tuple(ms)
|
||||
# ms
|
||||
@ -527,7 +512,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
|
||||
msw, msh = anns.scalefactor
|
||||
msize = Float64[]
|
||||
shapes = Vector{Shape}(undef, length(anns.strs))
|
||||
for i in eachindex(anns.strs)
|
||||
for i ∈ eachindex(anns.strs)
|
||||
str = _cycle(anns.strs, i)
|
||||
|
||||
# get the width and height of the string (in mm)
|
||||
@ -561,7 +546,7 @@ end
|
||||
|
||||
function Base.iterate(ea::EachAnn, i=1)
|
||||
if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y)
|
||||
return nothing
|
||||
return
|
||||
end
|
||||
|
||||
tmp = _cycle(ea.anns.strs, i)
|
||||
@ -574,11 +559,11 @@ function Base.iterate(ea::EachAnn, i = 1)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
annotations(::Nothing) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns::AMat) = map(annotations, anns)
|
||||
annotations(anns) = Any[anns]
|
||||
annotations(sa::SeriesAnnotations) = sa
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns) = Any[anns]
|
||||
annotations(::Nothing) = []
|
||||
|
||||
_annotationfont(sp::Subplot) = Plots.font(;
|
||||
family=sp[:annotationfontfamily],
|
||||
@ -589,15 +574,12 @@ _annotationfont(sp::Subplot) = Plots.font(;
|
||||
color=sp[:annotationcolor],
|
||||
)
|
||||
|
||||
_annotation(sp, font, lab, pos...; alphabet="abcdefghijklmnopqrstuvwxyz") = (
|
||||
if lab == :auto
|
||||
(pos..., text("($(alphabet[sp[:subplot_index]]))", font))
|
||||
else
|
||||
(pos..., isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab[1], font, lab[2:end]...) : text(lab, font))
|
||||
end
|
||||
_annotation(sp::Subplot, font, lab, pos...; alphabet="abcdefghijklmnopqrstuvwxyz") = (
|
||||
pos...,
|
||||
lab == :auto ? text("($(alphabet[sp[:subplot_index]]))", font) : _text_label(lab, font)
|
||||
)
|
||||
|
||||
# Expand arrays of coordinates, positions and labels into induvidual annotations
|
||||
# Expand arrays of coordinates, positions and labels into individual annotations
|
||||
# and make sure labels are of type PlotText
|
||||
function process_annotation(sp::Subplot, xs, ys, labs, font=_annotationfont(sp))
|
||||
anns = []
|
||||
@ -623,8 +605,6 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol,Tu
|
||||
anns
|
||||
end
|
||||
|
||||
process_any_label(lab, font=Font()) = lab isa Tuple ? text(lab...) : text(lab, font)
|
||||
|
||||
_relative_position(xmin, xmax, pos::Length{:pct}) = xmin + pos.value * (xmax - xmin)
|
||||
|
||||
# Give each annotation coordinates based on specified position
|
||||
@ -693,8 +673,6 @@ end
|
||||
# # I don't want to clash with ValidatedNumerics, but this would be nice:
|
||||
# ..(a::T, b::T) = (a, b)
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# style is :open or :closed (for now)
|
||||
@ -714,8 +692,7 @@ Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
|
||||
function arrow(args...)
|
||||
style = :simple
|
||||
side = :head
|
||||
headlength = 0.3
|
||||
headwidth = 0.3
|
||||
headlength = headwidth = 0.3
|
||||
setlength = false
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
@ -735,7 +712,7 @@ function arrow(args...)
|
||||
elseif T <: Tuple && length(arg) == 2
|
||||
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
|
||||
else
|
||||
@warn("Skipped arrow arg $arg")
|
||||
@warn "Skipped arrow arg $arg"
|
||||
end
|
||||
end
|
||||
Arrow(style, side, headlength, headwidth)
|
||||
@ -745,7 +722,7 @@ end
|
||||
# allow for do-block notation which gets called on every valid start/end pair which
|
||||
# we need to draw an arrow
|
||||
function add_arrows(func::Function, x::AVec, y::AVec)
|
||||
for i=2:length(x)
|
||||
for i ∈ 2:length(x)
|
||||
xyprev = (x[i-1], y[i-1])
|
||||
xy = (x[i], y[i])
|
||||
if ok(xyprev) && ok(xy)
|
||||
@ -774,13 +751,9 @@ end
|
||||
|
||||
@deprecate curve_points coords
|
||||
|
||||
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, Base.range(first(range), stop=last(range), length=n))
|
||||
|
||||
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
|
||||
# may create a loop if necessary. Assumes the view is [0,1]
|
||||
function directed_curve(args...; kw...)
|
||||
error("directed_curve has been moved to PlotRecipes")
|
||||
end
|
||||
coords(curve::BezierCurve, n::Integer=30; range=[0, 1]) = map(
|
||||
curve, Base.range(first(range), stop=last(range), length=n)
|
||||
)
|
||||
|
||||
function extrema_plus_buffer(v, buffmult=0.2)
|
||||
vmin, vmax = ignorenan_extrema(v)
|
||||
|
||||
@ -116,7 +116,7 @@ end
|
||||
end
|
||||
|
||||
@testset "Series Annotations" begin
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
square = Shape([(0., 0.), (1., 0.), (1., 1.), (0., 1.)])
|
||||
@test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin
|
||||
p = plot(
|
||||
[1, 2, 3],
|
||||
@ -130,7 +130,7 @@ end
|
||||
),
|
||||
)
|
||||
sa = p.series_list[1].plotattributes[:series_annotations]
|
||||
@test sa.strs == ["a"]
|
||||
@test only(sa.strs).str == "a"
|
||||
@test sa.font.family == "courier"
|
||||
@test sa.baseshape == square
|
||||
@test sa.scalefactor == (1, 4)
|
||||
@ -143,19 +143,17 @@ end
|
||||
xlims = (0, 5),
|
||||
series_annotations = permutedims([["1/1"], ["1/2"], ["1/3"], ["1/4"], ["1/5"]]),
|
||||
)
|
||||
@test spl.series_list[1].plotattributes[:series_annotations].strs == ["1/1"]
|
||||
@test spl.series_list[2].plotattributes[:series_annotations].strs == ["1/2"]
|
||||
@test spl.series_list[3].plotattributes[:series_annotations].strs == ["1/3"]
|
||||
@test spl.series_list[4].plotattributes[:series_annotations].strs == ["1/4"]
|
||||
@test spl.series_list[5].plotattributes[:series_annotations].strs == ["1/5"]
|
||||
for i ∈ 1:5
|
||||
@test only(spl.series_list[i].plotattributes[:series_annotations].strs).str == "1/$i"
|
||||
end
|
||||
|
||||
p = plot([1, 2], annotations=(1.5, 2, text("foo", :left)))
|
||||
x, y, txt = p.subplots[end][:annotations][end]
|
||||
x, y, txt = only(p.subplots[end][:annotations])
|
||||
@test (x, y) == (1.5, 2)
|
||||
@test txt.str == "foo"
|
||||
|
||||
p = plot([1, 2], annotations=((.1, .5), :auto))
|
||||
pos, txt = p.subplots[end][:annotations][end]
|
||||
pos, txt = only(p.subplots[end][:annotations])
|
||||
@test pos == (.1, .5)
|
||||
@test txt.str == "(a)"
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user