Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d657c0cb33 | |||
| 50f63cf1eb | |||
| 2b22dae757 | |||
| 7ca32b5edd | |||
| 3f5a1287be | |||
| 990e0f3f7f | |||
| 849d31d57f |
+1
-1
@@ -1,7 +1,7 @@
|
||||
name = "Plots"
|
||||
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
author = ["Tom Breloff (@tbreloff)"]
|
||||
version = "1.16.4"
|
||||
version = "1.16.6"
|
||||
|
||||
[deps]
|
||||
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
|
||||
|
||||
@@ -1081,7 +1081,7 @@ end
|
||||
function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng)
|
||||
fillrange_opt = PGFPlotsX.Options("line width" => "0", "draw opacity" => "0")
|
||||
fillrange_opt = merge(fillrange_opt, pgfx_fillstyle(series, i))
|
||||
push!(fillrange_opt, "markers" => "none") # no markers on fillranges
|
||||
push!(fillrange_opt, "mark" => "none") # no markers on fillranges
|
||||
push!(fillrange_opt, "forget plot" => nothing)
|
||||
opt = series.plotattributes
|
||||
args = RecipesPipeline.is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) :
|
||||
|
||||
@@ -474,6 +474,11 @@ mutable struct SeriesAnnotations
|
||||
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
|
||||
scalefactor::Tuple
|
||||
end
|
||||
|
||||
series_annotations(scalar) = series_annotations([scalar])
|
||||
function series_annotations(anns::AMat)
|
||||
map(series_annotations, anns)
|
||||
end
|
||||
function series_annotations(strs::AbstractVector, args...)
|
||||
fnt = font()
|
||||
shp = nothing
|
||||
@@ -570,6 +575,7 @@ end
|
||||
|
||||
annotations(::Nothing) = []
|
||||
annotations(anns::AVec) = anns
|
||||
annotations(anns::AMat) = map(annotations, anns)
|
||||
annotations(anns) = Any[anns]
|
||||
annotations(sa::SeriesAnnotations) = sa
|
||||
|
||||
|
||||
+11
-3
@@ -406,7 +406,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
calc_num_subplots(layout::AbstractLayout) = 1
|
||||
calc_num_subplots(layout::AbstractLayout) = get(layout.attr, :blank, false) ? 0 : 1
|
||||
function calc_num_subplots(layout::GridLayout)
|
||||
tot = 0
|
||||
for l in layout.grid
|
||||
@@ -775,9 +775,17 @@ end
|
||||
|
||||
"Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis."
|
||||
function twinx(sp::Subplot)
|
||||
sp[:right_margin] = max(sp[:right_margin], 30px)
|
||||
plot!(sp.plt, inset = (sp[:subplot_index], bbox(0,0,1,1)))
|
||||
plot!(sp.plt,
|
||||
inset = (sp[:subplot_index], bbox(0,0,1,1)),
|
||||
right_margin = sp[:right_margin],
|
||||
left_margin = sp[:left_margin],
|
||||
top_margin = sp[:top_margin],
|
||||
bottom_margin = sp[:bottom_margin],
|
||||
)
|
||||
twinsp = sp.plt.subplots[end]
|
||||
twinsp[:xaxis][:grid] = false
|
||||
twinsp[:yaxis][:grid] = false
|
||||
twinsp[:xaxis][:showaxis] = false
|
||||
twinsp[:yaxis][:mirror] = true
|
||||
twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0)
|
||||
link_axes!(sp[:xaxis], twinsp[:xaxis])
|
||||
|
||||
+34
-2
@@ -23,7 +23,38 @@ current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
|
||||
|
||||
Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
|
||||
Base.print(io::IO, plt::Plot) = print(io, string(plt))
|
||||
Base.show(io::IO, plt::Plot) = print(io, string(plt))
|
||||
function Base.show(io::IO, plt::Plot)
|
||||
print(io, string(plt))
|
||||
sp_ekwargs = getindex.(plt.subplots, :extra_kwargs)
|
||||
s_ekwargs = getindex.(plt.series_list, :extra_kwargs)
|
||||
if isempty(plt[:extra_plot_kwargs]) && all(isempty, sp_ekwargs) && all(isempty, s_ekwargs)
|
||||
return
|
||||
end
|
||||
print(io,"\nCaptured extra kwargs:\n")
|
||||
do_show = true
|
||||
for (key, value) in plt[:extra_plot_kwargs]
|
||||
do_show && println(io, " Plot:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
for (i, ekwargs) in enumerate(sp_ekwargs)
|
||||
for (key, value) in ekwargs
|
||||
do_show && println(io, " SubplotPlot{$i}:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
end
|
||||
for (i, ekwargs) in enumerate(s_ekwargs)
|
||||
for (key, value) in ekwargs
|
||||
do_show && println(io, " Series{$i}:")
|
||||
println(io, " "^4, key, ": ", value)
|
||||
do_show = false
|
||||
end
|
||||
do_show = true
|
||||
end
|
||||
end
|
||||
|
||||
getplot(plt::Plot) = plt
|
||||
getattr(plt::Plot, idx::Int = 1) = plt.attr
|
||||
@@ -60,7 +91,8 @@ end
|
||||
|
||||
# build a new plot from existing plots
|
||||
# note: we split into plt1 and plts_tail so we can dispatch correctly
|
||||
function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
plot(plt1::Plot, plts_tail::Plot...; kw...) = plot!(deepcopy(plt1), deepcopy.(plts_tail)...; kw...)
|
||||
function plot!(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
@nospecialize
|
||||
plotattributes = KW(kw)
|
||||
RecipesPipeline.preprocess_attributes!(plotattributes)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
using Plots: guidefont
|
||||
using Plots: guidefont, series_annotations
|
||||
import ImageMagick
|
||||
using VisualRegressionTests
|
||||
using Plots
|
||||
|
||||
+13
-3
@@ -35,13 +35,13 @@ end
|
||||
@testset "Axis limits" begin
|
||||
pl = plot(1:5, xlims=:symmetric, widen = false)
|
||||
@test Plots.xlims(pl) == (-5, 5)
|
||||
|
||||
|
||||
pl = plot(1:3)
|
||||
@test Plots.xlims(pl) == Plots.widen(1,3)
|
||||
|
||||
|
||||
pl = plot([1.05,2.0,2.95], ylims=:round)
|
||||
@test Plots.ylims(pl) == (1, 3)
|
||||
|
||||
|
||||
pl = plot(1:3, xlims=(1,5))
|
||||
@test Plots.xlims(pl) == (1, 5)
|
||||
|
||||
@@ -53,3 +53,13 @@ end
|
||||
ql = quiver([1, 2], [2, 1], [3, 4], quiver = ([1, -1], [0, 0], [1, -0.5]), arrow=true)
|
||||
@test ql[1][:projection] == "3d"
|
||||
end
|
||||
|
||||
@testset "twinx" begin
|
||||
pl = plot(1:10, margin = 2Plots.cm)
|
||||
twpl = twinx(pl)
|
||||
pl! = plot!(twinx(), -(1:10))
|
||||
@test twpl[:right_margin] == 2Plots.cm
|
||||
@test twpl[:left_margin] == 2Plots.cm
|
||||
@test twpl[:top_margin] == 2Plots.cm
|
||||
@test twpl[:bottom_margin] == 2Plots.cm
|
||||
end
|
||||
|
||||
+65
-41
@@ -2,58 +2,58 @@ using Plots, Test
|
||||
|
||||
@testset "Shapes" begin
|
||||
@testset "Type" begin
|
||||
square = Shape([(0,0.0),(1,0.0),(1,1.0),(0,1.0)])
|
||||
@test isa(square, Shape{Int64, Float64})
|
||||
@test coords(square) isa Tuple{Vector{S}, Vector{T}} where {T,S}
|
||||
square = Shape([(0, 0.0), (1, 0.0), (1, 1.0), (0, 1.0)])
|
||||
@test isa(square, Shape{Int64,Float64})
|
||||
@test coords(square) isa Tuple{Vector{S},Vector{T}} where {T,S}
|
||||
end
|
||||
|
||||
@testset "Copy" begin
|
||||
square = Shape([(0,0),(1,0),(1,1),(0,1)])
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
square2 = Shape(square)
|
||||
@test square2.x == square.x
|
||||
@test square2.y == square.y
|
||||
end
|
||||
|
||||
@testset "Center" begin
|
||||
square = Shape([(0,0),(1,0),(1,1),(0,1)])
|
||||
@test Plots.center(square) == (0.5,0.5)
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
@test Plots.center(square) == (0.5, 0.5)
|
||||
end
|
||||
|
||||
@testset "Translate" begin
|
||||
square = Shape([(0,0),(1,0),(1,1),(0,1)])
|
||||
squareUp = Shape([(0,1),(1,1),(1,2),(0,2)])
|
||||
squareUpRight = Shape([(1,1),(2,1),(2,2),(1,2)])
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
squareUp = Shape([(0, 1), (1, 1), (1, 2), (0, 2)])
|
||||
squareUpRight = Shape([(1, 1), (2, 1), (2, 2), (1, 2)])
|
||||
|
||||
@test Plots.translate(square,0,1).x == squareUp.x
|
||||
@test Plots.translate(square,0,1).y == squareUp.y
|
||||
@test Plots.translate(square, 0, 1).x == squareUp.x
|
||||
@test Plots.translate(square, 0, 1).y == squareUp.y
|
||||
|
||||
@test Plots.center(translate!(square,1)) == (1.5,1.5)
|
||||
@test Plots.center(translate!(square, 1)) == (1.5, 1.5)
|
||||
end
|
||||
|
||||
@testset "Rotate" begin
|
||||
# 2 radians rotation matrix
|
||||
R2 = [cos(2) sin(2); -sin(2) cos(2)]
|
||||
coords = [0 0; 1 0; 1 1; 0 1]'
|
||||
coordsRotated2 = R2*(coords.-0.5).+0.5
|
||||
coordsRotated2 = R2 * (coords .- 0.5) .+ 0.5
|
||||
|
||||
square = Shape([(0,0),(1,0),(1,1),(0,1)])
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
|
||||
# make a new, rotated square
|
||||
square2 = Plots.rotate(square, -2)
|
||||
@test square2.x ≈ coordsRotated2[1,:]
|
||||
@test square2.y ≈ coordsRotated2[2,:]
|
||||
@test square2.x ≈ coordsRotated2[1, :]
|
||||
@test square2.y ≈ coordsRotated2[2, :]
|
||||
|
||||
# unrotate the new square in place
|
||||
rotate!(square2, 2)
|
||||
@test square2.x ≈ coords[1,:]
|
||||
@test square2.y ≈ coords[2,:]
|
||||
@test square2.x ≈ coords[1, :]
|
||||
@test square2.y ≈ coords[2, :]
|
||||
end
|
||||
|
||||
@testset "Plot" begin
|
||||
ang = range(0, 2π, length = 60)
|
||||
ellipse(x, y, w, h) = Shape(w*sin.(ang).+x, h*cos.(ang).+y)
|
||||
myshapes = [ellipse(x,rand(),rand(),rand()) for x = 1:4]
|
||||
@test coords(myshapes) isa Tuple{Vector{Vector{S}}, Vector{Vector{T}}} where {T,S}
|
||||
ellipse(x, y, w, h) = Shape(w * sin.(ang) .+ x, h * cos.(ang) .+ y)
|
||||
myshapes = [ellipse(x, rand(), rand(), rand()) for x = 1:4]
|
||||
@test coords(myshapes) isa Tuple{Vector{Vector{S}},Vector{Vector{T}}} where {T,S}
|
||||
local p
|
||||
@test_nowarn p = plot(myshapes)
|
||||
@test p[1][1][:seriestype] == :shape
|
||||
@@ -62,7 +62,7 @@ end
|
||||
|
||||
@testset "Brush" begin
|
||||
@testset "Colors" begin
|
||||
baseline = brush(1, RGB(0,0,0))
|
||||
baseline = brush(1, RGB(0, 0, 0))
|
||||
@test brush(:black) == baseline
|
||||
@test brush("black") == baseline
|
||||
end
|
||||
@@ -76,7 +76,7 @@ end
|
||||
end
|
||||
@testset "Bad Argument" begin
|
||||
# using test_logs because test_warn seems to not work anymore
|
||||
@test_logs (:warn,"Unused brush arg: nothing (Nothing)") begin
|
||||
@test_logs (:warn, "Unused brush arg: nothing (Nothing)") begin
|
||||
brush(nothing)
|
||||
end
|
||||
end
|
||||
@@ -84,44 +84,68 @@ end
|
||||
|
||||
@testset "Fonts" begin
|
||||
@testset "Scaling" begin
|
||||
sizesToCheck = [:titlefontsize, :legendfontsize, :legendtitlefontsize,
|
||||
:xtickfontsize, :ytickfontsize, :ztickfontsize,
|
||||
:xguidefontsize, :yguidefontsize, :zguidefontsize,]
|
||||
sizesToCheck = [
|
||||
:titlefontsize,
|
||||
:legendfontsize,
|
||||
:legendtitlefontsize,
|
||||
:xtickfontsize,
|
||||
:ytickfontsize,
|
||||
:ztickfontsize,
|
||||
:xguidefontsize,
|
||||
:yguidefontsize,
|
||||
:zguidefontsize,
|
||||
]
|
||||
# get inital font sizes
|
||||
initialSizes = [Plots.default(s) for s in sizesToCheck ]
|
||||
initialSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
#scale up font sizes
|
||||
scalefontsizes(2)
|
||||
|
||||
# get inital font sizes
|
||||
doubledSizes = [Plots.default(s) for s in sizesToCheck ]
|
||||
doubledSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
@test doubledSizes == initialSizes*2
|
||||
@test doubledSizes == initialSizes * 2
|
||||
|
||||
# reset font sizes
|
||||
resetfontsizes()
|
||||
|
||||
finalSizes = [Plots.default(s) for s in sizesToCheck ]
|
||||
finalSizes = [Plots.default(s) for s in sizesToCheck]
|
||||
|
||||
@test finalSizes == initialSizes
|
||||
end
|
||||
end
|
||||
|
||||
@testset "Series Annotations" begin
|
||||
square = Shape([(0,0),(1,0),(1,1),(0,1)])
|
||||
@test_logs (:warn,"Unused SeriesAnnotations arg: triangle (Symbol)") begin
|
||||
p = plot([1,2,3],
|
||||
series_annotations=(["a"],
|
||||
2, # pass a scale factor
|
||||
(1,4), # pass two scale factors (overwrites first one)
|
||||
square, # pass a shape
|
||||
font(:courier), # pass an annotation font
|
||||
:triangle # pass an incorrect argument
|
||||
))
|
||||
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
|
||||
@test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin
|
||||
p = plot(
|
||||
[1, 2, 3],
|
||||
series_annotations = (
|
||||
["a"],
|
||||
2, # pass a scale factor
|
||||
(1, 4), # pass two scale factors (overwrites first one)
|
||||
square, # pass a shape
|
||||
font(:courier), # pass an annotation font
|
||||
:triangle, # pass an incorrect argument
|
||||
),
|
||||
)
|
||||
sa = p.series_list[1].plotattributes[:series_annotations]
|
||||
@test sa.strs == ["a"]
|
||||
@test sa.font.family == "courier"
|
||||
@test sa.baseshape == square
|
||||
@test sa.scalefactor == (1,4)
|
||||
@test sa.scalefactor == (1, 4)
|
||||
end
|
||||
spl = scatter(
|
||||
4.53 .* [1/1 1/2 1/3 1/4 1/5],
|
||||
[0 0 0 0 0],
|
||||
layout = (5, 1),
|
||||
ylims = (-1.1, 1.1),
|
||||
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"]
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user