From 10e9325635e7603f99afe5c48afa42bd4d4902e6 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 8 Aug 2021 00:10:27 +0200 Subject: [PATCH 1/7] avoid ambiguous += --- src/backends/gr.jl | 2 +- src/backends/pgfplotsx.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index e28fb2d8..8fb040ea 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -27,7 +27,7 @@ gr_markertype(k) = ( octagon = -24, cross = 2, xcross = 5, - + = 2, + (+) = 2, x = 5, star4 = -25, star5 = -26, diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 030ddefa..cde7fd9b 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -708,7 +708,7 @@ pgfx_get_marker(k) = get( none = "none", cross = "+", xcross = "x", - + = "+", + (+) = "+", x = "x", utriangle = "triangle*", dtriangle = "triangle*", From 9e824367bb930cccaa41382a2fdc71d04424f38f Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 8 Aug 2021 00:23:41 +0200 Subject: [PATCH 2/7] add configuration file --- .JuliaFormatter.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .JuliaFormatter.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 00000000..481cff0a --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1 @@ +whitespace_in_kwargs=false \ No newline at end of file From 1c84704a816505379cef898caf467eea42f0031a Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 8 Aug 2021 01:40:22 +0200 Subject: [PATCH 3/7] move format to separate action --- .github/workflows/format.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/format.yml diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 00000000..1b041417 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,26 @@ +name: Run JuliaFormatter + +on: + pull_request: + +jobs: + Benchmark: + if: "!contains(github.event.head_commit.message, '[skip ci]')" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@latest + with: + version: 1 + + # Setup + - name: Ubuntu TESTCMD + run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV + + # Check format + - name: Install JuliaFormatter and format + run: | + git diff --name-only --exit-code + $TESTCMD -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"' + $TESTCMD -e 'using JuliaFormatter; format(["src", "test"])' + git diff --exit-code From ffca3c130539ee51bbaa076d169a7be7dc9cc953 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 8 Aug 2021 20:25:36 +0200 Subject: [PATCH 4/7] update JuliaFormatter config file --- .JuliaFormatter.toml | 5 ++++- .github/workflows/benchmark.yml | 7 ++----- .github/workflows/ci.yml | 6 +++--- .github/workflows/format.yml | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 481cff0a..5e092a6d 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1 +1,4 @@ -whitespace_in_kwargs=false \ No newline at end of file +style = "blue" +import_to_using = false +always_use_return = false +short_to_long_function_def = false diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index ccc7bb31..4062fc8a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -1,4 +1,4 @@ -name: Run benchmarks +name: benchmarks on: pull_request: @@ -6,9 +6,6 @@ on: jobs: Benchmark: if: "!contains(github.event.head_commit.message, '[skip ci]')" - env: - GKS_ENCODING: "utf8" - GKSwstype: "100" runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -16,7 +13,7 @@ jobs: with: version: 1 - ## Setup + # Setup - name: Ubuntu TESTCMD run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV - name: Install Plots dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45a723a9..584bd3fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,9 +72,9 @@ jobs: # Run tests - name: Run Graphical test run: | - $TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true);' - $TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots");' - $TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes");' + $TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true)' + $TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots")' + $TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes")' - name: Codecov uses: julia-actions/julia-uploadcodecov@latest diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 1b041417..e983db8f 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,10 +1,10 @@ -name: Run JuliaFormatter +name: format on: pull_request: jobs: - Benchmark: + JuliaFormatter: if: "!contains(github.event.head_commit.message, '[skip ci]')" runs-on: ubuntu-latest steps: From 9164ee09cbbbd6626640bc385e7a542ffc4e5c98 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 8 Aug 2021 23:04:18 +0200 Subject: [PATCH 5/7] fix wrong method signature --- .JuliaFormatter.toml | 3 +++ src/backends/gr.jl | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 5e092a6d..49843713 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,4 +1,7 @@ style = "blue" import_to_using = false always_use_return = false +conditional_to_if = false +whitespace_typedefs = true short_to_long_function_def = false +annotate_untyped_fields_with_any = false diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 8fb040ea..49dace78 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -768,22 +768,20 @@ function _update_min_padding!(sp::Subplot{GRBackend}) h = 0mm if !isempty(first(xticks)) gr_set_font( - tickfont(xaxis), + tickfont(xaxis), sp, halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], valign = (xaxis[:mirror] ? :bottom : :top), rotation = xaxis[:rotation], - sp ) l = 0.01 + last(gr_get_ticks_size(xticks, xaxis[:rotation])) h = max(h, 1mm + get_size(sp)[2] * l * px) end if !isempty(first(yticks)) gr_set_font( - tickfont(yaxis), + tickfont(yaxis), sp, halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], valign = (yaxis[:mirror] ? :bottom : :top), rotation = yaxis[:rotation], - sp ) l = 0.01 + last(gr_get_ticks_size(yticks, yaxis[:rotation])) h = max(h, 1mm + get_size(sp)[2] * l * px) @@ -799,12 +797,11 @@ function _update_min_padding!(sp::Subplot{GRBackend}) if !isempty(first(zticks)) gr_set_font( - tickfont(zaxis), + tickfont(zaxis), sp, halign = (zaxis[:mirror] ? :left : :right), valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2], rotation = zaxis[:rotation], color = zaxis[:tickfontcolor], - sp ) l = 0.01 + first(gr_get_ticks_size(zticks, zaxis[:rotation])) w = 1mm + get_size(sp)[1] * l * px From a3eca8244e6651183bb43c0361744b7606a67fda Mon Sep 17 00:00:00 2001 From: t-bltg Date: Tue, 10 Aug 2021 19:21:50 +0200 Subject: [PATCH 6/7] disable formatting on exports --- .JuliaFormatter.toml | 9 +++++++-- src/Plots.jl | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 49843713..a580c42d 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,7 +1,12 @@ -style = "blue" +always_for_in = true import_to_using = false +align_pair_arrow = true +align_assignment = true +align_conditional = true always_use_return = false conditional_to_if = false -whitespace_typedefs = true +whitespace_in_kwargs = true +remove_extra_newlines = true +whitespace_ops_in_indices = true short_to_long_function_def = false annotate_untyped_fields_with_any = false diff --git a/src/Plots.jl b/src/Plots.jl index 5b067f0a..2efe1f7f 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -25,6 +25,7 @@ import JSON using Requires +#! format: off export grid, bbox, @@ -117,7 +118,7 @@ export scalefontsize, scalefontsizes, resetfontsizes - +#! format: on # --------------------------------------------------------- import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563 From c5db139bbb76b04d5b7b5417975df5a28bbd0c72 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Wed, 11 Aug 2021 07:57:46 +0200 Subject: [PATCH 7/7] run format(["src", "test"]) --- src/Plots.jl | 68 +- src/animation.jl | 170 ++-- src/arg_desc.jl | 360 ++++----- src/args.jl | 1130 ++++++++++++++++++--------- src/axes.jl | 236 ++++-- src/backends.jl | 720 ++++++++++++----- src/backends/deprecated/pgfplots.jl | 272 +++++-- src/backends/gaston.jl | 155 ++-- src/backends/gr.jl | 436 +++++++---- src/backends/hdf5.jl | 102 ++- src/backends/inspectdr.jl | 253 +++--- src/backends/pgfplotsx.jl | 498 ++++++------ src/backends/plotly.jl | 445 +++++++---- src/backends/plotlyjs.jl | 9 +- src/backends/pyplot.jl | 561 ++++++++----- src/backends/unicodeplots.jl | 46 +- src/backends/web.jl | 12 +- src/colorbars.jl | 27 +- src/components.jl | 511 ++++++------ src/examples.jl | 589 +++++++------- src/fileio.jl | 9 +- src/ijulia.jl | 18 +- src/init.jl | 43 +- src/layouts.jl | 244 +++--- src/legend.jl | 61 +- src/output.jl | 8 +- src/pipeline.jl | 52 +- src/plot.jl | 35 +- src/plotattr.jl | 37 +- src/precompile_includer.jl | 9 +- src/recipes.jl | 161 ++-- src/shorthands.jl | 45 +- src/subplots.jl | 40 +- src/themes.jl | 16 +- src/types.jl | 23 +- src/utils.jl | 300 +++---- test/imgcomp.jl | 16 +- test/integration_dates.jl | 30 +- test/runtests.jl | 85 +- test/test_axes.jl | 24 +- test/test_axis_letter.jl | 9 +- test/test_components.jl | 17 +- test/test_hdf5plots.jl | 25 +- test/test_pgfplotsx.jl | 785 +++++++++---------- test/test_pipeline.jl | 4 +- test/test_recipes.jl | 30 +- test/test_shorthands.jl | 42 +- 47 files changed, 5118 insertions(+), 3650 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index 2efe1f7f..bb0ea855 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -4,7 +4,17 @@ if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optle @eval Base.Experimental.@optlevel 1 end -const _current_plots_version = VersionNumber(split(first(filter(line -> occursin("version", line), readlines(normpath(@__DIR__, "..", "Project.toml")))), "\"")[2]) +const _current_plots_version = VersionNumber( + split( + first( + filter( + line -> occursin("version", line), + readlines(normpath(@__DIR__, "..", "Project.toml")), + ), + ), + "\"", + )[2], +) using Reexport @@ -137,7 +147,6 @@ ignorenan_extrema(x) = Base.extrema(x) # This makes it impossible to create row vectors of String and Symbol with the transpose operator. # This solves this issue, internally in Plots at least. - # commented out on the insistence of the METADATA maintainers #Base.transpose(x::Symbol) = x @@ -148,12 +157,13 @@ ignorenan_extrema(x) = Base.extrema(x) import Measures module PlotMeasures import Measures -import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h +import Measures: + Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h const BBox = Measures.Absolute2DBox # allow pixels and percentages const px = AbsoluteLength(0.254) -const pct = Length{:pct, Float64}(1.0) +const pct = Length{:pct,Float64}(1.0) Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value) Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value) @@ -168,7 +178,8 @@ import .PlotMeasures: Length, AbsoluteLength, Measure, width, height # --------------------------------------------------------- import RecipesPipeline -import RecipesPipeline: SliceIt, +import RecipesPipeline: + SliceIt, DefaultsDict, Formatted, AbstractSurface, @@ -220,33 +231,30 @@ include("backends/web.jl") include("shorthands.jl") -let PlotOrSubplot = Union{Plot, Subplot} - global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...) - global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...) - global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...) - global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...) - global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...) - global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...) - global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...) - global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...) - global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...) - global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...) - global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...) - global xticks!(plt::PlotOrSubplot, - ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...) - global yticks!(plt::PlotOrSubplot, - ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...) - global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...) - global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...) - global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...) - global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...) - global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...) - global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...) - global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...) - global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...) +let PlotOrSubplot = Union{Plot,Subplot} + global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...) + global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...) + global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...) + global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...) + global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...) + global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...) + global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin, xmax), kw...) + global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin, ymax), kw...) + global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin, zmax), kw...) + global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...) + global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...) + global xticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks, labels), kw...) + global yticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks, labels), kw...) + global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...) + global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...) + global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...) + global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...) + global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...) + global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...) + global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...) + global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...) end - # --------------------------------------------------------- const CURRENT_BACKEND = CurrentBackend(:none) diff --git a/src/animation.jl b/src/animation.jl index 0d89be65..9021059d 100644 --- a/src/animation.jl +++ b/src/animation.jl @@ -14,24 +14,24 @@ end Add a plot (the current plot if not specified) to an existing animation """ -function frame(anim::Animation, plt::P=current()) where P<:AbstractPlot +function frame(anim::Animation, plt::P = current()) where {P<:AbstractPlot} i = length(anim.frames) + 1 filename = @sprintf("%06d.png", i) png(plt, joinpath(anim.dir, filename)) push!(anim.frames, filename) end -giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif") -movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov") -mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4") -webmfn() = (isijulia() ? "tmp.webm" : tempname()*".webm") +giffn() = (isijulia() ? "tmp.gif" : tempname() * ".gif") +movfn() = (isijulia() ? "tmp.mov" : tempname() * ".mov") +mp4fn() = (isijulia() ? "tmp.mp4" : tempname() * ".mp4") +webmfn() = (isijulia() ? "tmp.webm" : tempname() * ".webm") mutable struct FrameIterator itr every::Int kw end -FrameIterator(itr; every=1, kw...) = FrameIterator(itr, every, kw) +FrameIterator(itr; every = 1, kw...) = FrameIterator(itr, every, kw) """ Animate from an iterator which returns the plot args each iteration. @@ -48,8 +48,8 @@ function animate(fitr::FrameIterator, fn = giffn(); kw...) end # most things will implement this -function animate(obj, fn = giffn(); every=1, fps=20, loop=0, kw...) - animate(FrameIterator(obj, every, kw), fn; fps=fps, loop=loop) +function animate(obj, fn = giffn(); every = 1, fps = 20, loop = 0, kw...) + animate(FrameIterator(obj, every, kw), fn; fps = fps, loop = loop) end # ----------------------------------------------- @@ -69,12 +69,16 @@ webm(anim::Animation, fn = webmfn(); kw...) = buildanimation(anim, fn, false; kw ffmpeg_framerate(fps) = "$fps" ffmpeg_framerate(fps::Rational) = "$(fps.num)/$(fps.den)" -function buildanimation(anim::Animation, fn::AbstractString, - is_animated_gif::Bool=true; - fps::Real = 20, loop::Integer = 0, - variable_palette::Bool=false, - verbose=false, - show_msg::Bool=true) +function buildanimation( + anim::Animation, + fn::AbstractString, + is_animated_gif::Bool = true; + fps::Real = 20, + loop::Integer = 0, + variable_palette::Bool = false, + verbose = false, + show_msg::Bool = true, +) if length(anim.frames) == 0 throw(ArgumentError("Cannot build empty animations")) end @@ -82,41 +86,49 @@ function buildanimation(anim::Animation, fn::AbstractString, fn = abspath(expanduser(fn)) animdir = anim.dir framerate = ffmpeg_framerate(fps) - verbose_level = (verbose isa Int ? verbose : - verbose ? 32 # "info" - : 16) # "error" + verbose_level = (verbose isa Int ? verbose : verbose ? 32 : 16) # "error" if is_animated_gif if variable_palette # generate a colorpalette for each frame for highest quality, but larger filesize - palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1" - ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`) + palette = "palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1" + ffmpeg_exe( + `-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`, + ) else # generate a colorpalette first so ffmpeg does not have to guess it - ffmpeg_exe(`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`) + ffmpeg_exe( + `-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`, + ) # then apply the palette to get better results - ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`) + ffmpeg_exe( + `-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`, + ) end else - ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`) + ffmpeg_exe( + `-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`, + ) end show_msg && @info("Saved animation to ", fn) AnimatedGif(fn) end - - # write out html to view the gif function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif) ext = file_extension(agif.filename) if ext == "gif" - html = "" - elseif ext in ("mov", "mp4","webm") + html = + "" + elseif ext in ("mov", "mp4", "webm") mimetype = ext == "mov" ? "video/quicktime" : "video/$ext" - html = "" + html = + "" else error("Cannot show animation with extension $ext: $agif") end @@ -125,65 +137,67 @@ function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif) return nothing end - # Only gifs can be shown via image/gif Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif" function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif) - open(fio-> write(io, fio), agif.filename) + open(fio -> write(io, fio), agif.filename) end - # ----------------------------------------------- function _animate(forloop::Expr, args...; callgif = false) - if forloop.head ∉ (:for, :while) - error("@animate macro expects a for- or while-block. got: $(forloop.head)") - end - - # add the call to frame to the end of each iteration - animsym = gensym("anim") - countersym = gensym("counter") - freqassert = :() - block = forloop.args[2] - - # create filter - n = length(args) - filterexpr = if n == 0 - # no filter... every iteration gets a frame - true - - elseif args[1] == :every - # filter every `freq` frames (starting with the first frame) - @assert n == 2 - freq = args[2] - freqassert = :(@assert isa($freq, Integer) && $freq > 0) - :(mod1($countersym, $freq) == 1) - - elseif args[1] == :when - # filter on custom expression - @assert n == 2 - args[2] - - else - error("Unsupported animate filter: $args") - end - - push!(block.args, :(if $filterexpr; Plots.frame($animsym); end)) - push!(block.args, :($countersym += 1)) - - # add a final call to `gif(anim)`? - retval = callgif ? :(Plots.gif($animsym)) : animsym - - # full expression: - esc(quote - $freqassert # if filtering, check frequency is an Integer > 0 - $animsym = Plots.Animation() # init animation object - let $countersym = 1 # init iteration counter - $forloop # for loop, saving a frame after each iteration + if forloop.head ∉ (:for, :while) + error("@animate macro expects a for- or while-block. got: $(forloop.head)") end - $retval # return the animation object, or the gif - end) + + # add the call to frame to the end of each iteration + animsym = gensym("anim") + countersym = gensym("counter") + freqassert = :() + block = forloop.args[2] + + # create filter + n = length(args) + filterexpr = if n == 0 + # no filter... every iteration gets a frame + true + + elseif args[1] == :every + # filter every `freq` frames (starting with the first frame) + @assert n == 2 + freq = args[2] + freqassert = :(@assert isa($freq, Integer) && $freq > 0) + :(mod1($countersym, $freq) == 1) + + elseif args[1] == :when + # filter on custom expression + @assert n == 2 + args[2] + + else + error("Unsupported animate filter: $args") + end + + push!(block.args, :( + if $filterexpr + Plots.frame($animsym) + end + )) + push!(block.args, :($countersym += 1)) + + # add a final call to `gif(anim)`? + retval = callgif ? :(Plots.gif($animsym)) : animsym + + # full expression: + esc(quote + $freqassert # if filtering, check frequency is an Integer > 0 + $animsym = Plots.Animation() # init animation object + let $countersym = 1 # init iteration counter + $forloop # for loop, saving a frame after each iteration + end + $retval # return the animation object, or the gif + end) end """ diff --git a/src/arg_desc.jl b/src/arg_desc.jl index b848bf70..da250471 100644 --- a/src/arg_desc.jl +++ b/src/arg_desc.jl @@ -1,187 +1,187 @@ const _arg_desc = KW( -# series args -:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.", -:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot", -:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.", -:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.", -:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)", -:linewidth => "Number. Width of the line (in pixels)", -:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).", -:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.", -:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.", -:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.", -:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.", -:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).", -:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.", -:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.", -:markersize => "Number or AbstractVector. Size (radius pixels) of the markers", -:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)", -:markerstrokewidth => "Number. Width of the marker stroke (border) in pixels", -:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.", -:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.", -:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`", -:smooth => "Bool. Add a regression line?", -:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`", -:x => "Various. Input data. First Dimension", -:y => "Various. Input data. Second Dimension", -:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.", -:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.", -:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).", -:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.", -:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.", -:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", -:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)", -:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).", -:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?", -:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)", -:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)", -:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.", -:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.", -:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.", -:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).", -:weights => "AbstractVector. Used in histogram types for weighted counts.", -:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default)", -:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.", -:contour_labels => "Bool. Show labels at the contour lines?", -:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.", -:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.", -:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.", -:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.", -:hover => "nothing or vector of strings. Text to display when hovering over each data point.", -:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.", + # series args + :label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.", + :seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot", + :seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.", + :seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.", + :linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)", + :linewidth => "Number. Width of the line (in pixels)", + :linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).", + :linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.", + :fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.", + :fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.", + :fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.", + :markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).", + :markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.", + :markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.", + :markersize => "Number or AbstractVector. Size (radius pixels) of the markers", + :markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)", + :markerstrokewidth => "Number. Width of the marker stroke (border) in pixels", + :markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.", + :markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.", + :bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`", + :smooth => "Bool. Add a regression line?", + :group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`", + :x => "Various. Input data. First Dimension", + :y => "Various. Input data. Second Dimension", + :z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.", + :marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.", + :line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).", + :fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.", + :levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.", + :orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", + :bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)", + :bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).", + :bar_edges => "Bool. Align bars to edges (true), or centers (the default)?", + :xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)", + :yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)", + :ribbon => "Number or AbstractVector. Creates a fillrange around the data points.", + :quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.", + :arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.", + :normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).", + :weights => "AbstractVector. Used in histogram types for weighted counts.", + :show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default)", + :contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.", + :contour_labels => "Bool. Show labels at the contour lines?", + :match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.", + :subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.", + :series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.", + :primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.", + :hover => "nothing or vector of strings. Text to display when hovering over each data point.", + :colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.", -# plot args -:plot_title => "String. Title for the whole plot (not the subplots)", -:plot_titlevspan => "Number in [0,1]. Vertical span of the whole plot title (fraction of the plot height)", -:background_color => "Color Type. Base color for all backgrounds.", -:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)", -:foreground_color => "Color Type. Base color for all foregrounds.", -:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot", -:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)", -:window_title => "String. Title of the standalone gui-window.", -:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`", -:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.", -:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).", -:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).", -:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.", -:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.", -:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots", -:dpi => "Number. Dots Per Inch of output figures", -:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.", -:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.", -:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`", -:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides", -:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes", + # plot args + :plot_title => "String. Title for the whole plot (not the subplots)", + :plot_titlevspan => "Number in [0,1]. Vertical span of the whole plot title (fraction of the plot height)", + :background_color => "Color Type. Base color for all backgrounds.", + :background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)", + :foreground_color => "Color Type. Base color for all foregrounds.", + :size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot", + :pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)", + :window_title => "String. Title of the standalone gui-window.", + :show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`", + :layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.", + :link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).", + :overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).", + :html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.", + :tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.", + :inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots", + :dpi => "Number. Dots Per Inch of output figures", + :thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.", + :display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.", + :extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`", + :fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides", + :warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes", -# subplot args -:title => "String. Subplot title.", -:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`", -:titlefontfamily => "String or Symbol. Font family of subplot title.", -:titlefontsize => "Integer. Font pointsize of subplot title.", -:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center", -:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center", -:titlefontrotation => "Real. Font rotation of subplot title", -:titlefontcolor => "Color Type. Font color of subplot title", -:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.", -:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.", -:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", -:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.", -:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", -:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", -:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.", -:legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.", -:legendfontfamily => "String or Symbol. Font family of legend entries.", -:legendfontsize => "Integer. Font pointsize of legend entries.", -:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center", -:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center", -:legendfontrotation => "Real. Font rotation of legend entries", -:legendfontcolor => "Color Type. Font color of legend entries", -:legendtitle => "String. Legend title.", -:legendtitlefontfamily => "String or Symbol. Font family of the legend title.", -:legendtitlefontsize => "Integer. Font pointsize the legend title.", -:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center", -:legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center", -:legendtitlefontrotation => "Real. Font rotation of the legend title", -:legendtitlefontcolor => "Color Type. Font color of the legend title", -:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)", -:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.", -:colorbar_fontfamily => "String or Symbol. Font family of colobar entries.", -:colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", -:colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.", -:colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.", -:colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries", -:colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`", -:colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.", -:legendfont => "Font. Font of legend items.", -:legendtitlefont => "Font. Font of the legend title.", -:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String, PlotText (created with `text(args...)`), or a tuple of arguments to `text` (e.g., `(\"Label\", 8, :red, :top)`). Add one-off text annotations at the x,y coordinates.", -:annotationfontfamily => "String or Symbol. Font family of annotations.", -:annotationfontsize => "Integer. Font pointsize of annotations.", -:annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.", -:annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.", -:annotationrotation => "Float. Rotation of annotations in degrees.", -:annotationcolor => "Colorant or :match. Color of annotations.", -:projection => "Symbol or String. '3d' or 'polar'", -:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.", -:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.", -:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.", -:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.", -:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.", -:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.", -:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.", -:colorbar_title => "String. Title of colorbar.", -:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)", -:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots", + # subplot args + :title => "String. Subplot title.", + :titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`", + :titlefontfamily => "String or Symbol. Font family of subplot title.", + :titlefontsize => "Integer. Font pointsize of subplot title.", + :titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center", + :titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center", + :titlefontrotation => "Real. Font rotation of subplot title", + :titlefontcolor => "Color Type. Font color of subplot title", + :background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.", + :background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.", + :background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", + :foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.", + :foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", + :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", + :color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.", + :legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.", + :legendfontfamily => "String or Symbol. Font family of legend entries.", + :legendfontsize => "Integer. Font pointsize of legend entries.", + :legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center", + :legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center", + :legendfontrotation => "Real. Font rotation of legend entries", + :legendfontcolor => "Color Type. Font color of legend entries", + :legendtitle => "String. Legend title.", + :legendtitlefontfamily => "String or Symbol. Font family of the legend title.", + :legendtitlefontsize => "Integer. Font pointsize the legend title.", + :legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center", + :legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center", + :legendtitlefontrotation => "Real. Font rotation of the legend title", + :legendtitlefontcolor => "Color Type. Font color of the legend title", + :colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)", + :clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.", + :colorbar_fontfamily => "String or Symbol. Font family of colobar entries.", + :colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", + :colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.", + :colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.", + :colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries", + :colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`", + :colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.", + :legendfont => "Font. Font of legend items.", + :legendtitlefont => "Font. Font of the legend title.", + :annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String, PlotText (created with `text(args...)`), or a tuple of arguments to `text` (e.g., `(\"Label\", 8, :red, :top)`). Add one-off text annotations at the x,y coordinates.", + :annotationfontfamily => "String or Symbol. Font family of annotations.", + :annotationfontsize => "Integer. Font pointsize of annotations.", + :annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.", + :annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.", + :annotationrotation => "Float. Rotation of annotations in degrees.", + :annotationcolor => "Colorant or :match. Color of annotations.", + :projection => "Symbol or String. '3d' or 'polar'", + :aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.", + :margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.", + :left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.", + :top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.", + :right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.", + :bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.", + :subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.", + :colorbar_title => "String. Title of colorbar.", + :framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)", + :camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots", -# axis args -:guide => "String. Axis guide (label).", -:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right", -:lims => """ - NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). - `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0] - `:symmetric` sets the limits to be symmetric around zero. - Set widen=true to widen the specified limits (as occurs when lims are not specified). - """, -:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", -:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`", -:rotation => "Number. Degrees rotation of tick labels.", -:flip => "Bool. Should we flip (reverse) the axis?", -:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.", -:tickfontfamily => "String or Symbol. Font family of tick labels.", -:tickfontsize => "Integer. Font pointsize of tick labels.", -:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center", -:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center", -:tickfontrotation => "Real. Font rotation of tick labels", -:tickfontcolor => "Color Type. Font color of tick labels", -:guidefontfamily => "String or Symbol. Font family of axes guides.", -:guidefontsize => "Integer. Font pointsize of axes guides.", -:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center", -:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center", -:guidefontrotation => "Real. Font rotation of axes guides", -:guidefontcolor => "Color Type. Font color of axes guides", -:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.", -:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).", -:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.", -:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).", -:mirror => "Bool. Switch the side of the tick labels (right or top).", -:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`", -:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.", -:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.", -:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)", -:gridlinewidth => "Number. Width of the grid lines (in pixels)", -:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.", -:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines", -:minorticks => "Integer. Intervals to divide the gap between major ticks into", -:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.", -:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)", -:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)", -:tick_direction => "Symbol. Direction of the ticks. `:in`, `:out` or `:none`", -:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`", -:widen => """ - Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. - Defaults to `:auto`, which widens unless limits were manually set. - """, -:draw_arrow => "Bool. Draw arrow at the end of the axis.", + # axis args + :guide => "String. Axis guide (label).", + :guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right", + :lims => """ + NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). + `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0] + `:symmetric` sets the limits to be symmetric around zero. + Set widen=true to widen the specified limits (as occurs when lims are not specified). + """, + :ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", + :scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`", + :rotation => "Number. Degrees rotation of tick labels.", + :flip => "Bool. Should we flip (reverse) the axis?", + :formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.", + :tickfontfamily => "String or Symbol. Font family of tick labels.", + :tickfontsize => "Integer. Font pointsize of tick labels.", + :tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center", + :tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center", + :tickfontrotation => "Real. Font rotation of tick labels", + :tickfontcolor => "Color Type. Font color of tick labels", + :guidefontfamily => "String or Symbol. Font family of axes guides.", + :guidefontsize => "Integer. Font pointsize of axes guides.", + :guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center", + :guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center", + :guidefontrotation => "Real. Font rotation of axes guides", + :guidefontcolor => "Color Type. Font color of axes guides", + :foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.", + :foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).", + :foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.", + :foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).", + :mirror => "Bool. Switch the side of the tick labels (right or top).", + :grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`", + :foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.", + :gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.", + :gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)", + :gridlinewidth => "Number. Width of the grid lines (in pixels)", + :foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.", + :minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines", + :minorticks => "Integer. Intervals to divide the gap between major ticks into", + :minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.", + :minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)", + :minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)", + :tick_direction => "Symbol. Direction of the ticks. `:in`, `:out` or `:none`", + :showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`", + :widen => """ + Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. + Defaults to `:auto`, which widens unless limits were manually set. + """, + :draw_arrow => "Bool. Draw arrow at the end of the axis.", ) diff --git a/src/args.jl b/src/args.jl index d4c0eb0e..57dd3298 100644 --- a/src/args.jl +++ b/src/args.jl @@ -1,7 +1,7 @@ function makeplural(s::Symbol) str = string(s) if last(str) != 's' - return Symbol(string(s,"s")) + return Symbol(string(s, "s")) end return s end @@ -25,7 +25,7 @@ function add_aliases(sym::Symbol, aliases::Symbol...) end function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol}) - for (k,v) in aliases + for (k, v) in aliases s = string(k) if '_' in s aliases[make_non_underscore(k)] = v @@ -44,22 +44,42 @@ end # ------------------------------------------------------------ const _allAxes = [:auto, :left, :right] -const _axesAliases = Dict{Symbol,Symbol}( - :a => :auto, - :l => :left, - :r => :right -) +const _axesAliases = Dict{Symbol,Symbol}(:a => :auto, :l => :left, :r => :right) -const _3dTypes = [ - :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d -] -const _allTypes = vcat([ - :none, :line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, - :heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins, - :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d, - :density, :bar, :hline, :vline, - :contour, :pie, :shape, :image -], _3dTypes) +const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d] +const _allTypes = vcat( + [ + :none, + :line, + :path, + :steppre, + :stepmid, + :steppost, + :sticks, + :scatter, + :heatmap, + :hexbin, + :barbins, + :barhist, + :histogram, + :scatterbins, + :scatterhist, + :stepbins, + :stephist, + :bins2d, + :histogram2d, + :histogram3d, + :density, + :bar, + :hline, + :vline, + :contour, + :pie, + :shape, + :image, + ], + _3dTypes, +) const _typeAliases = Dict{Symbol,Symbol}( :n => :none, @@ -102,7 +122,8 @@ add_non_underscore_aliases!(_typeAliases) const _histogram_like = [:histogram, :barhist, :barbins] const _line_like = [:line, :path, :steppre, :stepmid, :steppost] -const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image] +const _surface_like = + [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image] like_histogram(seriestype::Symbol) = seriestype in _histogram_like like_line(seriestype::Symbol) = seriestype in _line_like @@ -117,36 +138,36 @@ ispolar(series::Series) = ispolar(series.plotattributes[:subplot]) const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _styleAliases = Dict{Symbol,Symbol}( - :a => :auto, - :s => :solid, - :d => :dash, - :dd => :dashdot, - :ddd => :dashdotdot, + :a => :auto, + :s => :solid, + :d => :dash, + :dd => :dashdot, + :ddd => :dashdotdot, ) const _shape_keys = Symbol[ - :circle, - :rect, - :star5, - :diamond, - :hexagon, - :cross, - :xcross, - :utriangle, - :dtriangle, - :rtriangle, - :ltriangle, - :pentagon, - :heptagon, - :octagon, - :star4, - :star6, - :star7, - :star8, - :vline, - :hline, - :+, - :x, + :circle, + :rect, + :star5, + :diamond, + :hexagon, + :cross, + :xcross, + :utriangle, + :dtriangle, + :rtriangle, + :ltriangle, + :pentagon, + :heptagon, + :octagon, + :star4, + :star6, + :star7, + :star8, + :vline, + :hline, + :+, + :x, ] const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes)))) @@ -183,22 +204,22 @@ const _markerAliases = Dict{Symbol,Symbol}( :lighttri => :ltriangle, :lighttriangle => :ltriangle, # :+ => :cross, - :plus => :cross, + :plus => :cross, # :x => :xcross, - :X => :xcross, - :star => :star5, - :s => :star5, - :star1 => :star5, - :s2 => :star8, - :star2 => :star8, - :p => :pentagon, - :pent => :pentagon, - :h => :hexagon, - :hex => :hexagon, - :hep => :heptagon, - :o => :octagon, - :oct => :octagon, - :spike => :vline, + :X => :xcross, + :star => :star5, + :s => :star5, + :star1 => :star5, + :s2 => :star8, + :star2 => :star8, + :p => :pentagon, + :pent => :pentagon, + :h => :hexagon, + :hex => :hexagon, + :hep => :heptagon, + :o => :octagon, + :oct => :octagon, + :spike => :vline, ) const _positionAliases = Dict{Symbol,Symbol}( @@ -219,16 +240,34 @@ const _positionAliases = Dict{Symbol,Symbol}( const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt] const _logScales = [:ln, :log2, :log10] const _logScaleBases = Dict(:ln => ℯ, :log2 => 2.0, :log10 => 10.0) -const _scaleAliases = Dict{Symbol,Symbol}( - :none => :identity, - :log => :log10, -) +const _scaleAliases = Dict{Symbol,Symbol}(:none => :identity, :log => :log10) -const _allGridSyms = [:x, :y, :z, - :xy, :xz, :yx, :yz, :zx, :zy, - :xyz, :xzy, :yxz, :yzx, :zxy, :zyx, - :all, :both, :on, :yes, :show, - :none, :off, :no, :hide] +const _allGridSyms = [ + :x, + :y, + :z, + :xy, + :xz, + :yx, + :yz, + :zx, + :zy, + :xyz, + :xzy, + :yxz, + :yzx, + :zxy, + :zyx, + :all, + :both, + :on, + :yes, + :show, + :none, + :off, + :no, + :hide, +] const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing] hasgrid(arg::Nothing, letter) = false hasgrid(arg::Bool, letter) = arg @@ -236,17 +275,39 @@ function hasgrid(arg::Symbol, letter) if arg in _allGridSyms arg in (:all, :both, :on) || occursin(string(letter), string(arg)) else - @warn("Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead.") + @warn( + "Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead." + ) true end end hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter) -const _allShowaxisSyms = [:x, :y, :z, - :xy, :xz, :yx, :yz, :zx, :zy, - :xyz, :xzy, :yxz, :yzx, :zxy, :zyx, - :all, :both, :on, :yes, :show, - :off, :no, :hide] +const _allShowaxisSyms = [ + :x, + :y, + :z, + :xy, + :xz, + :yx, + :yz, + :zx, + :zy, + :xyz, + :xzy, + :yxz, + :yzx, + :zxy, + :zyx, + :all, + :both, + :on, + :yes, + :show, + :off, + :no, + :hide, +] const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)] showaxis(arg::Nothing, letter) = false showaxis(arg::Bool, letter) = arg @@ -254,19 +315,21 @@ function showaxis(arg::Symbol, letter) if arg in _allGridSyms arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg)) else - @warn("Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead.") + @warn( + "Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead." + ) true end end showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter) const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none] -const _framestyleAliases = Dict{Symbol, Symbol}( - :frame => :box, - :border => :box, - :on => :box, - :transparent => :semi, - :semitransparent => :semi, +const _framestyleAliases = Dict{Symbol,Symbol}( + :frame => :box, + :border => :box, + :on => :box, + :transparent => :semi, + :semitransparent => :semi, ) const _bar_width = 0.8 @@ -321,120 +384,118 @@ const _series_defaults = KW( :subplot => :auto, # which subplot(s) does this series belong to? :series_annotations => nothing, # a list of annotations which apply to the coordinates of this series :primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow - # one logical series to be broken up (path and markers, for example) - :hover => nothing, # text to display when hovering over the data points - :stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. - :connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh - :extra_kwargs => Dict() + # one logical series to be broken up (path and markers, for example) + :hover => nothing, # text to display when hovering over the data points + :stride => (1, 1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. + :connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh + :extra_kwargs => Dict(), ) - const _plot_defaults = KW( - :plot_title => "", - :plot_titleindex => 0, - :plot_titlefontsize => 16, - :plot_titlelocation => :center, # also :left or :right - :plot_titlefontfamily => :match, - :plot_titlefonthalign => :hcenter, - :plot_titlefontvalign => :vcenter, - :plot_titlefontrotation => 0.0, - :plot_titlefontcolor => :match, - :plot_titlevspan => 0.05, # vertical span of the plot title, here 5% - :background_color => colorant"white", # default for all backgrounds, - :background_color_outside => :match, # background outside grid, - :foreground_color => :auto, # default for all foregrounds, and title color, - :fontfamily => "sans-serif", - :size => (600,400), - :pos => (0,0), - :window_title => "Plots.jl", - :show => false, - :layout => 1, - :link => :none, - :overwrite_figure => true, - :html_output_format => :auto, - :tex_output_standalone => false, - :inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are - # the parent layout and the relative bounding box of inset subplots - :dpi => DPI, # dots per inch for images, etc - :thickness_scaling => 1, - :display_type => :auto, - :warn_on_unsupported => true, - :extra_plot_kwargs => Dict(), - :extra_kwargs => :series, # directs collection of extra_kwargs + :plot_title => "", + :plot_titleindex => 0, + :plot_titlefontsize => 16, + :plot_titlelocation => :center, # also :left or :right + :plot_titlefontfamily => :match, + :plot_titlefonthalign => :hcenter, + :plot_titlefontvalign => :vcenter, + :plot_titlefontrotation => 0.0, + :plot_titlefontcolor => :match, + :plot_titlevspan => 0.05, # vertical span of the plot title, here 5% + :background_color => colorant"white", # default for all backgrounds, + :background_color_outside => :match, # background outside grid, + :foreground_color => :auto, # default for all foregrounds, and title color, + :fontfamily => "sans-serif", + :size => (600, 400), + :pos => (0, 0), + :window_title => "Plots.jl", + :show => false, + :layout => 1, + :link => :none, + :overwrite_figure => true, + :html_output_format => :auto, + :tex_output_standalone => false, + :inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are + # the parent layout and the relative bounding box of inset subplots + :dpi => DPI, # dots per inch for images, etc + :thickness_scaling => 1, + :display_type => :auto, + :warn_on_unsupported => true, + :extra_plot_kwargs => Dict(), + :extra_kwargs => :series, # directs collection of extra_kwargs ) - const _subplot_defaults = KW( - :title => "", - :titlelocation => :center, # also :left or :right - :fontfamily_subplot => :match, - :titlefontfamily => :match, - :titlefontsize => 14, - :titlefonthalign => :hcenter, - :titlefontvalign => :vcenter, - :titlefontrotation => 0.0, - :titlefontcolor => :match, - :background_color_subplot => :match, # default for other bg colors... match takes plot default - :background_color_legend => :match, # background of legend - :background_color_inside => :match, # background inside grid - :foreground_color_subplot => :match, # default for other fg colors... match takes plot default - :foreground_color_legend => :match, # foreground of legend - :foreground_color_title => :match, # title color - :color_palette => :auto, - :legend => :best, - :legendtitle => nothing, - :colorbar => :legend, - :clims => :auto, - :colorbar_fontfamily => :match, - :colorbar_ticks => :auto, - :colorbar_tickfontfamily => :match, - :colorbar_tickfontsize => 8, - :colorbar_tickfonthalign => :hcenter, - :colorbar_tickfontvalign => :vcenter, - :colorbar_tickfontrotation => 0.0, - :colorbar_tickfontcolor => :match, - :colorbar_scale => :identity, - :colorbar_formatter => :auto, - :colorbar_discrete_values => [], - :colorbar_continuous_values => zeros(0), - :legendfontfamily => :match, - :legendfontsize => 8, - :legendfonthalign => :hcenter, - :legendfontvalign => :vcenter, - :legendfontrotation => 0.0, - :legendfontcolor => :match, - :legendtitlefontfamily => :match, - :legendtitlefontsize => 11, - :legendtitlefonthalign => :hcenter, - :legendtitlefontvalign => :vcenter, - :legendtitlefontrotation => 0.0, - :legendtitlefontcolor => :match, - :annotations => [], # annotation tuples... list of (x,y,annotation) - :annotationfontfamily => :match, - :annotationfontsize => 14, - :annotationhalign => :hcenter, - :annotationvalign => :vcenter, - :annotationrotation => 0.0, - :annotationcolor => :match, - :projection => :none, # can also be :polar or :3d - :aspect_ratio => :auto, # choose from :none or :equal - :margin => 1mm, - :left_margin => :match, - :top_margin => :match, - :right_margin => :match, - :bottom_margin => :match, - :subplot_index => -1, - :colorbar_title => "", - :colorbar_titlefontsize => 10, - :colorbar_title_location => :center, # also :left or :right - :colorbar_titlefontfamily => :match, - :colorbar_titlefonthalign => :hcenter, - :colorbar_titlefontvalign => :vcenter, + :title => "", + :titlelocation => :center, # also :left or :right + :fontfamily_subplot => :match, + :titlefontfamily => :match, + :titlefontsize => 14, + :titlefonthalign => :hcenter, + :titlefontvalign => :vcenter, + :titlefontrotation => 0.0, + :titlefontcolor => :match, + :background_color_subplot => :match, # default for other bg colors... match takes plot default + :background_color_legend => :match, # background of legend + :background_color_inside => :match, # background inside grid + :foreground_color_subplot => :match, # default for other fg colors... match takes plot default + :foreground_color_legend => :match, # foreground of legend + :foreground_color_title => :match, # title color + :color_palette => :auto, + :legend => :best, + :legendtitle => nothing, + :colorbar => :legend, + :clims => :auto, + :colorbar_fontfamily => :match, + :colorbar_ticks => :auto, + :colorbar_tickfontfamily => :match, + :colorbar_tickfontsize => 8, + :colorbar_tickfonthalign => :hcenter, + :colorbar_tickfontvalign => :vcenter, + :colorbar_tickfontrotation => 0.0, + :colorbar_tickfontcolor => :match, + :colorbar_scale => :identity, + :colorbar_formatter => :auto, + :colorbar_discrete_values => [], + :colorbar_continuous_values => zeros(0), + :legendfontfamily => :match, + :legendfontsize => 8, + :legendfonthalign => :hcenter, + :legendfontvalign => :vcenter, + :legendfontrotation => 0.0, + :legendfontcolor => :match, + :legendtitlefontfamily => :match, + :legendtitlefontsize => 11, + :legendtitlefonthalign => :hcenter, + :legendtitlefontvalign => :vcenter, + :legendtitlefontrotation => 0.0, + :legendtitlefontcolor => :match, + :annotations => [], # annotation tuples... list of (x,y,annotation) + :annotationfontfamily => :match, + :annotationfontsize => 14, + :annotationhalign => :hcenter, + :annotationvalign => :vcenter, + :annotationrotation => 0.0, + :annotationcolor => :match, + :projection => :none, # can also be :polar or :3d + :aspect_ratio => :auto, # choose from :none or :equal + :margin => 1mm, + :left_margin => :match, + :top_margin => :match, + :right_margin => :match, + :bottom_margin => :match, + :subplot_index => -1, + :colorbar_title => "", + :colorbar_titlefontsize => 10, + :colorbar_title_location => :center, # also :left or :right + :colorbar_titlefontfamily => :match, + :colorbar_titlefonthalign => :hcenter, + :colorbar_titlefontvalign => :vcenter, :colorbar_titlefontrotation => 0.0, - :colorbar_titlefontcolor => :match, - :framestyle => :axes, - :camera => (30,30), - :extra_kwargs => Dict() + :colorbar_titlefontcolor => :match, + :framestyle => :axes, + :camera => (30, 30), + :extra_kwargs => Dict(), ) const _axis_defaults = KW( @@ -500,33 +561,28 @@ const _suppress_warnings = Set{Symbol}([ const _axis_defaults_byletter = KW() function reset_axis_defaults_byletter!() - for letter in (:x,:y,:z) + for letter in (:x, :y, :z) _axis_defaults_byletter[letter] = KW() - for (k,v) in _axis_defaults + for (k, v) in _axis_defaults _axis_defaults_byletter[letter][k] = v end end end reset_axis_defaults_byletter!() -for letter in (:x,:y,:z), k in keys(_axis_defaults) +for letter in (:x, :y, :z), k in keys(_axis_defaults) # allow the underscore version too: xguide or x_guide add_aliases(Symbol(letter, k), Symbol(letter, "_", k)) end -const _all_defaults = KW[ - _series_defaults, - _plot_defaults, - _subplot_defaults -] +const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults] const _initial_defaults = deepcopy(_all_defaults) const _initial_axis_defaults = deepcopy(_axis_defaults) # to be able to reset font sizes to initial values -const _initial_plt_fontsizes = Dict( - :plot_titlefontsize => _plot_defaults[:plot_titlefontsize], -) +const _initial_plt_fontsizes = + Dict(:plot_titlefontsize => _plot_defaults[:plot_titlefontsize]) const _initial_sp_fontsizes = Dict( :titlefontsize => _subplot_defaults[:titlefontsize], @@ -542,7 +598,8 @@ const _initial_ax_fontsizes = Dict( :guidefontsize => _axis_defaults[:guidefontsize], ) -const _initial_fontsizes = merge(_initial_plt_fontsizes, _initial_sp_fontsizes, _initial_ax_fontsizes) +const _initial_fontsizes = + merge(_initial_plt_fontsizes, _initial_sp_fontsizes, _initial_ax_fontsizes) const _internal_args = [:plot_object, :series_plotindex, :markershape_to_add, :letter, :idxfilter] @@ -553,7 +610,8 @@ const _subplot_args = sort(union(collect(keys(_subplot_defaults)))) const _plot_args = sort(union(collect(keys(_plot_defaults)))) const _magic_axis_args = [:axis, :tickfont, :guidefont, :grid, :minorgrid] -const _magic_subplot_args = [:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont] +const _magic_subplot_args = + [:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont] const _magic_series_args = [:line, :marker, :fill] const _all_axis_args = sort(union([_axis_args; _magic_axis_args])) @@ -561,21 +619,29 @@ const _all_subplot_args = sort(union([_subplot_args; _magic_subplot_args])) const _all_series_args = sort(union([_series_args; _magic_series_args])) const _all_plot_args = _plot_args -const _all_args = sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args])) +const _all_args = + sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args])) is_subplot_attr(k) = k in _all_subplot_args is_series_attr(k) = k in _all_series_args -is_axis_attr(k) = Symbol(chop(string(k); head=1, tail=0)) in _all_axis_args +is_axis_attr(k) = Symbol(chop(string(k); head = 1, tail = 0)) in _all_axis_args is_axis_attr_noletter(k) = k in _all_axis_args RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k) is_default_attribute(k) = k in _internal_args || k in _all_args || is_axis_attr_noletter(k) # ----------------------------------------------------------------------------- -autopick_ignore_none_auto(arr::AVec, idx::Integer) = _cycle(setdiff(arr, [:none, :auto]), idx) +autopick_ignore_none_auto(arr::AVec, idx::Integer) = + _cycle(setdiff(arr, [:none, :auto]), idx) autopick_ignore_none_auto(notarr, idx::Integer) = notarr -function aliasesAndAutopick(plotattributes::AKW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int) +function aliasesAndAutopick( + plotattributes::AKW, + sym::Symbol, + aliases::Dict{Symbol,Symbol}, + options::AVec, + plotIndex::Int, +) if plotattributes[sym] == :auto plotattributes[sym] = autopick_ignore_none_auto(options, plotIndex) elseif haskey(aliases, plotattributes[sym]) @@ -583,17 +649,16 @@ function aliasesAndAutopick(plotattributes::AKW, sym::Symbol, aliases::Dict{Symb end end -aliases(aliasMap::Dict{Symbol,Symbol}, val) = sortedkeys(filter((k,v)-> v==val, aliasMap)) +aliases(aliasMap::Dict{Symbol,Symbol}, val) = + sortedkeys(filter((k, v) -> v == val, aliasMap)) # ----------------------------------------------------------------------------- - # margin -add_aliases(:left_margin , :leftmargin ) -add_aliases(:top_margin , :topmargin) -add_aliases(:bottom_margin , :bottommargin) -add_aliases(:right_margin ,:rightmargin) - +add_aliases(:left_margin, :leftmargin) +add_aliases(:top_margin, :topmargin) +add_aliases(:bottom_margin, :bottommargin) +add_aliases(:right_margin, :rightmargin) # colors add_aliases(:seriescolor, :c, :color, :colour) @@ -603,36 +668,176 @@ add_aliases(:markerstrokecolor, :msc, :mscolor, :mscolour, :markerstrokecolour) add_aliases(:markerstrokewidth, :msw, :mswidth) add_aliases(:fillcolor, :fc, :fcolor, :fcolour, :fillcolour) -add_aliases(:background_color, :bg, :bgcolor, :bg_color, :background, - :background_colour, :bgcolour, :bg_colour) -add_aliases(:background_color_legend, :bg_legend, :bglegend, :bgcolor_legend, :bg_color_legend, :background_legend, - :background_colour_legend, :bgcolour_legend, :bg_colour_legend) -add_aliases(:background_color_subplot, :bg_subplot, :bgsubplot, :bgcolor_subplot, :bg_color_subplot, :background_subplot, - :background_colour_subplot, :bgcolour_subplot, :bg_colour_subplot) -add_aliases(:background_color_inside, :bg_inside, :bginside, :bgcolor_inside, :bg_color_inside, :background_inside, - :background_colour_inside, :bgcolour_inside, :bg_colour_inside) -add_aliases(:background_color_outside, :bg_outside, :bgoutside, :bgcolor_outside, :bg_color_outside, :background_outside, - :background_colour_outside, :bgcolour_outside, :bg_colour_outside) -add_aliases(:foreground_color, :fg, :fgcolor, :fg_color, :foreground, - :foreground_colour, :fgcolour, :fg_colour) -add_aliases(:foreground_color_legend, :fg_legend, :fglegend, :fgcolor_legend, :fg_color_legend, :foreground_legend, - :foreground_colour_legend, :fgcolour_legend, :fg_colour_legend) -add_aliases(:foreground_color_subplot, :fg_subplot, :fgsubplot, :fgcolor_subplot, :fg_color_subplot, :foreground_subplot, - :foreground_colour_subplot, :fgcolour_subplot, :fg_colour_subplot) -add_aliases(:foreground_color_grid, :fg_grid, :fggrid, :fgcolor_grid, :fg_color_grid, :foreground_grid, - :foreground_colour_grid, :fgcolour_grid, :fg_colour_grid, :gridcolor) -add_aliases(:foreground_color_minor_grid, :fg_minor_grid, :fgminorgrid, :fgcolor_minorgrid, :fg_color_minorgrid, :foreground_minorgrid, - :foreground_colour_minor_grid, :fgcolour_minorgrid, :fg_colour_minor_grid, :minorgridcolor) -add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_color_title, :foreground_title, - :foreground_colour_title, :fgcolour_title, :fg_colour_title, :titlecolor) -add_aliases(:foreground_color_axis, :fg_axis, :fgaxis, :fgcolor_axis, :fg_color_axis, :foreground_axis, - :foreground_colour_axis, :fgcolour_axis, :fg_colour_axis, :axiscolor) -add_aliases(:foreground_color_border, :fg_border, :fgborder, :fgcolor_border, :fg_color_border, :foreground_border, - :foreground_colour_border, :fgcolour_border, :fg_colour_border, :bordercolor) -add_aliases(:foreground_color_text, :fg_text, :fgtext, :fgcolor_text, :fg_color_text, :foreground_text, - :foreground_colour_text, :fgcolour_text, :fg_colour_text, :textcolor) -add_aliases(:foreground_color_guide, :fg_guide, :fgguide, :fgcolor_guide, :fg_color_guide, :foreground_guide, - :foreground_colour_guide, :fgcolour_guide, :fg_colour_guide, :guidecolor) +add_aliases( + :background_color, + :bg, + :bgcolor, + :bg_color, + :background, + :background_colour, + :bgcolour, + :bg_colour, +) +add_aliases( + :background_color_legend, + :bg_legend, + :bglegend, + :bgcolor_legend, + :bg_color_legend, + :background_legend, + :background_colour_legend, + :bgcolour_legend, + :bg_colour_legend, +) +add_aliases( + :background_color_subplot, + :bg_subplot, + :bgsubplot, + :bgcolor_subplot, + :bg_color_subplot, + :background_subplot, + :background_colour_subplot, + :bgcolour_subplot, + :bg_colour_subplot, +) +add_aliases( + :background_color_inside, + :bg_inside, + :bginside, + :bgcolor_inside, + :bg_color_inside, + :background_inside, + :background_colour_inside, + :bgcolour_inside, + :bg_colour_inside, +) +add_aliases( + :background_color_outside, + :bg_outside, + :bgoutside, + :bgcolor_outside, + :bg_color_outside, + :background_outside, + :background_colour_outside, + :bgcolour_outside, + :bg_colour_outside, +) +add_aliases( + :foreground_color, + :fg, + :fgcolor, + :fg_color, + :foreground, + :foreground_colour, + :fgcolour, + :fg_colour, +) +add_aliases( + :foreground_color_legend, + :fg_legend, + :fglegend, + :fgcolor_legend, + :fg_color_legend, + :foreground_legend, + :foreground_colour_legend, + :fgcolour_legend, + :fg_colour_legend, +) +add_aliases( + :foreground_color_subplot, + :fg_subplot, + :fgsubplot, + :fgcolor_subplot, + :fg_color_subplot, + :foreground_subplot, + :foreground_colour_subplot, + :fgcolour_subplot, + :fg_colour_subplot, +) +add_aliases( + :foreground_color_grid, + :fg_grid, + :fggrid, + :fgcolor_grid, + :fg_color_grid, + :foreground_grid, + :foreground_colour_grid, + :fgcolour_grid, + :fg_colour_grid, + :gridcolor, +) +add_aliases( + :foreground_color_minor_grid, + :fg_minor_grid, + :fgminorgrid, + :fgcolor_minorgrid, + :fg_color_minorgrid, + :foreground_minorgrid, + :foreground_colour_minor_grid, + :fgcolour_minorgrid, + :fg_colour_minor_grid, + :minorgridcolor, +) +add_aliases( + :foreground_color_title, + :fg_title, + :fgtitle, + :fgcolor_title, + :fg_color_title, + :foreground_title, + :foreground_colour_title, + :fgcolour_title, + :fg_colour_title, + :titlecolor, +) +add_aliases( + :foreground_color_axis, + :fg_axis, + :fgaxis, + :fgcolor_axis, + :fg_color_axis, + :foreground_axis, + :foreground_colour_axis, + :fgcolour_axis, + :fg_colour_axis, + :axiscolor, +) +add_aliases( + :foreground_color_border, + :fg_border, + :fgborder, + :fgcolor_border, + :fg_color_border, + :foreground_border, + :foreground_colour_border, + :fgcolour_border, + :fg_colour_border, + :bordercolor, +) +add_aliases( + :foreground_color_text, + :fg_text, + :fgtext, + :fgcolor_text, + :fg_color_text, + :foreground_text, + :foreground_colour_text, + :fgcolour_text, + :fg_colour_text, + :textcolor, +) +add_aliases( + :foreground_color_guide, + :fg_guide, + :fgguide, + :fgcolor_guide, + :fg_color_guide, + :foreground_guide, + :foreground_colour_guide, + :fgcolour_guide, + :fg_colour_guide, + :guidecolor, +) # alphas add_aliases(:seriesalpha, :alpha, :α, :opacity) @@ -672,11 +877,29 @@ add_aliases(:zlims, :zlim, :zlimit, :zlimits) add_aliases(:zticks, :ztick) add_aliases(:zrotation, :zrot, :zr) add_aliases(:guidefontsize, :labelfontsize) -add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor, :surfcolour) +add_aliases( + :fill_z, + :fillz, + :fz, + :surfacecolor, + :surfacecolour, + :sc, + :surfcolor, + :surfcolour, +) add_aliases(:legend, :leg, :key) add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title) add_aliases(:colorbar, :cb, :cbar, :colorkey) -add_aliases(:colorbar_title, :colorbartitle, :cb_title, :cbtitle, :cbartitle, :cbar_title, :colorkeytitle, :colorkey_title) +add_aliases( + :colorbar_title, + :colorbartitle, + :cb_title, + :cbtitle, + :cbartitle, + :cbar_title, + :colorkeytitle, + :colorkey_title, +) add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits) add_aliases(:smooth, :regression, :reg) add_aliases(:levels, :nlevels, :nlev, :levs) @@ -694,18 +917,75 @@ add_aliases(:show_empty_bins, :showemptybins, :showempty, :show_empty) add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio) add_aliases(:subplot, :sp, :subplt, :splt) add_aliases(:projection, :proj) -add_aliases(:titlelocation, :title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment) -add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation, :text, :txt, :texts, :txts) +add_aliases( + :titlelocation, + :title_location, + :title_loc, + :titleloc, + :title_position, + :title_pos, + :titlepos, + :titleposition, + :title_align, + :title_alignment, +) +add_aliases( + :series_annotations, + :series_ann, + :seriesann, + :series_anns, + :seriesanns, + :series_annotation, + :text, + :txt, + :texts, + :txts, +) add_aliases(:html_output_format, :format, :fmt, :html_format) add_aliases(:orientation, :direction, :dir) add_aliases(:inset_subplots, :inset, :floating) add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str) add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw) add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls) -add_aliases(:minorgridlinewidth, :minorgridwidth, :minorgrid_linewidth, :minorgrid_width, :minorgridlw, :minorgrid_lw) -add_aliases(:minorgridstyle, :minorgrid_style, :minorgridlinestyle, :minorgrid_linestyle, :minorgrid_ls, :minorgridls) -add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border) -add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor) +add_aliases( + :minorgridlinewidth, + :minorgridwidth, + :minorgrid_linewidth, + :minorgrid_width, + :minorgridlw, + :minorgrid_lw, +) +add_aliases( + :minorgridstyle, + :minorgrid_style, + :minorgridlinestyle, + :minorgrid_linestyle, + :minorgrid_ls, + :minorgridls, +) +add_aliases( + :framestyle, + :frame_style, + :frame, + :axesstyle, + :axes_style, + :boxstyle, + :box_style, + :box, + :borderstyle, + :border_style, + :border, +) +add_aliases( + :tick_direction, + :tickdirection, + :tick_dir, + :tickdir, + :tick_orientation, + :tickorientation, + :tick_or, + :tickor, +) add_aliases(:camera, :cam, :viewangle, :view_angle) add_aliases(:contour_labels, :contourlabels, :clabels, :clabs) add_aliases(:warn_on_unsupported, :warn) @@ -723,7 +1003,7 @@ function parse_axis_kw(s::Symbol) s = string(s) for letter in ('x', 'y', 'z') if startswith(s, letter) - return (Symbol(letter), Symbol(chop(s, head=1, tail=0))) + return (Symbol(letter), Symbol(chop(s, head = 1, tail = 0))) end end return nothing @@ -781,7 +1061,7 @@ function default(; reset = true, kw...) end kw = KW(kw) RecipesPipeline.preprocess_attributes!(kw) - for (k,v) in kw + for (k, v) in kw default(k, v) end end @@ -812,107 +1092,116 @@ function handleColors!(plotattributes::AKW, arg, csym::Symbol) false end - - function processLineArg(plotattributes::AKW, arg) # seriestype if allLineTypes(arg) plotattributes[:seriestype] = arg - # linestyle + # linestyle elseif allStyles(arg) plotattributes[:linestyle] = arg elseif typeof(arg) <: Stroke arg.width === nothing || (plotattributes[:linewidth] = arg.width) - arg.color === nothing || (plotattributes[:linecolor] = arg.color == :auto ? :auto : plot_color(arg.color)) + arg.color === nothing || ( + plotattributes[:linecolor] = + arg.color == :auto ? :auto : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[:linealpha] = arg.alpha) arg.style === nothing || (plotattributes[:linestyle] = arg.style) elseif typeof(arg) <: Brush - arg.size === nothing || (plotattributes[:fillrange] = arg.size) - arg.color === nothing || (plotattributes[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color)) + arg.size === nothing || (plotattributes[:fillrange] = arg.size) + arg.color === nothing || ( + plotattributes[:fillcolor] = + arg.color == :auto ? :auto : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha) elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows) plotattributes[:arrow] = arg - # linealpha + # linealpha elseif allAlphas(arg) plotattributes[:linealpha] = arg - # linewidth + # linewidth elseif allReals(arg) plotattributes[:linewidth] = arg - # color + # color elseif !handleColors!(plotattributes, arg, :linecolor) @warn("Skipped line arg $arg.") - end end - function processMarkerArg(plotattributes::AKW, arg) # markershape if allShapes(arg) plotattributes[:markershape] = arg - # stroke style + # stroke style elseif allStyles(arg) plotattributes[:markerstrokestyle] = arg elseif typeof(arg) <: Stroke arg.width === nothing || (plotattributes[:markerstrokewidth] = arg.width) - arg.color === nothing || (plotattributes[:markerstrokecolor] = arg.color == :auto ? :auto : plot_color(arg.color)) + arg.color === nothing || ( + plotattributes[:markerstrokecolor] = + arg.color == :auto ? :auto : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[:markerstrokealpha] = arg.alpha) arg.style === nothing || (plotattributes[:markerstrokestyle] = arg.style) elseif typeof(arg) <: Brush - arg.size === nothing || (plotattributes[:markersize] = arg.size) - arg.color === nothing || (plotattributes[:markercolor] = arg.color == :auto ? :auto : plot_color(arg.color)) + arg.size === nothing || (plotattributes[:markersize] = arg.size) + arg.color === nothing || ( + plotattributes[:markercolor] = + arg.color == :auto ? :auto : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[:markeralpha] = arg.alpha) - # linealpha + # linealpha elseif allAlphas(arg) plotattributes[:markeralpha] = arg - # bool + # bool elseif typeof(arg) <: Bool plotattributes[:markershape] = arg ? :circle : :none - # markersize + # markersize elseif allReals(arg) plotattributes[:markersize] = arg - # markercolor + # markercolor elseif !handleColors!(plotattributes, arg, :markercolor) @warn("Skipped marker arg $arg.") - end end - function processFillArg(plotattributes::AKW, arg) # fr = get(plotattributes, :fillrange, 0) if typeof(arg) <: Brush - arg.size === nothing || (plotattributes[:fillrange] = arg.size) - arg.color === nothing || (plotattributes[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color)) + arg.size === nothing || (plotattributes[:fillrange] = arg.size) + arg.color === nothing || ( + plotattributes[:fillcolor] = + arg.color == :auto ? :auto : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha) elseif typeof(arg) <: Bool plotattributes[:fillrange] = arg ? 0 : nothing - # fillrange function + # fillrange function elseif allFunctions(arg) plotattributes[:fillrange] = arg - # fillalpha + # fillalpha elseif allAlphas(arg) plotattributes[:fillalpha] = arg - # fillrange provided as vector or number - elseif typeof(arg) <: Union{AbstractArray{<:Real}, Real} + # fillrange provided as vector or number + elseif typeof(arg) <: Union{AbstractArray{<:Real},Real} plotattributes[:fillrange] = arg elseif !handleColors!(plotattributes, arg, :fillcolor) @@ -922,7 +1211,6 @@ function processFillArg(plotattributes::AKW, arg) return end - function processGridArg!(plotattributes::AKW, arg, letter) if arg in _allGridArgs || isa(arg, Bool) plotattributes[Symbol(letter, :grid)] = hasgrid(arg, letter) @@ -931,23 +1219,26 @@ function processGridArg!(plotattributes::AKW, arg, letter) plotattributes[Symbol(letter, :gridstyle)] = arg elseif typeof(arg) <: Stroke - arg.width === nothing || (plotattributes[Symbol(letter, :gridlinewidth)] = arg.width) - arg.color === nothing || (plotattributes[Symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color)) + arg.width === nothing || + (plotattributes[Symbol(letter, :gridlinewidth)] = arg.width) + arg.color === nothing || ( + plotattributes[Symbol(letter, :foreground_color_grid)] = + arg.color in (:auto, :match) ? :match : plot_color(arg.color) + ) arg.alpha === nothing || (plotattributes[Symbol(letter, :gridalpha)] = arg.alpha) arg.style === nothing || (plotattributes[Symbol(letter, :gridstyle)] = arg.style) - # linealpha + # linealpha elseif allAlphas(arg) plotattributes[Symbol(letter, :gridalpha)] = arg - # linewidth + # linewidth elseif allReals(arg) plotattributes[Symbol(letter, :gridlinewidth)] = arg - # color + # color elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_grid)) @warn("Skipped grid arg $arg.") - end end @@ -960,23 +1251,29 @@ function processMinorGridArg!(plotattributes::AKW, arg, letter) plotattributes[Symbol(letter, :minorgrid)] = true elseif typeof(arg) <: Stroke - arg.width === nothing || (plotattributes[Symbol(letter, :minorgridlinewidth)] = arg.width) - arg.color === nothing || (plotattributes[Symbol(letter, :foreground_color_minor_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color)) - arg.alpha === nothing || (plotattributes[Symbol(letter, :minorgridalpha)] = arg.alpha) - arg.style === nothing || (plotattributes[Symbol(letter, :minorgridstyle)] = arg.style) + arg.width === nothing || + (plotattributes[Symbol(letter, :minorgridlinewidth)] = arg.width) + arg.color === nothing || ( + plotattributes[Symbol(letter, :foreground_color_minor_grid)] = + arg.color in (:auto, :match) ? :match : plot_color(arg.color) + ) + arg.alpha === nothing || + (plotattributes[Symbol(letter, :minorgridalpha)] = arg.alpha) + arg.style === nothing || + (plotattributes[Symbol(letter, :minorgridstyle)] = arg.style) plotattributes[Symbol(letter, :minorgrid)] = true - # linealpha + # linealpha elseif allAlphas(arg) plotattributes[Symbol(letter, :minorgridalpha)] = arg plotattributes[Symbol(letter, :minorgrid)] = true - # linewidth + # linewidth elseif allReals(arg) plotattributes[Symbol(letter, :minorgridlinewidth)] = arg plotattributes[Symbol(letter, :minorgrid)] = true - # color + # color elseif handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_minor_grid)) plotattributes[Symbol(letter, :minorgrid)] = true else @@ -1124,7 +1421,8 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end # fonts - for fontname in (:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont) + for fontname in + (:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont) args = RecipesPipeline.pop_kw!(plotattributes, fontname, ()) for arg in wraptuple(args) processFontArg!(plotattributes, fontname, arg) @@ -1136,7 +1434,8 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) processLineArg(plotattributes, arg) end - if haskey(plotattributes, :seriestype) && haskey(_typeAliases, plotattributes[:seriestype]) + if haskey(plotattributes, :seriestype) && + haskey(_typeAliases, plotattributes[:seriestype]) plotattributes[:seriestype] = _typeAliases[plotattributes[:seriestype]] end @@ -1149,7 +1448,9 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) RecipesPipeline.reset_kw!(plotattributes, :marker) if haskey(plotattributes, :markershape) plotattributes[:markershape] = _replace_markershape(plotattributes[:markershape]) - if plotattributes[:markershape] == :none && get(plotattributes, :seriestype, :path) in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected + if plotattributes[:markershape] == :none && + get(plotattributes, :seriestype, :path) in + (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected plotattributes[:markershape] = :circle end elseif anymarker @@ -1164,10 +1465,11 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) # handle series annotations if haskey(plotattributes, :series_annotations) - plotattributes[:series_annotations] = series_annotations(wraptuple(plotattributes[:series_annotations])...) + plotattributes[:series_annotations] = + series_annotations(wraptuple(plotattributes[:series_annotations])...) end - # convert into strokes and brushes + # convert into strokes and brushes if haskey(plotattributes, :arrow) a = plotattributes[:arrow] @@ -1182,7 +1484,6 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end end - # if get(plotattributes, :arrow, false) == true # plotattributes[:arrow] = arrow() # end @@ -1196,19 +1497,21 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end # framestyle - if haskey(plotattributes, :framestyle) && haskey(_framestyleAliases, plotattributes[:framestyle]) + if haskey(plotattributes, :framestyle) && + haskey(_framestyleAliases, plotattributes[:framestyle]) plotattributes[:framestyle] = _framestyleAliases[plotattributes[:framestyle]] end # warnings for moved recipes st = get(plotattributes, :seriestype, :path) if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots) - @warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`") + @warn( + "seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`" + ) end return end - # ----------------------------------------------------------------------------- const _already_warned = Dict{Symbol,Set{Symbol}}() @@ -1231,10 +1534,12 @@ function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes) end if !isempty(_to_warn) && - !get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported]) + !get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported]) for k in sort(collect(_to_warn)) push!(already_warned, k) - @warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))") + @warn( + "Keyword argument $k not supported with $pkg. Choose from: $(supported_attrs(pkg))" + ) end end return extra_kwargs @@ -1249,13 +1554,19 @@ function warn_on_unsupported(pkg::AbstractBackend, plotattributes) return end if !is_seriestype_supported(pkg, plotattributes[:seriestype]) - @warn("seriestype $(plotattributes[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))") + @warn( + "seriestype $(plotattributes[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))" + ) end if !is_style_supported(pkg, plotattributes[:linestyle]) - @warn("linestyle $(plotattributes[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))") + @warn( + "linestyle $(plotattributes[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))" + ) end if !is_marker_supported(pkg, plotattributes[:markershape]) - @warn("markershape $(plotattributes[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))") + @warn( + "markershape $(plotattributes[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))" + ) end end @@ -1267,13 +1578,14 @@ function warn_on_unsupported_scales(pkg::AbstractBackend, plotattributes::AKW) if haskey(plotattributes, k) v = plotattributes[k] if !is_scale_supported(pkg, v) - @warn("scale $v is unsupported with $pkg. Choose from: $(supported_scales(pkg))") + @warn( + "scale $v is unsupported with $pkg. Choose from: $(supported_scales(pkg))" + ) end end end end - # ----------------------------------------------------------------------------- function convertLegendValue(val::Symbol) @@ -1281,7 +1593,28 @@ function convertLegendValue(val::Symbol) :best elseif val in (:no, :none) :none - elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright, :outertopleft, :outertop, :outerright, :outerleft, :outerbottomright, :outerbottomleft, :outerbottom, :inline) + elseif val in ( + :right, + :left, + :top, + :bottom, + :inside, + :best, + :legend, + :topright, + :topleft, + :bottomleft, + :bottomright, + :outertopright, + :outertopleft, + :outertop, + :outerright, + :outerleft, + :outerbottomright, + :outerbottomleft, + :outerbottom, + :inline, + ) val else error("Invalid symbol for legend: $val") @@ -1289,38 +1622,42 @@ function convertLegendValue(val::Symbol) end convertLegendValue(val::Bool) = val ? :best : :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) # ----------------------------------------------------------------------------- - # 1-row matrices will give an element # multi-row matrices will give a column # InputWrapper just gives the contents # anything else is returned as-is function slice_arg(v::AMat, idx::Int) - c = mod1(idx, size(v,2)) - m,n = axes(v) - size(v,1) == 1 ? v[first(m),n[c]] : v[:,n[c]] + c = mod1(idx, size(v, 2)) + m, n = axes(v) + size(v, 1) == 1 ? v[first(m), n[c]] : v[:, n[c]] end slice_arg(wrapper::InputWrapper, idx) = wrapper.obj slice_arg(v, idx) = v - # given an argument key (k), extract the argument value for this index, # and set into plotattributes[k]. Matrices are sliced by column. # if nothing is set (or container is empty), return the existing value. -function slice_arg!(plotattributes_in, plotattributes_out, - k::Symbol, idx::Int, remove_pair::Bool) +function slice_arg!( + plotattributes_in, + plotattributes_out, + k::Symbol, + idx::Int, + remove_pair::Bool, +) v = get(plotattributes_in, k, plotattributes_out[k]) - plotattributes_out[k] = if haskey(plotattributes_in, k) && typeof(v) <: AMat && !isempty(v) - slice_arg(v, idx) - else - v - end + plotattributes_out[k] = + if haskey(plotattributes_in, k) && typeof(v) <: AMat && !isempty(v) + slice_arg(v, idx) + else + v + end if remove_pair RecipesPipeline.reset_kw!(plotattributes_in, k) end @@ -1384,15 +1721,15 @@ const _match_map = KW( const _match_map2 = KW( :background_color_subplot => :background_color, :foreground_color_subplot => :foreground_color, - :foreground_color_axis => :foreground_color_subplot, - :foreground_color_border => :foreground_color_subplot, - :foreground_color_grid => :foreground_color_subplot, - :foreground_color_minor_grid=> :foreground_color_subplot, - :foreground_color_guide => :foreground_color_subplot, - :foreground_color_text => :foreground_color_subplot, - :fontfamily_subplot => :fontfamily, - :tickfontfamily => :fontfamily_subplot, - :guidefontfamily => :fontfamily_subplot, + :foreground_color_axis => :foreground_color_subplot, + :foreground_color_border => :foreground_color_subplot, + :foreground_color_grid => :foreground_color_subplot, + :foreground_color_minor_grid => :foreground_color_subplot, + :foreground_color_guide => :foreground_color_subplot, + :foreground_color_text => :foreground_color_subplot, + :fontfamily_subplot => :fontfamily, + :tickfontfamily => :fontfamily_subplot, + :guidefontfamily => :fontfamily_subplot, ) # properly retrieve from plt.attr, passing `:match` to the correct key @@ -1405,7 +1742,6 @@ function Base.getindex(plt::Plot, k::Symbol) end end - # properly retrieve from sp.attr, passing `:match` to the correct key function Base.getindex(sp::Subplot, k::Symbol) v = sp.attr[k] @@ -1420,7 +1756,6 @@ function Base.getindex(sp::Subplot, k::Symbol) end end - # properly retrieve from axis.attr, passing `:match` to the correct key function Base.getindex(axis::Axis, k::Symbol) v = axis.plotattributes[k] @@ -1447,7 +1782,6 @@ Base.get(sp::Subplot, k::Symbol, v) = get(sp.attr, k, v) Base.get(axis::Axis, k::Symbol, v) = get(axis.plotattributes, k, v) Base.get(series::Series, k::Symbol, v) = get(series.plotattributes, k, v) - # ----------------------------------------------------------------------------- function fg_color(plotattributes::AKW) @@ -1469,16 +1803,14 @@ function fg_color_sp(plotattributes::AKW) end end - - # update attr from an input dictionary function _update_plot_args(plt::Plot, plotattributes_in::AKW) - for (k,v) in _plot_defaults + for (k, v) in _plot_defaults slice_arg!(plotattributes_in, plt.attr, k, 1, true) end # handle colors - plotattributes= plt.attr + plotattributes = plt.attr plt[:background_color] = plot_color(plotattributes[:background_color]) plt[:foreground_color] = fg_color(plotattributes) # bg = plot_color(plt.attr[:background_color]) @@ -1524,7 +1856,13 @@ function _update_subplot_colors(sp::Subplot) return end -function _update_axis(plt::Plot, sp::Subplot, plotattributes_in::AKW, letter::Symbol, subplot_index::Int) +function _update_axis( + plt::Plot, + sp::Subplot, + plotattributes_in::AKW, + letter::Symbol, + subplot_index::Int, +) # get (maybe initialize) the axis axis = get_axis(sp, letter) @@ -1540,7 +1878,12 @@ function _update_axis(plt::Plot, sp::Subplot, plotattributes_in::AKW, letter::Sy return end -function _update_axis(axis::Axis, plotattributes_in::AKW, letter::Symbol, subplot_index::Int) +function _update_axis( + axis::Axis, + plotattributes_in::AKW, + letter::Symbol, + subplot_index::Int, +) # build the KW of arguments from the letter version (i.e. xticks --> ticks) kw = KW() for k in _all_axis_args @@ -1588,7 +1931,13 @@ function _update_axis_links(plt::Plot, axis::Axis, letter::Symbol) end # update a subplots args and axes -function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in, subplot_index::Int, remove_pair::Bool) +function _update_subplot_args( + plt::Plot, + sp::Subplot, + plotattributes_in, + subplot_index::Int, + remove_pair::Bool, +) anns = RecipesPipeline.pop_kw!(sp.attr, :annotations) # # grab those args which apply to this subplot @@ -1605,7 +1954,9 @@ function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in, subplot lk = Symbol(letter, :lims) # warn against using `Range` in x,y,z lims - if !lims_warned && haskey(plotattributes_in, lk) && plotattributes_in[lk] isa AbstractRange + if !lims_warned && + haskey(plotattributes_in, lk) && + plotattributes_in[lk] isa AbstractRange @warn("lims should be a Tuple, not $(typeof(plotattributes_in[lk])).") lims_warned = true end @@ -1615,9 +1966,13 @@ end # ----------------------------------------------------------------------------- -has_black_border_for_default(st) = error("The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.") -has_black_border_for_default(st::Function) = error("The seriestype attribute only accepts Symbols, you passed the function $st.") -has_black_border_for_default(st::Symbol) = like_histogram(st) || st in (:hexbin, :bar, :shape) +has_black_border_for_default(st) = error( + "The seriestype attribute only accepts Symbols, you passed the $(typeof(st)) $st.", +) +has_black_border_for_default(st::Function) = + error("The seriestype attribute only accepts Symbols, you passed the function $st.") +has_black_border_for_default(st::Symbol) = + like_histogram(st) || st in (:hexbin, :bar, :shape) # converts a symbol or string into a Colorant or ColorGradient # and assigns a color automatically @@ -1630,7 +1985,8 @@ function get_series_color(c, sp::Subplot, n::Int, seriestype) plot_color(c) end -get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype) = map(x->get_series_color(x, sp, n, seriestype), c) +get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype) = + map(x -> get_series_color(x, sp, n, seriestype), c) function ensure_gradient!(plotattributes::AKW, csym::Symbol, asym::Symbol) if plotattributes[csym] isa ColorPalette @@ -1640,31 +1996,37 @@ function ensure_gradient!(plotattributes::AKW, csym::Symbol, asym::Symbol) end plotattributes[csym] = cgrad(plotattributes[csym], categorical = true, alpha = α) elseif !(plotattributes[csym] isa ColorGradient) - plotattributes[csym] = typeof(plotattributes[asym]) <: AbstractVector ? cgrad() : cgrad(alpha = plotattributes[asym]) + plotattributes[csym] = + typeof(plotattributes[asym]) <: AbstractVector ? cgrad() : + cgrad(alpha = plotattributes[asym]) end end function _replace_linewidth(plotattributes::AKW) # get a good default linewidth... 0 for surface and heatmaps if plotattributes[:linewidth] == :auto - plotattributes[:linewidth] = (get(plotattributes, :seriestype, :path) in (:surface,:heatmap,:image) ? 0 : 1) + plotattributes[:linewidth] = ( + get(plotattributes, :seriestype, :path) in (:surface, :heatmap, :image) ? 0 : 1 + ) end end function _slice_series_args!(plotattributes::AKW, plt::Plot, sp::Subplot, commandIndex::Int) for k in keys(_series_defaults) - haskey(plotattributes, k) && slice_arg!(plotattributes, plotattributes, k, commandIndex, false) + haskey(plotattributes, k) && + slice_arg!(plotattributes, plotattributes, k, commandIndex, false) end return plotattributes end -label_to_string(label::Bool, series_plotindex) = label ? label_to_string(:auto, series_plotindex) : "" +label_to_string(label::Bool, series_plotindex) = + label ? label_to_string(:auto, series_plotindex) : "" label_to_string(label::Nothing, series_plotindex) = "" label_to_string(label::Missing, series_plotindex) = "" function label_to_string(label::Symbol, series_plotindex) - if label==:auto + if label == :auto return string("y", series_plotindex) - elseif label==:none + elseif label == :none return "" else throw(ArgumentError("unsupported symbol $(label) passed to `label`")) @@ -1677,8 +2039,20 @@ function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot) globalIndex = plotattributes[:series_plotindex] plotIndex = _series_index(plotattributes, sp) - aliasesAndAutopick(plotattributes, :linestyle, _styleAliases, supported_styles(pkg), plotIndex) - aliasesAndAutopick(plotattributes, :markershape, _markerAliases, supported_markers(pkg), plotIndex) + aliasesAndAutopick( + plotattributes, + :linestyle, + _styleAliases, + supported_styles(pkg), + plotIndex, + ) + aliasesAndAutopick( + plotattributes, + :markershape, + _markerAliases, + supported_markers(pkg), + plotIndex, + ) # update alphas for asym in (:linealpha, :markeralpha, :fillalpha) @@ -1697,7 +2071,7 @@ function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot) # update other colors for s in (:line, :marker, :fill) - csym, asym = Symbol(s,:color), Symbol(s,:alpha) + csym, asym = Symbol(s, :color), Symbol(s, :alpha) plotattributes[csym] = if plotattributes[csym] == :auto plot_color(if has_black_border_for_default(stype) && s == :line sp[:foreground_color_subplot] @@ -1743,7 +2117,7 @@ function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot) plotattributes[:label] = label_to_string.(plotattributes[:label], globalIndex) _replace_linewidth(plotattributes) - plotattributes + plotattributes end function _series_index(plotattributes, sp) @@ -1764,7 +2138,7 @@ end #-------------------------------------------------- ## inspired by Base.@kwdef -macro add_attributes( level, expr ) +macro add_attributes(level, expr) expr = macroexpand(__module__, expr) # to expand @static expr isa Expr && expr.head === :struct || error("Invalid usage of @add_attributes") T = expr.args[2] @@ -1782,18 +2156,32 @@ macro add_attributes( level, expr ) # e.g. _series_defualts[key] = value exp_key = Symbol(lowercase(string(T)), "_", key) pl_key = makeplural(exp_key) - push!(insert_block.args, Expr( - :(=), Expr(:ref, Symbol("_", level, "_defaults"), QuoteNode(exp_key)), value - )) - push!(insert_block.args, :( - add_aliases($(QuoteNode(exp_key)), $(QuoteNode(pl_key))) - )) - push!(insert_block.args, :( - add_aliases($(QuoteNode(exp_key)), $(QuoteNode(make_non_underscore(exp_key)))) - )) - push!(insert_block.args, :( - add_aliases($(QuoteNode(exp_key)), $(QuoteNode(make_non_underscore(pl_key)))) - )) + push!( + insert_block.args, + Expr( + :(=), + Expr(:ref, Symbol("_", level, "_defaults"), QuoteNode(exp_key)), + value, + ), + ) + push!( + insert_block.args, + :(add_aliases($(QuoteNode(exp_key)), $(QuoteNode(pl_key)))), + ) + push!( + insert_block.args, + :(add_aliases( + $(QuoteNode(exp_key)), + $(QuoteNode(make_non_underscore(exp_key))), + )), + ) + push!( + insert_block.args, + :(add_aliases( + $(QuoteNode(exp_key)), + $(QuoteNode(make_non_underscore(pl_key))), + )), + ) end return quote $expr diff --git a/src/axes.jl b/src/axes.jl index fc99e5b8..31c339ee 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -1,5 +1,4 @@ - # xaxis(args...; kw...) = Axis(:x, args...; kw...) # yaxis(args...; kw...) = Axis(:y, args...; kw...) # zaxis(args...; kw...) = Axis(:z, args...; kw...) @@ -36,42 +35,41 @@ function process_axis_arg!(plotattributes::AKW, arg, letter = "") T = typeof(arg) arg = get(_scaleAliases, arg, arg) if typeof(arg) <: Font - plotattributes[Symbol(letter,:tickfont)] = arg - plotattributes[Symbol(letter,:guidefont)] = arg + plotattributes[Symbol(letter, :tickfont)] = arg + plotattributes[Symbol(letter, :guidefont)] = arg elseif arg in _allScales - plotattributes[Symbol(letter,:scale)] = arg + plotattributes[Symbol(letter, :scale)] = arg elseif arg in (:flip, :invert, :inverted) - plotattributes[Symbol(letter,:flip)] = true + plotattributes[Symbol(letter, :flip)] = true elseif T <: AbstractString - plotattributes[Symbol(letter,:guide)] = arg + plotattributes[Symbol(letter, :guide)] = arg - # xlims/ylims + # xlims/ylims elseif (T <: Tuple || T <: AVec) && length(arg) == 2 sym = typeof(arg[1]) <: Number ? :lims : :ticks - plotattributes[Symbol(letter,sym)] = arg + plotattributes[Symbol(letter, sym)] = arg - # xticks/yticks + # xticks/yticks elseif T <: AVec - plotattributes[Symbol(letter,:ticks)] = arg + plotattributes[Symbol(letter, :ticks)] = arg elseif arg === nothing - plotattributes[Symbol(letter,:ticks)] = [] + plotattributes[Symbol(letter, :ticks)] = [] elseif T <: Bool || arg in _allShowaxisArgs - plotattributes[Symbol(letter,:showaxis)] = showaxis(arg, letter) + plotattributes[Symbol(letter, :showaxis)] = showaxis(arg, letter) elseif typeof(arg) <: Number - plotattributes[Symbol(letter,:rotation)] = arg + plotattributes[Symbol(letter, :rotation)] = arg elseif typeof(arg) <: Function - plotattributes[Symbol(letter,:formatter)] = arg + plotattributes[Symbol(letter, :formatter)] = arg elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis)) @warn("Skipped $(letter)axis arg $arg") - end end @@ -87,15 +85,15 @@ function attr!(axis::Axis, args...; kw...) RecipesPipeline.preprocess_attributes!(KW(kw)) # then override for any keywords... only those keywords that already exists in plotattributes - for (k,v) in kw + for (k, v) in kw if haskey(plotattributes, k) if k == :discrete_values # add these discrete values to the axis for vi in v discrete_value!(axis, vi) end - #could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType - # or could perhaps check if dateformatter or datetimeformatter is in use + #could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType + # or could perhaps check if dateformatter or datetimeformatter is in use elseif k == :lims && isa(v, Tuple{Date,Date}) plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value) elseif k == :lims && isa(v, Tuple{DateTime,DateTime}) @@ -122,11 +120,8 @@ Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k) ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax)) -const _label_func = Dict{Symbol,Function}( - :log10 => x -> "10^$x", - :log2 => x -> "2^$x", - :ln => x -> "e^$x", -) +const _label_func = + Dict{Symbol,Function}(:log10 => x -> "10^$x", :log2 => x -> "2^$x", :ln => x -> "e^$x") labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string) const _label_func_tex = Dict{Symbol,Function}( @@ -136,7 +131,6 @@ const _label_func_tex = Dict{Symbol,Function}( ) labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode) - function optimal_ticks_and_labels(ticks, alims, scale, formatter) amin, amax = alims @@ -158,8 +152,8 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter) # are converted to 'DateTime integers' (actually floats) before # being passed to optimize_datetime_ticks. # (convert(Int, convert(DateTime, convert(Date, i))) == 87600000*i) - ticks, labels = optimize_datetime_ticks(864e5 * amin, 864e5 * amax; - k_min = 2, k_max = 4) + ticks, labels = + optimize_datetime_ticks(864e5 * amin, 864e5 * amax; k_min = 2, k_max = 4) # Now the ticks are converted back to floats corresponding to Dates. return ticks / 864e5, labels elseif formatter == RecipesPipeline.datetimeformatter @@ -198,7 +192,10 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter) if formatter in (:auto, :plain, :scientific, :engineering) map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter)) elseif formatter == :latex - map(x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), Showoff.showoff(unscaled_ticks, :auto)) + map( + x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), + Showoff.showoff(unscaled_ticks, :auto), + ) else # there was an override for the formatter... use that on the unscaled ticks map(formatter, unscaled_ticks) @@ -223,16 +220,22 @@ function get_ticks(sp::Subplot, axis::Axis; update = true) if update || !haskey(axis.plotattributes, :optimized_ticks) dvals = axis[:discrete_values] ticks = _transform_ticks(axis[:ticks]) - axis.plotattributes[:optimized_ticks] = if ticks isa Symbol && ticks !== :none && - ispolar(sp) && axis[:letter] === :x && !isempty(dvals) - collect(0:pi/4:7pi/4), string.(0:45:315) - else - cvals = axis[:continuous_values] - alims = axis_limits(sp, axis[:letter]) - scale = axis[:scale] - formatter = axis[:formatter] - get_ticks(ticks, cvals, dvals, alims, scale, formatter) - end + axis.plotattributes[:optimized_ticks] = + if ( + ticks isa Symbol && + ticks !== :none && + ispolar(sp) && + axis[:letter] === :x && + !isempty(dvals) + ) + collect(0:(pi / 4):(7pi / 4)), string.(0:45:315) + else + cvals = axis[:continuous_values] + alims = axis_limits(sp, axis[:letter]) + scale = axis[:scale] + formatter = axis[:formatter] + get_ticks(ticks, cvals, dvals, alims, scale, formatter) + end end return axis.plotattributes[:optimized_ticks] end @@ -297,7 +300,7 @@ end get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[Symbol(s, :axis)]) get_ticks(p::Plot, s::Symbol) = [get_ticks(sp, s) for sp in p.subplots] -function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where T +function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where {T} if ticks === :none return T[], String[] elseif !isempty(dvals) @@ -316,21 +319,21 @@ end get_ticks(ticks::AVec, cvals, dvals, args...) = optimal_ticks_and_labels(ticks, args...) function get_ticks(ticks::Int, dvals, cvals, args...) if !isempty(dvals) - rng = round.(Int, range(1, stop=length(dvals), length=ticks)) + rng = round.(Int, range(1, stop = length(dvals), length = ticks)) cvals[rng], string.(dvals[rng]) else optimal_ticks_and_labels(ticks, args...) end end -get_ticks(ticks::NTuple{2, Any}, args...) = ticks -get_ticks(::Nothing, cvals::T, args...) where T = T[], String[] +get_ticks(ticks::NTuple{2,Any}, args...) = ticks +get_ticks(::Nothing, cvals::T, args...) where {T} = T[], String[] get_ticks(ticks::Bool, args...) = ticks ? get_ticks(:auto, args...) : get_ticks(nothing, args...) -get_ticks(::T, args...) where T = error("Unknown ticks type in get_ticks: $T") +get_ticks(::T, args...) where {T} = error("Unknown ticks type in get_ticks: $T") _transform_ticks(ticks) = ticks -_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks) -_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2]) +_transform_ticks(ticks::AbstractArray{T}) where {T<:Dates.TimeType} = Dates.value.(ticks) +_transform_ticks(ticks::NTuple{2,Any}) = (_transform_ticks(ticks[1]), ticks[2]) function get_minor_ticks(sp, axis, ticks) axis[:minorticks] ∈ (:none, nothing, false) && !axis[:minorgrid] && return nothing @@ -350,30 +353,36 @@ function get_minor_ticks(sp, axis, ticks) sub = 1 # unused ratio = length(ticks) > 2 ? (ticks[3] - ticks[2]) / (ticks[2] - ticks[1]) : 1 first_step = ticks[2] - ticks[1] - last_step = ticks[end] - ticks[end-1] + last_step = ticks[end] - ticks[end - 1] ticks = [ticks[1] - first_step / ratio; ticks; ticks[end] + last_step * ratio] end # default to 9 intervals between major ticks for log10 scale and 5 intervals otherwise n_default = (scale == :log10) ? 9 : 5 - n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : n_default + n = + typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : + n_default minorticks = typeof(ticks[1])[] - for (i, hi) ∈ enumerate(ticks[2:end]) + for (i, hi) in enumerate(ticks[2:end]) lo = ticks[i] if isfinite(lo) && isfinite(hi) && hi > lo if log_scaled - for e ∈ 1:sub + for e in 1:sub lo_ = lo * base^(e - 1) hi_ = lo_ * base step = (hi_ - lo_) / n - append!(minorticks, collect( - lo_ + (e > 1 ? 0 : step) : step : hi_ - (e < sub ? 0 : step / 2) - )) + append!( + minorticks, + collect( + (lo_ + (e > 1 ? 0 : step)):step:(hi_ - (e < sub ? 0 : + step / 2)), + ), + ) end else step = (hi - lo) / n - append!(minorticks, collect(lo + step : step : hi - step / 2)) + append!(minorticks, collect((lo + step):step:(hi - step / 2))) end end end @@ -382,17 +391,15 @@ end # ------------------------------------------------------------------------- - function reset_extrema!(sp::Subplot) - for asym in (:x,:y,:z) - sp[Symbol(asym,:axis)][:extrema] = Extrema() + for asym in (:x, :y, :z) + sp[Symbol(asym, :axis)][:extrema] = Extrema() end for series in sp.series_list expand_extrema!(sp, series.plotattributes) end end - function expand_extrema!(ex::Extrema, v::Number) ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax @@ -407,14 +414,13 @@ end expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema] expand_extrema!(axis::Axis, ::Bool) = axis[:extrema] - function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number} ex = axis[:extrema] ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax ex end -function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number +function expand_extrema!(axis::Axis, v::AVec{N}) where {N<:Number} ex = axis[:extrema] for vi in v expand_extrema!(ex, vi) @@ -422,7 +428,6 @@ function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number ex end - function expand_extrema!(sp::Subplot, plotattributes::AKW) vert = isvertical(plotattributes) @@ -433,7 +438,12 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) else letter == :x ? :y : letter == :y ? :x : :z end] - if letter != :z && plotattributes[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2] + if ( + letter != :z && + plotattributes[:seriestype] == :straightline && + any(series[:seriestype] != :straightline for series in series_list(sp)) && + data[1] != data[2] + ) data = [NaN] end axis = sp[Symbol(letter, "axis")] @@ -442,7 +452,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) expand_extrema!(sp[:xaxis], data.x_extents) expand_extrema!(sp[:yaxis], data.y_extents) expand_extrema!(sp[:zaxis], data.z_extents) - elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf)) + elseif eltype(data) <: Number || + (isa(data, Surface) && all(di -> isa(di, Number), data.surf)) if !(eltype(data) <: Number) # huh... must have been a mis-typed surface? lets swap it out data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf)) @@ -452,7 +463,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) # TODO: need more here... gotta track the discrete reference value # as well as any coord offset (think of boxplot shape coords... they all # correspond to the same x-value) - plotattributes[letter], plotattributes[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data) + plotattributes[letter], plotattributes[Symbol(letter, "_discrete_indices")] = + discrete_value!(axis, data) expand_extrema!(axis, plotattributes[letter]) end end @@ -486,7 +498,9 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) bw = plotattributes[:bar_width] if bw === nothing - bw = plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data)))) + bw = + plotattributes[:bar_width] = + _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(data)))) end axis = sp.attr[Symbol(dsym, :axis)] expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw)) @@ -512,7 +526,7 @@ end # ------------------------------------------------------------------------- # push the limits out slightly -function widen(lmin, lmax, scale=:identity) +function widen(lmin, lmax, scale = :identity) f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale) span = f(lmax) - f(lmin) # eps = NaNMath.max(1e-16, min(1e-2span, 1e-10)) @@ -521,7 +535,28 @@ function widen(lmin, lmax, scale=:identity) end # figure out if widening is a good idea. -const _widen_seriestypes = (:line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d) +const _widen_seriestypes = ( + :line, + :path, + :steppre, + :stepmid, + :steppost, + :sticks, + :scatter, + :barbins, + :barhist, + :histogram, + :scatterbins, + :scatterhist, + :stepbins, + :stephist, + :bins2d, + :histogram2d, + :bar, + :shape, + :path3d, + :scatter3d, +) function default_should_widen(axis::Axis) if axis[:widen] isa Bool @@ -540,7 +575,7 @@ function default_should_widen(axis::Axis) end function round_limits(amin, amax, scale) - base = get(_logScaleBases, scale, 10.) + base = get(_logScaleBases, scale, 10.0) factor = base^(1 - round(log(base, amax - amin))) amin = floor(amin * factor) / factor amax = ceil(amax * factor) / factor @@ -548,7 +583,12 @@ function round_limits(amin, amax, scale) end # using the axis extrema and limit overrides, return the min/max value for this axis -function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(letter, :axis)]), consider_aspect = true) +function axis_limits( + sp, + letter, + should_widen = default_should_widen(sp[Symbol(letter, :axis)]), + consider_aspect = true, +) axis = sp[Symbol(letter, :axis)] ex = axis[:extrema] amin, amax = ex.emin, ex.emax @@ -594,7 +634,9 @@ function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(l end if ( - !has_user_lims && consider_aspect && letter in (:x, :y) && + !has_user_lims && + consider_aspect && + letter in (:x, :y) && !(sp[:aspect_ratio] in (:none, :auto) || RecipesPipeline.is3d(:sp)) ) aspect_ratio = isa(sp[:aspect_ratio], Number) ? sp[:aspect_ratio] : 1 @@ -664,11 +706,11 @@ end # add the discrete value for each item. return the continuous values and the indices function discrete_value!(axis::Axis, v::AMat) - n,m = axes(v) + n, m = axes(v) cmat = zeros(axes(v)) discrete_indices = similar(Array{Int}, axes(v)) for i in n, j in m - cmat[i,j], discrete_indices[i,j] = discrete_value!(axis, v[i,j]) + cmat[i, j], discrete_indices[i, j] = discrete_value!(axis, v[i, j]) end cmat, discrete_indices end @@ -711,7 +753,11 @@ function axis_drawing_info(sp, letter) if sp[:framestyle] != :grid push!(segments, reverse_if((amin, oa1), isy), reverse_if((amax, oa1), isy)) # don't show the 0 tick label for the origin framestyle - if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1 + if ( + sp[:framestyle] == :origin && + !(ticks in (:none, nothing, false)) && + length(ticks) > 1 + ) i = findfirst(==(0), ticks[1]) if i !== nothing deleteat!(ticks[1], i) @@ -765,11 +811,23 @@ function axis_drawing_info(sp, letter) ax_length = letter === :x ? height(sp.plotarea).value : width(sp.plotarea).value # add major grid segments - add_major_or_minor_segments(ticks[1], ax[:grid], grid_segments, 1.2 / ax_length, ax[:tick_direction] !== :none) + add_major_or_minor_segments( + ticks[1], + ax[:grid], + grid_segments, + 1.2 / ax_length, + ax[:tick_direction] !== :none, + ) # add minor grid segments if ax[:minorticks] ∉ (:none, nothing, false) || ax[:minorgrid] - add_major_or_minor_segments(minor_ticks, ax[:minorgrid], minorgrid_segments, 0.6 / ax_length, true) + add_major_or_minor_segments( + minor_ticks, + ax[:minorgrid], + minorgrid_segments, + 0.6 / ax_length, + true, + ) end end end @@ -780,7 +838,7 @@ function axis_drawing_info(sp, letter) tick_segments = tick_segments, grid_segments = grid_segments, minorgrid_segments = minorgrid_segments, - border_segments = border_segments + border_segments = border_segments, ) end @@ -816,8 +874,7 @@ function axis_drawing_info_3d(sp, letter) minorgrid_segments = Segments(3) border_segments = Segments(3) - - if sp[:framestyle] != :none# && letter === :x + if sp[:framestyle] != :none # && letter === :x na0, na1 = if sp[:framestyle] in (:origin, :zerolines) 0, 0 else @@ -837,7 +894,11 @@ function axis_drawing_info_3d(sp, letter) sort_3d_axes(amax, na0, fa0, letter), ) # don't show the 0 tick label for the origin framestyle - if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1 + if ( + sp[:framestyle] == :origin && + !(ticks in (:none, nothing, false)) && + length(ticks) > 1 + ) i0 = findfirst(==(0), ticks[1]) if i0 !== nothing deleteat!(ticks[1], i0) @@ -857,7 +918,8 @@ function axis_drawing_info_3d(sp, letter) if ax[:ticks] ∉ (:none, nothing, false) f = RecipesPipeline.scale_func(nax[:scale]) invf = RecipesPipeline.inverse_scale_func(nax[:scale]) - ga0, ga1 = sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1) + ga0, ga1 = + sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1) add_major_or_minor_segments(ticks, grid, segments, factor, cond) = begin ticks === nothing && return @@ -898,11 +960,23 @@ function axis_drawing_info_3d(sp, letter) end # add major grid segments - add_major_or_minor_segments(ticks[1], ax[:grid], grid_segments, 0.012, ax[:tick_direction] !== :none) + add_major_or_minor_segments( + ticks[1], + ax[:grid], + grid_segments, + 0.012, + ax[:tick_direction] !== :none, + ) # add minor grid segments if ax[:minorticks] ∉ (:none, nothing, false) || ax[:minorgrid] - add_major_or_minor_segments(minor_ticks, ax[:minorgrid], minorgrid_segments, 0.006, true) + add_major_or_minor_segments( + minor_ticks, + ax[:minorgrid], + minorgrid_segments, + 0.006, + true, + ) end end end @@ -913,7 +987,7 @@ function axis_drawing_info_3d(sp, letter) tick_segments = tick_segments, grid_segments = grid_segments, minorgrid_segments = minorgrid_segments, - border_segments = border_segments + border_segments = border_segments, ) end diff --git a/src/backends.jl b/src/backends.jl index 961c274a..09247960 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -1,12 +1,12 @@ struct NoBackend <: AbstractBackend end -const _backendType = Dict{Symbol, DataType}(:none => NoBackend) -const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none) +const _backendType = Dict{Symbol,DataType}(:none => NoBackend) +const _backendSymbol = Dict{DataType,Symbol}(NoBackend => :none) const _backends = Symbol[] const _initialized_backends = Set{Symbol}() const _default_backends = (:none, :gr, :plotly) -const _backend_packages = Dict{Symbol, Symbol}() +const _backend_packages = Dict{Symbol,Symbol}() "Returns a list of supported backends" backends() = _backends @@ -66,10 +66,11 @@ function text_size(lablen::Int, sz::Number, rot::Number = 0) # now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz - width = abs(sind(rot+90)) * width + abs(cosd(rot+90)) * ptsz + width = abs(sind(rot + 90)) * width + abs(cosd(rot + 90)) * ptsz width, height end -text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot) +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 @@ -104,8 +105,8 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot) # TODO: something different when `RecipesPipeline.is3d(sp) == true` - leftpad = tick_padding(sp, sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis]) - toppad = sp[:top_margin] + title_padding(sp) + leftpad = tick_padding(sp, sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis]) + toppad = sp[:top_margin] + title_padding(sp) rightpad = sp[:right_margin] bottompad = tick_padding(sp, sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis]) @@ -125,10 +126,9 @@ _update_plot_object(plt::Plot) = nothing # --------------------------------------------------------- - mutable struct CurrentBackend - sym::Symbol - pkg::AbstractBackend + sym::Symbol + pkg::AbstractBackend end CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym)) @@ -143,8 +143,10 @@ function _pick_default_backend() if sym in _backends backend(sym) else - @warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t" * - join(sort(_backends), "\n\t")) + @warn( + "You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t" * + join(sort(_backends), "\n\t") + ) _fallback_default_backend() end else @@ -152,7 +154,6 @@ function _pick_default_backend() end end - # --------------------------------------------------------- """ @@ -189,7 +190,8 @@ function backend(sym::Symbol) end end -const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize, :pgfplots] +const _deprecated_backends = + [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize, :pgfplots] function warn_on_deprecated_backend(bsym::Symbol) if bsym in _deprecated_backends @@ -201,23 +203,29 @@ function warn_on_deprecated_backend(bsym::Symbol) end end - - # --------------------------------------------------------- # these are args which every backend supports because they're not used in the backend code const _base_supported_args = [ :color_palette, - :background_color, :background_color_subplot, - :foreground_color, :foreground_color_subplot, + :background_color, + :background_color_subplot, + :foreground_color, + :foreground_color_subplot, :group, :seriestype, - :seriescolor, :seriesalpha, + :seriescolor, + :seriesalpha, :smooth, - :xerror, :yerror, :zerror, + :xerror, + :yerror, + :zerror, :subplot, - :x, :y, :z, - :show, :size, + :x, + :y, + :z, + :show, + :size, :margin, :left_margin, :right_margin, @@ -231,23 +239,21 @@ const _base_supported_args = [ :subplot_index, :discrete_values, :projection, - :show_empty_bins + :show_empty_bins, ] function merge_with_base_supported(v::AVec) v = vcat(v, _base_supported_args) for vi in v if haskey(_axis_defaults, vi) - for letter in (:x,:y,:z) - push!(v, Symbol(letter,vi)) + for letter in (:x, :y, :z) + push!(v, Symbol(letter, vi)) end end end Set(v) end - - @init_backend PyPlot @init_backend UnicodePlots @init_backend Plotly @@ -286,7 +292,6 @@ end # is_subplot_supported(::AbstractBackend) = false # is_subplot_supported() = is_subplot_supported(backend()) - ################################################################################ # initialize the backends @@ -305,39 +310,91 @@ _initialize_backend(pkg::GRBackend) = nothing const _gr_attr = merge_with_base_supported([ :annotations, - :background_color_legend, :background_color_inside, :background_color_outside, - :foreground_color_legend, :foreground_color_grid, :foreground_color_axis, - :foreground_color_text, :foreground_color_border, + :background_color_legend, + :background_color_inside, + :background_color_outside, + :foreground_color_legend, + :foreground_color_grid, + :foreground_color_axis, + :foreground_color_text, + :foreground_color_border, :label, - :seriescolor, :seriesalpha, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, - :fillrange, :fillcolor, :fillalpha, + :seriescolor, + :seriesalpha, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, + :fillrange, + :fillcolor, + :fillalpha, :bins, :layout, - :title, :window_title, - :guide, :lims, :ticks, :scale, :flip, - :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign, - :titlefontrotation, :titlefontcolor, - :legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign, - :legendfontrotation, :legendfontcolor, - :tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign, - :tickfontrotation, :tickfontcolor, - :guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign, - :guidefontrotation, :guidefontcolor, - :grid, :gridalpha, :gridstyle, :gridlinewidth, - :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, - :colorbar_titlefontfamily, :colorbar_titlefontsize, - :colorbar_titlefontvalign, :colorbar_titlefonthalign, - :colorbar_titlefontrotation, :colorbar_titlefontcolor, - :fill_z, :line_z, :marker_z, :levels, - :ribbon, :quiver, + :title, + :window_title, + :guide, + :lims, + :ticks, + :scale, + :flip, + :titlefontfamily, + :titlefontsize, + :titlefonthalign, + :titlefontvalign, + :titlefontrotation, + :titlefontcolor, + :legendfontfamily, + :legendfontsize, + :legendfonthalign, + :legendfontvalign, + :legendfontrotation, + :legendfontcolor, + :tickfontfamily, + :tickfontsize, + :tickfonthalign, + :tickfontvalign, + :tickfontrotation, + :tickfontcolor, + :guidefontfamily, + :guidefontsize, + :guidefonthalign, + :guidefontvalign, + :guidefontrotation, + :guidefontcolor, + :grid, + :gridalpha, + :gridstyle, + :gridlinewidth, + :legend, + :legendtitle, + :colorbar, + :colorbar_title, + :colorbar_entry, + :colorbar_titlefontfamily, + :colorbar_titlefontsize, + :colorbar_titlefontvalign, + :colorbar_titlefonthalign, + :colorbar_titlefontrotation, + :colorbar_titlefontcolor, + :fill_z, + :line_z, + :marker_z, + :levels, + :ribbon, + :quiver, :orientation, :overwrite_figure, :polar, :aspect_ratio, - :normalize, :weights, + :normalize, + :weights, :inset_subplots, :bar_width, :arrow, @@ -381,35 +438,79 @@ end const _plotly_attr = merge_with_base_supported([ :annotations, - :background_color_legend, :background_color_inside, :background_color_outside, - :foreground_color_legend, :foreground_color_guide, - :foreground_color_grid, :foreground_color_axis, - :foreground_color_text, :foreground_color_border, + :background_color_legend, + :background_color_inside, + :background_color_outside, + :foreground_color_legend, + :foreground_color_guide, + :foreground_color_grid, + :foreground_color_axis, + :foreground_color_text, + :foreground_color_border, :foreground_color_title, :label, - :seriescolor, :seriesalpha, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle, - :fillrange, :fillcolor, :fillalpha, + :seriescolor, + :seriesalpha, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, + :markerstrokestyle, + :fillrange, + :fillcolor, + :fillalpha, :bins, - :title, :titlelocation, - :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign, + :title, + :titlelocation, + :titlefontfamily, + :titlefontsize, + :titlefonthalign, + :titlefontvalign, :titlefontcolor, - :legendfontfamily, :legendfontsize, :legendfontcolor, - :tickfontfamily, :tickfontsize, :tickfontcolor, - :guidefontfamily, :guidefontsize, :guidefontcolor, + :legendfontfamily, + :legendfontsize, + :legendfontcolor, + :tickfontfamily, + :tickfontsize, + :tickfontcolor, + :guidefontfamily, + :guidefontsize, + :guidefontcolor, :window_title, - :guide, :lims, :ticks, :scale, :flip, :rotation, - :tickfont, :guidefont, :legendfont, - :grid, :gridalpha, :gridlinewidth, - :legend, :colorbar, :colorbar_title, :colorbar_entry, - :marker_z, :fill_z, :line_z, :levels, - :ribbon, :quiver, + :guide, + :lims, + :ticks, + :scale, + :flip, + :rotation, + :tickfont, + :guidefont, + :legendfont, + :grid, + :gridalpha, + :gridlinewidth, + :legend, + :colorbar, + :colorbar_title, + :colorbar_entry, + :marker_z, + :fill_z, + :line_z, + :levels, + :ribbon, + :quiver, :orientation, # :overwrite_figure, :polar, - :normalize, :weights, + :normalize, + :weights, # :contours, :aspect_ratio, :hover, @@ -420,7 +521,7 @@ const _plotly_attr = merge_with_base_supported([ :tick_direction, :camera, :contour_labels, - ]) +]) const _plotly_seriestype = [ :path, @@ -434,12 +535,24 @@ const _plotly_seriestype = [ :shape, :scattergl, :straightline, - :mesh3d + :mesh3d, ] const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot] const _plotly_marker = [ - :none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, - :cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline + :none, + :auto, + :circle, + :rect, + :diamond, + :utriangle, + :dtriangle, + :cross, + :xcross, + :pentagon, + :hexagon, + :octagon, + :vline, + :hline, ] const _plotly_scale = [:identity, :log10] @@ -454,23 +567,50 @@ const _pgfplots_attr = merge_with_base_supported([ :background_color_inside, # :background_color_outside, # :foreground_color_legend, - :foreground_color_grid, :foreground_color_axis, - :foreground_color_text, :foreground_color_border, + :foreground_color_grid, + :foreground_color_axis, + :foreground_color_text, + :foreground_color_border, :label, - :seriescolor, :seriesalpha, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle, - :fillrange, :fillcolor, :fillalpha, + :seriescolor, + :seriesalpha, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, + :markerstrokestyle, + :fillrange, + :fillcolor, + :fillalpha, :bins, # :bar_width, :bar_edges, :title, # :window_title, - :guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation, - :tickfont, :guidefont, :legendfont, - :grid, :legend, - :colorbar, :colorbar_title, - :fill_z, :line_z, :marker_z, :levels, + :guide, + :guide_position, + :lims, + :ticks, + :scale, + :flip, + :rotation, + :tickfont, + :guidefont, + :legendfont, + :grid, + :legend, + :colorbar, + :colorbar_title, + :fill_z, + :line_z, + :marker_z, + :levels, # :ribbon, :quiver, :arrow, # :orientation, # :overwrite_figure, @@ -482,9 +622,36 @@ const _pgfplots_attr = merge_with_base_supported([ :camera, :contour_labels, ]) -const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,] +const _pgfplots_seriestype = [ + :path, + :path3d, + :scatter, + :steppre, + :stepmid, + :steppost, + :histogram2d, + :ysticks, + :xsticks, + :contour, + :shape, + :straightline, +] const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] -const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline] #vcat(_allMarkers, Shape) +const _pgfplots_marker = [ + :none, + :auto, + :circle, + :rect, + :diamond, + :utriangle, + :dtriangle, + :cross, + :xcross, + :star5, + :pentagon, + :hline, + :vline, +] #vcat(_allMarkers, Shape) const _pgfplots_scale = [:identity, :ln, :log2, :log10] # ------------------------------------------------------------------------------ @@ -497,11 +664,11 @@ function _initialize_backend(pkg::PlotlyJSBackend) end end -const _plotlyjs_attr = _plotly_attr -const _plotlyjs_seriestype = _plotly_seriestype -const _plotlyjs_style = _plotly_style -const _plotlyjs_marker = _plotly_marker -const _plotlyjs_scale = _plotly_scale +const _plotlyjs_attr = _plotly_attr +const _plotlyjs_seriestype = _plotly_seriestype +const _plotlyjs_style = _plotly_style +const _plotlyjs_marker = _plotly_marker +const _plotlyjs_scale = _plotly_scale # ------------------------------------------------------------------------------ # pyplot @@ -519,36 +686,89 @@ end const _pyplot_attr = merge_with_base_supported([ :annotations, - :background_color_legend, :background_color_inside, :background_color_outside, - :foreground_color_grid, :foreground_color_legend, :foreground_color_title, - :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text, + :background_color_legend, + :background_color_inside, + :background_color_outside, + :foreground_color_grid, + :foreground_color_legend, + :foreground_color_title, + :foreground_color_axis, + :foreground_color_border, + :foreground_color_guide, + :foreground_color_text, :label, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, - :fillrange, :fillcolor, :fillalpha, - :bins, :bar_width, :bar_edges, :bar_position, - :title, :titlelocation, :titlefont, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, + :fillrange, + :fillcolor, + :fillalpha, + :bins, + :bar_width, + :bar_edges, + :bar_position, + :title, + :titlelocation, + :titlefont, :window_title, - :guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation, - :titlefontfamily, :titlefontsize, :titlefontcolor, - :legendfontfamily, :legendfontsize, :legendfontcolor, - :tickfontfamily, :tickfontsize, :tickfontcolor, - :guidefontfamily, :guidefontsize, :guidefontcolor, - :grid, :gridalpha, :gridstyle, :gridlinewidth, - :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, - :colorbar_ticks, :colorbar_tickfontfamily, :colorbar_tickfontsize, - :colorbar_tickfonthalign, :colorbar_tickfontvalign, - :colorbar_tickfontrotation, :colorbar_tickfontcolor, + :guide, + :guide_position, + :lims, + :ticks, + :scale, + :flip, + :rotation, + :titlefontfamily, + :titlefontsize, + :titlefontcolor, + :legendfontfamily, + :legendfontsize, + :legendfontcolor, + :tickfontfamily, + :tickfontsize, + :tickfontcolor, + :guidefontfamily, + :guidefontsize, + :guidefontcolor, + :grid, + :gridalpha, + :gridstyle, + :gridlinewidth, + :legend, + :legendtitle, + :colorbar, + :colorbar_title, + :colorbar_entry, + :colorbar_ticks, + :colorbar_tickfontfamily, + :colorbar_tickfontsize, + :colorbar_tickfonthalign, + :colorbar_tickfontvalign, + :colorbar_tickfontrotation, + :colorbar_tickfontcolor, :colorbar_scale, - :marker_z, :line_z, :fill_z, + :marker_z, + :line_z, + :fill_z, :levels, - :ribbon, :quiver, :arrow, + :ribbon, + :quiver, + :arrow, :orientation, :overwrite_figure, :polar, - :normalize, :weights, - :contours, :aspect_ratio, + :normalize, + :weights, + :contours, + :aspect_ratio, :clims, :inset_subplots, :dpi, @@ -557,7 +777,7 @@ const _pyplot_attr = merge_with_base_supported([ :tick_direction, :camera, :contour_labels, - ]) +]) const _pyplot_seriestype = [ :path, :steppre, @@ -598,18 +818,35 @@ const _gaston_attr = merge_with_base_supported([ # :foreground_color_legend, # :foreground_color_grid, :foreground_color_axis, # :foreground_color_text, :foreground_color_border, - :label, :seriescolor, :seriesalpha, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, + :label, + :seriescolor, + :seriesalpha, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, # :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle, # :fillrange, :fillcolor, :fillalpha, # :bins, # :bar_width, :bar_edges, - :title, :window_title, - :guide, :guide_position, - :lims, :ticks, :scale, :flip, :rotation, - :tickfont, :guidefont, - :legendfont, :grid, :legend, + :title, + :window_title, + :guide, + :guide_position, + :lims, + :ticks, + :scale, + :flip, + :rotation, + :tickfont, + :guidefont, + :legendfont, + :grid, + :legend, # :colorbar, :colorbar_title, # :fill_z, :line_z, :marker_z, :levels, # :ribbon, @@ -623,7 +860,7 @@ const _gaston_attr = merge_with_base_supported([ # :framestyle, # :camera, # :contour_labels, - ]) +]) const _gaston_seriestype = [ :path, @@ -632,7 +869,8 @@ const _gaston_seriestype = [ :steppre, :stepmid, :steppost, - :ysticks, :xsticks, + :ysticks, + :xsticks, :contour, :shape, :straightline, @@ -645,14 +883,7 @@ const _gaston_seriestype = [ :image, ] -const _gaston_style = [ - :auto, - :solid, - :dash, - :dot, - :dashdot, - :dashdotdot -] +const _gaston_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _gaston_marker = [ :none, @@ -687,14 +918,17 @@ const _unicodeplots_attr = merge_with_base_supported([ :markershape, :bins, :title, - :guide, :lims, - ]) + :guide, + :lims, +]) const _unicodeplots_seriestype = [ - :path, :scatter, :straightline, + :path, + :scatter, + :straightline, # :bar, :shape, :histogram2d, - :spy + :spy, ] const _unicodeplots_style = [:auto, :solid] const _unicodeplots_marker = [:none, :auto, :circle] @@ -708,33 +942,70 @@ const _canvas_type = Ref(:auto) const _hdf5_attr = merge_with_base_supported([ :annotations, - :background_color_legend, :background_color_inside, :background_color_outside, - :foreground_color_grid, :foreground_color_legend, :foreground_color_title, - :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text, + :background_color_legend, + :background_color_inside, + :background_color_outside, + :foreground_color_grid, + :foreground_color_legend, + :foreground_color_title, + :foreground_color_axis, + :foreground_color_border, + :foreground_color_guide, + :foreground_color_text, :label, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, - :fillrange, :fillcolor, :fillalpha, - :bins, :bar_width, :bar_edges, :bar_position, - :title, :titlelocation, :titlefont, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, + :fillrange, + :fillcolor, + :fillalpha, + :bins, + :bar_width, + :bar_edges, + :bar_position, + :title, + :titlelocation, + :titlefont, :window_title, - :guide, :lims, :ticks, :scale, :flip, :rotation, - :tickfont, :guidefont, :legendfont, - :grid, :legend, :colorbar, - :marker_z, :line_z, :fill_z, + :guide, + :lims, + :ticks, + :scale, + :flip, + :rotation, + :tickfont, + :guidefont, + :legendfont, + :grid, + :legend, + :colorbar, + :marker_z, + :line_z, + :fill_z, :levels, - :ribbon, :quiver, :arrow, + :ribbon, + :quiver, + :arrow, :orientation, :overwrite_figure, :polar, - :normalize, :weights, - :contours, :aspect_ratio, + :normalize, + :weights, + :contours, + :aspect_ratio, :clims, :inset_subplots, :dpi, :colorbar_title, - ]) +]) const _hdf5_seriestype = [ :path, :steppre, @@ -759,68 +1030,115 @@ const _hdf5_scale = [:identity, :ln, :log2, :log10] # Additional constants #Dict has problems using "Types" as keys. Initialize in "_initialize_backend": -const HDF5PLOT_MAP_STR2TELEM = Dict{String, Type}() -const HDF5PLOT_MAP_TELEM2STR = Dict{Type, String}() +const HDF5PLOT_MAP_STR2TELEM = Dict{String,Type}() +const HDF5PLOT_MAP_TELEM2STR = Dict{Type,String}() #Don't really like this global variable... Very hacky mutable struct HDF5Plot_PlotRef - ref::Union{Plot, Nothing} + ref::Union{Plot,Nothing} end const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing) - # ------------------------------------------------------------------------------ # inspectdr const _inspectdr_attr = merge_with_base_supported([ :annotations, - :background_color_legend, :background_color_inside, :background_color_outside, + :background_color_legend, + :background_color_inside, + :background_color_outside, # :foreground_color_grid, - :foreground_color_legend, :foreground_color_title, - :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text, + :foreground_color_legend, + :foreground_color_title, + :foreground_color_axis, + :foreground_color_border, + :foreground_color_guide, + :foreground_color_text, :label, - :seriescolor, :seriesalpha, - :linecolor, :linestyle, :linewidth, :linealpha, - :markershape, :markercolor, :markersize, :markeralpha, - :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, + :seriescolor, + :seriesalpha, + :linecolor, + :linestyle, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, + :markerstrokewidth, + :markerstrokecolor, + :markerstrokealpha, :markerstrokestyle, #Causes warning not to have it... what is this? - :fillcolor, :fillalpha, #:fillrange, -# :bins, :bar_width, :bar_edges, :bar_position, - :title, :titlelocation, + :fillcolor, + :fillalpha, #:fillrange, + # :bins, :bar_width, :bar_edges, :bar_position, + :title, + :titlelocation, :window_title, - :guide, :lims, :scale, #:ticks, :flip, :rotation, - :titlefontfamily, :titlefontsize, :titlefontcolor, - :legendfontfamily, :legendfontsize, :legendfontcolor, - :tickfontfamily, :tickfontsize, :tickfontcolor, - :guidefontfamily, :guidefontsize, :guidefontcolor, - :grid, :legend, #:colorbar, -# :marker_z, -# :line_z, -# :levels, - # :ribbon, :quiver, :arrow, -# :orientation, + :guide, + :lims, + :scale, #:ticks, :flip, :rotation, + :titlefontfamily, + :titlefontsize, + :titlefontcolor, + :legendfontfamily, + :legendfontsize, + :legendfontcolor, + :tickfontfamily, + :tickfontsize, + :tickfontcolor, + :guidefontfamily, + :guidefontsize, + :guidefontcolor, + :grid, + :legend, #:colorbar, + # :marker_z, + # :line_z, + # :levels, + # :ribbon, :quiver, :arrow, + # :orientation, :overwrite_figure, :polar, -# :normalize, :weights, -# :contours, :aspect_ratio, -# :clims, -# :inset_subplots, + # :normalize, :weights, + # :contours, :aspect_ratio, + # :clims, + # :inset_subplots, :dpi, -# :colorbar_title, - ]) + # :colorbar_title, +]) const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot] const _inspectdr_seriestype = [ - :path, :scatter, :shape, :straightline, #, :steppre, :stepmid, :steppost - ] + :path, + :scatter, + :shape, + :straightline, #, :steppre, :stepmid, :steppost +] #see: _allMarkers, _shape_keys const _inspectdr_marker = Symbol[ - :none, :auto, - :circle, :rect, :diamond, - :cross, :xcross, - :utriangle, :dtriangle, :rtriangle, :ltriangle, - :pentagon, :hexagon, :heptagon, :octagon, - :star4, :star5, :star6, :star7, :star8, - :vline, :hline, :+, :x, + :none, + :auto, + :circle, + :rect, + :diamond, + :cross, + :xcross, + :utriangle, + :dtriangle, + :rtriangle, + :ltriangle, + :pentagon, + :hexagon, + :heptagon, + :octagon, + :star4, + :star5, + :star6, + :star7, + :star8, + :vline, + :hline, + :+, + :x, ] const _inspectdr_scale = [:identity, :ln, :log2, :log10] diff --git a/src/backends/deprecated/pgfplots.jl b/src/backends/deprecated/pgfplots.jl index 718d8241..4c9f1ea3 100644 --- a/src/backends/deprecated/pgfplots.jl +++ b/src/backends/deprecated/pgfplots.jl @@ -27,7 +27,7 @@ const _pgfplots_markers = KW( :diamond => "diamond*", :pentagon => "pentagon*", :hline => "-", - :vline => "|" + :vline => "|", ) const _pgfplots_legend_pos = KW( @@ -38,7 +38,6 @@ const _pgfplots_legend_pos = KW( :outertopright => "outer north east", ) - const _pgf_series_extrastyle = KW( :steppre => "const plot mark right", :stepmid => "const plot mark mid", @@ -50,11 +49,7 @@ const _pgf_series_extrastyle = KW( # PGFPlots uses the anchors to define orientations for example to align left # one needs to use the right edge as anchor -const _pgf_annotation_halign = KW( - :center => "", - :left => "right", - :right => "left" -) +const _pgf_annotation_halign = KW(:center => "", :left => "right", :right => "left") const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] const _pgf_framestyle_defaults = Dict(:semi => :box) @@ -63,7 +58,9 @@ function pgf_framestyle(style::Symbol) return style else default_style = get(_pgf_framestyle_defaults, style, :axes) - @warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.") + @warn( + "Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead." + ) default_style end end @@ -78,15 +75,15 @@ end function pgf_color(grad::ColorGradient) # Can't handle ColorGradient here, fallback to defaults. - cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316,0.97868012) + cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316, 0.97868012) cstr, 1 end # Generates a colormap for pgfplots based on a ColorGradient function pgf_colormap(grad::ColorGradient) join(map(grad.colors) do c - @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c)) - end,", ") + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) + end, ", ") end pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling] @@ -94,7 +91,7 @@ pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt) pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot]) function pgf_fillstyle(plotattributes, i = 1) - cstr,a = pgf_color(get_fillcolor(plotattributes, i)) + cstr, a = pgf_color(get_fillcolor(plotattributes, i)) fa = get_fillalpha(plotattributes, i) if fa !== nothing a = fa @@ -126,8 +123,15 @@ end function pgf_marker(plotattributes, i = 1) shape = _cycle(plotattributes[:markershape], i) - cstr, a = pgf_color(plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i))) - cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i))) + cstr, a = pgf_color( + plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)), + ) + cstr_stroke, a_stroke = pgf_color( + plot_color( + get_markerstrokecolor(plotattributes, i), + get_markerstrokealpha(plotattributes, i), + ), + ) return string( "mark = $(get(_pgfplots_markers, shape, "*")),\n", "mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),\n", @@ -138,22 +142,28 @@ function pgf_marker(plotattributes, i = 1) line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)), rotate = $(shape == :dtriangle ? 180 : 0), $(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid")) - }" - ) + }", + ) end function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1) # Construct the style string. # Currently supports color and orientation - cstr,a = pgf_color(val.font.color) - push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text - x, y, - style=""" - $(get(_pgf_annotation_halign,val.font.halign,"")), - color=$cstr, draw opacity=$(convert(Float16,a)), - rotate=$(val.font.rotation), - font=$(pgf_font(val.font.pointsize, thickness_scaling)) - """)) + cstr, a = pgf_color(val.font.color) + push!( + o, + PGFPlots.Plots.Node( + val.str, # Annotation Text + x, + y, + style = """ + $(get(_pgf_annotation_halign,val.font.halign,"")), + color=$cstr, draw opacity=$(convert(Float16,a)), + rotate=$(val.font.rotation), + font=$(pgf_font(val.font.pointsize, thickness_scaling)) + """, + ), + ) end # -------------------------------------------------------------------------------------- @@ -241,7 +251,15 @@ function pgf_series(sp::Subplot, series::Series) # add fillrange if series[:fillrange] !== nothing && st != :shape - push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) + push!( + series_collection, + pgf_fillrange_series( + series, + i, + _cycle(series[:fillrange], rng), + seg_args..., + ), + ) end # build/return the series object @@ -313,7 +331,7 @@ end # ---------------------------------------------------------------- function pgf_axis(sp::Subplot, letter) - axis = sp[Symbol(letter,:axis)] + axis = sp[Symbol(letter, :axis)] style = [] kw = KW() @@ -324,7 +342,7 @@ function pgf_axis(sp::Subplot, letter) framestyle = pgf_framestyle(sp[:framestyle]) # axis guide - kw[Symbol(letter,:label)] = axis[:guide] + kw[Symbol(letter, :label)] = axis[:guide] # axis label position labelpos = "" @@ -336,7 +354,23 @@ function pgf_axis(sp::Subplot, letter) # Add label font cstr, α = pgf_color(plot_color(axis[:guidefontcolor])) - push!(style, string(letter, "label style = {", labelpos ,"font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}")) + push!( + style, + string( + letter, + "label style = {", + labelpos, + "font = ", + pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), + ", color = ", + cstr, + ", draw opacity = ", + α, + ", rotate = ", + axis[:guidefontrotation], + "}", + ), + ) # flip/reverse? axis[:flip] && push!(style, "$letter dir=reverse") @@ -344,7 +378,7 @@ function pgf_axis(sp::Subplot, letter) # scale scale = axis[:scale] if scale in (:log2, :ln, :log10) - kw[Symbol(letter,:mode)] = "log" + kw[Symbol(letter, :mode)] = "log" scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)") end @@ -363,16 +397,20 @@ function pgf_axis(sp::Subplot, letter) # limits # TODO: support zlims if letter != :z - lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) - kw[Symbol(letter,:min)] = lims[1] - kw[Symbol(letter,:max)] = lims[2] + lims = + ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : + axis_limits(sp, letter) + kw[Symbol(letter, :min)] = lims[1] + kw[Symbol(letter, :max)] = lims[2] end if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none ticks = get_ticks(sp, axis) #pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values - tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1] - push!(style, string(letter, "tick = {", join(tick_values,","), "}")) + tick_values = + ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : + ticks[1] + push!(style, string(letter, "tick = {", join(tick_values, ","), "}")) if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto # wrap the power part of label with } tick_labels = Vector{String}(undef, length(ticks[2])) @@ -381,21 +419,59 @@ function pgf_axis(sp::Subplot, letter) power = string("{", power, "}") tick_labels[i] = string(base, "^", power) end - push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}")) + push!( + style, + string(letter, "ticklabels = {\$", join(tick_labels, "\$,\$"), "\$}"), + ) elseif axis[:showaxis] - tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2] + tick_labels = + ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2] if axis[:formatter] in (:scientific, :auto) tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$") tick_labels = replace.(tick_labels, Ref("×" => "\\times")) end - push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}")) + push!(style, string(letter, "ticklabels = {", join(tick_labels, ","), "}")) else push!(style, string(letter, "ticklabels = {}")) end - push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside"))) + push!( + style, + string( + letter, + "tick align = ", + (axis[:tick_direction] == :out ? "outside" : "inside"), + ), + ) cstr, α = pgf_color(plot_color(axis[:tickfontcolor])) - push!(style, string(letter, "ticklabel style = {font = ", pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:tickfontrotation], "}")) - push!(style, string(letter, " grid style = {", pgf_linestyle(pgf_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]), "}")) + push!( + style, + string( + letter, + "ticklabel style = {font = ", + pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), + ", color = ", + cstr, + ", draw opacity = ", + α, + ", rotate = ", + axis[:tickfontrotation], + "}", + ), + ) + push!( + style, + string( + letter, + " grid style = {", + pgf_linestyle( + pgf_thickness_scaling(sp) * axis[:gridlinewidth], + axis[:foreground_color_grid], + axis[:gridalpha], + axis[:gridstyle], + ), + "}", + ), + ) end # framestyle @@ -412,7 +488,20 @@ function pgf_axis(sp::Subplot, letter) if framestyle == :zerolines push!(style, string("extra ", letter, " ticks = 0")) push!(style, string("extra ", letter, " tick labels = ")) - push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}")) + push!( + style, + string( + "extra ", + letter, + " tick style = {grid = major, major grid style = {", + pgf_linestyle( + pgf_thickness_scaling(sp), + axis[:foreground_color_border], + 1.0, + ), + "}}", + ), + ) end if !axis[:showaxis] @@ -421,7 +510,19 @@ function pgf_axis(sp::Subplot, letter) if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none) push!(style, string(letter, " axis line style = {draw opacity = 0}")) else - push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}")) + push!( + style, + string( + letter, + " axis line style = {", + pgf_linestyle( + pgf_thickness_scaling(sp), + axis[:foreground_color_border], + 1.0, + ), + "}", + ), + ) end # return the style list and KW args @@ -430,7 +531,6 @@ end # ---------------------------------------------------------------- - function _update_plot_object(plt::Plot{PGFPlotsBackend}) plt.o = PGFPlots.Axis[] # Obtain the total height of the plot by extracting the maximal bottom @@ -438,7 +538,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) total_height = bottom(bbox(plt.layout)) for sp in plt.subplots - # first build the PGFPlots.Axis object + # first build the PGFPlots.Axis object style = ["unbounded coords=jump"] kw = KW() @@ -456,18 +556,34 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) # A round on 2 decimal places should be enough precision for 300 dpi # plots. bb = bbox(sp) - push!(style, """ - xshift = $(left(bb).value)mm, - yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm, - axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])} - """) + push!( + style, + """ + xshift = $(left(bb).value)mm, + yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm, + axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])} +""", + ) kw[:width] = "$(width(bb).value)mm" kw[:height] = "$(height(bb).value)mm" if sp[:title] != "" kw[:title] = "$(sp[:title])" cstr, α = pgf_color(plot_color(sp[:titlefontcolor])) - push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}")) + push!( + style, + string( + "title style = {font = ", + pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), + ", color = ", + cstr, + ", draw opacity = ", + α, + ", rotate = ", + sp[:titlefontrotation], + "}", + ), + ) end if get_aspect_ratio(sp) in (1, :equal) @@ -481,15 +597,25 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) cstr, bg_alpha = pgf_color(plot_color(sp[:background_color_legend])) fg_alpha = alpha(plot_color(sp[:foreground_color_legend])) - push!(style, string( - "legend style = {", - pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid", ), ",", + push!( + style, + string( + "legend style = {", + pgf_linestyle( + pgf_thickness_scaling(sp), + sp[:foreground_color_legend], + fg_alpha, + "solid", + ), + ",", "fill = $cstr,", "fill opacity = $bg_alpha,", "text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),", - "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), - "}", - )) + "font = ", + pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), + "}", + ), + ) if any(s[:seriestype] == :contour for s in series_list(sp)) kw[:view] = "{0}{90}" @@ -520,7 +646,10 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) for series in series_list(sp) for col in (:markercolor, :fillcolor, :linecolor) if typeof(series.plotattributes[col]) == ColorGradient - push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}") + push!( + style, + "colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}", + ) if sp[:colorbar] == :none kw[:colorbar] = "false" @@ -543,17 +672,26 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) # add series annotations anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - pgf_add_annotation!(o, xi, yi, PlotText(str, fnt), pgf_thickness_scaling(series)) + for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y]) + pgf_add_annotation!( + o, + xi, + yi, + PlotText(str, fnt), + pgf_thickness_scaling(series), + ) end end # add the annotations for ann in sp[:annotations] - pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp)) + pgf_add_annotation!( + o, + locate_annotation(sp, ann...)..., + pgf_thickness_scaling(sp), + ) end - # add the PGFPlots.Axis to the list push!(plt.o, o) end @@ -568,7 +706,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend}) pgfplt = PGFPlots.plot(plt.o) # save a pdf - fn = tempname()*".pdf" + fn = tempname() * ".pdf" PGFPlots.save(PGFPlots.PDF(fn), pgfplt) # read it into io @@ -579,8 +717,12 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend}) end function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend}) - fn = tempname()*".tex" - PGFPlots.save(fn, backend_object(plt), include_preamble=plt.attr[:tex_output_standalone]) + fn = tempname() * ".tex" + PGFPlots.save( + fn, + backend_object(plt), + include_preamble = plt.attr[:tex_output_standalone], + ) write(io, read(open(fn), String)) end diff --git a/src/backends/gaston.jl b/src/backends/gaston.jl index 5c6ddc0f..223ce4b7 100644 --- a/src/backends/gaston.jl +++ b/src/backends/gaston.jl @@ -31,11 +31,11 @@ function _before_layout_calcs(plt::Plot{GastonBackend}) plt.o.layout = gaston_init_subplots(plt, sps) # Then add the series (curves in gaston) - for series ∈ plt.series_list + for series in plt.series_list gaston_add_series(plt, series) end - - for sp ∈ plt.subplots + + for sp in plt.subplots sp === nothing && continue for ann in sp[:annotations] x, y, val = locate_annotation(sp, ann...) @@ -57,7 +57,7 @@ function _update_plot_object(plt::Plot{GastonBackend}) nothing end -for (mime, term) ∈ ( +for (mime, term) in ( "application/eps" => "epscairo", "image/eps" => "epslatex", "application/pdf" => "pdfcairo", @@ -69,12 +69,19 @@ for (mime, term) ∈ ( "text/plain" => "dumb", ) @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GastonBackend}) - term = String($term); tmpfile = "$(Gaston.tempname()).$term" + term = String($term) + tmpfile = "$(Gaston.tempname()).$term" - Gaston.save(term=term, output=tmpfile, handle=plt.o.handle, saveopts=gaston_saveopts(plt)) - while !isfile(tmpfile) end # avoid race condition with read in next line + Gaston.save( + term = term, + output = tmpfile, + handle = plt.o.handle, + saveopts = gaston_saveopts(plt), + ) + while !isfile(tmpfile) + end # avoid race condition with read in next line write(io, read(tmpfile)) - rm(tmpfile, force=true) + rm(tmpfile, force = true) nothing end end @@ -88,7 +95,16 @@ _display(plt::Plot{GastonBackend}) = display(plt.o) function gaston_saveopts(plt::Plot{GastonBackend}) saveopts = String["size $(join(plt.attr[:size], ","))"] - push!(saveopts, gaston_font(plottitlefont(plt), rot=false, align=false, color=false, scale=1)) + push!( + saveopts, + gaston_font( + plottitlefont(plt), + rot = false, + align = false, + color = false, + scale = 1, + ), + ) push!(saveopts, "background $(gaston_color(plt.attr[:background_color]))") @@ -97,14 +113,14 @@ function gaston_saveopts(plt::Plot{GastonBackend}) # Scale all plot elements to match Plots.jl DPI standard scaling = plt.attr[:dpi] / Plots.DPI push!(saveopts, "fontscale $scaling lw $scaling dl $scaling ps $scaling") - + return join(saveopts, " ") end function gaston_get_subplots(n, plt_subplots, layout) nr, nc = size(layout) sps = Array{Any}(nothing, nr, nc) - for r ∈ 1:nr, c ∈ 1:nc # NOTE: col major + for r in 1:nr, c in 1:nc # NOTE: col major l = layout[r, c] if l isa GridLayout n, sub = gaston_get_subplots(n, plt_subplots, l) @@ -118,7 +134,7 @@ end function gaston_init_subplots(plt, sps) sz = nr, nc = size(sps) - for c ∈ 1:nc, r ∈ 1:nr # NOTE: row major + for c in 1:nc, r in 1:nr # NOTE: row major sp = sps[r, c] if sp isa Subplot || sp === nothing gaston_init_subplot(plt, sp) @@ -130,20 +146,28 @@ function gaston_init_subplots(plt, sps) return sz end -function gaston_init_subplot(plt::Plot{GastonBackend}, sp::Union{Nothing,Subplot{GastonBackend}}) +function gaston_init_subplot( + plt::Plot{GastonBackend}, + sp::Union{Nothing,Subplot{GastonBackend}}, +) if sp === nothing push!(plt.o.subplots, sp) else - dims = RecipesPipeline.is3d(sp) || sp.attr[:projection] == "3d" || needs_any_3d_axes(sp) ? 3 : 2 + dims = + RecipesPipeline.is3d(sp) || + sp.attr[:projection] == "3d" || + needs_any_3d_axes(sp) ? 3 : 2 any_label = false - for series ∈ series_list(sp) + for series in series_list(sp) if dims == 2 && series[:seriestype] ∈ (:heatmap, :contour) dims = 3 # we need heatmap/contour to use splot, not plot end any_label |= should_add_to_legend(series) end sp.o = Gaston.Plot( - dims=dims, curves=[], axesconf=gaston_parse_axes_args(plt, sp, dims, any_label), + dims = dims, + curves = [], + axesconf = gaston_parse_axes_args(plt, sp, dims, any_label), ) push!(plt.o.subplots, sp.o) end @@ -153,7 +177,7 @@ end function gaston_multiplot_pos_size(layout, parent_xy_wh) nr, nc = size(layout) dat = Array{Any}(nothing, nr, nc) - for r ∈ 1:nr, c ∈ 1:nc + for r in 1:nr, c in 1:nc l = layout[r, c] # width and height (pct) are multiplicative (parent) w = layout.widths[c].value * parent_xy_wh[3] @@ -181,7 +205,7 @@ end function gaston_multiplot_pos_size!(dat) nr, nc = size(dat) - for r ∈ 1:nr, c ∈ 1:nc + for r in 1:nr, c in 1:nc xy_wh_sp = dat[r, c] if xy_wh_sp isa Array gaston_multiplot_pos_size!(xy_wh_sp) @@ -197,15 +221,16 @@ function gaston_multiplot_pos_size!(dat) end function gaston_add_series(plt::Plot{GastonBackend}, series::Series) - sp = series[:subplot]; gsp = sp.o + sp = series[:subplot] + gsp = sp.o x, y, z = series[:x], series[:y], series[:z] st = series[:seriestype] curves = [] if gsp.dims == 2 && z === nothing - for (n, seg) ∈ enumerate(series_segments(series, st; check=true)) + for (n, seg) in enumerate(series_segments(series, st; check = true)) i, rng = seg.attr_index, seg.range - for sc ∈ gaston_seriesconf!(sp, series, i, n == 1) + for sc in gaston_seriesconf!(sp, series, i, n == 1) push!(curves, Gaston.Curve(x[rng], y[rng], nothing, nothing, sc)) end end @@ -213,35 +238,41 @@ function gaston_add_series(plt::Plot{GastonBackend}, series::Series) if z isa Surface z = z.surf if st == :image - z = reverse(Float32.(Gray.(z)), dims=1) # flip y axis + z = reverse(Float32.(Gray.(z)), dims = 1) # flip y axis nr, nc = size(z) if (ly = length(y)) == 2 && ly != nr - y = collect(range(y[1], y[2], length=nr)) + y = collect(range(y[1], y[2], length = nr)) end if (lx = length(x)) == 2 && lx != nc - x = collect(range(x[1], x[2], length=nc)) + x = collect(range(x[1], x[2], length = nc)) end elseif st == :heatmap - length(x) == size(z, 2) + 1 && (x = @view x[1:end-1]) - length(y) == size(z, 1) + 1 && (y = @view y[1:end-1]) + length(x) == size(z, 2) + 1 && (x = @view x[1:(end - 1)]) + length(y) == size(z, 1) + 1 && (y = @view y[1:(end - 1)]) end end if st == :mesh3d x, y, z = mesh3d_triangles(x, y, z, series[:connections]) end - for sc ∈ gaston_seriesconf!(sp, series, 1, true) + for sc in gaston_seriesconf!(sp, series, 1, true) push!(curves, Gaston.Curve(x, y, z, nothing, sc)) end end - for c ∈ curves - append = length(gsp.curves) > 0; push!(gsp.curves, c) - Gaston.write_data(c, gsp.dims, gsp.datafile, append=append) + for c in curves + append = length(gsp.curves) > 0 + push!(gsp.curves, c) + Gaston.write_data(c, gsp.dims, gsp.datafile, append = append) end nothing end -function gaston_seriesconf!(sp::Subplot{GastonBackend}, series::Series, i::Int, add_to_legend::Bool) +function gaston_seriesconf!( + sp::Subplot{GastonBackend}, + series::Series, + i::Int, + add_to_legend::Bool, +) #= gnuplot abbreviations (see gnuplot/src/set.c) --------------------------------------------- @@ -261,7 +292,9 @@ function gaston_seriesconf!(sp::Subplot{GastonBackend}, series::Series, i::Int, tc: textcolor w: with =# - gsp = sp.o; st = series[:seriestype]; extra = [] + gsp = sp.o + st = series[:seriestype] + extra = [] add_to_legend &= should_add_to_legend(series) curveconf = String[add_to_legend ? "title '$(series[:label])'" : "notitle"] @@ -320,18 +353,24 @@ function gaston_seriesconf!(sp::Subplot{GastonBackend}, series::Series, i::Int, end function gaston_parse_axes_args( - plt::Plot{GastonBackend}, sp::Subplot{GastonBackend}, dims::Int, any_label::Bool + plt::Plot{GastonBackend}, + sp::Subplot{GastonBackend}, + dims::Int, + any_label::Bool, ) # axesconf = String["set margins 2, 2, 2, 2"] # left, right, bottom, top axesconf = String[] polar = ispolar(sp) && dims == 2 # cannot splot in polar coordinates - for letter ∈ (:x, :y, :z) + for letter in (:x, :y, :z) (letter == :z && dims == 2) && continue axis = sp.attr[Symbol(letter, :axis)] # label names - push!(axesconf, "set $(letter)label '$(axis[:guide])' $(gaston_font(guidefont(axis)))") + push!( + axesconf, + "set $(letter)label '$(axis[:guide])' $(gaston_font(guidefont(axis)))", + ) mirror = axis[:mirror] ? "mirror" : "nomirror" if axis[:scale] == :identity @@ -349,7 +388,10 @@ function gaston_parse_axes_args( if polar push!(axesconf, "set size square\nunset $(letter)tics") else - push!(axesconf, "set $(letter)tics $(mirror) $(axis[:tick_direction]) $(gaston_font(tickfont(axis)))") + push!( + axesconf, + "set $(letter)tics $(mirror) $(axis[:tick_direction]) $(gaston_font(tickfont(axis)))", + ) # major tick locations if axis[:ticks] != :native @@ -372,7 +414,8 @@ function gaston_parse_axes_args( if axis[:grid] push!(axesconf, "set grid " * (polar ? "polar" : "$(letter)tics")) - axis[:minorgrid] && push!(axesconf, "set grid " * (polar ? "polar" : "m$(letter)tics")) + axis[:minorgrid] && + push!(axesconf, "set grid " * (polar ? "polar" : "m$(letter)tics")) end ratio = get_aspect_ratio(sp) @@ -399,12 +442,20 @@ function gaston_parse_axes_args( if (ttype = ticksType(rticks)) == :ticks gaston_ticks = string.(rticks) elseif ttype == :ticks_and_labels - gaston_ticks = String["'$l' $t" for (t, l) ∈ zip(rticks...)] + gaston_ticks = String["'$l' $t" for (t, l) in zip(rticks...)] end - push!(axesconf, "set rtics ( " * join(gaston_ticks, ", ") * " ) $(gaston_font(tickfont(sp.attr[:yaxis])))") + push!( + axesconf, + "set rtics ( " * + join(gaston_ticks, ", ") * + " ) $(gaston_font(tickfont(sp.attr[:yaxis])))", + ) push!(axesconf, "set trange [$(min(0, tmin)):$(max(2π, tmax))]") push!(axesconf, "set rrange [$rmin:$rmax]") - push!(axesconf, "set ttics 0,30 format \"%g\".GPVAL_DEGREE_SIGN $(gaston_font(tickfont(sp.attr[:xaxis])))") + push!( + axesconf, + "set ttics 0,30 format \"%g\".GPVAL_DEGREE_SIGN $(gaston_font(tickfont(sp.attr[:xaxis])))", + ) push!(axesconf, "set mttics 3") end @@ -421,7 +472,7 @@ function gaston_set_ticks!(axesconf, ticks, letter, maj_min, add) gaston_ticks = String[] if (ttype = ticksType(ticks)) == :ticks tick_locs = @view ticks[:] - for i ∈ eachindex(tick_locs) + for i in eachindex(tick_locs) tick = if maj_min == "m" "'' $(tick_locs[i]) 1" # see gnuplot manual 'Mxtics' else @@ -432,7 +483,7 @@ function gaston_set_ticks!(axesconf, ticks, letter, maj_min, add) elseif ttype == :ticks_and_labels tick_locs = @view ticks[1][:] tick_labels = @view ticks[2][:] - for i ∈ eachindex(tick_locs) + for i in eachindex(tick_locs) lab = gaston_enclose_tick_string(tick_labels[i]) push!(gaston_ticks, "'$lab' $(tick_locs[i])") end @@ -451,8 +502,11 @@ function gaston_set_legend!(axesconf, sp, any_label) if sp[:legend] ∉ (:none, :inline) && any_label leg == :best && (leg = :topright) - push!(axesconf, "set key " * (occursin("outer", string(leg)) ? "outside" : "inside")) - for position ∈ ("top", "bottom", "left", "right") + push!( + axesconf, + "set key " * (occursin("outer", string(leg)) ? "outside" : "inside"), + ) + for position in ("top", "bottom", "left", "right") occursin(position, string(leg)) && push!(axesconf, "set key $position") end push!(axesconf, "set key $(gaston_font(legendfont(sp), rot=false, align=false))") @@ -472,8 +526,8 @@ end # Helpers # -------------------------------------------- -gaston_halign(k) = (left=:left, hcenter=:center, right=:right)[k] -gaston_valign(k) = (top=:top, vcenter=:center, bottom=:bottom)[k] +gaston_halign(k) = (left = :left, hcenter = :center, right = :right)[k] +gaston_valign(k) = (top = :top, vcenter = :center, bottom = :bottom)[k] gaston_alpha(alpha) = alpha === nothing ? 0 : alpha @@ -489,7 +543,7 @@ gaston_mk_ms_mc(series::Series, clims, i::Int) = ( gaston_color(get_markercolor(series, clims, i), get_markeralpha(series, i)), ) -function gaston_font(f; rot=true, align=true, color=true, scale=1) +function gaston_font(f; rot = true, align = true, color = true, scale = 1) font = String["font '$(f.family),$(round(Int, scale * f.pointsize))'"] align && push!(font, "$(gaston_halign(f.halign))") rot && push!(font, "rotate by $(f.rotation)") @@ -498,8 +552,9 @@ function gaston_font(f; rot=true, align=true, color=true, scale=1) end function gaston_palette(gradient) - palette = String[]; n = -1 - for rgba ∈ gradient # FIXME: naive conversion, inefficient ? + palette = String[] + n = -1 + for rgba in gradient # FIXME: naive conversion, inefficient ? push!(palette, "$(n += 1) $(rgba.r) $(rgba.g) $(rgba.b)") end return '(' * join(palette, ", ") * ')' @@ -524,7 +579,7 @@ function gaston_marker(marker, alpha) return 1 end -function gaston_color(col, alpha=0) +function gaston_color(col, alpha = 0) col = single_color(col) # in case of gradients col = alphacolor(col, gaston_alpha(alpha)) # add a default alpha if non existent return "rgb '#$(hex(col, :aarrggbb))'" diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 49dace78..8a9cc952 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -6,7 +6,6 @@ import GR export GR - # -------------------------------------------------------------------------------------- gr_linetype(k) = (auto = 1, solid = 1, dash = 2, dot = 3, dashdot = 4, dashdotdot = -1)[k] @@ -92,14 +91,16 @@ const gr_font_family = Dict( gr_color(c) = gr_color(c, color_type(c)) -gr_color(c, ::Type{<:AbstractRGB}) = UInt32( round(UInt, clamp(alpha(c) * 255, 0, 255)) << 24 + - round(UInt, clamp(blue(c) * 255, 0, 255)) << 16 + - round(UInt, clamp(green(c) * 255, 0, 255)) << 8 + - round(UInt, clamp(red(c) * 255, 0, 255)) ) +gr_color(c, ::Type{<:AbstractRGB}) = UInt32( + round(UInt, clamp(alpha(c) * 255, 0, 255)) << 24 + + round(UInt, clamp(blue(c) * 255, 0, 255)) << 16 + + round(UInt, clamp(green(c) * 255, 0, 255)) << 8 + + round(UInt, clamp(red(c) * 255, 0, 255)), +) function gr_color(c, ::Type{<:AbstractGray}) g = round(UInt, clamp(gray(c) * 255, 0, 255)) α = round(UInt, clamp(alpha(c) * 255, 0, 255)) - rgba = UInt32( α<<24 + g<<16 + g<<8 + g ) + rgba = UInt32(α << 24 + g << 16 + g << 8 + g) end gr_color(c, ::Type) = gr_color(RGBA(c), RGB) @@ -108,43 +109,44 @@ function gr_getcolorind(c) convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c))) end -gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c,1))) -gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1))) -gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c,1))) -gr_set_bordercolor(c) = GR.setbordercolorind(gr_getcolorind(_cycle(c,1))) -gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c,1))) +gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c, 1))) +gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c, 1))) +gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c, 1))) +gr_set_bordercolor(c) = GR.setbordercolorind(gr_getcolorind(_cycle(c, 1))) +gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c, 1))) gr_set_transparency(α::Real) = GR.settransparency(clamp(α, 0, 1)) gr_set_transparency(::Nothing) = GR.settransparency(1) gr_set_transparency(c, α) = gr_set_transparency(α) gr_set_transparency(c::Colorant, ::Nothing) = gr_set_transparency(c) gr_set_transparency(c::Colorant) = GR.settransparency(alpha(c)) -gr_set_arrowstyle(s::Symbol) = GR.setarrowstyle(get( - ( - simple = 1, - hollow = 3, - filled = 4, - triangle = 5, - filledtriangle = 6, - closed = 6, - open = 5, +gr_set_arrowstyle(s::Symbol) = GR.setarrowstyle( + get( + ( + simple = 1, + hollow = 3, + filled = 4, + triangle = 5, + filledtriangle = 6, + closed = 6, + open = 5, + ), + s, + 1, ), - s, - 1, -)) +) # -------------------------------------------------------------------------------------- - # draw line segments, splitting x/y into contiguous/finite segments # note: this can be used for shapes by passing func `GR.fillarea` function gr_polyline(x, y, func = GR.polyline; arrowside = :none, arrowstyle = :simple) iend = 0 n = length(x) - while iend < n-1 + while iend < n - 1 # set istart to the first index that is finite istart = -1 - for j = iend+1:n + for j in (iend + 1):n if isfinite(x[j]) && isfinite(y[j]) istart = j break @@ -154,7 +156,7 @@ function gr_polyline(x, y, func = GR.polyline; arrowside = :none, arrowstyle = : if istart > 0 # iend is the last finite index iend = -1 - for j = istart+1:n + for j in (istart + 1):n if isfinite(x[j]) && isfinite(y[j]) iend = j else @@ -166,13 +168,13 @@ function gr_polyline(x, y, func = GR.polyline; arrowside = :none, arrowstyle = : # if we found a start and end, draw the line segment, otherwise we're done if istart > 0 && iend > 0 func(x[istart:iend], y[istart:iend]) - if arrowside in (:head,:both) + if arrowside in (:head, :both) gr_set_arrowstyle(arrowstyle) - GR.drawarrow(x[iend-1], y[iend-1], x[iend], y[iend]) + GR.drawarrow(x[iend - 1], y[iend - 1], x[iend], y[iend]) end - if arrowside in (:tail,:both) + if arrowside in (:tail, :both) gr_set_arrowstyle(arrowstyle) - GR.drawarrow(x[istart+1], y[istart+1], x[istart], y[istart]) + GR.drawarrow(x[istart + 1], y[istart + 1], x[istart], y[istart]) end else break @@ -183,10 +185,10 @@ end function gr_polyline3d(x, y, z, func = GR.polyline3d) iend = 0 n = length(x) - while iend < n-1 + while iend < n - 1 # set istart to the first index that is finite istart = -1 - for j = iend+1:n + for j in (iend + 1):n if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j]) istart = j break @@ -196,7 +198,7 @@ function gr_polyline3d(x, y, z, func = GR.polyline3d) if istart > 0 # iend is the last finite index iend = -1 - for j = istart+1:n + for j in (istart + 1):n if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j]) iend = j else @@ -218,7 +220,7 @@ gr_inqtext(x, y, s) = gr_inqtext(x, y, string(s)) function gr_inqtext(x, y, s::AbstractString) if length(s) >= 2 && s[1] == '$' && s[end] == '$' - GR.inqmathtex(x, y, s[2:end-1]) + GR.inqmathtex(x, y, s[2:(end - 1)]) elseif occursin('\\', s) || occursin("10^{", s) GR.inqtextext(x, y, s) else @@ -230,7 +232,7 @@ gr_text(x, y, s) = gr_text(x, y, string(s)) function gr_text(x, y, s::AbstractString) if length(s) >= 2 && s[1] == '$' && s[end] == '$' - GR.mathtex(x, y, s[2:end-1]) + GR.mathtex(x, y, s[2:(end - 1)]) elseif occursin('\\', s) || occursin("10^{", s) GR.textext(x, y, s) else @@ -252,7 +254,10 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) #draw angular grid if xaxis[:grid] gr_set_line( - xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid], sp + xaxis[:gridlinewidth], + xaxis[:gridstyle], + xaxis[:foreground_color_grid], + sp, ) gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:gridalpha]) for i in eachindex(α) @@ -263,7 +268,10 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) #draw radial grid if yaxis[:grid] gr_set_line( - yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid], sp + yaxis[:gridlinewidth], + yaxis[:gridstyle], + yaxis[:foreground_color_grid], + sp, ) gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:gridalpha]) for i in eachindex(rtick_values) @@ -285,7 +293,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) GR.drawarc(-1, 1, -1, 1, 0, 359) for i in eachindex(α) x, y = GR.wctondc(1.1 * sinf[i], 1.1 * cosf[i]) - GR.textext(x, y, string((360-α[i])%360, "^o")) + GR.textext(x, y, string((360 - α[i]) % 360, "^o")) end end @@ -302,14 +310,12 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) GR.restorestate() end - # using the axis extrema and limit overrides, return the min/max value for this axis gr_x_axislims(sp::Subplot) = axis_limits(sp, :x) gr_y_axislims(sp::Subplot) = axis_limits(sp, :y) gr_z_axislims(sp::Subplot) = axis_limits(sp, :z) gr_xy_axislims(sp::Subplot) = gr_x_axislims(sp)..., gr_y_axislims(sp)... - function gr_fill_viewport(vp::AVec{Float64}, c) GR.savestate() GR.selntran(0) @@ -365,7 +371,6 @@ function gr_draw_marker(series, xi, yi, clims, i, msize, strokewidth, shape::Sym GR.polymarker([xi], [yi]) end - # --------------------------------------------------------- function gr_set_line(lw, style, c, s) # s can be Subplot or Series @@ -374,7 +379,6 @@ function gr_set_line(lw, style, c, s) # s can be Subplot or Series gr_set_linecolor(c) end - function gr_set_fill(c) #, a) gr_set_fillcolor(c) #, a) GR.setfillintstyle(GR.INTSTYLE_SOLID) @@ -385,15 +389,21 @@ end gr_point_mult(s) = 1.5 * get_thickness_scaling(s) * px / pt / maximum(get_size(s)) # set the font attributes. -function gr_set_font(f::Font, s; halign = f.halign, valign = f.valign, - color = f.color, rotation = f.rotation) +function gr_set_font( + f::Font, + s; + halign = f.halign, + valign = f.valign, + color = f.color, + rotation = f.rotation, +) family = lowercase(f.family) GR.setcharheight(gr_point_mult(s) * f.pointsize) GR.setcharup(sind(-rotation), cosd(-rotation)) if haskey(gr_font_family, family) GR.settextfontprec( gr_font_family[family], - gr_font_family[family] >= 200 ? 3 : GR.TEXT_PRECISION_STRING + gr_font_family[family] >= 200 ? 3 : GR.TEXT_PRECISION_STRING, ) end gr_set_textcolor(color) @@ -408,7 +418,13 @@ end # -------------------------------------------------------------------------------------- # viewport plot area -function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas) +function gr_viewport_from_bbox( + sp::Subplot{GRBackend}, + bb::BoundingBox, + w, + h, + viewport_canvas, +) viewport = zeros(4) viewport[1] = viewport_canvas[2] * (left(bb) / w) viewport[2] = viewport_canvas[2] * (right(bb) / w) @@ -426,7 +442,7 @@ function gr_set_viewport_cmap(sp::Subplot, viewport_plotarea) viewport_plotarea[2] + (RecipesPipeline.is3d(sp) ? 0.07 : 0.02), viewport_plotarea[2] + (RecipesPipeline.is3d(sp) ? 0.10 : 0.05), viewport_plotarea[3], - viewport_plotarea[4] + viewport_plotarea[4], ) end @@ -436,7 +452,7 @@ function gr_set_viewport_polar(viewport_plotarea) xcenter = 0.5 * (xmin + xmax) ycenter = 0.5 * (ymin + ymax) r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin) - GR.setviewport(xcenter -r, xcenter + r, ycenter - r, ycenter + r) + GR.setviewport(xcenter - r, xcenter + r, ycenter - r, ycenter + r) GR.setwindow(-1, 1, -1, 1) r end @@ -445,16 +461,16 @@ struct GRColorbar gradients fills lines - GRColorbar() = new([],[],[]) + GRColorbar() = new([], [], []) end function gr_update_colorbar!(cbar::GRColorbar, series::Series) style = colorbar_style(series) style === nothing && return - list = style == cbar_gradient ? cbar.gradients : - style == cbar_fill ? cbar.fills : - style == cbar_lines ? cbar.lines : - error("Unknown colorbar style: $style.") + list = + style == cbar_gradient ? cbar.gradients : + style == cbar_fill ? cbar.fills : + style == cbar_lines ? cbar.lines : error("Unknown colorbar style: $style.") push!(list, series) end @@ -462,7 +478,7 @@ function gr_contour_levels(series::Series, clims) levels = contour_levels(series, clims) if isfilledcontour(series) # GR implicitly uses the maximal z value as the highest level - levels = levels[1:end-1] + levels = levels[1:(end - 1)] end levels end @@ -481,10 +497,9 @@ function gr_colorbar_colors(series::Series, clims) else colors = 1000:1255 end - round.(Int,colors) + round.(Int, colors) end - function _cbar_unique(values, propname) out = last(values) if any(x != out for x in values) @@ -504,7 +519,7 @@ function gr_draw_colorbar(cbar::GRColorbar, sp::Subplot, clims, viewport_plotare GR.setwindow(xmin, xmax, zmin, zmax) if !isempty(cbar.gradients) series = cbar.gradients - gr_set_gradient(_cbar_unique(get_colorgradient.(series),"color")) + gr_set_gradient(_cbar_unique(get_colorgradient.(series), "color")) gr_set_transparency(_cbar_unique(get_fillalpha.(series), "fill alpha")) GR.cellarray(xmin, xmax, zmax, zmin, 1, 256, 1000:1255) end @@ -520,18 +535,18 @@ function gr_draw_colorbar(cbar::GRColorbar, sp::Subplot, clims, viewport_plotare @warn "GR: highest contour level less than maximal z value is not supported." # replace levels, rather than assign to levels[end], to ensure type # promotion in case levels is an integer array - levels = [levels[1:end-1]; clims[2]] + levels = [levels[1:(end - 1)]; clims[2]] end colors = gr_colorbar_colors(last(series), clims) - for (from, to, color) in zip(levels[1:end-1], levels[2:end], colors) + for (from, to, color) in zip(levels[1:(end - 1)], levels[2:end], colors) GR.setfillcolorind(color) - GR.fillrect( xmin, xmax, from, to ) + GR.fillrect(xmin, xmax, from, to) end end if !isempty(cbar.lines) series = cbar.lines - gr_set_gradient(_cbar_unique(get_colorgradient.(series),"color")) + gr_set_gradient(_cbar_unique(get_colorgradient.(series), "color")) gr_set_line( _cbar_unique(get_linewidth.(series), "line width"), _cbar_unique(get_linestyle.(series), "line style"), @@ -543,7 +558,7 @@ function gr_draw_colorbar(cbar::GRColorbar, sp::Subplot, clims, viewport_plotare colors = gr_colorbar_colors(last(series), clims) for (line, color) in zip(levels, colors) GR.setlinecolorind(color) - GR.polyline([xmin,xmax], [line,line] ) + GR.polyline([xmin, xmax], [line, line]) end end @@ -559,9 +574,7 @@ function gr_draw_colorbar(cbar::GRColorbar, sp::Subplot, clims, viewport_plotare gr_set_font(title.font, sp) GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) GR.setcharup(-1, 0) - gr_text( - viewport_plotarea[2] + 0.1, gr_view_ycenter(viewport_plotarea), title.str - ) + gr_text(viewport_plotarea[2] + 0.1, gr_view_ycenter(viewport_plotarea), title.str) GR.restorestate() end @@ -569,8 +582,10 @@ end gr_view_xcenter(viewport_plotarea) = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2]) gr_view_ycenter(viewport_plotarea) = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]) -gr_view_xposition(viewport_plotarea, position) = viewport_plotarea[1] + position * (viewport_plotarea[2] - viewport_plotarea[1]) -gr_view_yposition(viewport_plotarea, position) = viewport_plotarea[3] + position * (viewport_plotarea[4] - viewport_plotarea[3]) +gr_view_xposition(viewport_plotarea, position) = + viewport_plotarea[1] + position * (viewport_plotarea[2] - viewport_plotarea[1]) +gr_view_yposition(viewport_plotarea, position) = + viewport_plotarea[3] + position * (viewport_plotarea[4] - viewport_plotarea[3]) function position(symb) if symb == :top || symb == :right @@ -594,9 +609,9 @@ end function gr_set_gradient(c) grad = _as_gradient(c) - for (i,z) in enumerate(range(0, stop=1, length=256)) + for (i, z) in enumerate(range(0, stop = 1, length = 256)) c = grad[z] - GR.setcolorrep(999+i, red(c), green(c), blue(c)) + GR.setcolorrep(999 + i, red(c), green(c), blue(c)) end grad end @@ -607,18 +622,19 @@ function gr_set_gradient(series::Series) end # this is our new display func... set up the viewport_canvas, compute bounding boxes, and display each subplot -function gr_display(plt::Plot, fmt="") +function gr_display(plt::Plot, fmt = "") GR.clearws() dpi_factor = fmt == "png" ? plt[:dpi] / Plots.DPI : 1 # collect some monitor/display sizes in meters and pixels - display_width_meters, display_height_meters, display_width_px, display_height_px = GR.inqdspsize() + display_width_meters, display_height_meters, display_width_px, display_height_px = + GR.inqdspsize() display_width_ratio = display_width_meters / display_width_px display_height_ratio = display_height_meters / display_height_px # compute the viewport_canvas, normalized to the larger dimension - viewport_canvas = Float64[0,1,0,1] + viewport_canvas = Float64[0, 1, 0, 1] w, h = get_size(plt) if w > h ratio = float(h) / w @@ -641,7 +657,7 @@ function gr_display(plt::Plot, fmt="") # subplots: for sp in plt.subplots - gr_display(sp, w*px, h*px, viewport_canvas) + gr_display(sp, w * px, h * px, viewport_canvas) end GR.updatews() @@ -718,7 +734,10 @@ function gr_axis_height(sp, axis) GR.savestate() ticks = get_ticks(sp, axis, update = false) gr_set_font(tickfont(axis), sp) - h = (ticks in (nothing, false, :none) ? 0 : last(gr_get_ticks_size(ticks, axis[:rotation]))) + h = ( + ticks in (nothing, false, :none) ? 0 : + last(gr_get_ticks_size(ticks, axis[:rotation])) + ) if axis[:guide] != "" gr_set_font(guidefont(axis), sp) h += last(gr_text_size(axis[:guide])) @@ -731,7 +750,10 @@ function gr_axis_width(sp, axis) GR.savestate() ticks = get_ticks(sp, axis, update = false) gr_set_font(tickfont(axis), sp) - w = (ticks in (nothing, false, :none) ? 0 : first(gr_get_ticks_size(ticks, axis[:rotation]))) + w = ( + ticks in (nothing, false, :none) ? 0 : + first(gr_get_ticks_size(ticks, axis[:rotation])) + ) if axis[:guide] != "" gr_set_font(guidefont(axis), sp) w += last(gr_text_size(axis[:guide])) @@ -749,10 +771,10 @@ function _update_min_padding!(sp::Subplot{GRBackend}) end end # Add margin given by the user - leftpad = 2mm + sp[:left_margin] - toppad = 2mm + sp[:top_margin] - rightpad = 2mm + sp[:right_margin] - bottompad = 2mm + sp[:bottom_margin] + leftpad = 2mm + sp[:left_margin] + toppad = 2mm + sp[:top_margin] + rightpad = 2mm + sp[:right_margin] + bottompad = 2mm + sp[:bottom_margin] # Add margin for title if sp[:title] != "" gr_set_font(titlefont(sp), sp) @@ -763,12 +785,14 @@ function _update_min_padding!(sp::Subplot{GRBackend}) if RecipesPipeline.is3d(sp) xaxis, yaxis, zaxis = sp[:xaxis], sp[:yaxis], sp[:zaxis] - xticks, yticks, zticks = get_ticks(sp, xaxis), get_ticks(sp, yaxis), get_ticks(sp, zaxis) + xticks, yticks, zticks = + get_ticks(sp, xaxis), get_ticks(sp, yaxis), get_ticks(sp, zaxis) # Add margin for x and y ticks h = 0mm if !isempty(first(xticks)) gr_set_font( - tickfont(xaxis), sp, + tickfont(xaxis), + sp, halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], valign = (xaxis[:mirror] ? :bottom : :top), rotation = xaxis[:rotation], @@ -778,7 +802,8 @@ function _update_min_padding!(sp::Subplot{GRBackend}) end if !isempty(first(yticks)) gr_set_font( - tickfont(yaxis), sp, + tickfont(yaxis), + sp, halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], valign = (yaxis[:mirror] ? :bottom : :top), rotation = yaxis[:rotation], @@ -797,7 +822,8 @@ function _update_min_padding!(sp::Subplot{GRBackend}) if !isempty(first(zticks)) gr_set_font( - tickfont(zaxis), sp, + tickfont(zaxis), + sp, halign = (zaxis[:mirror] ? :left : :right), valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2], rotation = zaxis[:rotation], @@ -825,7 +851,10 @@ function _update_min_padding!(sp::Subplot{GRBackend}) h = max(h, 1mm + get_size(sp)[2] * l * px) end if h > 0mm - if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) + if ( + xaxis[:guide_position] == :top || + (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) + ) toppad += h else bottompad += h @@ -836,7 +865,10 @@ function _update_min_padding!(sp::Subplot{GRBackend}) gr_set_font(guidefont(sp[:zaxis]), sp) l = last(gr_text_size(sp[:zaxis][:guide])) w = 1mm + get_size(sp)[2] * l * px - if zaxis[:guide_position] == :right || (zaxis[:guide_position] == :auto && zaxis[:mirror] == true) + if ( + zaxis[:guide_position] == :right || + (zaxis[:guide_position] == :auto && zaxis[:mirror] == true) + ) rightpad += w else leftpad += w @@ -871,7 +903,10 @@ function _update_min_padding!(sp::Subplot{GRBackend}) gr_set_font(guidefont(sp[:xaxis]), sp) l = last(gr_text_size(sp[:xaxis][:guide])) h = 1mm + get_size(sp)[2] * l * px - if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true) + if ( + sp[:xaxis][:guide_position] == :top || + (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true) + ) toppad += h else bottompad += h @@ -882,7 +917,10 @@ function _update_min_padding!(sp::Subplot{GRBackend}) gr_set_font(guidefont(sp[:yaxis]), sp) l = last(gr_text_size(sp[:yaxis][:guide])) w = 1mm + get_size(sp)[2] * l * px - if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true) + if ( + sp[:yaxis][:guide_position] == :right || + (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true) + ) rightpad += w else leftpad += w @@ -896,7 +934,7 @@ function _update_min_padding!(sp::Subplot{GRBackend}) end function is_equally_spaced(v) - d = collect(v[2:end] .- v[1:end-1]) + d = collect(v[2:end] .- v[1:(end - 1)]) all(d .≈ d[1]) end @@ -975,7 +1013,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end end - ## Legend function gr_add_legend(sp, leg, viewport_plotarea) @@ -989,13 +1026,17 @@ function gr_add_legend(sp, leg, viewport_plotarea) GR.setfillintstyle(GR.INTSTYLE_SOLID) gr_set_fillcolor(sp[:background_color_legend]) GR.fillrect( - xpos - leg.leftw, xpos + leg.textw + leg.rightw, - ypos + leg.dy, ypos - leg.h + xpos - leg.leftw, + xpos + leg.textw + leg.rightw, + ypos + leg.dy, + ypos - leg.h, ) # Allocating white space for actual legend width here gr_set_line(1, :solid, sp[:foreground_color_legend], sp) GR.drawrect( - xpos - leg.leftw, xpos + leg.textw + leg.rightw, - ypos + leg.dy, ypos - leg.h + xpos - leg.leftw, + xpos + leg.textw + leg.rightw, + ypos + leg.dy, + ypos - leg.h, ) # Drawing actual legend width here i = 0 if sp[:legendtitle] !== nothing @@ -1012,7 +1053,10 @@ function gr_add_legend(sp, leg, viewport_plotarea) lc = get_linecolor(series, clims) gr_set_line(sp[:legendfontsize] / 8, get_linestyle(series), lc, sp) - if (st == :shape || series[:fillrange] !== nothing) && series[:ribbon] === nothing + if ( + (st == :shape || series[:fillrange] !== nothing) && + series[:ribbon] === nothing + ) fc = get_fillcolor(series, clims) gr_set_fill(fc) #, series[:fillalpha]) l, r = xpos - leg.width_factor * 3.5, xpos - leg.width_factor / 2 @@ -1074,14 +1118,18 @@ function gr_legend_pos(sp::Subplot, 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) + 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]), - ] + !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) @@ -1091,53 +1139,73 @@ function gr_legend_pos(sp::Subplot, leg, viewport_plotarea) end if occursin("outer", str) 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) + xmirror = + xaxis[:guide_position] == :top || + (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) + ymirror = + yaxis[:guide_position] == :right || + (yaxis[:guide_position] == :auto && yaxis[:mirror] == true) end if occursin("right", str) if occursin("outer", str) # As per https://github.com/jheinen/GR.jl/blob/master/src/jlgr.jl#L525 - xpos = viewport_plotarea[2] + leg.xoffset + leg.leftw + ymirror * gr_axis_width(sp, sp[:yaxis]) + xpos = + viewport_plotarea[2] + + leg.xoffset + + leg.leftw + + ymirror * gr_axis_width(sp, sp[:yaxis]) else xpos = viewport_plotarea[2] - leg.rightw - leg.textw - leg.xoffset end elseif occursin("left", str) if occursin("outer", str) - xpos = viewport_plotarea[1] - !ymirror * gr_axis_width(sp, sp[:yaxis]) - leg.xoffset * 2 - leg.rightw - leg.textw + xpos = + viewport_plotarea[1] - !ymirror * gr_axis_width(sp, sp[:yaxis]) - + leg.xoffset * 2 - leg.rightw - leg.textw else xpos = viewport_plotarea[1] + leg.leftw + leg.xoffset end else - xpos = (viewport_plotarea[2] - viewport_plotarea[1]) / 2 + viewport_plotarea[1] + leg.leftw - leg.rightw - leg.textw - leg.xoffset * 2 + xpos = + (viewport_plotarea[2] - viewport_plotarea[1]) / 2 + + viewport_plotarea[1] + + leg.leftw - leg.rightw - leg.textw - leg.xoffset * 2 end if occursin("top", str) if s == :outertop - ypos = viewport_plotarea[4] + leg.yoffset + leg.h + xmirror * gr_axis_height(sp, sp[:xaxis]) + ypos = + viewport_plotarea[4] + + leg.yoffset + + leg.h + + xmirror * gr_axis_height(sp, sp[:xaxis]) else ypos = viewport_plotarea[4] - leg.yoffset - leg.dy end elseif occursin("bottom", str) if s == :outerbottom - ypos = viewport_plotarea[3] - leg.yoffset - leg.dy - !xmirror * gr_axis_height(sp, sp[:xaxis]) + ypos = + viewport_plotarea[3] - leg.yoffset - leg.dy - + !xmirror * gr_axis_height(sp, sp[:xaxis]) else ypos = viewport_plotarea[3] + leg.yoffset + leg.h end else # Adding min y to shift legend pos to correct graph (#2377) - ypos = (viewport_plotarea[4] - viewport_plotarea[3] + leg.h) / 2 + viewport_plotarea[3] + ypos = + (viewport_plotarea[4] - viewport_plotarea[3] + leg.h) / 2 + viewport_plotarea[3] end return xpos, ypos end -function gr_legend_pos(v::Tuple{S,T}, viewport_plotarea) where {S<:Real, T<:Real} +function gr_legend_pos(v::Tuple{S,T}, viewport_plotarea) where {S<:Real,T<:Real} xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1] ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3] - (xpos,ypos) + (xpos, ypos) end -function gr_legend_pos(theta::Real, leg, viewport_plotarea; axisclearance=nothing) - xcenter = +(viewport_plotarea[1:2]...)/2 - ycenter = +(viewport_plotarea[3:4]...)/2 +function gr_legend_pos(theta::Real, leg, viewport_plotarea; axisclearance = nothing) + xcenter = +(viewport_plotarea[1:2]...) / 2 + ycenter = +(viewport_plotarea[3:4]...) / 2 if isnothing(axisclearance) # Inner @@ -1148,12 +1216,13 @@ function gr_legend_pos(theta::Real, leg, viewport_plotarea; axisclearance=nothin ymax = viewport_plotarea[4] - leg.yoffset - leg.dy else # Outer - xmin = viewport_plotarea[1] - leg.xoffset - leg.rightw - leg.textw - axisclearance[1] + xmin = + viewport_plotarea[1] - leg.xoffset - leg.rightw - leg.textw - axisclearance[1] xmax = viewport_plotarea[2] + leg.xoffset + leg.leftw + axisclearance[2] ymin = viewport_plotarea[3] - leg.yoffset - leg.dy - axisclearance[3] ymax = viewport_plotarea[4] + leg.yoffset + leg.h + axisclearance[4] end - return legend_pos_from_angle(theta,xmin,xcenter,xmax,ymin,ycenter,ymax) + return legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax) end function gr_get_legend_geometry(viewport_plotarea, sp) @@ -1209,26 +1278,35 @@ function gr_get_legend_geometry(viewport_plotarea, sp) ) end - ## Viewport, window and scale function gr_update_viewport_legend!(viewport_plotarea, sp, leg) s = sp[:legend] 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) + xmirror = + xaxis[:guide_position] == :top || + (xaxis[:guide_position] == :auto && xaxis[: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 + (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]) + 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]) + 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 @@ -1239,11 +1317,17 @@ function gr_update_viewport_legend!(viewport_plotarea, sp, leg) if occursin("right", leg_str) viewport_plotarea[2] -= leg.leftw + leg.textw + leg.rightw + leg.xoffset elseif occursin("left", leg_str) - viewport_plotarea[1] += leg.leftw + leg.textw + leg.rightw + leg.xoffset + !ymirror * gr_axis_width(sp, sp[:yaxis]) + viewport_plotarea[1] += + leg.leftw + + leg.textw + + leg.rightw + + leg.xoffset + + !ymirror * gr_axis_width(sp, sp[:yaxis]) elseif occursin("top", leg_str) viewport_plotarea[4] -= leg.h + leg.dy + leg.yoffset elseif occursin("bottom", leg_str) - 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 if s === :inline @@ -1262,16 +1346,22 @@ function gr_update_viewport_ratio!(viewport_plotarea, sp) if ratio == :equal ratio = 1 end - viewport_ratio = (viewport_plotarea[2] - viewport_plotarea[1]) / (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_ratio = + (viewport_plotarea[2] - viewport_plotarea[1]) / + (viewport_plotarea[4] - viewport_plotarea[3]) window_ratio = (xmax - xmin) / (ymax - ymin) / ratio if window_ratio < viewport_ratio viewport_center = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2]) - viewport_size = (viewport_plotarea[2] - viewport_plotarea[1]) * window_ratio / viewport_ratio + viewport_size = + (viewport_plotarea[2] - viewport_plotarea[1]) * window_ratio / + viewport_ratio viewport_plotarea[1] = viewport_center - 0.5 * viewport_size viewport_plotarea[2] = viewport_center + 0.5 * viewport_size elseif window_ratio > viewport_ratio viewport_center = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]) - viewport_size = (viewport_plotarea[4] - viewport_plotarea[3]) * viewport_ratio / window_ratio + viewport_size = + (viewport_plotarea[4] - viewport_plotarea[3]) * viewport_ratio / + window_ratio viewport_plotarea[3] = viewport_center - 0.5 * viewport_size viewport_plotarea[4] = viewport_center + 0.5 * viewport_size end @@ -1293,12 +1383,12 @@ function gr_set_window(sp, viewport_plotarea) scaleop = 0 if xmax > xmin && ymax > ymin && zok - sp[:xaxis][:scale] == :log10 && (scaleop |= GR.OPTION_X_LOG) - sp[:yaxis][:scale] == :log10 && (scaleop |= GR.OPTION_Y_LOG) + sp[:xaxis][:scale] == :log10 && (scaleop |= GR.OPTION_X_LOG) + sp[:yaxis][:scale] == :log10 && (scaleop |= GR.OPTION_Y_LOG) needs_3d && sp[:zaxis][:scale] == :log10 && (scaleop |= GR.OPTION_Z_LOG) - sp[:xaxis][:flip] && (scaleop |= GR.OPTION_FLIP_X) - sp[:yaxis][:flip] && (scaleop |= GR.OPTION_FLIP_Y) - needs_3d && sp[:zaxis][:flip] && (scaleop |= GR.OPTION_FLIP_Z) + sp[:xaxis][:flip] && (scaleop |= GR.OPTION_FLIP_X) + sp[:yaxis][:flip] && (scaleop |= GR.OPTION_FLIP_Y) + needs_3d && sp[:zaxis][:flip] && (scaleop |= GR.OPTION_FLIP_Z) # NOTE: setwindow sets the "data coordinate" limits of the current "viewport" GR.setwindow(xmin, xmax, ymin, ymax) GR.setscale(scaleop) @@ -1312,7 +1402,6 @@ function gr_fill_plotarea(sp, viewport_plotarea) end end - ## Axes function gr_draw_axes(sp, viewport_plotarea) @@ -1325,7 +1414,10 @@ function gr_draw_axes(sp, viewport_plotarea) camera = round.(Int, sp[:camera]) - warn_invalid(val) = if val < 0 || val > 90 @warn "camera: $(val)° ∉ [0°, 90°]" end + warn_invalid(val) = + if val < 0 || val > 90 + @warn "camera: $(val)° ∉ [0°, 90°]" + end warn_invalid.(camera) GR.setspace(zmin, zmax, camera...) @@ -1335,7 +1427,8 @@ function gr_draw_axes(sp, viewport_plotarea) plot_area_x = [xmin, xmin, xmin, xmax, xmax, xmax, xmin] plot_area_y = [ymin, ymin, ymax, ymax, ymax, ymin, ymin] plot_area_z = [zmin, zmax, zmax, zmax, zmin, zmin, zmin] - x_bg, y_bg = RecipesPipeline.unzip(GR.wc3towc.(plot_area_x, plot_area_y, plot_area_z)) + x_bg, y_bg = + RecipesPipeline.unzip(GR.wc3towc.(plot_area_x, plot_area_y, plot_area_z)) GR.fillarea(x_bg, y_bg) for letter in (:x, :y, :z) @@ -1393,7 +1486,7 @@ function gr_draw_grid(sp, axis, segments, func = gr_polyline) axis[:gridlinewidth], axis[:gridstyle], axis[:foreground_color_grid], - sp + sp, ) gr_set_transparency(axis[:foreground_color_grid], axis[:gridalpha]) func(coords(segments)...) @@ -1406,7 +1499,7 @@ function gr_draw_minorgrid(sp, axis, segments, func = gr_polyline) axis[:minorgridlinewidth], axis[:minorgridstyle], axis[:foreground_color_minor_grid], - sp + sp, ) gr_set_transparency(axis[:foreground_color_minor_grid], axis[:minorgridalpha]) func(coords(segments)...) @@ -1485,7 +1578,6 @@ function gr_label_ticks_3d(sp, letter, ticks) famin, famax = axis_limits(sp, far_letter) n0, n1 = letter === :y ? (namax, namin) : (namin, namax) - # find out which axes we are dealing with i = findfirst(==(letter), (:x, :y, :z)) letters = axes_shift((:x, :y, :z), 1 - i) @@ -1535,7 +1627,7 @@ function gr_label_axis(sp, letter, viewport_plotarea) guide_position = axis[:guide_position] angle = float(axis[:guidefontrotation]) # github.com/JuliaPlots/Plots.jl/issues/3089 if letter === :y - angle += 180. # default angle = 0. should yield GR.setcharup(-1, 0) i.e. 180° + angle += 180.0 # default angle = 0. should yield GR.setcharup(-1, 0) i.e. 180° GR.setcharup(cosd(angle), sind(angle)) ypos = gr_view_yposition(viewport_plotarea, position(axis[:guidefontvalign])) yalign = alignment(axis[:guidefontvalign]) @@ -1547,16 +1639,21 @@ function gr_label_axis(sp, letter, viewport_plotarea) xpos = viewport_plotarea[1] - 0.03 - !mirror * gr_axis_width(sp, axis) end else - angle += 90. # default angle = 0. should yield GR.setcharup(0, 1) i.e. 90° + angle += 90.0 # default angle = 0. should yield GR.setcharup(0, 1) i.e. 90° GR.setcharup(cosd(angle), sind(angle)) xpos = gr_view_xposition(viewport_plotarea, position(axis[:guidefonthalign])) xalign = alignment(axis[:guidefonthalign]) if guide_position === :top || (guide_position == :auto && mirror) GR.settextalign(xalign, GR.TEXT_VALIGN_TOP) - ypos = viewport_plotarea[4] + 0.015 + (mirror ? gr_axis_height(sp, axis) : 0.015) + ypos = + viewport_plotarea[4] + + 0.015 + + (mirror ? gr_axis_height(sp, axis) : 0.015) else GR.settextalign(xalign, GR.TEXT_VALIGN_BOTTOM) - ypos = viewport_plotarea[3] - 0.015 - (mirror ? 0.015 : gr_axis_height(sp, axis)) + ypos = + viewport_plotarea[3] - 0.015 - + (mirror ? 0.015 : gr_axis_height(sp, axis)) end end gr_text(xpos, ypos, axis[:guide]) @@ -1627,7 +1724,6 @@ function gr_add_title(sp, viewport_plotarea, viewport_subplot) end end - ## Series function gr_add_series(sp, series) @@ -1693,7 +1789,7 @@ function gr_add_series(sp, series) # this is all we need to add the series_annotations text anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, x, y) + for (xi, yi, str, fnt) in EachAnn(anns, x, y) gr_set_font(fnt, sp) gr_text(GR.wctondc(xi, yi)..., str) end @@ -1702,16 +1798,16 @@ function gr_add_series(sp, series) gr_set_font(legendfont(sp), sp) gr_set_textcolor(plot_color(sp[:legendfontcolor])) if sp[:yaxis][:mirror] - (_,i) = sp[:xaxis][:flip] ? findmax(x) : findmin(x) + (_, i) = sp[:xaxis][:flip] ? findmax(x) : findmin(x) GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF) offset = -0.01 else - (_,i) = sp[:xaxis][:flip] ? findmin(x) : findmax(x) + (_, i) = sp[:xaxis][:flip] ? findmin(x) : findmax(x) GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) offset = 0.01 end - (x_l,y_l) = GR.wctondc(x[i],y[i]) - gr_text(x_l+offset,y_l,series[:label]) + (x_l, y_l) = GR.wctondc(x[i], y[i]) + gr_text(x_l + offset, y_l, series[:label]) end GR.restorestate() end @@ -1719,7 +1815,7 @@ end function gr_draw_segments(series, x, y, fillrange, clims) st = series[:seriestype] if x !== nothing && length(x) > 1 - segments = series_segments(series, st; check=true) + segments = series_segments(series, st; check = true) # do area fill if fillrange !== nothing GR.setfillintstyle(GR.INTSTYLE_SOLID) @@ -1740,9 +1836,7 @@ function gr_draw_segments(series, x, y, fillrange, clims) for segment in segments i, rng = segment.attr_index, segment.range lc = get_linecolor(series, clims, i) - gr_set_line( - get_linewidth(series, i), get_linestyle(series, i), lc, series - ) + gr_set_line(get_linewidth(series, i), get_linestyle(series, i), lc, series) arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none arrowstyle = isa(series[:arrow], Arrow) ? series[:arrow].style : :simple gr_set_fillcolor(lc) @@ -1756,13 +1850,11 @@ end function gr_draw_segments_3d(series, x, y, z, clims) if series[:seriestype] === :path3d && length(x) > 1 lz = series[:line_z] - segments = series_segments(series, :path3d; check=true) + segments = series_segments(series, :path3d; check = true) for segment in segments i, rng = segment.attr_index, segment.range lc = get_linecolor(series, clims, i) - gr_set_line( - get_linewidth(series, i), get_linestyle(series, i), lc, series - ) + gr_set_line(get_linewidth(series, i), get_linestyle(series, i), lc, series) gr_set_transparency(lc, get_linealpha(series, i)) GR.polyline3d(x[rng], y[rng], z[rng]) end @@ -1777,7 +1869,6 @@ function gr_draw_markers( msize = series[:markersize], strokewidth = series[:markerstrokewidth], ) - isempty(x) && return GR.setfillintstyle(GR.INTSTYLE_SOLID) @@ -1791,7 +1882,16 @@ function gr_draw_markers( msw = get_thickness_scaling(series) * _cycle(strokewidth, i) shape = _cycle(shapes, i) for j in rng - gr_draw_marker(series, _cycle(x, j), _cycle(y, j), clims, i, ms, msw, shape) + gr_draw_marker( + series, + _cycle(x, j), + _cycle(y, j), + clims, + i, + ms, + msw, + shape, + ) end end end @@ -1828,8 +1928,8 @@ function gr_draw_contour(series, x, y, z, clims) GR.setspace(clims[1], clims[2], 0, 90) gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series), series) gr_set_transparency(get_fillalpha(series)) - is_lc_black = let black=plot_color(:black) - plot_color(series[:linecolor]) in (black,[black]) + is_lc_black = let black = plot_color(:black) + plot_color(series[:linecolor]) in (black, [black]) end h = gr_contour_levels(series, clims) if series[:fillrange] !== nothing @@ -1866,7 +1966,12 @@ function gr_draw_surface(series, x, y, z, clims) GR.surface(x, y, z, get(e_kwargs, :display_option, GR.OPTION_FILLED_MESH)) elseif st === :mesh3d @warn "GR: mesh3d is experimental (no face colors)" - gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series), series) + gr_set_line( + get_linewidth(series), + get_linestyle(series), + get_linecolor(series), + series, + ) GR.polyline3d(mesh3d_triangles(x, y, z, series[:connections])...) else throw(ArgumentError("Not handled !")) @@ -1913,7 +2018,6 @@ function gr_draw_image(series, x, y, z, clims) GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba) end - # ---------------------------------------------------------------- for (mime, fmt) in ( @@ -1950,7 +2054,11 @@ function _display(plt::Plot{GRBackend}) ENV["GKS_FILEPATH"] = filepath gr_display(plt) GR.emergencyclosegks() - content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(read, filepath)), "\a") + content = string( + "\033]1337;File=inline=1;preserveAspectRatio=0:", + base64encode(open(read, filepath)), + "\a", + ) println(content) rm(filepath) else diff --git a/src/backends/hdf5.jl b/src/backends/hdf5.jl index 050992aa..9959a683 100644 --- a/src/backends/hdf5.jl +++ b/src/backends/hdf5.jl @@ -13,7 +13,6 @@ Read from .hdf5 file using: display(pread) ==# - #==TODO =============================================================================== 1. Support more features. @@ -56,7 +55,8 @@ import ..HDF5PLOT_MAP_STR2TELEM, ..HDF5PLOT_MAP_TELEM2STR import ..HDF5Plot_PlotRef, ..HDF5PLOT_PLOTREF import ..BoundingBox, ..Extrema, ..Length import ..RecipesPipeline.datetimeformatter -import ..PlotUtils.ColorPalette, ..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient +import ..PlotUtils.ColorPalette, + ..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient import ..Surface, ..Shape, ..Arrow import ..GridLayout, ..RootLayout import ..Font, ..PlotText, ..SeriesAnnotations @@ -66,14 +66,13 @@ import .._axis_defaults import ..plot, ..plot! #Types that already have built-in HDF5 support (just write out natively): -const HDF5_SupportedTypes = Union{Number, String} +const HDF5_SupportedTypes = Union{Number,String} #TODO: Types_HDF5Support #Dispatch types: -struct CplxTuple; end #Identifies a "complex" tuple structure (not merely numbers) +struct CplxTuple end #Identifies a "complex" tuple structure (not merely numbers) #HDF5 reader will auto-detect type correctly: -struct HDF5_AutoDetect; end #See HDF5_SupportedTypes - +struct HDF5_AutoDetect end #See HDF5_SupportedTypes #== ===============================================================================# @@ -82,13 +81,12 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1 #Possible element types of high-level data types: #(Used to add type information as an HDF5 string attribute) #(Also used to dispatch appropriate read function through _read_typed()) - _telem2str = Dict{String, Type}( + _telem2str = Dict{String,Type}( "NOTHING" => Nothing, "SYMBOL" => Symbol, "RGBA" => Colorant, #Write out any Colorant to an #RRGGBBAA string "TUPLE" => Tuple, - "CTUPLE" => CplxTuple, #Tuple of complex structures - + "CTUPLE" => CplxTuple, "EXTREMA" => Extrema, "LENGTH" => Length, "ARRAY" => Array, #Array{Any} (because Array{T<:Union{Number, String}} natively supported by HDF5) @@ -115,10 +113,12 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1 "SUBPLOT" => Subplot, ) merge!(HDF5PLOT_MAP_STR2TELEM, _telem2str) #Faster to create than push!()?? - merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM)) + merge!( + HDF5PLOT_MAP_TELEM2STR, + Dict{Type,String}(v => k for (k, v) in HDF5PLOT_MAP_STR2TELEM), + ) end - #==Helper functions ===============================================================================# @@ -151,19 +151,18 @@ function _hdf5_merge!(dest::AKW, src::AKW) end #_type_for_map returns the type to use with HDF5PLOT_MAP_TELEM2STR[], in case it is not concrete: -_type_for_map(::Type{T}) where T = T #Catch-all -_type_for_map(::Type{T}) where T<:BoundingBox = BoundingBox -_type_for_map(::Type{T}) where T<:ColorScheme = ColorScheme -_type_for_map(::Type{T}) where T<:Surface = Surface - +_type_for_map(::Type{T}) where {T} = T #Catch-all +_type_for_map(::Type{T}) where {T<:BoundingBox} = BoundingBox +_type_for_map(::Type{T}) where {T<:ColorScheme} = ColorScheme +_type_for_map(::Type{T}) where {T<:Surface} = Surface #==Read/write things like type name in attributes ===============================================================================# -function _write_datatype_attr(ds::Union{Group, Dataset}, ::Type{T}) where T +function _write_datatype_attr(ds::Union{Group,Dataset}, ::Type{T}) where {T} typestr = HDF5PLOT_MAP_TELEM2STR[T] HDF5.attributes(ds)["TYPE"] = typestr end -function _read_datatype_attr(ds::Union{Group, Dataset}) +function _read_datatype_attr(ds::Union{Group,Dataset}) if !Base.haskey(HDF5.attributes(ds), "TYPE") return HDF5_AutoDetect end @@ -173,7 +172,7 @@ function _read_datatype_attr(ds::Union{Group, Dataset}) end #Type parameter attributes: -function _write_typeparam_attr(ds::Dataset, v::Length{T}) where T +function _write_typeparam_attr(ds::Dataset, v::Length{T}) where {T} HDF5.attributes(ds)["TYPEPARAM"] = string(T) #Need to add units for Length end _read_typeparam_attr(ds::Dataset) = HDF5.read(HDF5.attributes(ds)["TYPEPARAM"]) @@ -186,8 +185,8 @@ _read_length_attr(::Type{Vector}, grp::Group) = HDF5.read(HDF5.attributes(grp)[" function _write_size_attr(grp::Group, v::Array) #of an array HDF5.attributes(grp)["SIZE"] = [size(v)...] end -_read_size_attr(::Type{Array}, grp::Group) = tuple(HDF5.read(HDF5.attributes(grp)["SIZE"])...) - +_read_size_attr(::Type{Array}, grp::Group) = + tuple(HDF5.read(HDF5.attributes(grp)["SIZE"])...) #==_write_typed(): Simple (leaf) datatypes. (Labels with type name.) ===============================================================================# @@ -228,9 +227,9 @@ function _write_typed(grp::Group, name::String, v::Length) end function _write_typed(grp::Group, name::String, v::typeof(datetimeformatter)) grp[name] = string(v) #Just write something that helps reader - _write_datatype_attr(grp[name], typeof(datetimeformatter)) + _write_datatype_attr(grp[name], typeof(datetimeformatter)) end -function _write_typed(grp::Group, name::String, v::Array{T}) where T<:Number #Default for arrays +function _write_typed(grp::Group, name::String, v::Array{T}) where {T<:Number} #Default for arrays grp[name] = v return #No need to _write_datatype_attr end @@ -238,8 +237,6 @@ function _write_typed(grp::Group, name::String, v::AbstractRange) _write_typed(grp, name, collect(v)) #For now end - - #== Helper functions for writing complex data structures ===============================================================================# @@ -270,20 +267,19 @@ function _write(grp::Group, name::String, d::AbstractDict) end #Write out arbitrary `struct`s: -function _writestructgeneric(grp::Group, obj::T) where T +function _writestructgeneric(grp::Group, obj::T) where {T} for fname in fieldnames(T) - v = getfield(obj, fname) - _write_typed(grp, String(fname), v) + v = getfield(obj, fname) + _write_typed(grp, String(fname), v) end return end - #==_write_typed(): More complex structures. (Labels with type name.) ===============================================================================# #Catch-all (default behaviour for `struct`s): -function _write_typed(grp::Group, name::String, v::T) where T +function _write_typed(grp::Group, name::String, v::T) where {T} #NOTE: need "name" parameter so that call signature is same with built-ins MT = _type_for_map(T) try #Check to see if type is supported @@ -299,12 +295,12 @@ function _write_typed(grp::Group, name::String, v::T) where T _writestructgeneric(objgrp, v) end -function _write_typed(grp::Group, name::String, v::Array{T}) where T +function _write_typed(grp::Group, name::String, v::Array{T}) where {T} _write_harray(grp, name, v) _write_datatype_attr(grp[name], Array) #{Any} end -function _write_typed(grp::Group, name::String, v::Tuple, ::Type{ELT}) where ELT<: Number #Basic Tuple +function _write_typed(grp::Group, name::String, v::Tuple, ::Type{ELT}) where {ELT<:Number} #Basic Tuple _write_typed(grp, name, [v...]) _write_datatype_attr(grp[name], Tuple) end @@ -315,12 +311,12 @@ end _write_typed(grp::Group, name::String, v::Tuple) = _write_typed(grp, name, v, eltype(v)) function _write_typed(grp::Group, name::String, v::Dict) -#= - tstr = string(Dict) - path = HDF5.name(grp) * "/" * name - @info("Type not supported: $tstr\npath: $path") - return -=# + #= + tstr = string(Dict) + path = HDF5.name(grp) * "/" * name + @info("Type not supported: $tstr\npath: $path") + return + =# #No support for structures with Dicts yet end function _write_typed(grp::Group, name::String, d::DefaultsDict) #Typically for plot attributes @@ -347,7 +343,6 @@ function _write_typed(grp::Group, name::String, v::Plot) #Don't write plot references end - #==_write(): Write out more complex structures NOTE: No need to write out type information (inferred from hierarchy) ===============================================================================# @@ -378,7 +373,11 @@ function _write(grp::Group, plt::Plot{HDF5Backend}) return end -function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString; name::String="_unnamed") +function hdf5plot_write( + plt::Plot{HDF5Backend}, + path::AbstractString; + name::String = "_unnamed", +) HDF5.h5open(path, "w") do file HDF5.write_dataset(file, "VERSION_INFO", _get_Plots_versionstr()) grp = HDF5.create_group(file, h5plotpath(name)) @@ -386,7 +385,6 @@ function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString; name::Stri end end - #== _read(): Read data, but not type information. ===============================================================================# @@ -417,7 +415,6 @@ function _read(::Type{Length}, ds::Dataset) end _read(::Type{typeof(datetimeformatter)}, ds::Dataset) = datetimeformatter - #== Helper functions for reading in complex data structures ===============================================================================# @@ -429,7 +426,7 @@ function _read_typed(grp::Group, name::String) end #_readstructgeneric: Needs object values to be written out with _write_typed(): -function _readstructgeneric(::Type{T}, grp::Group) where T +function _readstructgeneric(::Type{T}, grp::Group) where {T} vlist = Array{Any}(nothing, fieldcount(T)) for (i, fname) in enumerate(fieldnames(T)) vlist[i] = _read_typed(grp, String(fname)) @@ -454,7 +451,6 @@ function _read(::Type{KW}, grp::Group) return d end - #== _read(): More complex structures. ===============================================================================# @@ -463,7 +459,9 @@ _read(T::Type, grp::Group) = _readstructgeneric(T, grp) function _read(::Type{Array}, grp::Group) #Array{Any} sz = _read_size_attr(Array, grp) - if tuple(0) == sz; return []; end + if tuple(0) == sz + return [] + end result = Array{Any}(undef, sz) lidx = LinearIndices(sz) @@ -498,7 +496,9 @@ function _read(::Type{DefaultsDict}, grp::Group) #User should set DefaultsDict.defaults to one of: # _plot_defaults, _subplot_defaults, _axis_defaults, _series_defaults path = HDF5.name(ds) - @warn("Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot.") + @warn( + "Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot." + ) end function _read(::Type{Axis}, grp::Group) #1st arg appears to be ref to subplots. Seems to work without it. @@ -510,7 +510,6 @@ function _read(::Type{Subplot}, grp::Group) return HDF5PLOT_PLOTREF.ref.subplots[idx] end - #== _read(): Main plot structures ===============================================================================# @@ -538,7 +537,7 @@ function _read_plot(grp::Group) n = _read_length_attr(Vector, listgrp) #Construct new plot, +allocate subplots: - plt = plot(layout=n) + plt = plot(layout = n) HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout" agrp = HDF5.open_group(grp, "attr") @@ -552,17 +551,15 @@ function _read_plot(grp::Group) return plt end -function hdf5plot_read(path::AbstractString; name::String="_unnamed") +function hdf5plot_read(path::AbstractString; name::String = "_unnamed") HDF5.h5open(path, "r") do file grp = HDF5.open_group(file, h5plotpath("_unnamed")) return _read_plot(grp) end end - end #module _hdf5_implementation - #==Implement Plots.jl backend interface for HDF5Backend ===============================================================================# @@ -640,7 +637,8 @@ end #==Interface actually required to use HDF5Backend ===============================================================================# -hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) = _hdf5_implementation.hdf5plot_write(plt, path) +hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) = + _hdf5_implementation.hdf5plot_write(plt, path) hdf5plot_write(path::AbstractString) = _hdf5_implementation.hdf5plot_write(current(), path) hdf5plot_read(path::AbstractString) = _hdf5_implementation.hdf5plot_read(path) diff --git a/src/backends/inspectdr.jl b/src/backends/inspectdr.jl index ac362838..e5db6d2b 100644 --- a/src/backends/inspectdr.jl +++ b/src/backends/inspectdr.jl @@ -44,16 +44,16 @@ _inspectdr_mapcolor(v::Colorant) = v function _inspectdr_mapcolor(g::PlotUtils.ColorGradient) @warn("Color gradients are currently unsupported in InspectDR.") #Pick middle color: - _inspectdr_mapcolor(g.colors[div(1+end,2)]) + _inspectdr_mapcolor(g.colors[div(1 + end, 2)]) end function _inspectdr_mapcolor(v::AVec) @warn("Vectors of colors are currently unsupported in InspectDR.") #Pick middle color: - _inspectdr_mapcolor(v[div(1+end,2)]) + _inspectdr_mapcolor(v[div(1 + end, 2)]) end #Hack: suggested point size does not seem adequate relative to plot size, for some reason. -_inspectdr_mapptsize(v) = 1.5*v +_inspectdr_mapptsize(v) = 1.5 * v function _inspectdr_add_annotations(plot, x, y, val) #What kind of annotation is this? @@ -61,14 +61,21 @@ end #plot::InspectDR.Plot2D function _inspectdr_add_annotations(plot, x, y, val::PlotText) - vmap = Dict{Symbol, Symbol}(:top=>:t, :bottom=>:b) #:vcenter - hmap = Dict{Symbol, Symbol}(:left=>:l, :right=>:r) #:hcenter + vmap = Dict{Symbol,Symbol}(:top => :t, :bottom => :b) #:vcenter + hmap = Dict{Symbol,Symbol}(:left => :l, :right => :r) #:hcenter align = Symbol(get(vmap, val.font.valign, :c), get(hmap, val.font.halign, :c)) - fnt = InspectDR.Font(val.font.family, val.font.pointsize, - color =_inspectdr_mapcolor(val.font.color) + fnt = InspectDR.Font( + val.font.family, + val.font.pointsize, + color = _inspectdr_mapcolor(val.font.color), ) - ann = InspectDR.atext(val.str, x=x, y=y, - font=fnt, angle=val.font.rotation, align=align + ann = InspectDR.atext( + val.str, + x = x, + y = y, + font = fnt, + angle = val.font.rotation, + align = align, ) InspectDR.add(plot, ann) return @@ -84,7 +91,9 @@ function _inspectdr_getaxisticks(ticks, gridlines, xfrm) if ticks == :native #keep current elseif ttype == :ticks_and_labels - pos = ticks[1]; labels = ticks[2]; nticks = length(ticks[1]) + pos = ticks[1] + labels = ticks[2] + nticks = length(ticks[1]) newticks = TickCustom[TickCustom(_xfrm(pos[i]), labels[i]) for i in 1:nticks] gridlines = InspectDR.GridLinesCustom(gridlines) gridlines.major = newticks @@ -129,8 +138,8 @@ end # --------------------------------------------------------------------------- function _inspectdr_getscale(s::Symbol, yaxis::Bool) -#TODO: Support :asinh, :sqrt - kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis + #TODO: Support :asinh, :sqrt + kwargs = yaxis ? (:tgtmajor => 8, :tgtminor => 2) : () #More grid lines on y-axis if :log2 == s return InspectDR.AxisScale(:log2; kwargs...) elseif :log10 == s @@ -145,13 +154,12 @@ end # --------------------------------------------------------------------------- #Glyph used when plotting "Shape"s: -INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline( - 2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y -) +INSPECTDR_GLYPH_SHAPE = + InspectDR.GlyphPolyline(2 * InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y) mutable struct InspecDRPlotRef - mplot::Union{Nothing, InspectDR.Multiplot} - gui::Union{Nothing, InspectDR.GtkPlot} + mplot::Union{Nothing,InspectDR.Multiplot} + gui::Union{Nothing,InspectDR.GtkPlot} end _inspectdr_getmplot(::Any) = nothing @@ -200,7 +208,9 @@ end function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend}) plot = sp.o #Don't do anything without a "subplot" object: Will process later. - if nothing == plot; return; end + if nothing == plot + return + end plot.data = [] plot.userannot = [] #Clear old markers/text annotation/polyline "annotation" return plot @@ -219,7 +229,9 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series) clims = get_clims(sp, series) #Don't do anything without a "subplot" object: Will process later. - if nothing == plot; return; end + if nothing == plot + return + end _vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors x, y = if st == :straightline @@ -230,30 +242,33 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series) #No support for polar grid... but can still perform polar transformation: if ispolar(sp) - Θ = x; r = y - x = r.*cos.(Θ); y = r.*sin.(Θ) + Θ = x + r = y + x = r .* cos.(Θ) + y = r .* sin.(Θ) end # doesn't handle mismatched x/y - wrap data (pyplot behaviour): - nx = length(x); ny = length(y) + nx = length(x) + ny = length(y) if nx < ny - series[:x] = Float64[x[mod1(i,nx)] for i=1:ny] + series[:x] = Float64[x[mod1(i, nx)] for i in 1:ny] elseif ny > nx - series[:y] = Float64[y[mod1(i,ny)] for i=1:nx] + series[:y] = Float64[y[mod1(i, ny)] for i in 1:nx] end -#= TODO: Eventually support - series[:fillcolor] #I think this is fill under line - zorder = series[:series_plotindex] + #= TODO: Eventually support + series[:fillcolor] #I think this is fill under line + zorder = series[:series_plotindex] -For st in :shape: - zorder = series[:series_plotindex], -=# + For st in :shape: + zorder = series[:series_plotindex], + =# if st in (:shape,) x, y = shape_data(series) nmax = 0 - for (i,rng) in enumerate(iter_segments(x, y)) + for (i, rng) in enumerate(iter_segments(x, y)) nmax = i if length(rng) > 1 linewidth = series[:linewidth] @@ -261,11 +276,12 @@ For st in :shape: linecolor = _inspectdr_mapcolor(_cycle(c, i)) c = plot_color(get_fillcolor(series), get_fillalpha(series)) fillcolor = _inspectdr_mapcolor(_cycle(c, i)) - line = InspectDR.line( - style=:solid, width=linewidth, color=linecolor - ) + line = InspectDR.line(style = :solid, width = linewidth, color = linecolor) apline = InspectDR.PolylineAnnotation( - x[rng], y[rng], line=line, fillcolor=fillcolor + x[rng], + y[rng], + line = line, + fillcolor = fillcolor, ) InspectDR.add(plot, apline) end @@ -278,21 +294,24 @@ For st in :shape: linecolor = _inspectdr_mapcolor(_cycle(c, i)) c = plot_color(get_fillcolor(series), get_fillalpha(series)) fillcolor = _inspectdr_mapcolor(_cycle(c, i)) - wfrm = InspectDR.add(plot, Float64[], Float64[], id=series[:label]) + wfrm = InspectDR.add(plot, Float64[], Float64[], id = series[:label]) wfrm.line = InspectDR.line( - style=:none, width=linewidth, #linewidth affects glyph + style = :none, + width = linewidth, #linewidth affects glyph ) wfrm.glyph = InspectDR.glyph( - shape = INSPECTDR_GLYPH_SHAPE, size = 8, - color = linecolor, fillcolor = fillcolor + shape = INSPECTDR_GLYPH_SHAPE, + size = 8, + color = linecolor, + fillcolor = fillcolor, ) end - elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost) + elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost) #NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think). linewidth = series[:linewidth] #More efficient & allows some support for markerstrokewidth: - _style = (0==linewidth ? :none : series[:linestyle]) - wfrm = InspectDR.add(plot, x, y, id=series[:label]) + _style = (0 == linewidth ? :none : series[:linestyle]) + wfrm = InspectDR.add(plot, x, y, id = series[:label]) wfrm.line = InspectDR.line( style = _style, width = series[:linewidth], @@ -306,14 +325,18 @@ For st in :shape: wfrm.glyph = InspectDR.glyph( shape = _inspectdr_mapglyph(series[:markershape]), size = _inspectdr_mapglyphsize(series[:markersize]), - color = _inspectdr_mapcolor(plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series))), - fillcolor = _inspectdr_mapcolor(plot_color(get_markercolor(series, clims), get_markeralpha(series))), + color = _inspectdr_mapcolor( + plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series)), + ), + fillcolor = _inspectdr_mapcolor( + plot_color(get_markercolor(series, clims), get_markeralpha(series)), + ), ) end # this is all we need to add the series_annotations text anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, x, y) + for (xi, yi, str, fnt) in EachAnn(anns, x, y) _inspectdr_add_annotations(plot, xi, yi, PlotText(str, fnt)) end return @@ -333,66 +356,72 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend}) plot = sp.o strip = plot.strips[1] #Only 1 strip supported with Plots.jl - xaxis = sp[:xaxis]; yaxis = sp[:yaxis] + xaxis = sp[:xaxis] + yaxis = sp[:yaxis] xgrid_show = xaxis[:grid] ygrid_show = yaxis[:grid] strip.grid = InspectDR.GridRect( - vmajor=xgrid_show, # vminor=xgrid_show, - hmajor=ygrid_show, # hminor=ygrid_show, + vmajor = xgrid_show, # vminor=xgrid_show, + hmajor = ygrid_show, # hminor=ygrid_show, ) - plot.xscale = _inspectdr_getscale(xaxis[:scale], false) - strip.yscale = _inspectdr_getscale(yaxis[:scale], true) - xmin, xmax = axis_limits(sp, :x) - ymin, ymax = axis_limits(sp, :y) - if ispolar(sp) - #Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax) - rmax = NaNMath.max(abs(ymin), abs(ymax)) - xmin, xmax = -rmax, rmax - ymin, ymax = -rmax, rmax - end - plot.xext_full = InspectDR.PExtents1D(xmin, xmax) - strip.yext_full = InspectDR.PExtents1D(ymin, ymax) - #Set current extents = full extents (needed for _eval(strip.grid,...)) - plot.xext = plot.xext_full - strip.yext = strip.yext_full - _inspectdr_setticks(sp, plot, strip, xaxis, yaxis) + plot.xscale = _inspectdr_getscale(xaxis[:scale], false) + strip.yscale = _inspectdr_getscale(yaxis[:scale], true) + xmin, xmax = axis_limits(sp, :x) + ymin, ymax = axis_limits(sp, :y) + if ispolar(sp) + #Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax) + rmax = NaNMath.max(abs(ymin), abs(ymax)) + xmin, xmax = -rmax, rmax + ymin, ymax = -rmax, rmax + end + plot.xext_full = InspectDR.PExtents1D(xmin, xmax) + strip.yext_full = InspectDR.PExtents1D(ymin, ymax) + #Set current extents = full extents (needed for _eval(strip.grid,...)) + plot.xext = plot.xext_full + strip.yext = strip.yext_full + _inspectdr_setticks(sp, plot, strip, xaxis, yaxis) a = plot.annotation - a.title = sp[:title] - a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]] + a.title = sp[:title] + a.xlabel = xaxis[:guide] + a.ylabels = [yaxis[:guide]] #Modify base layout of new object: l = plot.layout.defaults = deepcopy(InspectDR.defaults.plotlayout) - #IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots. - #Works because plot uses defaults (not user-overwritten `layout.values`) - l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot]) - l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside]) - l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis]) - l.font_title = InspectDR.Font(sp[:titlefontfamily], - _inspectdr_mapptsize(sp[:titlefontsize]), - color = _inspectdr_mapcolor(sp[:titlefontcolor]) - ) - #Cannot independently control fonts of axes with InspectDR: - l.font_axislabel = InspectDR.Font(xaxis[:guidefontfamily], - _inspectdr_mapptsize(xaxis[:guidefontsize]), - color = _inspectdr_mapcolor(xaxis[:guidefontcolor]) - ) - l.font_ticklabel = InspectDR.Font(xaxis[:tickfontfamily], - _inspectdr_mapptsize(xaxis[:tickfontsize]), - color = _inspectdr_mapcolor(xaxis[:tickfontcolor]) - ) - l.enable_legend = (sp[:legend] != :none) - #l.halloc_legend = 150 #TODO: compute??? - l.font_legend = InspectDR.Font(sp[:legendfontfamily], - _inspectdr_mapptsize(sp[:legendfontsize]), - color = _inspectdr_mapcolor(sp[:legendfontcolor]) - ) - l.frame_legend.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend]) + #IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots. + #Works because plot uses defaults (not user-overwritten `layout.values`) + l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot]) + l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside]) + l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis]) + l.font_title = InspectDR.Font( + sp[:titlefontfamily], + _inspectdr_mapptsize(sp[:titlefontsize]), + color = _inspectdr_mapcolor(sp[:titlefontcolor]), + ) + #Cannot independently control fonts of axes with InspectDR: + l.font_axislabel = InspectDR.Font( + xaxis[:guidefontfamily], + _inspectdr_mapptsize(xaxis[:guidefontsize]), + color = _inspectdr_mapcolor(xaxis[:guidefontcolor]), + ) + l.font_ticklabel = InspectDR.Font( + xaxis[:tickfontfamily], + _inspectdr_mapptsize(xaxis[:tickfontsize]), + color = _inspectdr_mapcolor(xaxis[:tickfontcolor]), + ) + l.enable_legend = (sp[:legend] != :none) + #l.halloc_legend = 150 #TODO: compute??? + l.font_legend = InspectDR.Font( + sp[:legendfontfamily], + _inspectdr_mapptsize(sp[:legendfontsize]), + color = _inspectdr_mapcolor(sp[:legendfontcolor]), + ) + l.frame_legend.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend]) - #_round!() ensures values use integer spacings (looks better on screen): - InspectDR._round!(InspectDR.autofit2font!(l, legend_width=10.0)) #10 "em"s wide + #_round!() ensures values use integer spacings (looks better on screen): + InspectDR._round!(InspectDR.autofit2font!(l, legend_width = 10.0)) #10 "em"s wide return end @@ -400,7 +429,9 @@ end # for the calcs function _before_layout_calcs(plt::Plot{InspectDRBackend}) mplot = _inspectdr_getmplot(plt.o) - if nothing == mplot; return; end + if nothing == mplot + return + end mplot.title = plt[:plot_title] if "" == mplot.title @@ -409,7 +440,7 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend}) end mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside]) - mplot.layout[:frame] = mplot.layout[:frame] #register changes + mplot.layout[:frame] = mplot.layout[:frame] #register changes resize!(mplot.subplots, length(plt.subplots)) nsubplots = length(plt.subplots) for (i, sp) in enumerate(plt.subplots) @@ -453,17 +484,19 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{InspectDRBackend}) plot = sp.o - if !isa(plot, InspectDR.Plot2D); return sp.minpad; end + if !isa(plot, InspectDR.Plot2D) + return sp.minpad + end #Computing plotbounds with 0-BoundingBox returns required padding: - bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0)) + bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0, 0, 0, 0)) #NOTE: plotbounds always pads for titles, legends, etc. even if not in use. #TODO: possibly zero-out items not in use?? # add in the user-specified margin to InspectDR padding: - leftpad = abs(bb.xmin)*px + sp[:left_margin] - toppad = abs(bb.ymin)*px + sp[:top_margin] - rightpad = abs(bb.xmax)*px + sp[:right_margin] - bottompad = abs(bb.ymax)*px + sp[:bottom_margin] + leftpad = abs(bb.xmin) * px + sp[:left_margin] + toppad = abs(bb.ymin) * px + sp[:top_margin] + rightpad = abs(bb.xmax) * px + sp[:right_margin] + bottompad = abs(bb.ymax) * px + sp[:bottom_margin] sp.minpad = (leftpad, toppad, rightpad, bottompad) end @@ -472,21 +505,25 @@ end # Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations]) function _update_plot_object(plt::Plot{InspectDRBackend}) mplot = _inspectdr_getmplot(plt.o) - if nothing == mplot; return; end + if nothing == mplot + return + end mplot.bblist = InspectDR.BoundingBox[] for (i, sp) in enumerate(plt.subplots) figw, figh = sp.plt[:size] - pcts = bbox_to_pcts(sp.bbox, figw*px, figh*px) + pcts = bbox_to_pcts(sp.bbox, figw * px, figh * px) _left, _bottom, _width, _height = pcts - ymax = 1.0-_bottom + ymax = 1.0 - _bottom ymin = ymax - _height - bb = InspectDR.BoundingBox(_left, _left+_width, ymin, ymax) + bb = InspectDR.BoundingBox(_left, _left + _width, ymin, ymax) push!(mplot.bblist, bb) end gplot = _inspectdr_getgui(plt.o) - if nothing == gplot; return; end + if nothing == gplot + return + end gplot.src = mplot #Ensure still references current plot InspectDR.refresh(gplot) @@ -522,7 +559,9 @@ end # Display/show the plot (open a GUI window, or browser page, for example). function _display(plt::Plot{InspectDRBackend}) mplot = _inspectdr_getmplot(plt.o) - if nothing == mplot; return; end + if nothing == mplot + return + end gplot = _inspectdr_getgui(plt.o) if nothing == gplot diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index cde7fd9b..e63bd9ae 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -8,23 +8,11 @@ Base.@kwdef mutable struct PGFPlotsXPlot function PGFPlotsXPlot(is_created, was_shown, the_plot) pgfx_plot = new(is_created, was_shown, the_plot) # tikz libraries - PGFPlotsX.push_preamble!( - pgfx_plot.the_plot, - "\\usetikzlibrary{arrows.meta}", - ) - PGFPlotsX.push_preamble!( - pgfx_plot.the_plot, - "\\usetikzlibrary{backgrounds}", - ) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{backgrounds}") # pgfplots libraries - PGFPlotsX.push_preamble!( - pgfx_plot.the_plot, - "\\usepgfplotslibrary{patchplots}", - ) - PGFPlotsX.push_preamble!( - pgfx_plot.the_plot, - "\\usepgfplotslibrary{fillbetween}", - ) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}") + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween}") # compatibility fixes # add background layer to standard layers PGFPlotsX.push_preamble!( @@ -89,7 +77,7 @@ function Base.push!(pgfx_plot::PGFPlotsXPlot, item) end function pgfx_split_extra_opts(extra) - return (get(extra, :add, nothing), filter( x-> first(x) != :add, extra)) + return (get(extra, :add, nothing), filter(x -> first(x) != :add, extra)) end function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if !pgfx_plot.is_created || pgfx_plot.was_shown @@ -101,8 +89,9 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) extra_plot = wraptuple(extra_plot) push!(the_plot, extra_plot...) end - bgc = plt.attr[:background_color_outside] == :match ? - plt.attr[:background_color] : plt.attr[:background_color_outside] + bgc = + plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] : + plt.attr[:background_color_outside] if bgc isa Colors.Colorant cstr = plot_color(bgc) a = alpha(cstr) @@ -125,9 +114,14 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if sp[:subplot_index] == plt[:plot_titleindex] x = dx + sp_width / 2 - 10mm # FIXME: get rid of magic constant y = dy + sp_height / 2 - pgfx_add_annotation!(the_plot, x, y, PlotText(plt[:plot_title], plottitlefont(plt)), pgfx_thickness_scaling(plt); + pgfx_add_annotation!( + the_plot, + x, + y, + PlotText(plt[:plot_title], plottitlefont(plt)), + pgfx_thickness_scaling(plt); cs = "", - options = PGFPlotsX.Options("anchor" => "center") + options = PGFPlotsX.Options("anchor" => "center"), ) continue end @@ -152,29 +146,22 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "point meta min" => get_clims(sp)[1], "title" => sp[:title], "title style" => PGFPlotsX.Options( - pgfx_get_title_pos(title_loc)..., - "font" => pgfx_font( - sp[:titlefontsize], - pgfx_thickness_scaling(sp), - ), + pgfx_get_title_pos(title_loc)..., + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), "color" => title_cstr, "draw opacity" => title_a, "rotate" => sp[:titlefontrotation], ), "legend style" => pgfx_get_legend_style(sp), - "axis background/.style" => PGFPlotsX.Options( - "fill" => bgc_inside, - "opacity" => bgc_inside_a, - ), + "axis background/.style" => + PGFPlotsX.Options("fill" => bgc_inside, "opacity" => bgc_inside_a), # These are for layouting "anchor" => "north west", "xshift" => string(dx), "yshift" => string(-dy), ) - sp_width > 0 * mm ? push!(axis_opt, "width" => string(axis_width)) : - nothing - sp_height > 0 * mm ? push!(axis_opt, "height" => string(axis_height)) : - nothing + sp_width > 0 * mm ? push!(axis_opt, "width" => string(axis_width)) : nothing + sp_height > 0 * mm ? push!(axis_opt, "height" => string(axis_height)) : nothing for letter in (:x, :y, :z) if letter != :z || RecipesPipeline.is3d(sp) pgfx_axis!(axis_opt, sp, letter) @@ -216,11 +203,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) if hascolorbar(sp) cticks = get_colorbar_ticks(sp)[2] - colorbar_style = PGFPlotsX.Options( - "title" => sp[:colorbar_title], - ) + colorbar_style = PGFPlotsX.Options("title" => sp[:colorbar_title]) if sp[:colorbar] === :top - push!(colorbar_style, + push!( + colorbar_style, "at" => string((0.5, 1.05)), "anchor" => "south", "xtick" => string("{", join(cticks, ","), "}"), @@ -228,7 +214,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "xticklabel style" => pgfx_get_colorbar_ticklabel_style(sp), ) else - push!(colorbar_style, + push!( + colorbar_style, "ytick" => string("{", join(cticks, ","), "}"), "yticklabel style" => pgfx_get_colorbar_ticklabel_style(sp), ) @@ -279,15 +266,19 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) "color" => single_color(opt[:linecolor]), "name path" => string(series_id), ) - extra_series, extra_series_opt = pgfx_split_extra_opts(series[:extra_kwargs]) + extra_series, extra_series_opt = + pgfx_split_extra_opts(series[:extra_kwargs]) series_opt = merge(series_opt, PGFPlotsX.Options(extra_series_opt...)) - if RecipesPipeline.is3d(series) || st in (:heatmap, :contour) || (st == :quiver && opt[:z] !== nothing) + if ( + RecipesPipeline.is3d(series) || + st in (:heatmap, :contour) || + (st == :quiver && opt[:z] !== nothing) + ) series_func = PGFPlotsX.Plot3 else series_func = PGFPlotsX.Plot end - if sf !== nothing && - !isfilledcontour(series) && series[:ribbon] === nothing + if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing push!(series_opt, "area legend" => nothing) end pgfx_add_series!(Val(st), axis, series_opt, series, series_func, opt) @@ -337,7 +328,7 @@ end function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, opt) # treat segments - segments = collect(series_segments(series, series[:seriestype]; check=true)) + segments = collect(series_segments(series, series[:seriestype]; check = true)) sf = opt[:fillrange] for (k, segment) in enumerate(segments) i, rng = segment.attr_index, segment.range @@ -351,10 +342,7 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o scale_factor = 0.00125 mark_size = opt[:markersize] * scale_factor path = join( - [ - "($(x[i] * mark_size), $(y[i] * mark_size))" - for i in eachindex(x) - ], + ["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ", ) c = get_markercolor(series, i) @@ -372,31 +360,26 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o segment_opt = merge(segment_opt, pgfx_marker(opt, i)) end # add fillrange - if sf !== nothing && - !isfilledcontour(series) - if sf isa Number || sf isa AVec - pgfx_fillrange_series!( - axis, - series, - series_func, - i, - _cycle(sf, rng), - rng, - ) + if sf !== nothing && !isfilledcontour(series) + if sf isa Number || sf isa AVec + pgfx_fillrange_series!(axis, series, series_func, i, _cycle(sf, rng), rng) elseif sf isa Tuple && series[:ribbon] !== nothing for sfi in sf - pgfx_fillrange_series!( - axis, - series, - series_func, - i, - _cycle(sfi, rng), - rng, - ) + pgfx_fillrange_series!( + axis, + series, + series_func, + i, + _cycle(sfi, rng), + rng, + ) end end - if k == 1 && - series[:subplot][:legend] != :none && pgfx_should_add_to_legend(series) + if ( + k == 1 && + series[:subplot][:legend] != :none && + pgfx_should_add_to_legend(series) + ) pgfx_filllegend!(series_opt, opt) end end @@ -405,46 +388,44 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o if arrow isa Arrow arrow_opt = merge( segment_opt, - PGFPlotsX.Options("quiver" => PGFPlotsX.Options( - "u" => "\\thisrow{u}", - "v" => "\\thisrow{v}", - pgfx_arrow(arrow, :head) => nothing, - ) - ) + PGFPlotsX.Options( + "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(arrow, :head) => nothing, + ), + ), ) if arrow.side == :head - x_arrow = opt[:x][rng][end-1:end] - y_arrow = opt[:y][rng][end-1:end] - x_path = opt[:x][rng][1:end-1] - y_path = opt[:y][rng][1:end-1] + x_arrow = opt[:x][rng][(end - 1):end] + y_arrow = opt[:y][rng][(end - 1):end] + x_path = opt[:x][rng][1:(end - 1)] + y_path = opt[:y][rng][1:(end - 1)] elseif arrow.side == :tail x_arrow = opt[:x][rng][2:-1:1] y_arrow = opt[:y][rng][2:-1:1] x_path = opt[:x][rng][2:end] y_path = opt[:y][rng][2:end] elseif arrow.side == :both - x_arrow = opt[:x][rng][[2,1,end-1,end]] - y_arrow = opt[:y][rng][[2,1,end-1,end]] - x_path = opt[:x][rng][2:end-1] - y_path = opt[:y][rng][2:end-1] + x_arrow = opt[:x][rng][[2, 1, end - 1, end]] + y_arrow = opt[:y][rng][[2, 1, end - 1, end]] + x_path = opt[:x][rng][2:(end - 1)] + y_path = opt[:y][rng][2:(end - 1)] end coordinates = PGFPlotsX.Table([ - :x => x_arrow[1:2:end-1], - :y => y_arrow[1:2:end-1], - :u => [x_arrow[i] - x_arrow[i-1] for i in 2:2:lastindex(x_arrow)], - :v => [y_arrow[i] - y_arrow[i-1] for i in 2:2:lastindex(y_arrow)], - ]) - arrow_plot = - series_func(merge(series_opt, arrow_opt), coordinates) + :x => x_arrow[1:2:(end - 1)], + :y => y_arrow[1:2:(end - 1)], + :u => [x_arrow[i] - x_arrow[i - 1] for i in 2:2:lastindex(x_arrow)], + :v => [y_arrow[i] - y_arrow[i - 1] for i in 2:2:lastindex(y_arrow)], + ]) + arrow_plot = series_func(merge(series_opt, arrow_opt), coordinates) push!(axis, arrow_plot) coordinates = PGFPlotsX.Table(x_path, y_path) - segment_plot = - series_func(merge(series_opt, segment_opt), coordinates) + segment_plot = series_func(merge(series_opt, segment_opt), coordinates) push!(axis, segment_plot) else coordinates = PGFPlotsX.Table(pgfx_series_arguments(series, opt, rng)...) - segment_plot = - series_func(merge(series_opt, segment_opt), coordinates) + segment_plot = series_func(merge(series_opt, segment_opt), coordinates) push!(axis, segment_plot) end # fill between functions @@ -466,7 +447,10 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o end # for segments # get that last marker if !isnothing(opt[:y]) && !any(isnan, opt[:y]) && opt[:markershape] isa AVec - additional_plot = PGFPlotsX.PlotInc(pgfx_marker(opt, length(segments) + 1), PGFPlotsX.Coordinates(tuple((last(opt[:x]), last(opt[:y]))))) + additional_plot = PGFPlotsX.PlotInc( + pgfx_marker(opt, length(segments) + 1), + PGFPlotsX.Coordinates(tuple((last(opt[:x]), last(opt[:y])))), + ) push!(axis, additional_plot) end end @@ -503,9 +487,7 @@ function pgfx_add_series!(::Val{:surface}, axis, series_opt, series, series_func end function pgfx_add_series!(::Val{:wireframe}, axis, series_opt, series, series_func, opt) - push!(series_opt, "mesh" => nothing, - "mesh/rows" => length(opt[:x]) - ) + push!(series_opt, "mesh" => nothing, "mesh/rows" => length(opt[:x])) pgfx_add_series!(axis, series_opt, series, series_func, opt) end @@ -530,12 +512,15 @@ function pgfx_add_series!(::Val{:heatmap}, axis, series_opt, series, series_func end function pgfx_add_series!(::Val{:mesh3d}, axis, series_opt, series, series_func, opt) - ptable = join([ string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...) ], "\n ") + ptable = join( + [string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...)], + "\n ", + ) push!( series_opt, "patch" => nothing, "table/row sep" => "\\\\", - "patch table" => ptable + "patch table" => ptable, ) pgfx_add_series!(axis, series_opt, series, series_func, opt) end @@ -570,9 +555,10 @@ function pgfx_add_series!(::Val{:contour3d}, axis, series_opt, series, series_fu series_opt, "contour prepared" => PGFPlotsX.Options("labels" => opt[:contour_labels]), ) - series_opt = merge( series_opt, pgfx_linestyle(opt) ) + series_opt = merge(series_opt, pgfx_linestyle(opt)) args = pgfx_series_arguments(series, opt) - series_plot = series_func(series_opt, PGFPlotsX.Table(Contour.contours(args..., opt[:levels]))) + series_plot = + series_func(series_opt, PGFPlotsX.Table(Contour.contours(args..., opt[:levels]))) push!(axis, series_plot) pgfx_add_legend!(axis, series, opt) end @@ -670,7 +656,8 @@ function pgfx_add_legend!(axis, series, opt, i = 1) return nothing end -pgfx_series_arguments(series, opt, range) = (arg[range] for arg in pgfx_series_arguments(series, opt)) +pgfx_series_arguments(series, opt, range) = + (arg[range] for arg in pgfx_series_arguments(series, opt)) function pgfx_series_arguments(series, opt) st = series[:seriestype] return if st in (:contour, :contour3d) @@ -734,7 +721,7 @@ pgfx_get_xguide_pos(k) = get( left = "at={(ticklabel* cs:-0.02)}, anchor=east,", ), k, - "at={(ticklabel cs:0.5)}, anchor=near ticklabel" + "at={(ticklabel cs:0.5)}, anchor=near ticklabel", ) pgfx_get_yguide_pos(k) = get( @@ -744,7 +731,7 @@ pgfx_get_yguide_pos(k) = get( bottom = "at={(ticklabel* cs:-0.02)}, anchor=north,", ), k, - "at={(ticklabel cs:0.5)}, anchor=near ticklabel" + "at={(ticklabel cs:0.5)}, anchor=near ticklabel", ) pgfx_get_legend_pos(k) = get( @@ -769,25 +756,27 @@ pgfx_get_legend_pos(k) = get( Symbol(k), ("at" => string((1.02, 1)), "anchor" => "north west"), ) -pgfx_get_legend_pos(t::Tuple{S,T}) where {S<:Real,T<:Real} = ("at" => "{$(string(t))}", "anchor" => "north west") -pgfx_get_legend_pos(nt::NamedTuple) = ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor)) -pgfx_get_legend_pos(theta::Real) = pgfx_get_legend_pos((theta,:inner)) -function pgfx_get_legend_pos(v::Tuple{S,Symbol}) where S <: Real - (s,c) = sincosd(v[1]) +pgfx_get_legend_pos(t::Tuple{S,T}) where {S<:Real,T<:Real} = + ("at" => "{$(string(t))}", "anchor" => "north west") +pgfx_get_legend_pos(nt::NamedTuple) = + ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor)) +pgfx_get_legend_pos(theta::Real) = pgfx_get_legend_pos((theta, :inner)) +function pgfx_get_legend_pos(v::Tuple{S,Symbol}) where {S<:Real} + (s, c) = sincosd(v[1]) anchors = [ - "south west" "south" "south east"; - "west" "center" "east"; - "north west" "north" "north east"; - ] + "south west" "south" "south east" + "west" "center" "east" + "north west" "north" "north east" + ] if v[2] === :inner - rect = (0.07,0.5,1.0,0.07,0.52,1.0) - anchor = anchors[legend_anchor_index(s),legend_anchor_index(c)] + rect = (0.07, 0.5, 1.0, 0.07, 0.52, 1.0) + anchor = anchors[legend_anchor_index(s), legend_anchor_index(c)] else - rect = (-0.15,0.5,1.05,-0.15,0.52,1.1) - anchor = anchors[4-legend_anchor_index(s),4-legend_anchor_index(c)] + rect = (-0.15, 0.5, 1.05, -0.15, 0.52, 1.1) + anchor = anchors[4 - legend_anchor_index(s), 4 - legend_anchor_index(c)] end - return ("at"=>"$(string(legend_pos_from_angle(v[1],rect...)))", "anchor"=>anchor) + return ("at" => "$(string(legend_pos_from_angle(v[1],rect...)))", "anchor" => anchor) end function pgfx_get_legend_style(sp) @@ -805,12 +794,15 @@ function pgfx_get_legend_style(sp) "fill" => cstr, "fill opacity" => a, "text opacity" => alpha(plot_color(sp[:legendfontcolor])), - "font" => pgfx_font( - sp[:legendfontsize], - pgfx_thickness_scaling(sp), - ), + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)), "text" => plot_color(sp[:legendfontcolor]), - "cells" => PGFPlotsX.Options("anchor" => get((left = "west", right = "east", hcenter = "center"), legfont.halign, "west")), + "cells" => PGFPlotsX.Options( + "anchor" => get( + (left = "west", right = "east", hcenter = "center"), + legfont.halign, + "west", + ), + ), pgfx_get_legend_pos(sp[:legend])..., ) end @@ -819,21 +811,23 @@ pgfx_get_colorbar_pos(s) = get((left = " left", bottom = " horizontal", top = " horizontal"), s, "") pgfx_get_colorbar_pos(b::Bool) = "" -pgfx_get_title_pos(s) = - get(( +pgfx_get_title_pos(s) = get( + ( left = ("at" => "{(0,1)}", "anchor" => "south west"), right = ("at" => "{(1,1)}", "anchor" => "south east"), - ), s, - ("at" => "{(0.5,1)}", "anchor" => "south")) + ), + s, + ("at" => "{(0.5,1)}", "anchor" => "south"), +) pgfx_get_title_pos(t::Tuple) = ("at" => "{$(string(t))}", "anchor" => "south") -pgfx_get_title_pos(nt::NamedTuple) = ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor)) +pgfx_get_title_pos(nt::NamedTuple) = + ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor)) function pgfx_get_ticklabel_style(sp, axis) cstr = plot_color(axis[:tickfontcolor]) return PGFPlotsX.Options( - "font" => pgfx_font( - axis[:tickfontsize], pgfx_thickness_scaling(sp) - ), "color" => cstr, + "font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, "draw opacity" => alpha(cstr), "rotate" => axis[:tickfontrotation], ) @@ -842,9 +836,8 @@ end function pgfx_get_colorbar_ticklabel_style(sp) cstr = plot_color(sp[:colorbar_tickfontcolor]) return PGFPlotsX.Options( - "font" => pgfx_font( - sp[:colorbar_tickfontsize], pgfx_thickness_scaling(sp) - ), "color" => cstr, + "font" => pgfx_font(sp[:colorbar_tickfontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, "draw opacity" => alpha(cstr), "rotate" => sp[:colorbar_tickfontrotation], ) @@ -888,12 +881,20 @@ function pgfx_colormap(v::Vector{<:Colorant}) end, "\n") end function pgfx_colormap(cg::ColorGradient) - join(map(1:length(cg)) do i - @sprintf("rgb(%.8f)=(%.8f,%.8f,%.8f)", cg.values[i], red(cg.colors[i]), green(cg.colors[i]), blue(cg.colors[i])) - end, "\n") + join( + map(1:length(cg)) do i + @sprintf( + "rgb(%.8f)=(%.8f,%.8f,%.8f)", + cg.values[i], + red(cg.colors[i]), + green(cg.colors[i]), + blue(cg.colors[i]) + ) + end, + "\n", + ) end - function pgfx_framestyle(style::Symbol) if style in (:box, :axes, :origin, :zerolines, :grid, :none) return style @@ -950,20 +951,20 @@ end function pgfx_should_add_to_legend(series::Series) series.plotattributes[:primary] && - !( - series.plotattributes[:seriestype] in ( - :hexbin, - :bins2d, - :histogram2d, - :hline, - :vline, - :contour, - :contourf, - :contour3d, - :heatmap, - :image, + !( + series.plotattributes[:seriestype] in ( + :hexbin, + :bins2d, + :histogram2d, + :hline, + :vline, + :contour, + :contourf, + :contour3d, + :heatmap, + :image, + ) ) - ) end function pgfx_marker(plotattributes, i = 1) @@ -980,8 +981,9 @@ function pgfx_marker(plotattributes, i = 1) pgfx_thickness_scaling(plotattributes) * 0.75 * _cycle(plotattributes[:markersize], i) - mark_freq = !any(isnan, plotattributes[:y]) && plotattributes[:markershape] isa AVec ? - length(plotattributes[:markershape]) : 1 + mark_freq = + !any(isnan, plotattributes[:y]) && plotattributes[:markershape] isa AVec ? + length(plotattributes[:markershape]) : 1 return PGFPlotsX.Options( "mark" => shape isa Shape ? "PlotsShape$i" : pgfx_get_marker(shape), "mark size" => "$mark_size pt", @@ -1004,12 +1006,21 @@ function pgfx_marker(plotattributes, i = 1) else 0 end, - pgfx_get_linestyle(_cycle(plotattributes[:markerstrokestyle], i)) => nothing, + pgfx_get_linestyle(_cycle(plotattributes[:markerstrokestyle], i)) => + nothing, ), ) end -function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1; cs = "axis cs:", options = PGFPlotsX.Options()) +function pgfx_add_annotation!( + o, + x, + y, + val, + thickness_scaling = 1; + cs = "axis cs:", + options = PGFPlotsX.Options(), +) # Construct the style string. cstr = val.font.color a = alpha(cstr) @@ -1017,17 +1028,23 @@ function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1; cs = "axis cs o, join([ "\\node", - sprint(PGFPlotsX.print_tex, merge( - PGFPlotsX.Options( - get((hcenter = "", left = "right", right = "left"), val.font.halign, "") => - nothing, - "color" => cstr, - "draw opacity" => convert(Float16, a), - "rotate" => val.font.rotation, - "font" => pgfx_font(val.font.pointsize, thickness_scaling), + sprint( + PGFPlotsX.print_tex, + merge( + PGFPlotsX.Options( + get( + (hcenter = "", left = "right", right = "left"), + val.font.halign, + "", + ) => nothing, + "color" => cstr, + "draw opacity" => convert(Float16, a), + "rotate" => val.font.rotation, + "font" => pgfx_font(val.font.pointsize, thickness_scaling), + ), + options, ), - options - )), + ), string(" at (", cs, x, ",", y, ") {", val.str, "};"), ]), ) @@ -1097,12 +1114,10 @@ function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng) 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]) : + args = + RecipesPipeline.is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) : (opt[:x][rng], opt[:y][rng]) - push!( - axis, - PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)), - ) + push!(axis, PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...))) return axis end @@ -1132,8 +1147,8 @@ function pgfx_sanitize_string(s::AbstractString) s = replace(s, r"\\?\{" => "\\{") s = replace(s, r"\\?\}" => "\\}") s = map(split(s, "")) do s - isascii(s) ? s : latexify(s) - end |> join + isascii(s) ? s : latexify(s) + end |> join end @require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin using .LaTeXStrings @@ -1144,60 +1159,58 @@ end end end function pgfx_sanitize_plot!(plt) - for (key, value) in plt.attr - if value isa Union{AbstractString, AbstractVector{<:AbstractString}} - plt.attr[key] = pgfx_sanitize_string.(value) - end + for (key, value) in plt.attr + if value isa Union{AbstractString,AbstractVector{<:AbstractString}} + plt.attr[key] = pgfx_sanitize_string.(value) end - for subplot in plt.subplots - for (key, value) in subplot.attr - if key == :annotations && subplot.attr[:annotations] !== nothing - old_ann = subplot.attr[key] - for i in eachindex(old_ann) - subplot.attr[key][i] = (old_ann[i][1], old_ann[i][2], pgfx_sanitize_string(old_ann[i][3])) - end - elseif value isa Union{AbstractString, AbstractVector{<:AbstractString}} - subplot.attr[key] = pgfx_sanitize_string.(value) + end + for subplot in plt.subplots + for (key, value) in subplot.attr + if key == :annotations && subplot.attr[:annotations] !== nothing + old_ann = subplot.attr[key] + for i in eachindex(old_ann) + subplot.attr[key][i] = + (old_ann[i][1], old_ann[i][2], pgfx_sanitize_string(old_ann[i][3])) end + elseif value isa Union{AbstractString,AbstractVector{<:AbstractString}} + subplot.attr[key] = pgfx_sanitize_string.(value) end end - for series in plt.series_list - for (key, value) in series.plotattributes - if key == :series_annotations && series.plotattributes[:series_annotations] !== nothing - old_ann = series.plotattributes[key].strs - for i in eachindex(old_ann) - series.plotattributes[key].strs[i] = pgfx_sanitize_string(old_ann[i]) - end - elseif value isa Union{AbstractString, AbstractVector{<:AbstractString}} - series.plotattributes[key] = pgfx_sanitize_string.(value) + end + for series in plt.series_list + for (key, value) in series.plotattributes + if key == :series_annotations && + series.plotattributes[:series_annotations] !== nothing + old_ann = series.plotattributes[key].strs + for i in eachindex(old_ann) + series.plotattributes[key].strs[i] = pgfx_sanitize_string(old_ann[i]) end + elseif value isa Union{AbstractString,AbstractVector{<:AbstractString}} + series.plotattributes[key] = pgfx_sanitize_string.(value) end end - ## + end + ## end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis = sp[Symbol(letter, :axis)] # turn off scaled ticks + push!(opt, "scaled $(letter) ticks" => "false", string(letter, :label) => axis[:guide]) + tick_color = plot_color(axis[:foreground_color_axis]) push!( opt, - "scaled $(letter) ticks" => "false", - string(letter, :label) => axis[:guide], - ) - tick_color = plot_color(axis[:foreground_color_axis]) - push!(opt, - "$(letter) tick style" => PGFPlotsX.Options( - "color" => color(tick_color), - "opacity" => alpha(tick_color), - ), + "$(letter) tick style" => + PGFPlotsX.Options("color" => color(tick_color), "opacity" => alpha(tick_color)), ) tick_label_color = plot_color(axis[:tickfontcolor]) - push!(opt, + push!( + opt, "$(letter) tick label style" => PGFPlotsX.Options( "color" => color(tick_color), "opacity" => alpha(tick_color), - "rotate" => axis[:rotation] + "rotate" => axis[:rotation], ), ) @@ -1219,7 +1232,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) opt, string(letter, "label style") => PGFPlotsX.Options( labelpos => nothing, - "font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)), + "font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)), "color" => cstr, "draw opacity" => α, "rotate" => axis[:guidefontrotation], @@ -1233,8 +1246,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) scale = axis[:scale] if scale in (:log2, :ln, :log10) push!(opt, string(letter, :mode) => "log") - scale == :ln || - push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)") + scale == :ln || push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)") end # ticks on or off @@ -1252,7 +1264,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) end # limits - lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : + lims = + ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) push!(opt, string(letter, :min) => lims[1], string(letter, :max) => lims[2]) @@ -1263,12 +1276,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1] - push!( - opt, - string(letter, "tick") => string("{", join(tick_values, ","), "}"), - ) - if axis[:showaxis] && - axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto + push!(opt, string(letter, "tick") => string("{", join(tick_values, ","), "}")) + if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto # wrap the power part of label with } tick_labels = Vector{String}(undef, length(ticks[2])) for (i, label) in enumerate(ticks[2]) @@ -1283,25 +1292,20 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) ) elseif axis[:showaxis] tick_labels = - ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : - ticks[2] + ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2] if axis[:formatter] in (:scientific, :auto) tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$") tick_labels = replace.(tick_labels, Ref("×" => "\\times")) end push!( opt, - string(letter, "ticklabels") => - string("{", join(tick_labels, ","), "}"), + string(letter, "ticklabels") => string("{", join(tick_labels, ","), "}"), ) else push!(opt, string(letter, "ticklabels") => "{}") end if axis[:tick_direction] === :none - push!( - opt, - string(letter, "tick style") => "draw=none", - ) + push!(opt, string(letter, "tick style") => "draw=none") else push!( opt, @@ -1309,9 +1313,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) (axis[:tick_direction] == :out ? "outside" : "inside"), ) end - push!( - opt, string(letter, "ticklabel style") => pgfx_get_ticklabel_style(sp, axis) - ) + push!(opt, string(letter, "ticklabel style") => pgfx_get_ticklabel_style(sp, axis)) push!( opt, string(letter, " grid style") => pgfx_linestyle( @@ -1335,7 +1337,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) minor_ticks push!( opt, - string("extra ", letter, " ticks") => string("{", join(minor_ticks, ","), "}"), + string("extra ", letter, " ticks") => + string("{", join(minor_ticks, ","), "}"), ) push!(opt, string("extra ", letter, " tick labels") => "") push!( @@ -1348,7 +1351,9 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) axis[:minorgridalpha], axis[:minorgridstyle], ), - "major tick length" => typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 || axis[:minorticks] ? "0.1cm" : "0" + "major tick length" => + typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 || + axis[:minorticks] ? "0.1cm" : "0", ), ) end @@ -1405,7 +1410,8 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{PGFPlotsXBackend}) leg = sp[:legend] - if leg in (:best, :outertopright, :outerright, :outerbottomright) || (leg isa Tuple && leg[1] >= 1) + if leg in (:best, :outertopright, :outerright, :outerbottomright) || + (leg isa Tuple && leg[1] >= 1) sp.minpad = (0mm, 0mm, 5mm, 0mm) else sp.minpad = (0mm, 0mm, 0mm, 0mm) @@ -1425,33 +1431,21 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend}) end for mime in ("application/pdf", "image/svg+xml") - @eval function _show( - io::IO, - mime::MIME{Symbol($mime)}, - plt::Plot{PGFPlotsXBackend}, - ) + @eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend}) plt.o.was_shown = true show(io, mime, plt.o.the_plot) end end - function _show( - io::IO, - mime::MIME{Symbol("image/png")}, - plt::Plot{PGFPlotsXBackend}, - ) - plt.o.was_shown = true - plt_file = tempname() * ".png" - PGFPlotsX.pgfsave(plt_file, plt.o.the_plot; dpi=plt[:dpi]) - write(io, read(plt_file)) - rm(plt_file; force = true) - end +function _show(io::IO, mime::MIME{Symbol("image/png")}, plt::Plot{PGFPlotsXBackend}) + plt.o.was_shown = true + plt_file = tempname() * ".png" + PGFPlotsX.pgfsave(plt_file, plt.o.the_plot; dpi = plt[:dpi]) + write(io, read(plt_file)) + rm(plt_file; force = true) +end -function _show( - io::IO, - mime::MIME{Symbol("application/x-tex")}, - plt::Plot{PGFPlotsXBackend}, -) +function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend}) plt.o.was_shown = true PGFPlotsX.print_tex( io, diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index edc9ced9..8a47fc1b 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -7,12 +7,13 @@ function _plotly_framestyle(style::Symbol) return style else default_style = get((semi = :box, origin = :zerolines), style, :axes) - @warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was chosen instead.") + @warn( + "Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was chosen instead." + ) default_style end end - # -------------------------------------------------------------------------------------- using UUIDs @@ -23,7 +24,7 @@ function labelfunc(scale::Symbol, backend::PlotlyBackend) texfunc = labelfunc_tex(scale) function (x) tex_x = texfunc(x) - sup_x = replace( tex_x, r"\^{(.*)}"=>s"\1" ) + sup_x = replace(tex_x, r"\^{(.*)}" => s"\1") # replace dash with \minus (U+2212) replace(sup_x, "-" => "−") end @@ -32,30 +33,25 @@ end function plotly_font(font::Font, color = font.color) KW( :family => font.family, - :size => round(Int, font.pointsize*1.4), + :size => round(Int, font.pointsize * 1.4), :color => rgba_string(color), ) end - -function plotly_annotation_dict(x, y, val; xref="paper", yref="paper") - KW( - :text => val, - :xref => xref, - :x => x, - :yref => yref, - :y => y, - :showarrow => false, - ) +function plotly_annotation_dict(x, y, val; xref = "paper", yref = "paper") + KW(:text => val, :xref => xref, :x => x, :yref => yref, :y => y, :showarrow => false) end -function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper") - merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW( - :font => plotly_font(ptxt.font), - :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, - :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, - :rotation => -ptxt.font.rotation, - )) +function plotly_annotation_dict(x, y, ptxt::PlotText; xref = "paper", yref = "paper") + merge( + plotly_annotation_dict(x, y, ptxt.str; xref = xref, yref = yref), + KW( + :font => plotly_font(ptxt.font), + :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, + :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, + :rotation => -ptxt.font.rotation, + ), + ) end # function get_annotation_dict_for_arrow(plotattributes::KW, xyprev::Tuple, xy::Tuple, a::Arrow) @@ -100,9 +96,9 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts) if aspect_ratio == :equal aspect_ratio = 1.0 end - xmin,xmax = axis_limits(sp, :x) - ymin,ymax = axis_limits(sp, :y) - want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio + xmin, xmax = axis_limits(sp, :x) + ymin, ymax = axis_limits(sp, :y) + want_ratio = ((xmax - xmin) / (ymax - ymin)) / aspect_ratio parea_ratio = width(plotarea) / height(plotarea) if want_ratio > parea_ratio # need to shrink y @@ -118,34 +114,34 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts) pcts end - # this method gets the start/end in percentage of the canvas for this axis direction function plotly_domain(sp::Subplot) figw, figh = sp.plt[:size] - pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px) + pcts = bbox_to_pcts(sp.plotarea, figw * px, figh * px) pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts) x_domain = [pcts[1], pcts[1] + pcts[3]] y_domain = [pcts[2], pcts[2] + pcts[4]] return x_domain, y_domain end - function plotly_axis(axis, sp, anchor = nothing, domain = nothing) letter = axis[:letter] framestyle = sp[:framestyle] ax = KW( - :visible => framestyle != :none, - :title => axis[:guide], - :showgrid => axis[:grid], - :gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])), - :gridwidth => axis[:gridlinewidth], - :zeroline => framestyle == :zerolines, + :visible => framestyle != :none, + :title => axis[:guide], + :showgrid => axis[:grid], + :gridcolor => + rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])), + :gridwidth => axis[:gridlinewidth], + :zeroline => framestyle == :zerolines, :zerolinecolor => rgba_string(axis[:foreground_color_axis]), - :showline => framestyle in (:box, :axes) && axis[:showaxis], - :linecolor => rgba_string(plot_color(axis[:foreground_color_axis])), - :ticks => axis[:tick_direction] === :out ? "outside" : - axis[:tick_direction] === :in ? "inside" : "", - :mirror => framestyle == :box, + :showline => framestyle in (:box, :axes) && axis[:showaxis], + :linecolor => rgba_string(plot_color(axis[:foreground_color_axis])), + :ticks => + axis[:tick_direction] === :out ? "outside" : + axis[:tick_direction] === :in ? "inside" : "", + :mirror => framestyle == :box, :showticklabels => axis[:showaxis], ) if anchor !== nothing @@ -166,7 +162,9 @@ function plotly_axis(axis, sp, anchor = nothing, domain = nothing) if !(axis[:ticks] in (nothing, :none, false)) ax[:titlefont] = plotly_font(guidefont(axis)) ax[:tickfont] = plotly_font(tickfont(axis)) - ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis]) + ax[:tickcolor] = + framestyle in (:zerolines, :grid) || !axis[:showaxis] ? + rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis]) ax[:linecolor] = rgba_string(axis[:foreground_color_axis]) # ticks @@ -195,10 +193,7 @@ function plotly_axis(axis, sp, anchor = nothing, domain = nothing) end function plotly_polaraxis(sp::Subplot, axis::Axis) - ax = KW( - :visible => axis[:showaxis], - :showline => axis[:grid], - ) + ax = KW(:visible => axis[:showaxis], :showline => axis[:grid]) if axis[:letter] == :x ax[:range] = rad2deg.(axis_limits(sp, :x)) @@ -216,7 +211,7 @@ function plotly_layout(plt::Plot) w, h = plt[:size] plotattributes_out[:width], plotattributes_out[:height] = w, h plotattributes_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside]) - plotattributes_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20) + plotattributes_out[:margin] = KW(:l => 0, :b => 20, :r => 0, :t => 20) plotattributes_out[:annotations] = KW[] @@ -237,9 +232,12 @@ function plotly_layout(plt::Plot) else 0.5 * (left(bb) + right(bb)) end - titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px) + titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w * px, h * px) title_font = font(titlefont(sp), :top) - push!(plotattributes_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font))) + push!( + plotattributes_out[:annotations], + plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)), + ) end plotattributes_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside]) @@ -248,8 +246,10 @@ function plotly_layout(plt::Plot) sp[:framestyle] = _plotly_framestyle(sp[:framestyle]) if ispolar(sp) - plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis]) - plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis]) + plotattributes_out[Symbol("angularaxis$(spidx)")] = + plotly_polaraxis(sp, sp[:xaxis]) + plotattributes_out[Symbol("radialaxis$(spidx)")] = + plotly_polaraxis(sp, sp[:yaxis]) else x_domain, y_domain = plotly_domain(sp) if RecipesPipeline.is3d(sp) @@ -264,15 +264,15 @@ function plotly_layout(plt::Plot) #2.6 multiplier set camera eye such that whole plot can be seen :camera => KW( :eye => KW( - :x => cosd(azim)*sind(theta)*2.6, - :y => sind(azim)*sind(theta)*2.6, - :z => cosd(theta)*2.6, + :x => cosd(azim) * sind(theta) * 2.6, + :y => sind(azim) * sind(theta) * 2.6, + :z => cosd(theta) * 2.6, ), ), ) else plotattributes_out[Symbol("xaxis$(x_idx)")] = - plotly_axis(sp[:xaxis], sp, string("y", y_idx) , x_domain) + plotly_axis(sp[:xaxis], sp, string("y", y_idx), x_domain) # don't allow yaxis to be reupdated/reanchored in a linked subplot if spidx == y_idx plotattributes_out[Symbol("yaxis$(y_idx)")] = @@ -286,16 +286,28 @@ function plotly_layout(plt::Plot) # annotations for ann in sp[:annotations] - append!(plotattributes_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")]) + append!( + plotattributes_out[:annotations], + KW[plotly_annotation_dict( + locate_annotation(sp, ann...)...; + xref = "x$(x_idx)", + yref = "y$(y_idx)", + )], + ) end # series_annotations for series in series_list(sp) anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) - push!(plotattributes_out[:annotations], plotly_annotation_dict( - xi, - yi, - PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)") + for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y]) + push!( + plotattributes_out[:annotations], + plotly_annotation_dict( + xi, + yi, + PlotText(str, fnt); + xref = "x$(x_idx)", + yref = "y$(y_idx)", + ), ) end end @@ -318,26 +330,25 @@ function plotly_layout(plt::Plot) end # turn off hover if nothing's using it - if all(series -> series.plotattributes[:hover] in (false,:none), plt.series_list) + if all(series -> series.plotattributes[:hover] in (false, :none), plt.series_list) plotattributes_out[:hovermode] = "none" end plotattributes_out = recursive_merge(plotattributes_out, plt.attr[:extra_plot_kwargs]) end - function plotly_add_legend!(plotattributes_out::KW, sp::Subplot) plotattributes_out[:showlegend] = sp[:legend] != :none legend_position = plotly_legend_pos(sp[:legend]) if sp[:legend] != :none plotattributes_out[:legend] = KW( - :bgcolor => rgba_string(sp[:background_color_legend]), + :bgcolor => rgba_string(sp[:background_color_legend]), :bordercolor => rgba_string(sp[:foreground_color_legend]), :borderwidth => 1, :traceorder => "normal", :xanchor => legend_position.xanchor, :yanchor => legend_position.yanchor, - :font => plotly_font(legendfont(sp)), + :font => plotly_font(legendfont(sp)), :tracegroupgap => 0, :x => legend_position.coords[1], :y => legend_position.coords[2], @@ -361,55 +372,71 @@ function plotly_legend_pos(pos::Symbol) xouterright = 1.05 xouterleft = -0.15 plotly_legend_position_mapping = ( - right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"), - left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"), - top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"), - bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"), - bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"), + right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"), + left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"), + top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"), + bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"), + bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"), bottomright = (coords = [1.0, ybot], xanchor = "right", yanchor = "bottom"), - topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"), - topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"), - outertop =(coords = [center, youtertop ], xanchor = "upper", yanchor = "middle"), - outerbottom =(coords = [center, youterbot], xanchor = "lower", yanchor = "middle"), - outerleft =(coords = [xouterleft, center], xanchor = "left", yanchor = "top"), - outerright =(coords = [xouterright, center], xanchor = "right", yanchor = "top"), - outertopleft =(coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"), - outertopright = (coords = [xouterright, ytop], xanchor = "upper", yanchor = "right"), - outerbottomleft =(coords = [xouterleft, ybot], xanchor = "lower", yanchor = "left"), - outerbottomright =(coords = [xouterright, ybot], xanchor = "lower", yanchor = "right"), - default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto") + topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"), + topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"), + outertop = (coords = [center, youtertop], xanchor = "upper", yanchor = "middle"), + outerbottom = (coords = [center, youterbot], xanchor = "lower", yanchor = "middle"), + outerleft = (coords = [xouterleft, center], xanchor = "left", yanchor = "top"), + outerright = (coords = [xouterright, center], xanchor = "right", yanchor = "top"), + outertopleft = (coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"), + outertopright = ( + coords = [xouterright, ytop], + xanchor = "upper", + yanchor = "right", + ), + outerbottomleft = ( + coords = [xouterleft, ybot], + xanchor = "lower", + yanchor = "left", + ), + outerbottomright = ( + coords = [xouterright, ybot], + xanchor = "lower", + yanchor = "right", + ), + default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto"), ) - legend_position = get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default) + legend_position = + get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default) end -plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = (coords=v, xanchor="left", yanchor="top") +plotly_legend_pos(v::Tuple{S,T}) where {S<:Real,T<:Real} = + (coords = v, xanchor = "left", yanchor = "top") plotly_legend_pos(theta::Real) = plotly_legend_pos((theta, :inner)) -function plotly_legend_pos(v::Tuple{S,Symbol}) where S<:Real - (s,c) = sincosd(v[1]) +function plotly_legend_pos(v::Tuple{S,Symbol}) where {S<:Real} + (s, c) = sincosd(v[1]) xanchors = ["left", "center", "right"] yanchors = ["bottom", "middle", "top"] if v[2] === :inner - rect = (0.07,0.5,1.0,0.07,0.52,1.0) + rect = (0.07, 0.5, 1.0, 0.07, 0.52, 1.0) xanchor = xanchors[legend_anchor_index(c)] yanchor = yanchors[legend_anchor_index(s)] else - rect = (-0.15,0.5,1.05,-0.15,0.52,1.1) - xanchor = xanchors[4-legend_anchor_index(c)] - yanchor = yanchors[4-legend_anchor_index(s)] + rect = (-0.15, 0.5, 1.05, -0.15, 0.52, 1.1) + xanchor = xanchors[4 - legend_anchor_index(c)] + yanchor = yanchors[4 - legend_anchor_index(s)] end - return (coords=legend_pos_from_angle(v[1],rect...), xanchor=xanchor, yanchor=yanchor) + return ( + coords = legend_pos_from_angle(v[1], rect...), + xanchor = xanchor, + yanchor = yanchor, + ) end - function plotly_layout_json(plt::Plot) JSON.json(plotly_layout(plt), 4) end - plotly_colorscale(cg::ColorGradient, α = nothing) = [[v, rgba_string(plot_color(cg.colors[v], α))] for v in cg.values] function plotly_colorscale(c::AbstractVector{<:Colorant}, α = nothing) @@ -428,13 +455,12 @@ function plotly_colorscale(cg::PlotUtils.CategoricalColorGradient, α = nothing) cinds = repeat(1:n, inner = 2) vinds = vcat((i:(i + 1) for i in 1:n)...) return [ - [cg.values[vinds[i]], rgba_string(plot_color(color_list(cg)[cinds[i]], α))] - for i in eachindex(cinds) + [cg.values[vinds[i]], rgba_string(plot_color(color_list(cg)[cinds[i]], α))] for + i in eachindex(cinds) ] end plotly_colorscale(c, α = nothing) = plotly_colorscale(_as_gradient(c), α) - get_plotly_marker(k, def) = get( ( rect = "square", @@ -461,12 +487,11 @@ function plotly_link_indicies(plt::Plot, sp::Subplot) x_idx, y_idx end - # the Shape contructor will automatically close the shape. since we need it closed, # we split by NaNs and then construct/destruct the shapes to get the closed coords function plotly_close_shapes(x, y) xs, ys = nansplit(x), nansplit(y) - for i=eachindex(xs) + for i in eachindex(xs) shape = Shape(xs[i], ys[i]) xs[i], ys[i] = coords(shape) end @@ -479,7 +504,7 @@ function plotly_data(series::Series, letter::Symbol, data) data = if axis[:ticks] == :native && data !== nothing plotly_native_data(axis, data) else - data + data end if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d) @@ -512,7 +537,9 @@ function plotly_convert_to_datetime(x::AbstractArray, formatter::Function) elseif formatter == timeformatter map(xi -> string(Dates.Date(Dates.now()), " ", formatter(xi)), x) else - error("Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter") + error( + "Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter", + ) end end #ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z) @@ -550,11 +577,12 @@ function plotly_series(plt::Plot, series::Series) x, y = straightline_data(series, 100) z = series[:z] else - x, y, z = series[:x], series[:y], series[:z] + x, y, z = series[:x], series[:y], series[:z] end - x, y, z = (plotly_data(series, letter, data) - for (letter, data) in zip((:x, :y, :z), (x, y, z)) + x, y, z = ( + plotly_data(series, letter, data) for + (letter, data) in zip((:x, :y, :z), (x, y, z)) ) plotattributes_out[:name] = series[:label] @@ -562,7 +590,8 @@ function plotly_series(plt::Plot, series::Series) isscatter = st in (:scatter, :scatter3d, :scattergl) hasmarker = isscatter || series[:markershape] != :none hasline = st in (:path, :path3d, :straightline) - hasfillrange = st in (:path, :scatter, :scattergl, :straightline) && + hasfillrange = + st in (:path, :scatter, :scattergl, :straightline) && (isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple)) plotattributes_out[:colorbar] = KW(:title => sp[:colorbar_title]) @@ -580,7 +609,8 @@ function plotly_series(plt::Plot, series::Series) y = heatmap_edges(y, sp[:yaxis][:scale]) plotattributes_out[:type] = "heatmap" plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z - plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) + plotattributes_out[:colorscale] = + plotly_colorscale(series[:fillcolor], series[:fillalpha]) plotattributes_out[:showscale] = hascolorbar(sp) elseif st == :contour @@ -588,24 +618,31 @@ function plotly_series(plt::Plot, series::Series) plotattributes_out[:type] = "contour" plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z plotattributes_out[:ncontours] = series[:levels] + 2 - plotattributes_out[:contours] = KW(:coloring => filled ? "fill" : "lines", :showlabels => series[:contour_labels] == true) - plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha]) + plotattributes_out[:contours] = KW( + :coloring => filled ? "fill" : "lines", + :showlabels => series[:contour_labels] == true, + ) + plotattributes_out[:colorscale] = + plotly_colorscale(series[:linecolor], series[:linealpha]) plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series) elseif st in (:surface, :wireframe) - plotattributes_out[:type] = "surface" + plotattributes_out[:type] = "surface" plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z if st == :wireframe plotattributes_out[:hidesurface] = true wirelines = KW( :show => true, - :color => rgba_string(plot_color(series[:linecolor], series[:linealpha])), + :color => + rgba_string(plot_color(series[:linecolor], series[:linealpha])), :highlightwidth => series[:linewidth], ) - plotattributes_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines) + plotattributes_out[:contours] = + KW(:x => wirelines, :y => wirelines, :z => wirelines) plotattributes_out[:showscale] = false else - plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) + plotattributes_out[:colorscale] = + plotly_colorscale(series[:fillcolor], series[:fillalpha]) plotattributes_out[:opacity] = series[:fillalpha] if series[:fill_z] !== nothing plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z]) @@ -613,24 +650,34 @@ function plotly_series(plt::Plot, series::Series) plotattributes_out[:showscale] = hascolorbar(sp) end elseif st == :mesh3d - plotattributes_out[:type] = "mesh3d" + plotattributes_out[:type] = "mesh3d" plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z - if series[:connections] !== nothing - if typeof(series[:connections]) <: Tuple{Array,Array,Array} - i,j,k = series[:connections] - if !(length(i) == length(j) == length(k)) - throw(ArgumentError("Argument connections must consist of equally sized arrays.")) - end - plotattributes_out[:i] = i - plotattributes_out[:j] = j - plotattributes_out[:k] = k - else - throw(ArgumentError("Argument connections has to be a tuple of three arrays.")) - end - end - plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) - plotattributes_out[:color] = rgba_string(plot_color(series[:fillcolor], series[:fillalpha])) + if series[:connections] !== nothing + if typeof(series[:connections]) <: Tuple{Array,Array,Array} + i, j, k = series[:connections] + if !(length(i) == length(j) == length(k)) + throw( + ArgumentError( + "Argument connections must consist of equally sized arrays.", + ), + ) + end + plotattributes_out[:i] = i + plotattributes_out[:j] = j + plotattributes_out[:k] = k + else + throw( + ArgumentError( + "Argument connections has to be a tuple of three arrays.", + ), + ) + end + end + plotattributes_out[:colorscale] = + plotly_colorscale(series[:fillcolor], series[:fillalpha]) + plotattributes_out[:color] = + rgba_string(plot_color(series[:fillcolor], series[:fillalpha])) plotattributes_out[:opacity] = series[:fillalpha] if series[:fill_z] !== nothing plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z]) @@ -645,12 +692,25 @@ function plotly_series(plt::Plot, series::Series) if hasmarker inds = eachindex(x) plotattributes_out[:marker] = KW( - :symbol => get_plotly_marker(series[:markershape], string(series[:markershape])), + :symbol => + get_plotly_marker(series[:markershape], string(series[:markershape])), # :opacity => series[:markeralpha], :size => 2 * _cycle(series[:markersize], inds), - :color => rgba_string.(plot_color.(get_markercolor.(series, inds), get_markeralpha.(series, inds))), + :color => + rgba_string.( + plot_color.( + get_markercolor.(series, inds), + get_markeralpha.(series, inds), + ), + ), :line => KW( - :color => rgba_string.(plot_color.(get_markerstrokecolor.(series, inds), get_markerstrokealpha.(series, inds))), + :color => + rgba_string.( + plot_color.( + get_markerstrokecolor.(series, inds), + get_markerstrokealpha.(series, inds), + ), + ), :width => _cycle(series[:markerstrokewidth], inds), ), ) @@ -663,7 +723,7 @@ function plotly_series(plt::Plot, series::Series) end function plotly_series_shapes(plt::Plot, series::Series, clims) - segments = series_segments(series; check=true) + segments = series_segments(series; check = true) plotattributes_outs = Vector{KW}(undef, length(segments)) # TODO: create a plotattributes_out for each polygon @@ -678,8 +738,9 @@ function plotly_series_shapes(plt::Plot, series::Series, clims) :legendgroup => series[:label], ) - x, y = (plotly_data(series, letter, data) - for (letter, data) in zip((:x, :y), shape_data(series, 100)) + x, y = ( + plotly_data(series, letter, data) for + (letter, data) in zip((:x, :y), shape_data(series, 100)) ) for (k, segment) in enumerate(segments) @@ -687,22 +748,29 @@ function plotly_series_shapes(plt::Plot, series::Series, clims) length(rng) < 2 && continue # to draw polygons, we actually draw lines with fill - plotattributes_out = merge(plotattributes_base, KW( - :type => "scatter", - :mode => "lines", - :x => vcat(x[rng], x[rng[1]]), - :y => vcat(y[rng], y[rng[1]]), - :fill => "tozeroy", - :fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))), - )) + plotattributes_out = merge( + plotattributes_base, + KW( + :type => "scatter", + :mode => "lines", + :x => vcat(x[rng], x[rng[1]]), + :y => vcat(y[rng], y[rng[1]]), + :fill => "tozeroy", + :fillcolor => rgba_string( + plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + ), + ), + ) if series[:markerstrokewidth] > 0 plotattributes_out[:line] = KW( - :color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))), + :color => rgba_string( + plot_color(get_linecolor(series, clims, i), get_linealpha(series, i)), + ), :width => get_linewidth(series, i), :dash => string(get_linestyle(series, i)), ) end - plotattributes_out[:showlegend] = k==1 ? should_add_to_legend(series) : false + plotattributes_out[:showlegend] = k == 1 ? should_add_to_legend(series) : false plotly_polar!(plotattributes_out, series) plotly_hover!(plotattributes_out, _cycle(series[:hover], i)) plotattributes_outs[k] = plotattributes_out @@ -712,7 +780,10 @@ function plotly_series_shapes(plt::Plot, series::Series, clims) elseif series[:line_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line)) elseif series[:marker_z] !== nothing - push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker)) + push!( + plotattributes_outs, + plotly_colorbar_hack(series, plotattributes_base, :marker), + ) end plotattributes_outs end @@ -723,37 +794,46 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z isscatter = st in (:scatter, :scatter3d, :scattergl) hasmarker = isscatter || series[:markershape] != :none hasline = st in (:path, :path3d, :straightline) - hasfillrange = st in (:path, :scatter, :scattergl, :straightline) && + hasfillrange = + st in (:path, :scatter, :scattergl, :straightline) && (isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple)) segments = collect(series_segments(series, st)) - plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments)) + plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1) * length(segments)) - needs_scatter_fix = !isscatter && hasmarker && !any(isnan,y) && length(segments) > 1 + needs_scatter_fix = !isscatter && hasmarker && !any(isnan, y) && length(segments) > 1 for (k, segment) in enumerate(segments) i, rng = segment.attr_index, segment.range - + plotattributes_out = deepcopy(plotattributes_base) - plotattributes_out[:showlegend] = k==1 ? should_add_to_legend(series) : false + plotattributes_out[:showlegend] = k == 1 ? should_add_to_legend(series) : false plotattributes_out[:legendgroup] = series[:label] # set the type if st in (:path, :scatter, :scattergl, :straightline) - plotattributes_out[:type] = st==:scattergl ? "scattergl" : "scatter" + plotattributes_out[:type] = st == :scattergl ? "scattergl" : "scatter" plotattributes_out[:mode] = if hasmarker hasline ? "lines+markers" : "markers" else hasline ? "lines" : "none" end - if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple) + if series[:fillrange] == true || + series[:fillrange] == 0 || + isa(series[:fillrange], Tuple) plotattributes_out[:fill] = "tozeroy" - plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))) - elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real} + plotattributes_out[:fillcolor] = rgba_string( + plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + ) + elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real},Real} plotattributes_out[:fill] = "tonexty" - plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))) + plotattributes_out[:fillcolor] = rgba_string( + plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + ) elseif !(series[:fillrange] in (false, nothing)) - @warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])") + @warn( + "fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])" + ) end plotattributes_out[:x], plotattributes_out[:y] = x[rng], y[rng] @@ -764,20 +844,32 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z else hasline ? "lines" : "none" end - plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x[rng], y[rng], z[rng] + plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = + x[rng], y[rng], z[rng] end # add "marker" if hasmarker - mcolor = rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))) - lcolor = rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))) + mcolor = rgba_string( + plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i)), + ) + lcolor = rgba_string( + plot_color( + get_markerstrokecolor(series, i), + get_markerstrokealpha(series, i), + ), + ) plotattributes_out[:marker] = KW( - :symbol => get_plotly_marker(_cycle(series[:markershape], i), string(_cycle(series[:markershape], i))), + :symbol => get_plotly_marker( + _cycle(series[:markershape], i), + string(_cycle(series[:markershape], i)), + ), # :opacity => needs_scatter_fix ? [1, 0] : 1, :size => 2 * _cycle(series[:markersize], i), :color => needs_scatter_fix ? [mcolor, "rgba(0, 0, 0, 0.000)"] : mcolor, :line => KW( - :color => needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor, + :color => + needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor, :width => _cycle(series[:markerstrokewidth], i), ), ) @@ -786,7 +878,9 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z # add "line" if hasline plotattributes_out[:line] = KW( - :color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))), + :color => rgba_string( + plot_color(get_linecolor(series, clims, i), get_linealpha(series, i)), + ), :width => get_linewidth(series, i), :shape => if st == :steppre "vh" @@ -813,8 +907,12 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z if typeof(series[:fillrange]) <: Real series[:fillrange] = fill(series[:fillrange], length(rng)) elseif typeof(series[:fillrange]) <: Tuple - f1 = typeof(series[:fillrange][1]) <: Real ? fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng] - f2 = typeof(series[:fillrange][2]) <: Real ? fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng] + f1 = + typeof(series[:fillrange][1]) <: Real ? + fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng] + f2 = + typeof(series[:fillrange][2]) <: Real ? + fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng] series[:fillrange] = (f1, f2) end if isa(series[:fillrange], AbstractVector) @@ -824,13 +922,15 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z else # if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange # is the series that will do the filling - plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], series[:fillrange]) + plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = + concatenate_fillrange(x[rng], series[:fillrange]) plotattributes_out_fillrange[:line][:width] = 0 delete!(plotattributes_out, :fill) delete!(plotattributes_out, :fillcolor) end - plotattributes_outs[(2k-1):(2k)] = [plotattributes_out_fillrange, plotattributes_out] + plotattributes_outs[(2k - 1):(2k)] = + [plotattributes_out_fillrange, plotattributes_out] else plotattributes_outs[k] = plotattributes_out end @@ -841,7 +941,10 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z elseif series[:fill_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill)) elseif series[:marker_z] !== nothing - push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker)) + push!( + plotattributes_outs, + plotly_colorbar_hack(series, plotattributes_base, :marker), + ) end plotattributes_outs @@ -871,7 +974,6 @@ function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symb return plotattributes_out end - function plotly_polar!(plotattributes_out::KW, series::Series) # convert polar plots x/y to theta/radius if ispolar(series[:subplot]) @@ -910,11 +1012,15 @@ html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt) function plotly_html_head(plt::Plot) plotly = - use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)" + use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : + "https://cdn.plot.ly/$(_plotly_min_js_filename)" include_mathjax = get(plt[:extra_plot_kwargs], :include_mathjax, "") - mathjax_file = include_mathjax != "cdn" ? ("file://" * include_mathjax) : "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML" - mathjax_head = include_mathjax == "" ? "" : "\n\t\t" + mathjax_file = + include_mathjax != "cdn" ? ("file://" * include_mathjax) : + "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML" + mathjax_head = + include_mathjax == "" ? "" : "\n\t\t" if isijulia() mathjax_head @@ -934,8 +1040,9 @@ function plotly_html_body(plt, style = nothing) if isijulia() # require.js adds .js automatically plotly_no_ext = - use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)" - plotly_no_ext = plotly_no_ext[1:end-3] + use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : + "https://cdn.plot.ly/$(_plotly_min_js_filename)" + plotly_no_ext = plotly_no_ext[1:(end - 3)] requirejs_prefix = """ requirejs.config({ @@ -984,12 +1091,10 @@ function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{Plotly plotly_show_js(io, plot) end - function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend}) write(io, embeddable_html(plt)) end - function _display(plt::Plot{PlotlyBackend}) standalone_html_window(plt) end diff --git a/src/backends/plotlyjs.jl b/src/backends/plotlyjs.jl index 374bc58f..8dfc373e 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -25,16 +25,19 @@ for (mime, fmt) in ( "image/svg+xml" => "svg", "image/eps" => "eps", ) - @eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt) + @eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) = + PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt) end # Use the Plotly implementation for json and html: -_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) = plotly_show_js(io, plt) +_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) = + plotly_show_js(io, plt) html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt) html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt) -_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, embeddable_html(plt)) +_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = + write(io, embeddable_html(plt)) _display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt)) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index f46de620..2ef25820 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -3,7 +3,6 @@ is_marker_supported(::PyPlotBackend, shape::Shape) = true - # -------------------------------------------------------------------------------------- # problem: https://github.com/tbreloff/Plots.jl/issues/308 @@ -19,16 +18,17 @@ pyfont = PyPlot.pyimport("matplotlib.font_manager") pyticker = PyPlot.pyimport("matplotlib.ticker") pycmap = PyPlot.pyimport("matplotlib.cm") pynp = PyPlot.pyimport("numpy") -pynp."seterr"(invalid="ignore") +pynp."seterr"(invalid = "ignore") pytransforms = PyPlot.pyimport("matplotlib.transforms") pycollections = PyPlot.pyimport("matplotlib.collections") pyart3d = PyPlot.art3D pyrcparams = PyPlot.PyDict(PyPlot.matplotlib."rcParams") - # "support" matplotlib v1.5 set_facecolor_sym = if PyPlot.version < v"2" - @warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0") + @warn( + "You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0" + ) :set_axis_bgcolor else :set_facecolor @@ -39,7 +39,6 @@ if !isdefined(PyPlot.PyCall, :_setproperty!) @warn "Plots no longer supports PyCall < 1.90.0 and PyPlot < 2.8.0. Either update PyCall and PyPlot or pin Plots to a version <= 0.23.2." end - # # convert colorant to 4-tuple RGBA # py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha)) # py_color(cvec::ColorVector, α=nothing) = map(py_color, convertColor(cvec, α).v) @@ -73,23 +72,22 @@ py_color(c::Colorant, α) = py_color(plot_color(c, α)) function py_colormap(cg::ColorGradient) pyvals = collect(zip(cg.values, py_color(PlotUtils.color_list(cg)))) cm = pycolors."LinearSegmentedColormap"."from_list"("tmp", pyvals) - cm."set_bad"(color=(0,0,0,0.0), alpha=0.0) + cm."set_bad"(color = (0, 0, 0, 0.0), alpha = 0.0) cm end function py_colormap(cg::PlotUtils.CategoricalColorGradient) r = range(0, stop = 1, length = 256) pyvals = collect(zip(r, py_color(cg[r]))) cm = pycolors."LinearSegmentedColormap"."from_list"("tmp", pyvals) - cm."set_bad"(color=(0,0,0,0.0), alpha=0.0) + cm."set_bad"(color = (0, 0, 0, 0.0), alpha = 0.0) cm end py_colormap(c) = py_colormap(_as_gradient(c)) - function py_shading(c, z) cmap = py_colormap(c) - ls = pycolors."LightSource"(270,45) - ls."shade"(z, cmap, vert_exag=0.1, blend_mode="soft") + ls = pycolors."LightSource"(270, 45) + ls."shade"(z, cmap, vert_exag = 0.1, blend_mode = "soft") end # get the style (solid, dashed, etc) @@ -106,12 +104,12 @@ end function py_marker(marker::Shape) x, y = coords(marker) n = length(x) - mat = zeros(n+1,2) - for i=1:n - mat[i,1] = x[i] - mat[i,2] = y[i] + mat = zeros(n + 1, 2) + for i in 1:n + mat[i, 1] = x[i] + mat[i, 2] = y[i] end - mat[n+1,:] = mat[1,:] + mat[n + 1, :] = mat[1, :] pypath."Path"(mat) end @@ -199,22 +197,22 @@ function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series) nx, ny = length(x), length(y) if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny if nx < ny - series[:x] = Float64[x[mod1(i,nx)] for i=1:ny] + series[:x] = Float64[x[mod1(i, nx)] for i in 1:ny] else - series[:y] = Float64[y[mod1(i,ny)] for i=1:nx] + series[:y] = Float64[y[mod1(i, ny)] for i in 1:nx] end end end end function py_linecolormap(series::Series) - py_colormap(cgrad(series[:linecolor], alpha=get_linealpha(series))) + py_colormap(cgrad(series[:linecolor], alpha = get_linealpha(series))) end function py_markercolormap(series::Series) - py_colormap(cgrad(series[:markercolor], alpha=get_markeralpha(series))) + py_colormap(cgrad(series[:markercolor], alpha = get_markeralpha(series))) end function py_fillcolormap(series::Series) - py_colormap(cgrad(series[:fillcolor], alpha=get_fillalpha(series))) + py_colormap(cgrad(series[:fillcolor], alpha = get_fillalpha(series))) end # --------------------------------------------------------------------------- @@ -246,12 +244,11 @@ py_drawfig(fig) = fig."draw"(py_renderer(fig)) # get a vector [left, right, bottom, top] in PyPlot coords (origin is bottom-left!) py_extents(obj) = obj."get_window_extent"()."get_points"() - # compute a bounding box (with origin top-left), however pyplot gives coords with origin bottom-left function py_bbox(obj) fl, fr, fb, ft = py_extents(obj."get_figure"()) l, r, b, t = py_extents(obj) - BoundingBox(l*px, (ft-t)*px, (r-l)*px, (t-b)*px) + BoundingBox(l * px, (ft - t) * px, (r - l) * px, (t - b) * px) end py_bbox(::Nothing) = BoundingBox(0mm, 0mm) @@ -267,13 +264,13 @@ end # bounding box: union of axis tick labels function py_bbox_ticks(ax, letter) - labels = getproperty(ax, Symbol("get_"*letter*"ticklabels"))() + labels = getproperty(ax, Symbol("get_" * letter * "ticklabels"))() py_bbox(labels) end # bounding box: axis guide function py_bbox_axislabel(ax, letter) - pyaxis_label = getproperty(ax, Symbol("get_"*letter*"axis"))().label + pyaxis_label = getproperty(ax, Symbol("get_" * letter * "axis"))().label py_bbox(pyaxis_label) end @@ -304,7 +301,7 @@ end # Create the window/figure for this backend. function _create_backend_figure(plt::Plot{PyPlotBackend}) - w,h = map(px2inch, Tuple(s * plt[:dpi] / Plots.DPI for s in plt[:size])) + w, h = map(px2inch, Tuple(s * plt[:dpi] / Plots.DPI for s in plt[:size])) # # reuse the current figure? fig = if plt[:overwrite_figure] @@ -326,21 +323,15 @@ end function py_init_subplot(plt::Plot{PyPlotBackend}, sp::Subplot{PyPlotBackend}) fig = plt.o proj = sp[:projection] - proj = (proj in (nothing,:none) ? nothing : string(proj)) + proj = (proj in (nothing, :none) ? nothing : string(proj)) # add a new axis, and force it to create a new one by setting a distinct label - ax = fig."add_axes"( - [0,0,1,1], - label = string(gensym()), - projection = proj - ) + ax = fig."add_axes"([0, 0, 1, 1], label = string(gensym()), projection = proj) sp.o = ax end - # --------------------------------------------------------------------------- - # function _series_added(pkg::PyPlotBackend, plt::Plot, plotattributes::KW) # TODO: change this to accept Subplot?? # function _series_added(plt::Plot{PyPlotBackend}, series::Series) @@ -373,7 +364,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end end - xyargs = (st in _3dTypes ? (x,y,z) : (x,y)) + xyargs = (st in _3dTypes ? (x, y, z) : (x, y)) # handle zcolor and get c/cmap needs_colorbar = hascolorbar(sp) @@ -392,7 +383,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) handles = [] discrete_colorbar_values = nothing - # pass in an integer value as an arg, but a levels list as a keyword arg levels = series[:levels] levelargs = if isscalar(levels) @@ -442,18 +432,22 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # end # push!(handles, handle) # else - for (k, segment) in enumerate(series_segments(series, st; check=true)) + for (k, segment) in enumerate(series_segments(series, st; check = true)) i, rng = segment.attr_index, segment.range - handle = ax."plot"((arg[rng] for arg in xyargs)...; - label = k == 1 ? series[:label] : "", - zorder = series[:series_plotindex], - color = py_color(single_color(get_linecolor(series, clims, i)), get_linealpha(series, i)), - linewidth = py_thickness_scale(plt, get_linewidth(series, i)), - linestyle = py_linestyle(st, get_linestyle(series, i)), - solid_capstyle = "butt", - dash_capstyle = "butt", - drawstyle = py_stepstyle(st) - )[1] + handle = ax."plot"( + (arg[rng] for arg in xyargs)...; + label = k == 1 ? series[:label] : "", + zorder = series[:series_plotindex], + color = py_color( + single_color(get_linecolor(series, clims, i)), + get_linealpha(series, i), + ), + linewidth = py_thickness_scale(plt, get_linewidth(series, i)), + linestyle = py_linestyle(st, get_linestyle(series, i)), + solid_capstyle = "butt", + dash_capstyle = "butt", + drawstyle = py_stepstyle(st), + )[1] push!(handles, handle) end # end @@ -473,11 +467,15 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) :linestyle => py_linestyle(st, get_linestyle(series)), ) add_arrows(x, y) do xyprev, xy - ax."annotate"("", - xytext = (0.001xyprev[1] + 0.999xy[1], 0.001xyprev[2] + 0.999xy[2]), + ax."annotate"( + "", + xytext = ( + 0.001xyprev[1] + 0.999xy[1], + 0.001xyprev[2] + 0.999xy[2], + ), xy = xy, arrowprops = arrowprops, - zorder = 999 + zorder = 999, ) end end @@ -486,9 +484,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end # add markers? - if series[:markershape] != :none && st in ( - :path, :scatter, :path3d, :scatter3d, :steppre, :stepmid, :steppost, :bar - ) + if series[:markershape] != :none && + st in (:path, :scatter, :path3d, :scatter3d, :steppre, :stepmid, :steppost, :bar) for segment in series_segments(series, :scatter) i, rng = segment.attr_index, segment.range xyargs = if st == :bar && !isvertical(series) @@ -505,15 +502,22 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end end - handle = ax."scatter"(xyargs...; + handle = ax."scatter"( + xyargs...; label = series[:label], zorder = series[:series_plotindex] + 0.5, marker = py_marker(_cycle(series[:markershape], i)), - s = py_thickness_scale(plt, _cycle(series[:markersize], i)).^ 2, - facecolors = py_color(get_markercolor(series, i), get_markeralpha(series, i)), - edgecolors = py_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i)), + s = py_thickness_scale(plt, _cycle(series[:markersize], i)) .^ 2, + facecolors = py_color( + get_markercolor(series, i), + get_markeralpha(series, i), + ), + edgecolors = py_color( + get_markerstrokecolor(series, i), + get_markerstrokealpha(series, i), + ), linewidths = py_thickness_scale(plt, get_markerstrokewidth(series, i)), - extrakw... + extrakw..., ) push!(handles, handle) end @@ -521,16 +525,19 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) if st == :hexbin extrakw[:mincnt] = get(series[:extra_kwargs], :mincnt, nothing) - extrakw[:edgecolors] = get(series[:extra_kwargs], :edgecolors, py_color(get_linecolor(series))) - handle = ax."hexbin"(x, y; + extrakw[:edgecolors] = + get(series[:extra_kwargs], :edgecolors, py_color(get_linecolor(series))) + handle = ax."hexbin"( + x, + y; label = series[:label], C = series[:weights], - gridsize = series[:bins]==:auto ? 100 : series[:bins], # 100 is the default value + gridsize = series[:bins] == :auto ? 100 : series[:bins], # 100 is the default value linewidths = py_thickness_scale(plt, series[:linewidth]), alpha = series[:fillalpha], cmap = py_fillcolormap(series), # applies to the pcolorfast object zorder = series[:series_plotindex], - extrakw... + extrakw..., ) push!(handles, handle) end @@ -550,12 +557,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end # contour lines - handle = ax."contour"(x, y, z, levelargs...; + handle = ax."contour"( + x, + y, + z, + levelargs...; label = series[:label], zorder = series[:series_plotindex], linewidths = py_thickness_scale(plt, series[:linewidth]), linestyles = py_linestyle(st, series[:linestyle]), - extrakw... + extrakw..., ) if series[:contour_labels] == true ax."clabel"(handle, handle.levels) @@ -564,11 +575,15 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # contour fills if series[:fillrange] !== nothing - handle = ax."contourf"(x, y, z, levelargs...; + handle = ax."contourf"( + x, + y, + z, + levelargs...; label = series[:label], zorder = series[:series_plotindex] + 0.5, alpha = series[:fillalpha], - extrakw... + extrakw..., ) push!(handles, handle) end @@ -582,49 +597,56 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) if st == :surface if series[:fill_z] !== nothing # the surface colors are different than z-value - extrakw[:facecolors] = py_shading( - series[:fillcolor], - py_handle_surface(series[:fill_z]), - ) + extrakw[:facecolors] = + py_shading(series[:fillcolor], py_handle_surface(series[:fill_z])) extrakw[:shade] = false else extrakw[:cmap] = py_fillcolormap(series) end end - handle = getproperty(ax, st == :surface ? :plot_surface : :plot_wireframe)(x, y, z; + handle = getproperty(ax, st == :surface ? :plot_surface : :plot_wireframe)( + x, + y, + z; label = series[:label], zorder = series[:series_plotindex], rstride = series[:stride][1], cstride = series[:stride][2], linewidth = py_thickness_scale(plt, series[:linewidth]), edgecolor = py_color(get_linecolor(series)), - extrakw... + extrakw..., ) push!(handles, handle) # contours on the axis planes if series[:contours] - for (zdir,mat) in (("x",x), ("y",y), ("z",z)) + for (zdir, mat) in (("x", x), ("y", y), ("z", z)) offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat) - handle = ax."contourf"(x, y, z, levelargs...; + handle = ax."contourf"( + x, + y, + z, + levelargs...; zdir = zdir, cmap = py_fillcolormap(series), - offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat) # where to draw the contour plane + offset = (zdir == "y" ? ignorenan_maximum : ignorenan_minimum)(mat), # where to draw the contour plane ) push!(handles, handle) end end - elseif typeof(z) <: AbstractVector # tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots) - handle = ax."plot_trisurf"(x, y, z; + handle = ax."plot_trisurf"( + x, + y, + z; label = series[:label], zorder = series[:series_plotindex], cmap = py_fillcolormap(series), linewidth = py_thickness_scale(plt, series[:linewidth]), edgecolor = py_color(get_linecolor(series)), - extrakw... + extrakw..., ) push!(handles, handle) else @@ -640,7 +662,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) z = if eltype(z) <: Colors.AbstractGray float(z) elseif eltype(z) <: Colorant - map(c -> Float64[red(c),green(c),blue(c),alpha(c)], z) + map(c -> Float64[red(c), green(c), blue(c), alpha(c)], z) else z # hopefully it's in a data format that will "just work" with imshow end @@ -650,7 +672,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) cmap = py_colormap(cgrad(plot_color([:black, :white]))), vmin = 0.0, vmax = 1.0, - extent = (xmin - dx, xmax + dx, ymax + dy, ymin - dy) + extent = (xmin - dx, xmax + dx, ymax + dy, ymin - dy), ) push!(handles, handle) @@ -670,13 +692,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) discrete_colorbar_values = dvals end - handle = ax."pcolormesh"(x, y, py_mask_nans(z); + handle = ax."pcolormesh"( + x, + y, + py_mask_nans(z); label = series[:label], zorder = series[:series_plotindex], cmap = py_fillcolormap(series), alpha = series[:fillalpha], # edgecolors = (series[:linewidth] > 0 ? py_linecolor(series) : "face"), - extrakw... + extrakw..., ) push!(handles, handle) end @@ -691,11 +716,17 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) path; label = series[:label], zorder = series[:series_plotindex], - edgecolor = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)), - facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), + edgecolor = py_color( + get_linecolor(series, clims, i), + get_linealpha(series, i), + ), + facecolor = py_color( + get_fillcolor(series, clims, i), + get_fillalpha(series, i), + ), linewidth = py_thickness_scale(plt, get_linewidth(series, i)), linestyle = py_linestyle(st, get_linestyle(series, i)), - fill = true + fill = true, ) push!(handle, ax."add_patch"(patches)) end @@ -719,16 +750,23 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) :fill_betweenx, y[rng], x[rng] end n = length(dim1) - args = if typeof(fillrange) <: Union{Real, AVec} + args = if typeof(fillrange) <: Union{Real,AVec} dim1, _cycle(fillrange, rng), dim2 elseif is_2tuple(fillrange) dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng) end - handle = getproperty(ax, f)(args..., trues(n), false, py_fillstepstyle(st); + handle = getproperty(ax, f)( + args..., + trues(n), + false, + py_fillstepstyle(st); zorder = series[:series_plotindex], - facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)), - linewidths = 0 + facecolor = py_color( + get_fillcolor(series, clims, i), + get_fillalpha(series, i), + ), + linewidths = 0, ) push!(handles, handle) end @@ -736,7 +774,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # this is all we need to add the series_annotations text anns = series[:series_annotations] - for (xi,yi,str,fnt) in EachAnn(anns, x, y) + for (xi, yi, str, fnt) in EachAnn(anns, x, y) py_add_annotations(sp, xi, yi, PlotText(str, fnt)) end end @@ -751,23 +789,22 @@ end function py_surround_latextext(latexstring, env) if !isempty(latexstring) && latexstring[1] == '$' && latexstring[end] == '$' - unenclosed = latexstring[2:end-1] + unenclosed = latexstring[2:(end - 1)] else unenclosed = latexstring end PyPlot.LaTeXStrings.latexstring(env, "{", unenclosed, "}") end - function py_set_ticks(sp, ax, ticks, letter, env) ticks == :auto && return - axis = getproperty(ax, Symbol(letter,"axis")) + axis = getproperty(ax, Symbol(letter, "axis")) if ticks == :none || ticks === nothing || ticks == false kw = KW() - for dir in (:top,:bottom,:left,:right) - kw[dir] = kw[Symbol(:label,dir)] = false + for dir in (:top, :bottom, :left, :right) + kw[dir] = kw[Symbol(:label, dir)] = false end - axis."set_tick_params"(;which="both", kw...) + axis."set_tick_params"(; which = "both", kw...) return end @@ -829,7 +866,8 @@ function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol) 10 end axis = sp[Symbol(letter, :axis)] - kw[Symbol(:linthresh, pyletter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) + kw[Symbol(:linthresh, pyletter)] = + NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) "symlog" end func(arg; kw...) @@ -857,25 +895,29 @@ function py_set_axis_colors(sp, ax, a::Axis) py_set_spine_color(ax.spines, py_color(a[:foreground_color_border])) axissym = Symbol(a[:letter], :axis) if PyPlot.PyCall.hasproperty(ax, axissym) - tickcolor = sp[:framestyle] in (:zerolines, :grid) ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis]) - ax."tick_params"(axis=string(a[:letter]), which="both", - colors=tickcolor, - labelcolor=py_color(a[:tickfontcolor])) + tickcolor = + sp[:framestyle] in (:zerolines, :grid) ? + py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : + py_color(a[:foreground_color_axis]) + ax."tick_params"( + axis = string(a[:letter]), + which = "both", + colors = tickcolor, + labelcolor = py_color(a[:tickfontcolor]), + ) getproperty(ax, axissym).label.set_color(py_color(a[:guidefontcolor])) end end - # -------------------------------------------------------------------------- - function _before_layout_calcs(plt::Plot{PyPlotBackend}) # update the fig w, h = plt[:size] fig = plt.o fig."clear"() dpi = plt[:dpi] - fig."set_size_inches"(w/DPI, h/DPI, forward = true) + fig."set_size_inches"(w / DPI, h / DPI, forward = true) getproperty(fig, set_facecolor_sym)(py_color(plt[:background_color_outside])) fig."set_dpi"(plt[:dpi]) @@ -915,7 +957,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) :title end getproperty(ax, func)."set_text"(sp[:title]) - getproperty(ax, func)."set_fontsize"(py_thickness_scale(plt, sp[:titlefontsize])) + getproperty(ax, func)."set_fontsize"( + py_thickness_scale(plt, sp[:titlefontsize]), + ) getproperty(ax, func)."set_family"(sp[:titlefontfamily]) getproperty(ax, func)."set_color"(py_color(sp[:titlefontcolor])) # ax[:set_title](sp[:title], loc = loc) @@ -928,14 +972,17 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) colorbar_series = slist[findfirst(hascolorbar.(slist))] handle = colorbar_series[:serieshandle][end] kw = KW() - if !isempty(sp[:zaxis][:discrete_values]) && colorbar_series[:seriestype] == :heatmap + if !isempty(sp[:zaxis][:discrete_values]) && + colorbar_series[:seriestype] == :heatmap locator, formatter = get_locator_and_formatter(sp[:zaxis][:discrete_values]) # kw[:values] = eachindex(sp[:zaxis][:discrete_values]) kw[:values] = sp[:zaxis][:continuous_values] kw[:ticks] = locator kw[:format] = formatter kw[:boundaries] = vcat(0, kw[:values] + 0.5) - elseif any(colorbar_series[attr] !== nothing for attr in (:line_z, :fill_z, :marker_z)) + elseif any( + colorbar_series[attr] !== nothing for attr in (:line_z, :fill_z, :marker_z) + ) cmin, cmax = get_clims(sp) norm = pycolors."Normalize"(vmin = cmin, vmax = cmax) f = if colorbar_series[:line_z] !== nothing @@ -952,8 +999,11 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) kw[:spacing] = "proportional" if RecipesPipeline.is3d(sp) || ispolar(sp) - cbax = fig."add_axes"([0.9, 0.1, 0.03, 0.8], label=string("cbar", sp[:subplot_index])) - cb = fig."colorbar"(handle; cax=cbax, kw...) + cbax = fig."add_axes"( + [0.9, 0.1, 0.03, 0.8], + label = string("cbar", sp[:subplot_index]), + ) + cb = fig."colorbar"(handle; cax = cbax, kw...) else # divider approach works only with 2d plots divider = axes_grid1.make_axes_locatable(ax) @@ -962,7 +1012,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) # cbax = divider.append_axes("right", size=width, pad=pad) # This approach does not work well in subplots colorbar_position = "right" colorbar_pad = "2.5%" - colorbar_orientation="vertical" + colorbar_orientation = "vertical" if sp[:colorbar] == :left colorbar_position = string(sp[:colorbar]) @@ -970,15 +1020,25 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) elseif sp[:colorbar] == :top colorbar_position = string(sp[:colorbar]) colorbar_pad = "2.5%" - colorbar_orientation="horizontal" + colorbar_orientation = "horizontal" elseif sp[:colorbar] == :bottom colorbar_position = string(sp[:colorbar]) colorbar_pad = "5%" - colorbar_orientation="horizontal" + colorbar_orientation = "horizontal" end - cbax = divider.append_axes(colorbar_position, size="5%", pad=colorbar_pad, label=string("cbar", sp[:subplot_index])) # Reasonable value works most of the usecases - cb = fig."colorbar"(handle; cax=cbax, orientation = colorbar_orientation, kw...) + cbax = divider.append_axes( + colorbar_position, + size = "5%", + pad = colorbar_pad, + label = string("cbar", sp[:subplot_index]), + ) # Reasonable value works most of the usecases + cb = fig."colorbar"( + handle; + cax = cbax, + orientation = colorbar_orientation, + kw..., + ) if sp[:colorbar] == :left cbax.yaxis.set_ticks_position("left") @@ -987,10 +1047,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) elseif sp[:colorbar] == :bottom cbax.xaxis.set_ticks_position("bottom") end - end - cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:colorbar_titlefontsize]),family=sp[:colorbar_titlefontfamily], color = py_color(sp[:colorbar_titlefontcolor])) + cb."set_label"( + sp[:colorbar_title], + size = py_thickness_scale(plt, sp[:colorbar_titlefontsize]), + family = sp[:colorbar_titlefontfamily], + color = py_color(sp[:colorbar_titlefontcolor]), + ) # cb."formatter".set_useOffset(false) # This for some reason does not work, must be a pyplot bug, instead this is a workaround: cb."formatter".set_powerlimits((-Inf, Inf)) @@ -1002,38 +1066,37 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if sp[:colorbar] in (:top, :bottom) axis = sp[:xaxis] # colorbar inherits from x axis cbar_axis = cb."ax"."xaxis" - ticks_letter=:x + ticks_letter = :x else axis = sp[:yaxis] # colorbar inherits from y axis cbar_axis = cb."ax"."yaxis" - ticks_letter=:y + ticks_letter = :y end py_set_scale(cb.ax, sp, sp[:colorbar_scale], ticks_letter) - sp[:colorbar_ticks] == :native ? nothing : py_set_ticks(sp, cb.ax, ticks, ticks_letter, env) + sp[:colorbar_ticks] == :native ? nothing : + py_set_ticks(sp, cb.ax, ticks, ticks_letter, env) for lab in cbar_axis."get_ticklabels"() - lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize])) - lab."set_family"(sp[:colorbar_tickfontfamily]) - lab."set_color"(py_color(sp[:colorbar_tickfontcolor])) + lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize])) + lab."set_family"(sp[:colorbar_tickfontfamily]) + lab."set_color"(py_color(sp[:colorbar_tickfontcolor])) end # Adjust thickness of the cbar ticks intensity = 0.5 cbar_axis."set_tick_params"( direction = axis[:tick_direction] == :out ? "out" : "in", - width=py_thickness_scale(plt, intensity), - length = axis[:tick_direction] == :none ? 0 : 5 * py_thickness_scale(plt, intensity) + width = py_thickness_scale(plt, intensity), + length = axis[:tick_direction] == :none ? 0 : + 5 * py_thickness_scale(plt, intensity), ) - - cb.outline."set_linewidth"(py_thickness_scale(plt, 1)) sp.attr[:cbar_handle] = cb sp.attr[:cbar_ax] = cbax end - # framestyle if !ispolar(sp) && !RecipesPipeline.is3d(sp) for pos in ("left", "right", "top", "bottom") @@ -1053,11 +1116,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) ax.spines[spine]."set_linewidth"(py_thickness_scale(plt, intensity)) ax.spines[spine]."set_alpha"(intensity) elseif sp[:framestyle] == :box - ax.tick_params(top=true) # Add ticks too - ax.tick_params(right=true) # Add ticks too + ax.tick_params(top = true) # Add ticks too + ax.tick_params(right = true) # Add ticks too elseif sp[:framestyle] in (:axes, :origin) - sp[:xaxis][:mirror] ? ax.spines["bottom"]."set_visible"(false) : ax.spines["top"]."set_visible"(false) - sp[:yaxis][:mirror] ? ax.spines["left"]."set_visible"(false) : ax.spines["right"]."set_visible"(false) + sp[:xaxis][:mirror] ? ax.spines["bottom"]."set_visible"(false) : + ax.spines["top"]."set_visible"(false) + sp[:yaxis][:mirror] ? ax.spines["left"]."set_visible"(false) : + ax.spines["right"]."set_visible"(false) if sp[:framestyle] == :origin ax.spines["bottom"]."set_position"("zero") ax.spines["left"]."set_position"("zero") @@ -1073,8 +1138,16 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) end end if sp[:framestyle] == :zerolines - ax."axhline"(y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75)) - ax."axvline"(x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75)) + ax."axhline"( + y = 0, + color = py_color(sp[:xaxis][:foreground_color_axis]), + lw = py_thickness_scale(plt, 0.75), + ) + ax."axvline"( + x = 0, + color = py_color(sp[:yaxis][:foreground_color_axis]), + lw = py_thickness_scale(plt, 0.75), + ) end end @@ -1117,20 +1190,20 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) "family" => axis[:tickfontfamily], "size" => py_thickness_scale(plt, axis[:tickfontsize]), "rotation" => axis[:tickfontrotation], - ) + ), ) - positions = getproperty(ax, Symbol("get_",letter,"ticks"))() + positions = getproperty(ax, Symbol("get_", letter, "ticks"))() pyaxis.set_major_locator(pyticker.FixedLocator(positions)) if RecipesPipeline.is3d(sp) - getproperty(ax, Symbol("set_",letter,"ticklabels"))( + getproperty(ax, Symbol("set_", letter, "ticklabels"))( positions; - (Symbol(k) => v for (k, v) in fontProperties)... + (Symbol(k) => v for (k, v) in fontProperties)..., ) else - getproperty(ax, Symbol("set_",letter,"ticklabels"))( + getproperty(ax, Symbol("set_", letter, "ticklabels"))( positions, - fontdict=fontProperties, + fontdict = fontProperties, ) end @@ -1142,9 +1215,10 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) intensity = 0.5 # This value corresponds to scaling of other grid elements pyaxis."set_tick_params"( direction = axis[:tick_direction] == :out ? "out" : "in", - width=py_thickness_scale(plt, intensity), - length = axis[:tick_direction] == :none ? 0 : 5 * py_thickness_scale(plt, intensity) - ) + width = py_thickness_scale(plt, intensity), + length = axis[:tick_direction] == :none ? 0 : + 5 * py_thickness_scale(plt, intensity), + ) getproperty(ax, Symbol("set_", letter, "label"))(axis[:guide]) if get(axis.plotattributes, :flip, false) @@ -1163,14 +1237,15 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) pyaxis."label"."set_rotation"(axis[:guidefontrotation]) end - if axis[:grid] && !(ticks in (:none, nothing, false)) fgcolor = py_color(axis[:foreground_color_grid]) - pyaxis."grid"(true, + pyaxis."grid"( + true, color = fgcolor, linestyle = py_linestyle(:line, axis[:gridstyle]), linewidth = py_thickness_scale(plt, axis[:gridlinewidth]), - alpha = axis[:gridalpha]) + alpha = axis[:gridalpha], + ) ax."set_axisbelow"(true) else pyaxis."grid"(false) @@ -1178,11 +1253,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) # if axis[:minorticks] > 1 - pyaxis."set_minor_locator"(PyPlot.matplotlib.ticker.AutoMinorLocator(axis[:minorticks])) + pyaxis."set_minor_locator"( + PyPlot.matplotlib.ticker.AutoMinorLocator(axis[:minorticks]), + ) pyaxis."set_tick_params"( which = "minor", direction = axis[:tick_direction] == :out ? "out" : "in", - length = axis[:tick_direction] == :none ? 0 : py_thickness_scale(plt, intensity), + length = axis[:tick_direction] == :none ? 0 : + py_thickness_scale(plt, intensity), ) end @@ -1193,19 +1271,20 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) pyaxis."set_tick_params"( which = "minor", direction = axis[:tick_direction] == :out ? "out" : "in", - length = axis[:tick_direction] == :none ? 0 : py_thickness_scale(plt, intensity) + length = axis[:tick_direction] == :none ? 0 : + py_thickness_scale(plt, intensity), ) - pyaxis."grid"(true, + pyaxis."grid"( + true, which = "minor", color = fgcolor, linestyle = py_linestyle(:line, axis[:minorgridstyle]), linewidth = py_thickness_scale(plt, axis[:minorgridlinewidth]), - alpha = axis[:minorgridalpha]) + alpha = axis[:minorgridalpha], + ) end - - py_set_axis_colors(sp, ax, axis) end @@ -1219,9 +1298,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if !ispolar(sp) ax.spines[string(dir)].set_visible(false) end - kw[dir] = kw[Symbol(:label,dir)] = false + kw[dir] = kw[Symbol(:label, dir)] = false end - ax."xaxis"."set_tick_params"(; which="both", kw...) + ax."xaxis"."set_tick_params"(; which = "both", kw...) end if !sp[:yaxis][:showaxis] kw = KW() @@ -1229,9 +1308,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if !ispolar(sp) ax.spines[string(dir)].set_visible(false) end - kw[dir] = kw[Symbol(:label,dir)] = false + kw[dir] = kw[Symbol(:label, dir)] = false end - ax."yaxis"."set_tick_params"(; which="both", kw...) + ax."yaxis"."set_tick_params"(; which = "both", kw...) end # aspect ratio @@ -1244,7 +1323,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if RecipesPipeline.is3d(sp) #convert azimuthal to match GR behaviour #view_init(elevation, azimuthal) so reverse :camera args - ax."view_init"((sp[:camera].-(90,0))[end:-1:1]...) + ax."view_init"((sp[:camera] .- (90, 0))[end:-1:1]...) end # legend @@ -1261,7 +1340,6 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) py_drawfig(fig) end - # Set the (left, top, right, bottom) minimum padding around the plot area # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{PyPlotBackend}) @@ -1277,28 +1355,32 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend}) rightpad = 0mm bottompad = 0mm - for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), py_bbox_legend(ax)) + for bb in ( + py_bbox_axis(ax, "x"), + py_bbox_axis(ax, "y"), + py_bbox_title(ax), + py_bbox_legend(ax), + ) if ispositive(width(bb)) && ispositive(height(bb)) - leftpad = max(leftpad, left(plotbb) - left(bb)) - toppad = max(toppad, top(plotbb) - top(bb)) - rightpad = max(rightpad, right(bb) - right(plotbb)) - bottompad = max(bottompad, bottom(bb) - bottom(plotbb)) + leftpad = max(leftpad, left(plotbb) - left(bb)) + toppad = max(toppad, top(plotbb) - top(bb)) + rightpad = max(rightpad, right(bb) - right(plotbb)) + bottompad = max(bottompad, bottom(bb) - bottom(plotbb)) end end if haskey(sp.attr, :cbar_ax) # Treat colorbar the same way ax = sp.attr[:cbar_handle]."ax" - for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), ) + for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax)) if ispositive(width(bb)) && ispositive(height(bb)) - leftpad = max(leftpad, left(plotbb) - left(bb)) - toppad = max(toppad, top(plotbb) - top(bb)) - rightpad = max(rightpad, right(bb) - right(plotbb)) - bottompad = max(bottompad, bottom(bb) - bottom(plotbb)) + leftpad = max(leftpad, left(plotbb) - left(bb)) + toppad = max(toppad, top(plotbb) - top(bb)) + rightpad = max(rightpad, right(bb) - right(plotbb)) + bottompad = max(bottompad, bottom(bb) - bottom(plotbb)) end end end - # optionally add the width of colorbar labels and colorbar to rightpad if RecipesPipeline.is3d(sp) && haskey(sp.attr, :cbar_ax) bb = py_bbox(sp.attr[:cbar_handle]."ax"."get_yticklabels"()) @@ -1316,27 +1398,28 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend}) sp.minpad = Tuple(dpi_factor .* [leftpad, toppad, rightpad, bottompad]) end - # ----------------------------------------------------------------- function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val) ax = sp.o - ax."annotate"(val, xy = (x,y), zorder = 999, annotation_clip = false) + ax."annotate"(val, xy = (x, y), zorder = 999, annotation_clip = false) end - function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText) ax = sp.o - ax."annotate"(val.str, - xy = (x,y), + ax."annotate"( + val.str, + xy = (x, y), family = val.font.family, color = py_color(val.font.color), - horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign), - verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign), + horizontalalignment = val.font.halign == :hcenter ? "center" : + string(val.font.halign), + verticalalignment = val.font.valign == :vcenter ? "center" : + string(val.font.valign), rotation = val.font.rotation, size = py_thickness_scale(sp.plt, val.font.pointsize), zorder = 999, - annotation_clip = false + annotation_clip = false, ) end @@ -1345,21 +1428,21 @@ end 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]) + (s, c) = sincosd(pos[1]) if pos[2] === :outer s = -s c = -c end - yanchors = ["lower","center","upper"] - xanchors = ["left","center","right"] + 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 +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) + 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) + legend_pos_from_angle(pos[1], 0.0, 0.5, 1.0, 0.0, 0.5, 1.0) end py_legend_bbox(pos) = pos @@ -1374,32 +1457,66 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) if should_add_to_legend(series) clims = get_clims(sp, series) # add a line/marker and a label - push!(handles, + push!( + handles, if series[:seriestype] == :shape || series[:fillrange] !== nothing pypatches."Patch"( - edgecolor = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), - facecolor = py_color(single_color(get_fillcolor(series, clims)), get_fillalpha(series)), - linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)), - linestyle = py_linestyle(series[:seriestype], get_linestyle(series)), - capstyle = "butt" + edgecolor = py_color( + single_color(get_linecolor(series, clims)), + get_linealpha(series), + ), + facecolor = py_color( + single_color(get_fillcolor(series, clims)), + get_fillalpha(series), + ), + linewidth = py_thickness_scale( + plt, + clamp(get_linewidth(series), 0, 5), + ), + linestyle = py_linestyle( + series[:seriestype], + get_linestyle(series), + ), + capstyle = "butt", ) - elseif series[:seriestype] in (:path, :straightline, :scatter, :steppre, :stepmid, :steppost) + elseif series[:seriestype] in + (:path, :straightline, :scatter, :steppre, :stepmid, :steppost) hasline = get_linewidth(series) > 0 - PyPlot.plt."Line2D"((0, 1),(0,0), - color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), - linewidth = py_thickness_scale(plt, hasline * sp[:legendfontsize] / 8), + PyPlot.plt."Line2D"( + (0, 1), + (0, 0), + color = py_color( + single_color(get_linecolor(series, clims)), + get_linealpha(series), + ), + linewidth = py_thickness_scale( + plt, + hasline * sp[:legendfontsize] / 8, + ), linestyle = py_linestyle(:path, get_linestyle(series)), - solid_capstyle = "butt", solid_joinstyle = "miter", - dash_capstyle = "butt", dash_joinstyle = "miter", + solid_capstyle = "butt", + solid_joinstyle = "miter", + dash_capstyle = "butt", + dash_joinstyle = "miter", marker = py_marker(_cycle(series[:markershape], 1)), markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]), - markeredgecolor = py_color(single_color(get_markerstrokecolor(series)), get_markerstrokealpha(series)), - markerfacecolor = py_color(single_color(get_markercolor(series, clims)), get_markeralpha(series)), - markeredgewidth = py_thickness_scale(plt, 0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] / first(series[:markersize])) # retain the markersize/markerstroke ratio from the markers on the plot + markeredgecolor = py_color( + single_color(get_markerstrokecolor(series)), + get_markerstrokealpha(series), + ), + markerfacecolor = py_color( + single_color(get_markercolor(series, clims)), + get_markeralpha(series), + ), + markeredgewidth = py_thickness_scale( + plt, + 0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] / + first(series[:markersize]), + ), # retain the markersize/markerstroke ratio from the markers on the plot ) else series[:serieshandle][1] - end + end, ) push!(labels, series[:label]) end @@ -1408,7 +1525,8 @@ 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, + leg = ax."legend"( + handles, labels, loc = py_legend_pos(leg), bbox_to_anchor = py_legend_bbox(leg), @@ -1418,18 +1536,28 @@ 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)) leg."set_zorder"(1000) if sp[:legendtitle] !== nothing leg."set_title"(sp[:legendtitle]) - PyPlot.plt."setp"(leg."get_title"(), color = py_color(sp[:legendtitlefontcolor]), family = sp[:legendtitlefontfamily], fontsize = py_thickness_scale(plt, sp[:legendtitlefontsize])) + PyPlot.plt."setp"( + leg."get_title"(), + color = py_color(sp[:legendtitlefontcolor]), + family = sp[:legendtitlefontfamily], + fontsize = py_thickness_scale(plt, sp[:legendtitlefontsize]), + ) end for txt in leg."get_texts"() - PyPlot.plt."setp"(txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily], fontsize = py_thickness_scale(plt, sp[:legendfontsize])) + PyPlot.plt."setp"( + txt, + color = py_color(sp[:legendfontcolor]), + family = sp[:legendfontfamily], + fontsize = py_thickness_scale(plt, sp[:legendfontsize]), + ) end end end @@ -1437,7 +1565,6 @@ end # ----------------------------------------------------------------- - # Use the bounding boxes (and methods left/top/right/bottom/width/height) `sp.bbox` and `sp.plotarea` to # position the subplot in the backend. function _update_plot_object(plt::Plot{PyPlotBackend}) @@ -1445,14 +1572,19 @@ function _update_plot_object(plt::Plot{PyPlotBackend}) ax = sp.o ax === nothing && return figw, figh = sp.plt[:size] - figw, figh = figw*px, figh*px + figw, figh = figw * px, figh * px pcts = bbox_to_pcts(sp.plotarea, figw, figh) ax."set_position"(pcts) if haskey(sp.attr, :cbar_ax) && RecipesPipeline.is3d(sp) # 2D plots are completely handled by axis dividers cbw = sp.attr[:cbar_width] # this is the bounding box of just the colors of the colorbar (not labels) - cb_bbox = BoundingBox(right(sp.bbox)-cbw - 2mm, top(sp.bbox) + 2mm, _cbar_width-1mm, height(sp.bbox) - 4mm) + cb_bbox = BoundingBox( + right(sp.bbox) - cbw - 2mm, + top(sp.bbox) + 2mm, + _cbar_width - 1mm, + height(sp.bbox) - 4mm, + ) pcts = bbox_to_pcts(cb_bbox, figw, figh) sp.attr[:cbar_ax]."set_position"(pcts) end @@ -1465,26 +1597,25 @@ end _display(plt::Plot{PyPlotBackend}) = plt.o."show"() - for (mime, fmt) in ( - "application/eps" => "eps", - "image/eps" => "eps", - "application/pdf" => "pdf", - "image/png" => "png", - "application/postscript" => "ps", - "image/svg+xml" => "svg", - "application/x-tex" => "pgf" + "application/eps" => "eps", + "image/eps" => "eps", + "application/pdf" => "pdf", + "image/png" => "png", + "application/postscript" => "ps", + "image/svg+xml" => "svg", + "application/x-tex" => "pgf", ) @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend}) fig = plt.o fig."canvas"."print_figure"( io, - format=$fmt, + format = $fmt, # bbox_inches = "tight", # figsize = map(px2inch, plt[:size]), facecolor = fig."get_facecolor"(), edgecolor = "none", - dpi = plt[:dpi] + dpi = plt[:dpi], ) end end diff --git a/src/backends/unicodeplots.jl b/src/backends/unicodeplots.jl index f0042436..74e5bce6 100644 --- a/src/backends/unicodeplots.jl +++ b/src/backends/unicodeplots.jl @@ -1,7 +1,6 @@ # https://github.com/Evizero/UnicodePlots.jl - # don't warn on unsupported... there's just too many warnings!! warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing @@ -17,7 +16,6 @@ function _canvas_map() ) end - # do all the magic here... build it all at once, since we need to know about all the series at the very beginning function rebuildUnicodePlot!(plt::Plot, width, height) plt.o = [] @@ -25,8 +23,8 @@ function rebuildUnicodePlot!(plt::Plot, width, height) for sp in plt.subplots xaxis = sp[:xaxis] yaxis = sp[:yaxis] - xlim = axis_limits(sp, :x) - ylim = axis_limits(sp, :y) + xlim = axis_limits(sp, :x) + ylim = axis_limits(sp, :y) # make vectors xlim = [xlim[1], xlim[2]] @@ -49,13 +47,16 @@ function rebuildUnicodePlot!(plt::Plot, width, height) if length(sp.series_list) == 1 series = sp.series_list[1] if series[:seriestype] == :spy - push!(plt.o, UnicodePlots.spy( - series[:z].surf, - width = width, - height = height, - title = sp[:title], - canvas = canvas_type - )) + push!( + plt.o, + UnicodePlots.spy( + series[:z].surf, + width = width, + height = height, + title = sp[:title], + canvas = canvas_type, + ), + ) continue end end @@ -65,13 +66,16 @@ function rebuildUnicodePlot!(plt::Plot, width, height) # canvas_type = UnicodePlots.BarplotGraphics # end - o = UnicodePlots.Plot(x, y, canvas_type; + o = UnicodePlots.Plot( + x, + y, + canvas_type; width = width, height = height, title = sp[:title], xlim = xlim, ylim = ylim, - border = isijulia() ? :ascii : :solid + border = isijulia() ? :ascii : :solid, ) # set the axis labels @@ -88,7 +92,6 @@ function rebuildUnicodePlot!(plt::Plot, width, height) end end - # add a single series function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim) # get the function, or special handling for step/bar/hist @@ -102,8 +105,8 @@ function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim) func = UnicodePlots.lineplot! elseif st == :scatter || plotattributes[:markershape] != :none func = UnicodePlots.scatterplot! - # elseif st == :bar - # func = UnicodePlots.barplot! + # elseif st == :bar + # func = UnicodePlots.barplot! elseif st == :shape func = UnicodePlots.lineplot! else @@ -121,10 +124,14 @@ function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim) label = addlegend ? plotattributes[:label] : "" # if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide - color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto + color = + plotattributes[:linecolor] in UnicodePlots.color_cycle ? + plotattributes[:linecolor] : :auto # add the series - x, y = RecipesPipeline.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y)))) + x, y = RecipesPipeline.unzip( + collect(Base.Iterators.filter(xy -> isfinite(xy[1]) && isfinite(xy[2]), zip(x, y))), + ) func(o, x, y; color = color, name = label) end @@ -162,7 +169,7 @@ end function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend}) w, h = plt[:size] - plt.attr[:color_palette] = [RGB(0,0,0)] + plt.attr[:color_palette] = [RGB(0, 0, 0)] rebuildUnicodePlot!(plt, div(w, 10), div(h, 20)) end @@ -172,7 +179,6 @@ function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend}) nothing end - function _display(plt::Plot{UnicodePlotsBackend}) unicodeplots_rebuild(plt) map(show, plt.o) diff --git a/src/backends/web.jl b/src/backends/web.jl index 876858cf..92b6b185 100644 --- a/src/backends/web.jl +++ b/src/backends/web.jl @@ -3,7 +3,10 @@ # CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl -function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl")) +function standalone_html( + plt::AbstractPlot; + title::AbstractString = get(plt.attr, :window_title, "Plots.jl"), +) """ @@ -49,7 +52,8 @@ function standalone_html_window(plt::AbstractPlot) old = use_local_dependencies[] # save state to restore afterwards # if we open a browser ourself, we can host local files, so # when we have a local plotly downloaded this is the way to go! - use_local_dependencies[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[]) + use_local_dependencies[] = + plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[]) filename = write_temp_html(plt) open_browser_window(filename) # restore for other backends @@ -58,7 +62,9 @@ end # uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html function html_to_png(html_fn, png_fn, w, h) - run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`) + run( + `wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`, + ) end function show_png_from_html(io::IO, plt::AbstractPlot) diff --git a/src/colorbars.jl b/src/colorbars.jl index b0f9996a..db59c7ef 100644 --- a/src/colorbars.jl +++ b/src/colorbars.jl @@ -1,10 +1,11 @@ # These functions return an operator for use in `get_clims(::Seres, op)` -process_clims(lims::Tuple{<:Number,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ∘ ignorenan_extrema +process_clims(lims::Tuple{<:Number,<:Number}) = + (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ∘ ignorenan_extrema process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema # don't specialize on ::Function otherwise python functions won't work process_clims(f) = f -function get_clims(sp::Subplot, op=process_clims(sp[:clims])) +function get_clims(sp::Subplot, op = process_clims(sp[:clims])) zmin, zmax = Inf, -Inf for series in series_list(sp) if series[:colorbar_entry] @@ -14,7 +15,7 @@ function get_clims(sp::Subplot, op=process_clims(sp[:clims])) return zmin <= zmax ? (zmin, zmax) : (NaN, NaN) end -function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims])) +function get_clims(sp::Subplot, series::Series, op = process_clims(sp[:clims])) zmin, zmax = if series[:colorbar_entry] get_clims(sp, op) else @@ -30,13 +31,18 @@ Finds the limits for the colorbar by taking the "z-values" for the series and pa which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite values of the input. """ -function get_clims(series::Series, op=ignorenan_extrema) +function get_clims(series::Series, op = ignorenan_extrema) zmin, zmax = Inf, -Inf z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin) - for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z]) - if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real}) + for vals in ( + series[:seriestype] in z_colored_series ? series[:z] : nothing, + series[:line_z], + series[:marker_z], + series[:fill_z], + ) + if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing,Real}) zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...) - elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real}) + elseif (vals !== nothing) && (eltype(vals) <: Union{Missing,Real}) zmin, zmax = _update_clims(zmin, zmax, op(vals)...) end end @@ -60,8 +66,8 @@ function colorbar_style(series::Series) cbar_fill elseif iscontour(series) cbar_lines - elseif series[:seriestype] ∈ (:heatmap,:surface) || - any(series[z] !== nothing for z ∈ [:marker_z,:line_z,:fill_z]) + elseif series[:seriestype] ∈ (:heatmap, :surface) || + any(series[z] !== nothing for z in [:marker_z, :line_z, :fill_z]) cbar_gradient else nothing @@ -69,7 +75,8 @@ function colorbar_style(series::Series) end hascolorbar(series::Series) = colorbar_style(series) !== nothing -hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp)) +hascolorbar(sp::Subplot) = + sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp)) function get_colorbar_ticks(sp::Subplot; update = true) if update || !haskey(sp.attr, :colorbar_optimized_ticks) diff --git a/src/components.jl b/src/components.jl index b6a8feb3..e8eadc72 100644 --- a/src/components.jl +++ b/src/components.jl @@ -12,7 +12,7 @@ compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angl # ------------------------------------------------------------- -struct Shape{X<:Number, Y<:Number} +struct Shape{X<:Number,Y<:Number} x::Vector{X} y::Vector{Y} # function Shape(x::AVec, y::AVec) @@ -52,75 +52,83 @@ function coords(shapes::AVec{<:Shape}) end "get an array of tuples of points on a circle with radius `r`" -partialcircle(start_θ, end_θ, n=20, r=1) = [ - (r*cos(u), r*sin(u)) for u in range(start_θ, stop=end_θ, length=n) -] +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]) - ret = eltype(x)[] - done = false - while !done - for o in ordering - try - push!(ret, popfirst!(o)) - catch - end +function weave(x, y; ordering = Vector[x, y]) + ret = eltype(x)[] + done = false + while !done + for o in ordering + try + push!(ret, popfirst!(o)) + catch + end + end + done = isempty(x) && isempty(y) end - done = isempty(x) && isempty(y) - end - ret + ret end "create a star by weaving together points from an outer and inner circle. `n` is the number of arms" -function makestar(n; offset=-0.5, radius=1.0) +function makestar(n; offset = -0.5, radius = 1.0) z1 = offset * π z2 = z1 + π / (n) - outercircle = partialcircle(z1, z1 + 2π, n+1, radius) - innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius) + outercircle = partialcircle(z1, z1 + 2π, n + 1, radius) + innercircle = partialcircle(z2, z2 + 2π, n + 1, 0.4radius) Shape(weave(outercircle, innercircle)) end "create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle" -makeshape(n; offset=-0.5, radius=1.0) = Shape( - partialcircle(offset * π, offset * π + 2π, n+1, radius) -) +makeshape(n; offset = -0.5, radius = 1.0) = + Shape(partialcircle(offset * π, offset * π + 2π, n + 1, radius)) -function makecross(; offset=-0.5, radius=1.0) +function makecross(; offset = -0.5, radius = 1.0) z2 = offset * π - z1 = z2 - π/8 + z1 = z2 - π / 8 outercircle = partialcircle(z1, z1 + 2π, 9, radius) innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius) - Shape(weave(outercircle, innercircle, - ordering=Vector[outercircle, innercircle, outercircle])) + Shape( + weave( + outercircle, + innercircle, + ordering = Vector[outercircle, innercircle, outercircle], + ), + ) end -from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle)) +from_polar(angle, dist) = P2(dist * cos(angle), dist * sin(angle)) -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)] +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), - :rect => makeshape(4, offset=-0.25), - :diamond => makeshape(4), - :utriangle => makeshape(3, offset=0.5), - :dtriangle => makeshape(3, offset=-0.5), - :rtriangle => makeshape(3, offset=0.0), - :ltriangle => makeshape(3, offset=1.0), - :pentagon => makeshape(5), - :hexagon => makeshape(6), - :heptagon => makeshape(7), - :octagon => makeshape(8), - :cross => makecross(offset=-0.25), - :xcross => makecross(), - :vline => Shape([(0, 1), (0, -1)]), - :hline => Shape([(1, 0), (-1, 0)]), - ) + :rect => makeshape(4, offset = -0.25), + :diamond => makeshape(4), + :utriangle => makeshape(3, offset = 0.5), + :dtriangle => makeshape(3, offset = -0.5), + :rtriangle => makeshape(3, offset = 0.0), + :ltriangle => makeshape(3, offset = 1.0), + :pentagon => makeshape(5), + :hexagon => makeshape(6), + :heptagon => makeshape(7), + :octagon => makeshape(8), + :cross => makecross(offset = -0.25), + :xcross => makecross(), + :vline => Shape([(0, 1), (0, -1)]), + :hline => Shape([(1, 0), (-1, 0)]), +) for n in 4:8 - _shapes[Symbol("star$n")] = makestar(n) + _shapes[Symbol("star$n")] = makestar(n) end Shape(k::Symbol) = deepcopy(_shapes[k]) @@ -133,13 +141,13 @@ function center(shape::Shape) x, y = coords(shape) n = length(x) A, Cx, Cy = 0, 0, 0 - for i ∈ 1:n - ip1 = i == n ? 1 : i+1 + for i in 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 - ip1 = i == n ? 1 : i+1 + for i in 1:n + ip1 = i == n ? 1 : i + 1 m = (x[i] * y[ip1] - x[ip1] * y[i]) Cx += (x[i] + x[ip1]) * m Cy += (y[i] + y[ip1]) * m @@ -147,47 +155,43 @@ function center(shape::Shape) Cx / 6A, Cy / 6A end -function scale!(shape::Shape, x::Real, y::Real=x, c=center(shape)) +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 in eachindex(sx) sx[i] = (sx[i] - cx) * x + cx sy[i] = (sy[i] - cy) * y + cy end shape end -scale(shape::Shape, x::Real, y::Real=x, c=center(shape)) = scale!(deepcopy(shape), x, y, c) - +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) +function translate!(shape::Shape, x::Real, y::Real = x) sx, sy = coords(shape) - for i ∈ eachindex(sx) + for i in eachindex(sx) sx[i] += x sy[i] += y end shape end -translate(shape::Shape, x::Real, y::Real=x) = translate!(deepcopy(shape), x, y) +translate(shape::Shape, x::Real, y::Real = x) = translate!(deepcopy(shape), x, y) -rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = ( - (x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx -) +rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = + ((x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx) -rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = ( - (y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery -) +rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) = + ((y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery) -rotate(x::Real, y::Real, θ::Real, c=center(shape)) = ( - rotate_x(x, y, Θ, c...), - rotate_y(x, y, Θ, c...), -) +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)) +function rotate!(shape::Shape, Θ::Real, c = center(shape)) x, y = coords(shape) - for i ∈ eachindex(x) + for i in eachindex(x) xi = rotate_x(x[i], y[i], Θ, c...) yi = rotate_y(x[i], y[i], Θ, c...) x[i], y[i] = xi, yi @@ -196,7 +200,7 @@ function rotate!(shape::Shape, Θ::Real, c=center(shape)) end "rotate an object in space" -function rotate(shape::Shape, θ::Real, c=center(shape)) +function rotate(shape::Shape, θ::Real, c = center(shape)) x, y = coords(shape) x_new = rotate_x.(x, y, θ, c...) y_new = rotate_y.(x, y, θ, c...) @@ -206,12 +210,12 @@ end # ----------------------------------------------------------------------- mutable struct Font - family::AbstractString - pointsize::Int - halign::Symbol - valign::Symbol - rotation::Float64 - color::Colorant + family::AbstractString + pointsize::Int + halign::Symbol + valign::Symbol + rotation::Float64 + color::Colorant end """ @@ -232,71 +236,71 @@ 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 - color = colorant"black" + # defaults + family = "sans-serif" + pointsize = 14 + halign = :hcenter + valign = :vcenter + rotation = 0 + color = colorant"black" - for arg in args - T = typeof(arg) + for arg in args + T = typeof(arg) - if T == Font - family = arg.family - pointsize = arg.pointsize - halign = arg.halign - valign = arg.valign - rotation = arg.rotation - color = arg.color - elseif arg == :center - halign = :hcenter - valign = :vcenter - elseif arg ∈ _haligns - halign = arg - elseif arg ∈ _valigns - valign = arg - elseif T <: Colorant - color = arg - elseif T <: Symbol || T <: AbstractString - try - color = parse(Colorant, string(arg)) - catch - family = string(arg) - end - elseif typeof(arg) <: Integer - pointsize = arg - elseif typeof(arg) <: Real - rotation = convert(Float64, arg) - else - @warn "Unused font arg: $arg ($(typeof(arg)))" + if T == Font + family = arg.family + pointsize = arg.pointsize + halign = arg.halign + valign = arg.valign + rotation = arg.rotation + color = arg.color + elseif arg == :center + halign = :hcenter + valign = :vcenter + elseif arg ∈ _haligns + halign = arg + elseif arg ∈ _valigns + valign = arg + elseif T <: Colorant + color = arg + elseif T <: Symbol || T <: AbstractString + try + color = parse(Colorant, string(arg)) + catch + family = string(arg) + end + elseif typeof(arg) <: Integer + pointsize = arg + elseif typeof(arg) <: Real + rotation = convert(Float64, arg) + else + @warn "Unused font arg: $arg ($(typeof(arg)))" + end end - end - 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: $sym" + 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: $sym" + end end - end - Font(family, pointsize, halign, valign, rotation, color) + Font(family, pointsize, halign, valign, rotation, color) end function scalefontsize(k::Symbol, factor::Number) @@ -332,7 +336,7 @@ function scalefontsizes() f = default(k) if k in keys(_initial_fontsizes) factor = f / _initial_fontsizes[k] - scalefontsize(k, 1.0/factor) + scalefontsize(k, 1.0 / factor) end end @@ -341,7 +345,7 @@ function scalefontsizes() if k in keys(_initial_fontsizes) f = default(Symbol(letter, k)) factor = f / _initial_fontsizes[k] - scalefontsize(Symbol(letter, k), 1.0/factor) + scalefontsize(Symbol(letter, k), 1.0 / factor) end end end @@ -351,8 +355,8 @@ resetfontsizes() = scalefontsizes() "Wrap a string with font info" struct PlotText - str::AbstractString - font::Font + str::AbstractString + font::Font end PlotText(str) = PlotText(string(str), font()) @@ -372,10 +376,10 @@ Base.length(t::PlotText) = length(t.str) # ----------------------------------------------------------------------- struct Stroke - width - color - alpha - style + width + color + alpha + style end """ @@ -383,67 +387,66 @@ end Define the properties of the stroke used in plotting lines """ -function stroke(args...; alpha=nothing) - width = 1 - color = :black - style = :solid +function stroke(args...; alpha = nothing) + width = 1 + color = :black + style = :solid - for arg in args - T = typeof(arg) + for arg in args + T = typeof(arg) - # if arg in _allStyles - if allStyles(arg) - style = arg - elseif T <: Colorant - color = arg - elseif T <: Symbol || T <: AbstractString - try - color = parse(Colorant, string(arg)) - catch - end - elseif allAlphas(arg) - alpha = arg - elseif allReals(arg) - width = arg - else - @warn "Unused stroke arg: $arg ($(typeof(arg)))" + # if arg in _allStyles + if allStyles(arg) + style = arg + elseif T <: Colorant + color = arg + elseif T <: Symbol || T <: AbstractString + try + color = parse(Colorant, string(arg)) + catch + end + elseif allAlphas(arg) + alpha = arg + elseif allReals(arg) + width = arg + else + @warn "Unused stroke arg: $arg ($(typeof(arg)))" + end end - end - Stroke(width, color, alpha, style) + Stroke(width, color, alpha, style) end - struct Brush - size # fillrange, markersize, or any other sizey attribute - color - alpha + size # fillrange, markersize, or any other sizey attribute + color + alpha end -function brush(args...; alpha=nothing) - size = 1 - color = :black +function brush(args...; alpha = nothing) + size = 1 + color = :black - for arg in args - T = typeof(arg) + for arg in args + T = typeof(arg) - if T <: Colorant - color = arg - elseif T <: Symbol || T <: AbstractString - try - color = parse(Colorant, string(arg)) - catch - end - elseif allAlphas(arg) - alpha = arg - elseif allReals(arg) - size = arg - else - @warn "Unused brush arg: $arg ($(typeof(arg)))" + if T <: Colorant + color = arg + elseif T <: Symbol || T <: AbstractString + try + color = parse(Colorant, string(arg)) + catch + end + elseif allAlphas(arg) + alpha = arg + elseif allReals(arg) + size = arg + else + @warn "Unused brush arg: $arg ($(typeof(arg)))" + end end - end - Brush(size, color, alpha) + Brush(size, color, alpha) end # ----------------------------------------------------------------------- @@ -451,7 +454,7 @@ end mutable struct SeriesAnnotations strs::AVec # the labels/names font::Font - baseshape::Union{Shape, AVec{Shape}, Nothing} + baseshape::Union{Shape,AVec{Shape},Nothing} scalefactor::Tuple end @@ -490,10 +493,10 @@ function series_annotations(strs::AVec, args...) # scale!(s, scalefactor, scalefactor, (0, 0)) # end # end - SeriesAnnotations([_text_label(s, fnt) for s ∈ strs], fnt, shp, scalefactor) + SeriesAnnotations([_text_label(s, fnt) for s in strs], fnt, shp, scalefactor) end -function series_annotations_shapes!(series::Series, scaletype::Symbol=:pixels) +function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels) anns = series[:series_annotations] # msw, msh = anns.scalefactor # ms = series[:markersize] @@ -512,7 +515,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 ∈ eachindex(anns.strs) + for i in eachindex(anns.strs) str = _cycle(anns.strs, i) # get the width and height of the string (in mm) @@ -530,7 +533,8 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol=:pixels) maxscale = max(xscale, yscale) push!(msize, maxscale) baseshape = _cycle(anns.baseshape, i) - shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0, 0)) + shapes[i] = + scale(baseshape, msw * xscale / maxscale, msh * yscale / maxscale, (0, 0)) end series[:markershape] = shapes series[:markersize] = msize @@ -544,7 +548,7 @@ mutable struct EachAnn y end -function Base.iterate(ea::EachAnn, i=1) +function Base.iterate(ea::EachAnn, i = 1) if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y) return end @@ -555,7 +559,7 @@ function Base.iterate(ea::EachAnn, i=1) else tmp, ea.anns.font end - ((_cycle(ea.x, i), _cycle(ea.y, i), str, fnt), i+1) + ((_cycle(ea.x, i), _cycle(ea.y, i), str, fnt), i + 1) end # ----------------------------------------------------------------------- @@ -566,36 +570,41 @@ annotations(anns) = Any[anns] annotations(::Nothing) = [] _annotationfont(sp::Subplot) = Plots.font(; - family=sp[:annotationfontfamily], - pointsize=sp[:annotationfontsize], - halign=sp[:annotationhalign], - valign=sp[:annotationvalign], - rotation=sp[:annotationrotation], - color=sp[:annotationcolor], + family = sp[:annotationfontfamily], + pointsize = sp[:annotationfontsize], + halign = sp[:annotationhalign], + valign = sp[:annotationvalign], + rotation = sp[:annotationrotation], + color = sp[:annotationcolor], ) -_annotation(sp::Subplot, font, lab, pos...; alphabet="abcdefghijklmnopqrstuvwxyz") = ( - pos..., - lab == :auto ? text("($(alphabet[sp[:subplot_index]]))", font) : _text_label(lab, font) +_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 individual annotations # and make sure labels are of type PlotText -function process_annotation(sp::Subplot, xs, ys, labs, font=_annotationfont(sp)) +function process_annotation(sp::Subplot, xs, ys, labs, font = _annotationfont(sp)) anns = [] labs = makevec(labs) xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs) ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys) for i in 1:max(xlength, ylength, length(labs)) - x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i) - x = typeof(x) <: TimeType ? Dates.value(x) : x - y = typeof(y) <: TimeType ? Dates.value(y) : y - push!(anns, _annotation(sp, font, lab, x, y)) + x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i) + x = typeof(x) <: TimeType ? Dates.value(x) : x + y = typeof(y) <: TimeType ? Dates.value(y) : y + push!(anns, _annotation(sp, font, lab, x, y)) end anns end -function process_annotation(sp::Subplot, positions::Union{AVec{Symbol}, Symbol, Tuple}, labs, font=_annotationfont(sp)) +function process_annotation( + sp::Subplot, + positions::Union{AVec{Symbol},Symbol,Tuple}, + labs, + font = _annotationfont(sp), +) anns = [] positions, labs = makevec(positions), makevec(labs) for i in 1:max(length(positions), length(labs)) @@ -609,47 +618,52 @@ _relative_position(xmin, xmax, pos::Length{:pct}) = xmin + pos.value * (xmax - x # Give each annotation coordinates based on specified position function locate_annotation( - sp::Subplot, pos::Symbol, label::PlotText; - position_multiplier=Dict{Symbol, Tuple{Float64, Float64}}( - :topleft => (0.1pct, 0.9pct), - :topcenter => (0.5pct, 0.9pct), - :topright => (0.9pct, 0.9pct), - :bottomleft => (0.1pct, 0.1pct), - :bottomcenter => (0.5pct, 0.1pct), - :bottomright => (0.9pct, 0.1pct), - ) + sp::Subplot, + pos::Symbol, + label::PlotText; + position_multiplier = Dict{Symbol,Tuple{Float64,Float64}}( + :topleft => (0.1pct, 0.9pct), + :topcenter => (0.5pct, 0.9pct), + :topright => (0.9pct, 0.9pct), + :bottomleft => (0.1pct, 0.1pct), + :bottomcenter => (0.5pct, 0.1pct), + :bottomright => (0.9pct, 0.1pct), + ), ) x, y = position_multiplier[pos] ( - _relative_position(axis_limits(sp, :x)..., x), - _relative_position(axis_limits(sp, :y)..., y), - label + _relative_position(axis_limits(sp, :x)..., x), + _relative_position(axis_limits(sp, :y)..., y), + label, ) end locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label) locate_annotation(sp::Subplot, x, y, z, label::PlotText) = (x, y, z, label) -locate_annotation(sp::Subplot, rel::NTuple{2, <:Number}, label::PlotText) = ( - _relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct), - _relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct), - label +locate_annotation(sp::Subplot, rel::NTuple{2,<:Number}, label::PlotText) = ( + _relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct), + _relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct), + label, ) -locate_annotation(sp::Subplot, rel::NTuple{3, <:Number}, label::PlotText) = ( - _relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct), - _relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct), - _relative_position(axis_limits(sp, :z)..., rel[3] * Plots.pct), - label +locate_annotation(sp::Subplot, rel::NTuple{3,<:Number}, label::PlotText) = ( + _relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct), + _relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct), + _relative_position(axis_limits(sp, :z)..., rel[3] * Plots.pct), + label, ) # ----------------------------------------------------------------------- "type which represents z-values for colors and sizes (and anything else that might come up)" struct ZValues - values::Vector{Float64} - zrange::Tuple{Float64, Float64} + values::Vector{Float64} + zrange::Tuple{Float64,Float64} end -function zvalues(values::AVec{T}, zrange::Tuple{T, T}=(ignorenan_minimum(values), ignorenan_maximum(values))) where T<:Real - ZValues(collect(float(values)), map(Float64, zrange)) +function zvalues( + values::AVec{T}, + zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)), +) where {T<:Real} + ZValues(collect(float(values)), map(Float64, zrange)) end # ----------------------------------------------------------------------- @@ -667,7 +681,6 @@ struct SurfaceFunction <: AbstractSurface f::Function end - # ----------------------------------------------------------------------- # # I don't want to clash with ValidatedNumerics, but this would be nice: @@ -718,15 +731,14 @@ function arrow(args...) Arrow(style, side, headlength, headwidth) 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) - xyprev = (x[i-1], y[i-1]) + for i in 2:length(x) + xyprev = (x[i - 1], y[i - 1]) xy = (x[i], y[i]) if ok(xyprev) && ok(xy) - if i == length(x) || !ok(x[i+1], y[i+1]) + if i == length(x) || !ok(x[i + 1], y[i + 1]) # add the arrow from xyprev to xy func(xyprev, xy) end @@ -736,28 +748,27 @@ end # ----------------------------------------------------------------------- "create a BezierCurve for plotting" -mutable struct BezierCurve{T <: GeometryBasics.Point} +mutable struct BezierCurve{T<:GeometryBasics.Point} control_points::Vector{T} end function (bc::BezierCurve)(t::Real) p = zero(P2) - n = length(bc.control_points)-1 + n = length(bc.control_points) - 1 for i in 0:n - p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i + p += bc.control_points[i + 1] * binomial(n, i) * (1 - t)^(n - i) * t^i end p 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) -) +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) +function extrema_plus_buffer(v, buffmult = 0.2) vmin, vmax = ignorenan_extrema(v) - vdiff = vmax-vmin + vdiff = vmax - vmin buffer = vdiff * buffmult vmin - buffer, vmax + buffer end diff --git a/src/examples.jl b/src/examples.jl index 2f165f98..6cd1e9b3 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -28,35 +28,33 @@ const _examples = PlotExample[ to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the animation. """, - [:( - begin - p = plot([sin, cos], zeros(0), leg = false, xlims = (0, 2π), ylims = (-1, 1)) - anim = Animation() - for x in range(0, stop = 2π, length = 20) - push!(p, x, Float64[sin(x), cos(x)]) - frame(anim) + [ + :( + begin + p = plot( + [sin, cos], + zeros(0), + leg = false, + xlims = (0, 2π), + ylims = (-1, 1), + ) + anim = Animation() + for x in range(0, stop = 2π, length = 20) + push!(p, x, Float64[sin(x), cos(x)]) + frame(anim) + end end - end - )], + ), + ], ), PlotExample( # 3 "Parametric plots", "Plot function pair (x(u), y(u)).", - [ - :( + [:( begin - plot( - sin, - x -> sin(2x), - 0, - 2π, - line = 4, - leg = false, - fill = (0, :orange), - ) + plot(sin, x -> sin(2x), 0, 2π, line = 4, leg = false, fill = (0, :orange)) end - ), - ], + )], ), PlotExample( # 4 "Colors", @@ -120,7 +118,6 @@ const _examples = PlotExample[ ), ], ), - PlotExample( # 6 "Images", "Plot an image. y-axis is set to flipped", @@ -128,7 +125,9 @@ const _examples = PlotExample[ :( begin import FileIO - path = download("http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png") + path = download( + "http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png", + ) img = FileIO.load(path) plot(img) end @@ -189,12 +188,11 @@ const _examples = PlotExample[ PlotExample( # 11 "Line types", "", - [ - :( + [:( begin linetypes = [:path :steppre :steppost :sticks :scatter] n = length(linetypes) - x = Vector[sort(rand(20)) for i = 1:n] + x = Vector[sort(rand(20)) for i in 1:n] y = rand(20, n) plot( x, @@ -204,8 +202,7 @@ const _examples = PlotExample[ ms = 15, ) end - ), - ], + )], ), PlotExample( # 12 "Line styles", @@ -236,10 +233,8 @@ const _examples = PlotExample[ [ :( begin - markers = filter( - m -> m in Plots.supported_markers(), - Plots._shape_keys, - ) + markers = + filter(m -> m in Plots.supported_markers(), Plots._shape_keys) markers = permutedims(markers) n = length(markers) x = range(0, stop = 10, length = n + 2)[2:(end - 1)] @@ -270,17 +265,11 @@ const _examples = PlotExample[ PlotExample( # 15 "Histogram", "", - [ - :( + [:( begin - histogram( - randn(1000), - bins = :scott, - weights = repeat(1:5, outer = 200), - ) + histogram(randn(1000), bins = :scott, weights = repeat(1:5, outer = 200)) end - ), - ], + )], ), PlotExample( # 16 "Subplots", @@ -326,15 +315,13 @@ const _examples = PlotExample[ PlotExample( # 18 "", "", - [ - :( - begin - using Random - Random.seed!(111) - plot!(Plots.fakedata(100, 10)) - end - ) - ] + [:( + begin + using Random + Random.seed!(111) + plot!(Plots.fakedata(100, 10)) + end + )], ), PlotExample( # 19 "Open/High/Low/Close", @@ -357,8 +344,7 @@ const _examples = PlotExample[ bot[i] + hgt[i], bot[i], closepct[i] * hgt[i] + bot[i], - ) - for i = 1:n + ) for i in 1:n ] ohlc(y) end @@ -396,11 +382,7 @@ const _examples = PlotExample[ ) annotate!([ (5, y[5], ("this is #5", 16, :red, :center)), - ( - 10, - y[10], - ("this is #10", :right, 20, "courier"), - ), + (10, y[10], ("this is #10", :right, 20, "courier")), ]) scatter!( range(2, stop = 8, length = 6), @@ -579,8 +561,8 @@ const _examples = PlotExample[ "", [:( begin - xs = [string("x", i) for i = 1:10] - ys = [string("y", i) for i = 1:4] + xs = [string("x", i) for i in 1:10] + ys = [string("y", i) for i in 1:4] z = float((1:4) * reshape(1:10, 1, :)) heatmap(xs, ys, z, aspect_ratio = 1) end @@ -615,12 +597,7 @@ const _examples = PlotExample[ begin import RDatasets singers = RDatasets.dataset("lattice", "singer") - @df singers violin( - :VoicePart, - :Height, - line = 0, - fill = (0.2, :blue), - ) + @df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue)) @df singers boxplot!( :VoicePart, :Height, @@ -648,11 +625,7 @@ const _examples = PlotExample[ anim = Animation() for x in range(1, stop = 2π, length = 20) - plot(push!( - p, - x, - Float64[sin(x), cos(x), atan(x), cos(x), log(x)], - )) + plot(push!(p, x, Float64[sin(x), cos(x), atan(x), cos(x), log(x)])) frame(anim) end end @@ -677,18 +650,8 @@ const _examples = PlotExample[ 10 => ones(40), -10 => ones(40), ) - b = spdiagm( - 0 => 1:50, - 1 => 1:49, - -1 => 1:49, - 10 => 1:40, - -10 => 1:40, - ) - plot( - spy(a), - spy(b), - title = ["Unique nonzeros" "Different nonzeros"], - ) + b = spdiagm(0 => 1:50, 1 => 1:49, -1 => 1:49, 10 => 1:40, -10 => 1:40) + plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"]) end ), ], @@ -753,51 +716,37 @@ const _examples = PlotExample[ You can use the `line_z` and `marker_z` properties to associate a color with each line segment or marker in the plot. """, - [ - :( - begin - t = range(0, stop = 1, length = 100) - θ = 6π .* t - x = t .* cos.(θ) - y = t .* sin.(θ) - p1 = plot(x, y, line_z = t, linewidth = 3, legend = false) - p2 = scatter( - x, - y, - marker_z = +, - color = :bluesreds, - legend = false, - ) - plot(p1, p2) - end - ), - ], + [:( + begin + t = range(0, stop = 1, length = 100) + θ = 6π .* t + x = t .* cos.(θ) + y = t .* sin.(θ) + p1 = plot(x, y, line_z = t, linewidth = 3, legend = false) + p2 = scatter(x, y, marker_z = +, color = :bluesreds, legend = false) + plot(p1, p2) + end + )], ), PlotExample( # 36 "Portfolio Composition maps", """ see: http://stackoverflow.com/a/37732384/5075246 """, - [ - :( - begin - using Random - Random.seed!(111) - tickers = ["IBM", "Google", "Apple", "Intel"] - N = 10 - D = length(tickers) - weights = rand(N, D) - weights ./= sum(weights, dims = 2) - returns = sort!((1:N) + D * randn(N)) + [:( + begin + using Random + Random.seed!(111) + tickers = ["IBM", "Google", "Apple", "Intel"] + N = 10 + D = length(tickers) + weights = rand(N, D) + weights ./= sum(weights, dims = 2) + returns = sort!((1:N) + D * randn(N)) - portfoliocomposition( - weights, - returns, - labels = permutedims(tickers), - ) - end - ), - ], + portfoliocomposition(weights, returns, labels = permutedims(tickers)) + end + )], ), PlotExample( # 37 "Ribbons", @@ -810,10 +759,7 @@ const _examples = PlotExample[ :( begin plot( - plot( - 0:10; - ribbon = (LinRange(0, 2, 11), LinRange(0, 1, 11)), - ), + plot(0:10; ribbon = (LinRange(0, 2, 11), LinRange(0, 1, 11))), plot(0:10; ribbon = 0:0.5:5), plot(0:10; ribbon = sqrt), plot(0:10; ribbon = 1), @@ -878,11 +824,7 @@ const _examples = PlotExample[ plot!([(0, 0), (0, 0.9), (2, 0.9), (3, 1), (4, 0.9), (80, 0)]) plot!([(0, 0), (0, 0.9), (3, 0.9), (4, 1), (5, 0.9), (80, 0)]) plot!([(0, 0), (0, 0.9), (4, 0.9), (5, 1), (6, 0.9), (80, 0)]) - lens!( - [1, 6], - [0.9, 1.1], - inset = (1, bbox(0.5, 0.0, 0.4, 0.4)), - ) + lens!([1, 6], [0.9, 1.1], inset = (1, bbox(0.5, 0.0, 0.4, 0.4))) end end, ], @@ -890,17 +832,15 @@ const _examples = PlotExample[ PlotExample( # 41 "Array Types", "Plots supports different `Array` types that follow the `AbstractArray` interface, like `StaticArrays` and `OffsetArrays.`", - [ - quote - begin - using StaticArrays, OffsetArrays - sv = SVector{10}(rand(10)) - ov = OffsetVector(rand(10), -2) - plot([sv, ov], label = ["StaticArray" "OffsetArray"]) - plot!(3ov, ribbon=ov, label="OffsetArray ribbon") - end - end, - ], + [quote + begin + using StaticArrays, OffsetArrays + sv = SVector{10}(rand(10)) + ov = OffsetVector(rand(10), -2) + plot([sv, ov], label = ["StaticArray" "OffsetArray"]) + plot!(3ov, ribbon = ov, label = "OffsetArray ribbon") + end + end], ), PlotExample( # 42 "Setting defaults and font arguments", @@ -916,7 +856,7 @@ const _examples = PlotExample[ tickfont = (12, :orange), guide = "x", framestyle = :zerolines, - yminorgrid = true + yminorgrid = true, ) plot( [sin, cos], @@ -935,29 +875,25 @@ const _examples = PlotExample[ PlotExample( # 43 "Heatmap with DateTime axis", "", - [ - quote - begin - using Dates - z = rand(5, 5) - x = DateTime.(2016:2020) - y = 1:5 - heatmap(x, y, z) - end - end, - ], + [quote + begin + using Dates + z = rand(5, 5) + x = DateTime.(2016:2020) + y = 1:5 + heatmap(x, y, z) + end + end], ), PlotExample( # 44 "Linked axes", "", - [ - quote - begin - x = -5:0.1:5 - plot(plot(x, x->x^2), plot(x, x->sin(x)), layout = 2, link = :y) - end - end, - ], + [quote + begin + x = -5:0.1:5 + plot(plot(x, x -> x^2), plot(x, x -> sin(x)), layout = 2, link = :y) + end + end], ), PlotExample( # 45 "Error bars and array type recipes", @@ -972,8 +908,21 @@ const _examples = PlotExample[ value(m::Measurement) = m.val uncertainty(m::Measurement) = m.err - @recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:Measurement} - if !(get(plotattributes, :seriestype, :path) in [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]) + @recipe function f( + ::Type{T}, + m::T, + ) where {T<:AbstractArray{<:Measurement}} + if !( + get(plotattributes, :seriestype, :path) in [ + :contour, + :contourf, + :contour3d, + :heatmap, + :surface, + :wireframe, + :image, + ] + ) error_sym = Symbol(plotattributes[:letter], :error) plotattributes[error_sym] = uncertainty.(m) end @@ -983,14 +932,14 @@ const _examples = PlotExample[ x = Measurement.(10sort(rand(10)), rand(10)) y = Measurement.(10sort(rand(10)), rand(10)) z = Measurement.(10sort(rand(10)), rand(10)) - surf = Measurement.((1:10) .* (1:10)', rand(10,10)) + surf = Measurement.((1:10) .* (1:10)', rand(10, 10)) plot( scatter(x, [x y]), scatter(x, y, z), heatmap(x, y, surf), wireframe(x, y, surf), - legend = :topleft + legend = :topleft, ) end end, @@ -1003,9 +952,9 @@ const _examples = PlotExample[ using GeometryBasics using Distributions d = MvNormal([1.0 0.75; 0.75 2.0]) - plot([(1,2),(3,2),(2,1),(2,3)]) - scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25) - end] + plot([(1, 2), (3, 2), (2, 1), (2, 3)]) + scatter!(Point2.(eachcol(rand(d, 1000))), alpha = 0.25) + end], ), PlotExample( # 47 "Mesh3d", @@ -1019,22 +968,29 @@ const _examples = PlotExample[ :( begin # specify the vertices - x=[0, 1, 2, 0] - y=[0, 0, 1, 2] - z=[0, 2, 0, 1] + x = [0, 1, 2, 0] + y = [0, 0, 1, 2] + z = [0, 2, 0, 1] # specify the triangles # every column is one triangle, # where the values denote the indices of the vertices of the triangle - i=[0, 0, 0, 1] - j=[1, 2, 3, 2] - k=[2, 3, 1, 3] + i = [0, 0, 0, 1] + j = [1, 2, 3, 2] + k = [2, 3, 1, 3] # the four triangles gives above give a tetrahedron mesh3d( - x, y, z; connections=(i, j, k), - title="triangles", xlabel="x", ylabel="y", zlabel="z", - legend=:none, margin=2Plots.mm + x, + y, + z; + connections = (i, j, k), + title = "triangles", + xlabel = "x", + ylabel = "y", + zlabel = "z", + legend = :none, + margin = 2Plots.mm, ) end ), @@ -1043,75 +999,90 @@ const _examples = PlotExample[ PlotExample( # 48 "Vectors of markershapes and segments", "", - [quote - using Base.Iterators: cycle, take + [ + quote + using Base.Iterators: cycle, take - yv = ones(9) - ys = [1; 1; NaN; ones(6)] - y = 5 .- [yv 2ys 3yv 4ys] + yv = ones(9) + ys = [1; 1; NaN; ones(6)] + y = 5 .- [yv 2ys 3yv 4ys] - plt_color_rows = plot( - y, - seriestype = [:path :path :scatter :scatter], - markershape = collect(take(cycle((:utriangle, :rect)), 9)), - markersize = 8, - color = collect(take(cycle((:red, :black)), 9)) - ) + plt_color_rows = plot( + y, + seriestype = [:path :path :scatter :scatter], + markershape = collect(take(cycle((:utriangle, :rect)), 9)), + markersize = 8, + color = collect(take(cycle((:red, :black)), 9)), + ) - plt_z_cols = plot( - y, - markershape = [:utriangle :x :circle :square], - markersize = [5 10 10 5], - marker_z = [5 4 3 2], - line_z = [1 3 3 1], - linewidth = [1 10 5 1] - ) + plt_z_cols = plot( + y, + markershape = [:utriangle :x :circle :square], + markersize = [5 10 10 5], + marker_z = [5 4 3 2], + line_z = [1 3 3 1], + linewidth = [1 10 5 1], + ) - plot(plt_color_rows, plt_z_cols) - end] + plot(plt_color_rows, plt_z_cols) + end, + ], ), PlotExample( # 49 "Polar heatmaps", "", [quote - x = range(0, 2π, length=9) - y = 0:4 - z = (1:4) .+ (1:8)' - heatmap(x, y, z, projection = :polar) - end] + x = range(0, 2π, length = 9) + y = 0:4 + z = (1:4) .+ (1:8)' + heatmap(x, y, z, projection = :polar) + end], ), PlotExample( # 50 "3D surface with axis guides", "", - [quote - f(x,a) = 1/x + a*x^2 - xs = collect(0.1:0.05:2.0); - as = collect(0.2:0.1:2.0); + [ + quote + f(x, a) = 1 / x + a * x^2 + xs = collect(0.1:0.05:2.0) + as = collect(0.2:0.1:2.0) - x_grid = [x for x in xs for y in as]; - a_grid = [y for x in xs for y in as]; + x_grid = [x for x in xs for y in as] + a_grid = [y for x in xs for y in as] - plot(x_grid, a_grid, f.(x_grid,a_grid), - st = :surface, - xlabel = "longer xlabel", - ylabel = "longer ylabel", - zlabel = "longer zlabel", - ) - end] + plot( + x_grid, + a_grid, + f.(x_grid, a_grid), + st = :surface, + xlabel = "longer xlabel", + ylabel = "longer ylabel", + zlabel = "longer zlabel", + ) + end, + ], ), PlotExample( # 51 "Images with custom axes", "", - [quote - using Plots - using TestImages - img = testimage("lighthouse") + [ + quote + using Plots + using TestImages + img = testimage("lighthouse") - # plot the image reversing the first dimension and setting yflip = false - plot([-π, π], [-1, 1], reverse(img, dims=1), yflip=false, aspect_ratio=:none) - # plot other data - plot!(sin, -π, π, lw=3, color=:red) - end] + # plot the image reversing the first dimension and setting yflip = false + plot( + [-π, π], + [-1, 1], + reverse(img, dims = 1), + yflip = false, + aspect_ratio = :none, + ) + # plot other data + plot!(sin, -π, π, lw = 3, color = :red) + end, + ], ), PlotExample( # 52 "3d quiver", @@ -1119,9 +1090,9 @@ const _examples = PlotExample[ [quote using Plots - ϕs = range(-π, π, length=50) - θs = range(0, π, length=25) - θqs = range(1, π-1, length=25) + ϕs = range(-π, π, length = 50) + θs = range(0, π, length = 25) + θqs = range(1, π - 1, length = 25) x = vec([sin(θ) * cos(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)]) y = vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)]) @@ -1131,25 +1102,43 @@ const _examples = PlotExample[ v = 0.1 * vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θqs)]) w = 0.1 * vec([cos(θ) for (ϕ, θ) in Iterators.product(ϕs, θqs)]) - quiver(x,y,z, quiver=(u,v,w)) - end] + quiver(x, y, z, quiver = (u, v, w)) + end], ), PlotExample( # 53 "Step Types", "A comparison of the various step-like `seriestype`s", [ :( - begin - x = 1:5 - y = [1, 2, 3, 2, 1] - default(shape=:circle) - plot( - plot(x, y, markershape=:circle, seriestype=:steppre, label="steppre"), - plot(x, y, markershape=:circle, seriestype=:stepmid, label="stepmid"), - plot(x, y, markershape=:circle, seriestype=:steppost, label="steppost"), - layout=(3,1) - ) - end + begin + x = 1:5 + y = [1, 2, 3, 2, 1] + default(shape = :circle) + plot( + plot( + x, + y, + markershape = :circle, + seriestype = :steppre, + label = "steppre", + ), + plot( + x, + y, + markershape = :circle, + seriestype = :stepmid, + label = "stepmid", + ), + plot( + x, + y, + markershape = :circle, + seriestype = :steppost, + label = "steppost", + ), + layout = (3, 1), + ) + end ), ], ), @@ -1158,22 +1147,22 @@ const _examples = PlotExample[ "", [ :( - begin - plot( - rand(10, 4), - layout=4, - xguide="x guide", - yguide="y guide", - xguidefonthalign=[:left :right :right :left], - yguidefontvalign=[:top :bottom :bottom :top], - xguideposition=:top, - yguideposition=[:right :left :right :left], - ymirror=[false true true false], - xmirror=[false false true true], - legend=false, - seriestype=[:bar :scatter :path :stepmid] - ) - end + begin + plot( + rand(10, 4), + layout = 4, + xguide = "x guide", + yguide = "y guide", + xguidefonthalign = [:left :right :right :left], + yguidefontvalign = [:top :bottom :bottom :top], + xguideposition = :top, + yguideposition = [:right :left :right :left], + ymirror = [false true true false], + xmirror = [false false true true], + legend = false, + seriestype = [:bar :scatter :path :stepmid], + ) + end ), ], ), @@ -1182,44 +1171,60 @@ const _examples = PlotExample[ "", [ :( - begin - using LinearAlgebra - scalefontsizes(.4) + begin + using LinearAlgebra + scalefontsizes(0.4) - x, y = collect(-6:0.5:10), collect(-8:0.5:8) + x, y = collect(-6:0.5:10), collect(-8:0.5:8) - args = x, y, (x, y) -> sinc(norm([x, y]) / π) - kwargs = Dict(:xlabel=>"x", :ylabel=>"y", :zlabel=>"z", :grid=>true, :minorgrid=>true) + args = x, y, (x, y) -> sinc(norm([x, y]) / π) + kwargs = Dict( + :xlabel => "x", + :ylabel => "y", + :zlabel => "z", + :grid => true, + :minorgrid => true, + ) - plots = [wireframe(args..., title = "wire"; kwargs...)] + plots = [wireframe(args..., title = "wire"; kwargs...)] - for ax ∈ (:x, :y, :z) - push!(plots, wireframe( - args..., - title = "wire-flip-$ax", - xflip = ax == :x, - yflip = ax == :y, - zflip = ax == :z; - kwargs..., - )) + for ax in (:x, :y, :z) + push!( + plots, + wireframe( + args..., + title = "wire-flip-$ax", + xflip = ax == :x, + yflip = ax == :y, + zflip = ax == :z; + kwargs..., + ), + ) + end + + for ax in (:x, :y, :z) + push!( + plots, + wireframe( + args..., + title = "wire-mirror-$ax", + xmirror = ax == :x, + ymirror = ax == :y, + zmirror = ax == :z; + kwargs..., + ), + ) + end + + plt = plot( + plots..., + layout = (@layout [_ ° _; ° ° °; ° ° °]), + margin = 0Plots.px, + ) + + resetfontsizes() + plt end - - for ax ∈ (:x, :y, :z) - push!(plots, wireframe( - args..., - title = "wire-mirror-$ax", - xmirror = ax == :x, - ymirror = ax == :y, - zmirror = ax == :z; - kwargs..., - )) - end - - plt = plot(plots..., layout=(@layout [_ ° _; ° ° °; ° ° °]), margin=0Plots.px) - - resetfontsizes() - plt - end ), ], ), @@ -1252,8 +1257,6 @@ _backend_skips = Dict( ], ) - - # --------------------------------------------------------------------------------- # make and display one plot diff --git a/src/fileio.jl b/src/fileio.jl index dbb0469e..624eeff5 100644 --- a/src/fileio.jl +++ b/src/fileio.jl @@ -1,8 +1,10 @@ # --------------------------------------------------------- # A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert -_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString) -_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x) +_fileio_load(@nospecialize(filename::AbstractString)) = + FileIO.load(filename::AbstractString) +_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = + FileIO.save(filename::AbstractString, x) function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot) fn = tempname() @@ -21,4 +23,5 @@ function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot) write(io, read(open(pngfn), String)) end -const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend} +const PDFBackends = + Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend} diff --git a/src/ijulia.jl b/src/ijulia.jl index 7d2786ee..3cf8da78 100644 --- a/src/ijulia.jl +++ b/src/ijulia.jl @@ -1,15 +1,14 @@ const use_local_dependencies = Ref(false) const use_local_plotlyjs = Ref(false) - function _init_ijulia_plotting() # IJulia is more stable with local file - use_local_plotlyjs[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[]) + use_local_plotlyjs[] = + plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[]) ENV["MPLBACKEND"] = "Agg" end - """ Add extra jupyter mimetypes to display_dict based on the plot backed. @@ -20,22 +19,17 @@ frontends like jupyterlab and nteract. _ijulia__extra_mime_info!(plt::Plot, out::Dict) = out function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict) - out["application/vnd.plotly.v1+json"] = Dict( - :data => plotly_series(plt), - :layout => plotly_layout(plt) - ) + out["application/vnd.plotly.v1+json"] = + Dict(:data => plotly_series(plt), :layout => plotly_layout(plt)) out end function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict) - out["application/vnd.plotly.v1+json"] = Dict( - :data => plotly_series(plt), - :layout => plotly_layout(plt) - ) + out["application/vnd.plotly.v1+json"] = + Dict(:data => plotly_series(plt), :layout => plotly_layout(plt)) out end - function _ijulia_display_dict(plt::Plot) output_type = Symbol(plt.attr[:html_output_format]) if output_type == :auto diff --git a/src/init.jl b/src/init.jl index 8b17f5b9..8f8303a6 100644 --- a/src/init.jl +++ b/src/init.jl @@ -1,8 +1,7 @@ using REPL using Scratch -const plotly_local_file_path = Ref{Union{Nothing, String}}(nothing) - +const plotly_local_file_path = Ref{Union{Nothing,String}}(nothing) function _plots_defaults() if isdefined(Main, :PLOTS_DEFAULTS) @@ -12,7 +11,6 @@ function _plots_defaults() end end - function __init__() user_defaults = _plots_defaults() if haskey(user_defaults, :theme) @@ -21,14 +19,27 @@ function __init__() default(; user_defaults...) end - insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay()) + insert!( + Base.Multimedia.displays, + findlast( + x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, + Base.Multimedia.displays, + ) + 1, + PlotsDisplay(), + ) - atreplinit(i -> begin - while PlotsDisplay() in Base.Multimedia.displays - popdisplay(PlotsDisplay()) - end - insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay()) - end) + atreplinit( + i -> begin + while PlotsDisplay() in Base.Multimedia.displays + popdisplay(PlotsDisplay()) + end + insert!( + Base.Multimedia.displays, + findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, + PlotsDisplay(), + ) + end, + ) @require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin fn = joinpath(@__DIR__, "backends", "hdf5.jl") @@ -84,9 +95,13 @@ function __init__() end if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true" - global plotly_local_file_path[] = joinpath(@get_scratch!("plotly"), _plotly_min_js_filename) + global plotly_local_file_path[] = + joinpath(@get_scratch!("plotly"), _plotly_min_js_filename) if !isfile(plotly_local_file_path[]) - download("https://cdn.plot.ly/$(_plotly_min_js_filename)", plotly_local_file_path[]) + download( + "https://cdn.plot.ly/$(_plotly_min_js_filename)", + plotly_local_file_path[], + ) end use_local_plotlyjs[] = true @@ -94,8 +109,8 @@ function __init__() use_local_dependencies[] = use_local_plotlyjs[] - @require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin - _show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt) + _show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = + _show_pdfbackends(io, mime, plt) end end diff --git a/src/layouts.jl b/src/layouts.jl index 5b79b8f6..3d620fd1 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -18,16 +18,16 @@ ispositive(m::Measure) = m.value > 0 # union together bounding boxes function Base.:+(bb1::BoundingBox, bb2::BoundingBox) # empty boxes don't change the union - ispositive(width(bb1)) || return bb2 + ispositive(width(bb1)) || return bb2 ispositive(height(bb1)) || return bb2 - ispositive(width(bb2)) || return bb1 + ispositive(width(bb2)) || return bb1 ispositive(height(bb2)) || return bb1 l = min(left(bb1), left(bb2)) t = min(top(bb1), top(bb2)) r = max(right(bb1), right(bb2)) b = max(bottom(bb1), bottom(bb2)) - BoundingBox(l, t, r-l, b-t) + BoundingBox(l, t, r - l, b - t) end # this creates a bounding box in the parent's scope, where the child bounding box @@ -53,7 +53,7 @@ end # convert a bounding box from absolute coords to percentages... # returns an array of percentages of figure size: [left, bottom, width, height] function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true) - mms = Float64[f(bb).value for f in (left,bottom,width,height)] + mms = Float64[f(bb).value for f in (left, bottom, width, height)] if flipy mms[2] = figh.value - mms[2] # flip y when origin in bottom-left end @@ -61,7 +61,10 @@ function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true) end function Base.show(io::IO, bbox::BoundingBox) - print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}") + print( + io, + "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}", + ) end # ----------------------------------------------------------- @@ -83,12 +86,11 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol) end if pct != 0 amin, amax = axis_limits(sp, letter) - xy += pct * (amax-amin) + xy += pct * (amax - amin) end xy end - # ----------------------------------------------------------- # AbstractLayout @@ -160,7 +162,8 @@ parent_bbox(layout::AbstractLayout) = bbox(parent(layout)) # padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout)) update_position!(layout::AbstractLayout) = nothing -update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing +update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm, 0mm, 0mm, 0mm]) = + nothing left(layout::AbstractLayout) = left(bbox(layout)) top(layout::AbstractLayout) = top(bbox(layout)) @@ -206,7 +209,7 @@ mutable struct EmptyLayout <: AbstractLayout end EmptyLayout(parent = RootLayout(); kw...) = EmptyLayout(parent, defaultbox, KW(kw)) -Base.size(layout::EmptyLayout) = (0,0) +Base.size(layout::EmptyLayout) = (0, 0) Base.length(layout::EmptyLayout) = 0 Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing @@ -235,22 +238,25 @@ columns of different width. """ grid(args...; kw...) = GridLayout(args...; kw...) -function GridLayout(dims...; - parent = RootLayout(), - widths = zeros(dims[2]), - heights = zeros(dims[1]), - kw...) +function GridLayout( + dims...; + parent = RootLayout(), + widths = zeros(dims[2]), + heights = zeros(dims[1]), + kw..., +) grid = Matrix{AbstractLayout}(undef, dims...) layout = GridLayout( parent, (20mm, 5mm, 2mm, 10mm), defaultbox, grid, - Measure[w*pct for w in widths], - Measure[h*pct for h in heights], + Measure[w * pct for w in widths], + Measure[h * pct for h in heights], # convert(Vector{Float64}, widths), # convert(Vector{Float64}, heights), - KW(kw)) + KW(kw), + ) for i in eachindex(grid) grid[i] = EmptyLayout(layout) end @@ -259,9 +265,9 @@ end Base.size(layout::GridLayout) = size(layout.grid) Base.length(layout::GridLayout) = length(layout.grid) -Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c] +Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r, c] function Base.setindex!(layout::GridLayout, v, r::Int, c::Int) - layout.grid[r,c] = v + layout.grid[r, c] = v end leftpad(layout::GridLayout) = layout.minpad[1] @@ -269,7 +275,6 @@ toppad(layout::GridLayout) = layout.minpad[2] rightpad(layout::GridLayout) = layout.minpad[3] bottompad(layout::GridLayout) = layout.minpad[4] - # here's how this works... first we recursively "update the minimum padding" (which # means to calculate the minimum size needed from the edge of the subplot to plot area) # for the whole layout tree. then we can compute the "padding borders" of this @@ -281,14 +286,13 @@ bottompad(layout::GridLayout) = layout.minpad[4] function _update_min_padding!(layout::GridLayout) map(_update_min_padding!, layout.grid) layout.minpad = ( - maximum(map(leftpad, layout.grid[:,1])), - maximum(map(toppad, layout.grid[1,:])), - maximum(map(rightpad, layout.grid[:,end])), - maximum(map(bottompad, layout.grid[end,:])) + maximum(map(leftpad, layout.grid[:, 1])), + maximum(map(toppad, layout.grid[1, :])), + maximum(map(rightpad, layout.grid[:, end])), + maximum(map(bottompad, layout.grid[end, :])), ) end - function update_position!(layout::GridLayout) map(update_position!, layout.grid) end @@ -307,7 +311,9 @@ function recompute_lengths(v) end leftover = 1.0pct - tot if cnt > 1 && leftover.value <= 0 - error("Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover") + error( + "Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover", + ) end # now fill in the blanks @@ -315,21 +321,21 @@ function recompute_lengths(v) end # recursively compute the bounding boxes for the layout and plotarea (relative to canvas!) -function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) +function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm, 0mm, 0mm]) nr, nc = size(layout) # # create a matrix for each minimum padding direction # _update_min_padding!(layout) - minpad_left = map(leftpad, layout.grid) - minpad_top = map(toppad, layout.grid) - minpad_right = map(rightpad, layout.grid) + minpad_left = map(leftpad, layout.grid) + minpad_top = map(toppad, layout.grid) + minpad_right = map(rightpad, layout.grid) minpad_bottom = map(bottompad, layout.grid) # get the max horizontal (left and right) padding over columns, # and max vertical (bottom and top) padding over rows # TODO: add extra padding here - pad_left = maximum(minpad_left, dims = 1) - pad_top = maximum(minpad_top, dims = 2) - pad_right = maximum(minpad_right, dims = 1) + pad_left = maximum(minpad_left, dims = 1) + pad_top = maximum(minpad_top, dims = 2) + pad_right = maximum(minpad_right, dims = 1) pad_bottom = maximum(minpad_bottom, dims = 2) # make sure the perimeter match the parent @@ -343,7 +349,7 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0 total_pad_vertical = sum(pad_top + pad_bottom) # now we can compute the total plot area in each direction - total_plotarea_horizontal = width(layout) - total_pad_horizontal + total_plotarea_horizontal = width(layout) - total_pad_horizontal total_plotarea_vertical = height(layout) - total_pad_vertical # recompute widths/heights @@ -355,19 +361,22 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0 # denom_h = sum(layout.heights) # we have all the data we need... lets compute the plot areas and set the bounding boxes - for r=1:nr, c=1:nc - child = layout[r,c] + for r in 1:nr, c in 1:nc + child = layout[r, c] # get the top-left corner of this child... the first one is top-left of the parent (i.e. layout) - child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox)) - child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox)) + child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c - 1].bbox)) + child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r - 1, c].bbox)) # compute plot area plotarea_left = child_left + pad_left[c] plotarea_top = child_top + pad_top[r] plotarea_width = total_plotarea_horizontal * layout.widths[c] plotarea_height = total_plotarea_vertical * layout.heights[r] - plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height)) + plotarea!( + child, + BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height), + ) # compute child bbox child_width = pad_left[c] + plotarea_width + pad_right[c] @@ -377,10 +386,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0 # this is the minimum perimeter as decided by this child's parent, so that # all children on this border have the same value min_child_perimeter = [ - c == 1 ? layout.minpad[1] : pad_left[c], - r == 1 ? layout.minpad[2] : pad_top[r], + c == 1 ? layout.minpad[1] : pad_left[c], + r == 1 ? layout.minpad[2] : pad_top[r], c == nc ? layout.minpad[3] : pad_right[c], - r == nr ? layout.minpad[4] : pad_bottom[r] + r == nr ? layout.minpad[4] : pad_bottom[r], ] # recursively update the child's children @@ -395,12 +404,15 @@ function update_inset_bboxes!(plt::Plot) p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox]) plotarea!(sp, p_area) - bbox!(sp, bbox( - left(p_area) - leftpad(sp), - top(p_area) - toppad(sp), - width(p_area) + leftpad(sp) + rightpad(sp), - height(p_area) + toppad(sp) + bottompad(sp) - )) + bbox!( + sp, + bbox( + left(p_area) - leftpad(sp), + top(p_area) - toppad(sp), + width(p_area) + leftpad(sp) + rightpad(sp), + height(p_area) + toppad(sp) + bottompad(sp), + ), + ) end end @@ -441,7 +453,9 @@ end function layout_args(plotattributes::AKW, n_override::Integer) layout, n = layout_args(n_override, get(plotattributes, :layout, n_override)) if n != n_override - error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.") + error( + "When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.", + ) end layout, n end @@ -451,27 +465,27 @@ function layout_args(n::Integer) GridLayout(nr, nc), n end -function layout_args(sztup::NTuple{2, Integer}) +function layout_args(sztup::NTuple{2,Integer}) nr, nc = sztup - GridLayout(nr, nc), nr*nc + GridLayout(nr, nc), nr * nc end layout_args(n_override::Integer, n::Integer) = layout_args(n) -layout_args(n, sztup::NTuple{2, Integer}) = layout_args(sztup) +layout_args(n, sztup::NTuple{2,Integer}) = layout_args(sztup) -function layout_args(n, sztup::Tuple{Colon, Integer}) +function layout_args(n, sztup::Tuple{Colon,Integer}) nc = sztup[2] nr = ceil(Int, n / nc) GridLayout(nr, nc), n end -function layout_args(n, sztup::Tuple{Integer, Colon}) +function layout_args(n, sztup::Tuple{Integer,Colon}) nr = sztup[1] nc = ceil(Int, n / nr) GridLayout(nr, nc), n end -function layout_args(sztup::NTuple{3, Integer}) +function layout_args(sztup::NTuple{3,Integer}) n, nr, nc = sztup nr, nc = compute_gridsize(n, nr, nc) GridLayout(nr, nc), n @@ -488,16 +502,13 @@ layout_args(n_override::Integer, layout::GridLayout) = layout_args(layout) layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh") - # ---------------------------------------------------------------------- - function build_layout(args...) layout, n = layout_args(args...) build_layout(layout, n, Array{Plot}(undef, 0)) end - # n is the number of subplots... function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot}) nr, nc = size(layout) @@ -505,15 +516,15 @@ function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot}) spmap = SubplotMap() empty = isempty(plts) i = 0 - for r = 1:nr, c = 1:nc + for r in 1:nr, c in 1:nc l = layout[r, c] if isa(l, EmptyLayout) && !get(l.attr, :blank, false) if empty # initialize the inner subplots recursively - sp = Subplot(backend(), parent=layout) + sp = Subplot(backend(), parent = layout) layout[r, c] = sp push!(subplots, sp) - spmap[attr(l,:label,gensym())] = sp + spmap[attr(l, :label, gensym())] = sp inc = 1 else # build a layout from a list of existing Plot objects @@ -524,19 +535,19 @@ function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot}) inc = length(plt.subplots) end if get(l.attr, :width, :auto) != :auto - layout.widths[c] = attr(l,:width) + layout.widths[c] = attr(l, :width) end if get(l.attr, :height, :auto) != :auto - layout.heights[r] = attr(l,:height) + layout.heights[r] = attr(l, :height) end i += inc elseif isa(l, GridLayout) # sub-grid if get(l.attr, :width, :auto) != :auto - layout.widths[c] = attr(l,:width) + layout.widths[c] = attr(l, :width) end if get(l.attr, :height, :auto) != :auto - layout.heights[r] = attr(l,:height) + layout.heights[r] = attr(l, :height) end l, sps, m = build_layout(l, n - i, plts) append!(subplots, sps) @@ -551,7 +562,6 @@ function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot}) layout, subplots, spmap end - # ---------------------------------------------------------------------- # @layout macro @@ -563,9 +573,9 @@ function add_layout_pct!(kw::AKW, v::Expr, idx::Integer, nidx::Integer) if length(v.args) == 3 && isa(num, Number) units = v.args[3] if units == :h - return kw[:h] = num*pct + return kw[:h] = num * pct elseif units == :w - return kw[:w] = num*pct + return kw[:w] = num * pct elseif units in (:pct, :px, :mm, :cm, :inch) idx == 1 && (kw[:w] = v) (idx == 2 || nidx == 1) && (kw[:h] = v) @@ -578,23 +588,29 @@ end function add_layout_pct!(kw::AKW, v::Number, idx::Integer) # kw[idx == 1 ? :w : :h] = v*pct - idx == 1 && (kw[:w] = v*pct) - (idx == 2 || nidx == 1) && (kw[:h] = v*pct) + idx == 1 && (kw[:w] = v * pct) + (idx == 2 || nidx == 1) && (kw[:h] = v * pct) end -isrow(v) = isa(v, Expr) && v.head in (:hcat,:row) +isrow(v) = isa(v, Expr) && v.head in (:hcat, :row) iscol(v) = isa(v, Expr) && v.head == :vcat rowsize(v) = isrow(v) ? length(v.args) : 1 - function create_grid(expr::Expr) if iscol(expr) create_grid_vcat(expr) elseif isrow(expr) - :(let cell = GridLayout(1, $(length(expr.args))) - $([:(cell[1,$i] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...) - cell - end) + :( + let cell = GridLayout(1, $(length(expr.args))) + $( + [ + :(cell[1, $i] = $(create_grid(v))) for + (i, v) in enumerate(expr.args) + ]... + ) + cell + end + ) elseif expr.head == :curly create_grid_curly(expr) @@ -613,39 +629,58 @@ function create_grid_vcat(expr::Expr) nr = length(expr.args) nc = rmin body = Expr(:block) - for r=1:nr + for r in 1:nr arg = expr.args[r] if isrow(arg) - for (c,item) in enumerate(arg.args) - push!(body.args, :(cell[$r,$c] = $(create_grid(item)))) + for (c, item) in enumerate(arg.args) + push!(body.args, :(cell[$r, $c] = $(create_grid(item)))) end else - push!(body.args, :(cell[$r,1] = $(create_grid(arg)))) + push!(body.args, :(cell[$r, 1] = $(create_grid(arg)))) end end - :(let cell = GridLayout($nr, $nc) - $body - cell - end) + :( + let cell = GridLayout($nr, $nc) + $body + cell + end + ) else # otherwise just build one row at a time - :(let cell = GridLayout($(length(expr.args)), 1) - $([:(cell[$i,1] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...) - cell - end) + :( + let cell = GridLayout($(length(expr.args)), 1) + $( + [ + :(cell[$i, 1] = $(create_grid(v))) for + (i, v) in enumerate(expr.args) + ]... + ) + cell + end + ) end end function create_grid_curly(expr::Expr) kw = KW() - for (i,arg) in enumerate(expr.args[2:end]) - add_layout_pct!(kw, arg, i, length(expr.args)-1) + for (i, arg) in enumerate(expr.args[2:end]) + add_layout_pct!(kw, arg, i, length(expr.args) - 1) end s = expr.args[1] if isa(s, Expr) && s.head == :call && s.args[1] == :grid - create_grid(:(grid($(s.args[2:end]...), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))) + create_grid( + :(grid( + $(s.args[2:end]...), + width = $(get(kw, :w, QuoteNode(:auto))), + height = $(get(kw, :h, QuoteNode(:auto))), + )), + ) elseif isa(s, Symbol) - :(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto))))) + :(EmptyLayout( + label = $(QuoteNode(s)), + width = $(get(kw, :w, QuoteNode(:auto))), + height = $(get(kw, :h, QuoteNode(:auto))), + )) else error("Unknown use of curly brackets: $expr") end @@ -659,14 +694,13 @@ macro layout(mat::Expr) create_grid(mat) end - # ------------------------------------------------------------------------- # make all reference the same axis extrema/values. # merge subplot lists. function link_axes!(axes::Axis...) a1 = axes[1] - for i=2:length(axes) + for i in 2:length(axes) a2 = axes[i] expand_extrema!(a1, ignorenan_extrema(a2)) for k in (:extrema, :discrete_values, :continuous_values, :discrete_map) @@ -688,8 +722,8 @@ function link_subplots(a::AbstractArray{AbstractLayout}, axissym::Symbol) for l in a if isa(l, Subplot) push!(subplots, l) - elseif isa(l, GridLayout) && size(l) == (1,1) - push!(subplots, l[1,1]) + elseif isa(l, GridLayout) && size(l) == (1, 1) + push!(subplots, l[1, 1]) end end subplots @@ -705,20 +739,19 @@ function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol) end # don't do anything for most layout types -function link_axes!(l::AbstractLayout, link::Symbol) -end +function link_axes!(l::AbstractLayout, link::Symbol) end # process a GridLayout, recursively linking axes according to the link symbol function link_axes!(layout::GridLayout, link::Symbol) nr, nc = size(layout) if link in (:x, :both) - for c=1:nc - link_axes!(layout.grid[:,c], :xaxis) + for c in 1:nc + link_axes!(layout.grid[:, c], :xaxis) end end if link in (:y, :both) - for r=1:nr - link_axes!(layout.grid[r,:], :yaxis) + for r in 1:nr + link_axes!(layout.grid[r, :], :yaxis) end end if link == :square @@ -744,8 +777,9 @@ end "Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis." function twinx(sp::Subplot) - 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], @@ -756,7 +790,7 @@ function twinx(sp::Subplot) twinsp[:yaxis][:grid] = false twinsp[:xaxis][:showaxis] = false twinsp[:yaxis][:mirror] = true - twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0) + twinsp[:background_color_inside] = RGBA{Float64}(0, 0, 0, 0) link_axes!(sp[:xaxis], twinsp[:xaxis]) twinsp end diff --git a/src/legend.jl b/src/legend.jl index 0b996619..0d3c3def 100644 --- a/src/legend.jl +++ b/src/legend.jl @@ -8,20 +8,19 @@ Return `(x,y)` at an angle `theta` degrees from `xmax`, `ymin`, `ymax`). """ function legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax) - (s,c) = sincosd(theta) - x = c < 0 ? (xmin-xcenter)/c : (xmax-xcenter)/c - y = s < 0 ? (ymin-ycenter)/s : (ymax-ycenter)/s - A = min(x,y) - return (xcenter + A*c, ycenter + A*s) + (s, c) = sincosd(theta) + x = c < 0 ? (xmin - xcenter) / c : (xmax - xcenter) / c + y = s < 0 ? (ymin - ycenter) / s : (ymax - ycenter) / s + A = min(x, y) + return (xcenter + A * c, ycenter + A * s) end - """ 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 + x < -1 // 3 && return 1 + x < 1 // 3 && return 2 return 3 end @@ -32,28 +31,28 @@ 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::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::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) - ) + ( + 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), +) diff --git a/src/output.jl b/src/output.jl index 92f7ec01..785a7cc7 100644 --- a/src/output.jl +++ b/src/output.jl @@ -73,7 +73,6 @@ function txt(plt::Plot, fn::AbstractString) end txt(fn::AbstractString) = txt(current(), fn) - # ---------------------------------------------------------------- const _savemap = Dict( @@ -128,7 +127,6 @@ function savefig(plt::Plot, fn::AbstractString) end savefig(fn::AbstractString) = savefig(current(), fn) - # --------------------------------------------------------- """ @@ -186,8 +184,8 @@ function _show(io::IO, ::MIME"text/html", plt::Plot) end # delegate showable to _show instead -function Base.showable(m::M, plt::P) where {M <: MIME, P <: Plot} - return hasmethod(_show, Tuple{IO, M, P}) +function Base.showable(m::M, plt::P) where {M<:MIME,P<:Plot} + return hasmethod(_show, Tuple{IO,M,P}) end function _display(plt::Plot) @@ -224,7 +222,6 @@ Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) = "Close all open gui windows of the current backend" closeall() = closeall(backend()) - # function html_output_format(fmt) # if fmt == "png" # @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot) @@ -241,7 +238,6 @@ closeall() = closeall(backend()) # # html_output_format("svg") - # --------------------------------------------------------- # Atom PlotPane # --------------------------------------------------------- diff --git a/src/pipeline.jl b/src/pipeline.jl index 88305e31..bb87a69e 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -30,7 +30,6 @@ function RecipesPipeline.warn_on_recipe_aliases!( end end - ## Grouping RecipesPipeline.splittable_attribute(plt::Plot, key, val::SeriesAnnotations, len) = @@ -41,7 +40,6 @@ function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations, return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor) end - ## Preprocessing attributes function RecipesPipeline.preprocess_axis_args!(plt::Plot, plotattributes, letter) # Fix letter for seriestypes that are x only but data gets passed as y @@ -62,7 +60,6 @@ RecipesPipeline.is_axis_attribute(plt::Plot, attr) = is_axis_attr_noletter(attr) RecipesPipeline.is_subplot_attribute(plt::Plot, attr) = is_subplot_attr(attr) # in src/args.jl - ## User recipes function RecipesPipeline.process_userrecipe!(plt::Plot, kw_list, kw) @@ -84,13 +81,15 @@ function _preprocess_userrecipe(kw::AKW) # map marker_z if it's a Function if isa(get(kw, :marker_z, nothing), Function) # TODO: should this take y and/or z as arguments? - kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : + kw[:marker_z] = + isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : map(kw[:marker_z], kw[:x], kw[:y], kw[:z]) end # map line_z if it's a Function if isa(get(kw, :line_z, nothing), Function) - kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : + kw[:line_z] = + isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : map(kw[:line_z], kw[:x], kw[:y], kw[:z]) end @@ -140,15 +139,12 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW) end end - RecipesPipeline.get_axis_limits(plt::Plot, letter) = axis_limits(plt[1], letter, false) - ## Plot recipes RecipesPipeline.type_alias(plt::Plot) = get(_typeAliases, st, st) - ## Plot setup function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list) @@ -159,18 +155,18 @@ end function RecipesPipeline.process_sliced_series_attributes!(plt::Plots.Plot, kw_list) # swap errors - err_inds = findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list) + err_inds = + findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list) for ind in err_inds - if get(kw_list[ind-1],:seriestype,:path) == :scatter + if get(kw_list[ind - 1], :seriestype, :path) == :scatter tmp = copy(kw_list[ind]) - kw_list[ind] = copy(kw_list[ind-1]) - kw_list[ind-1] = tmp + kw_list[ind] = copy(kw_list[ind - 1]) + kw_list[ind - 1] = tmp end end return nothing end - # TODO: Should some of this logic be moved to RecipesPipeline? function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) # merge in anything meant for the Plot @@ -193,7 +189,6 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) plt.init = true end - # handle inset subplots insets = plt[:inset_subplots] if insets !== nothing @@ -226,7 +221,7 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) # Subplot/Axis attributes set by a user/series recipe apply only to the # Subplot object which they belong to. # TODO: allow matrices to still apply to all subplots - sp_attrs = Dict{Subplot, Any}() + sp_attrs = Dict{Subplot,Any}() for kw in kw_list # get the Subplot object to which the series belongs. sps = get(kw, :subplot, :auto) @@ -294,13 +289,13 @@ function _add_plot_title!(plt) if plot_title != "" the_layout = plt.layout vspan = plt[:plot_titlevspan] - plt.layout = grid(2, 1, heights=(vspan, 1 - vspan)) - plt.layout.grid[1, 1] = subplot = Subplot(plt.backend, parent=plt.layout[1, 1]) + plt.layout = grid(2, 1, heights = (vspan, 1 - vspan)) + plt.layout.grid[1, 1] = subplot = Subplot(plt.backend, parent = plt.layout[1, 1]) plt.layout.grid[2, 1] = the_layout subplot.plt = plt # propagate arguments plt[:plot_titleXXX] --> subplot[:titleXXX] - for sym ∈ filter(x -> startswith(string(x), "plot_title"), keys(_plot_defaults)) - subplot[Symbol(string(sym)[length("plot_") + 1:end])] = plt[sym] + for sym in filter(x -> startswith(string(x), "plot_title"), keys(_plot_defaults)) + subplot[Symbol(string(sym)[(length("plot_") + 1):end])] = plt[sym] end top = plt.backend isa PyPlotBackend ? nothing : 0mm bot = 0mm @@ -346,7 +341,10 @@ function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T} st = _override_seriestype_check(plotattributes, st) # change to a 3d projection for this subplot? - if RecipesPipeline.needs_3d_axes(st) || (st == :quiver && plotattributes[:z] !== nothing) + if ( + RecipesPipeline.needs_3d_axes(st) || + (st == :quiver && plotattributes[:z] !== nothing) + ) sp.attr[:projection] = "3d" end @@ -362,8 +360,10 @@ function _override_seriestype_check(plotattributes::AKW, st::Symbol) # do we want to override the series type? if !RecipesPipeline.is3d(st) && !(st in (:contour, :contour3d, :quiver)) z = plotattributes[:z] - if z !== nothing && - (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z)) + if ( + z !== nothing && + (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z)) + ) st = (st == :scatter ? :scatter3d : :path3d) plotattributes[:seriestype] = st end @@ -374,7 +374,7 @@ end function needs_any_3d_axes(sp::Subplot) any( RecipesPipeline.needs_3d_axes( - _override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype]) + _override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype]), ) for s in series_list(sp) ) end @@ -399,9 +399,9 @@ end function _add_the_series(plt, sp, plotattributes) extra_kwargs = warn_on_unsupported_args(plt.backend, plotattributes) if (kw = plt[:extra_kwargs]) isa AbstractDict - plt[:extra_plot_kwargs] = get(kw,:plot,KW()) - sp[:extra_kwargs] = get(kw,:subplot, KW()) - plotattributes[:extra_kwargs] = get(kw,:series,KW()) + plt[:extra_plot_kwargs] = get(kw, :plot, KW()) + sp[:extra_kwargs] = get(kw, :subplot, KW()) + plotattributes[:extra_kwargs] = get(kw, :series, KW()) elseif plt[:extra_kwargs] == :plot plt[:extra_plot_kwargs] = extra_kwargs elseif plt[:extra_kwargs] == :subplot diff --git a/src/plot.jl b/src/plot.jl index fe614a67..ba689a0b 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -1,6 +1,6 @@ mutable struct CurrentPlot - nullableplot::Union{AbstractPlot, Nothing} + nullableplot::Union{AbstractPlot,Nothing} end const CURRENT_PLOT = CurrentPlot(nothing) @@ -20,17 +20,20 @@ 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)) 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) + if ( + isempty(plt[:extra_plot_kwargs]) && + all(isempty, sp_ekwargs) && + all(isempty, s_ekwargs) + ) return end - print(io,"\nCaptured extra kwargs:\n") + print(io, "\nCaptured extra kwargs:\n") do_show = true for (key, value) in plt[:extra_plot_kwargs] do_show && println(io, " Plot:") @@ -62,7 +65,6 @@ convertSeriesIndex(plt::Plot, n::Int) = n # --------------------------------------------------------- - """ The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one: @@ -91,7 +93,8 @@ end # build a new plot from existing plots # note: we split into plt1, plt2 and plts_tail so we can dispatch correctly -plot(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) = plot!(deepcopy(plt1), deepcopy(plt2), deepcopy.(plts_tail)...; kw...) +plot(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) = + plot!(deepcopy(plt1), deepcopy(plt2), deepcopy.(plts_tail)...; kw...) function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) @nospecialize plotattributes = KW(kw) @@ -102,8 +105,8 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) plts = Array{Plot}(undef, n) plts[1] = plt1 plts[2] = plt2 - for (i,plt) in enumerate(plts_tail) - plts[i+2] = plt + for (i, plt) in enumerate(plts_tail) + plts[i + 2] = plt end # compute the layout @@ -130,9 +133,9 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) plt.init = true series_attr = KW() - for (k,v) in plotattributes + for (k, v) in plotattributes if is_series_attr(k) - series_attr[k] = pop!(plotattributes,k) + series_attr[k] = pop!(plotattributes, k) end end @@ -163,7 +166,7 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) _add_plot_title!(plt) # first apply any args for the subplots - for (idx,sp) in enumerate(plt.subplots) + for (idx, sp) in enumerate(plt.subplots) _update_subplot_args(plt, sp, plotattributes, idx, false) end @@ -173,8 +176,6 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) plt end - - # this adds to the current plot, or creates a new plot if none are current function plot!(args...; kw...) @nospecialize @@ -210,14 +211,13 @@ function _plot!(plt::Plot, plotattributes, args) return plt end - # we're getting ready to display/output. prep for layout calcs, then update # the plot object after function prepare_output(plt::Plot) _before_layout_calcs(plt) w, h = plt.attr[:size] - plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px) + plt.layout.bbox = BoundingBox(0mm, 0mm, w * px, h * px) # One pass down and back up the tree to compute the minimum padding # of the children on the perimeter. This is an backend callback. @@ -229,9 +229,10 @@ function prepare_output(plt::Plot) # spedific to :plot_title see _add_plot_title! force_minpad = get(plt, :force_minpad, ()) if !isempty(force_minpad) - for i ∈ eachindex(plt.layout.grid) + for i in eachindex(plt.layout.grid) plt.layout.grid[i].minpad = Tuple( - i === nothing ? j : i for (i, j) ∈ zip(force_minpad, plt.layout.grid[i].minpad) + i === nothing ? j : i for + (i, j) in zip(force_minpad, plt.layout.grid[i].minpad) ) end end diff --git a/src/plotattr.jl b/src/plotattr.jl index d695d16e..c9449830 100644 --- a/src/plotattr.jl +++ b/src/plotattr.jl @@ -1,8 +1,10 @@ -const _attribute_defaults = Dict(:Series => _series_defaults, - :Subplot => _subplot_defaults, - :Plot => _plot_defaults, - :Axis => _axis_defaults) +const _attribute_defaults = Dict( + :Series => _series_defaults, + :Subplot => _subplot_defaults, + :Plot => _plot_defaults, + :Axis => _axis_defaults, +) attrtypes() = join(keys(_attribute_defaults), ", ") attributes(attrtype::Symbol) = sort(collect(keys(_attribute_defaults[attrtype]))) @@ -21,7 +23,9 @@ Look up the properties of a Plots attribute, or specify an attribute type. Call The information is the same as that given on https://docs.juliaplots.org/latest/attributes/. """ function plotattr() - println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())") + println( + "Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())", + ) end function plotattr(attrtype::Symbol) @@ -44,27 +48,32 @@ printnothing(x) = x printnothing(x::Nothing) = "nothing" function plotattr(attrtype::Symbol, attribute::AbstractString) - in(attrtype, keys(_attribute_defaults)) || ArgumentError("`attrtype` must match one of $(attrtypes())") + in(attrtype, keys(_attribute_defaults)) || + ArgumentError("`attrtype` must match one of $(attrtypes())") attribute = Symbol(lookup_aliases(attrtype, attribute)) desc = get(_arg_desc, attribute, "") first_period_idx = findfirst(isequal('.'), desc) - if isnothing(first_period_idx) + if isnothing(first_period_idx) typedesc = "" desc = strip(desc) else - typedesc = desc[1:first_period_idx-1] - desc = strip(desc[first_period_idx+1:end]) + typedesc = desc[1:(first_period_idx - 1)] + desc = strip(desc[(first_period_idx + 1):end]) end - als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort - als = join(map(string,als), ", ") + als = keys(filter(x -> x[2] == attribute, _keyAliases)) |> collect |> sort + als = join(map(string, als), ", ") def = _attribute_defaults[attrtype][attribute] - # Looks up the different elements and plots them - println("$(printnothing(attribute)) ", typedesc == "" ? "" : "{$(printnothing(typedesc))}", "\n", + println( + "$(printnothing(attribute)) ", + typedesc == "" ? "" : "{$(printnothing(typedesc))}", + "\n", als == "" ? "" : "$(printnothing(als))\n", "\n$(printnothing(desc))\n", - "$(printnothing(attrtype)) attribute, ", def == "" ? "" : " default: $(printnothing(def))") + "$(printnothing(attrtype)) attribute, ", + def == "" ? "" : " default: $(printnothing(def))", + ) end diff --git a/src/precompile_includer.jl b/src/precompile_includer.jl index ed5fe1c5..2a19fe91 100644 --- a/src/precompile_includer.jl +++ b/src/precompile_includer.jl @@ -1,6 +1,5 @@ should_precompile = true - # Don't edit the following! Instead change the script for `snoop_bot`. ismultios = false ismultiversion = false @@ -8,13 +7,11 @@ ismultiversion = false @static if !should_precompile # nothing elseif !ismultios && !ismultiversion - @static if isfile(joinpath( - @__DIR__, - "../deps/SnoopCompile/precompile/precompile_Plots.jl", - )) + @static if isfile( + joinpath(@__DIR__, "../deps/SnoopCompile/precompile/precompile_Plots.jl"), + ) include("../deps/SnoopCompile/precompile/precompile_Plots.jl") _precompile_() end else - end # precompile_enclosure diff --git a/src/recipes.jl b/src/recipes.jl index cd1dce43..0466d66c 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -41,17 +41,16 @@ function all_seriestypes() sort(collect(sts)) end - # ---------------------------------------------------------------------------------- num_series(x::AMat) = size(x, 2) num_series(x) = 1 -RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T")) +RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = + throw(MethodError(T, "Unmatched plot recipe: $T")) # --------------------------------------------------------------------------- - # for seriestype `line`, need to sort by x values const POTENTIAL_VECTOR_ARGUMENTS = [ @@ -114,8 +113,8 @@ end @recipe function f(::Type{Val{:hline}}, x, y, z) n = length(y) - newx = repeat(Float64[1, 2, NaN], n) - newy = vec(Float64[yi for i = 1:3, yi in y]) + newx = repeat(Float64[1, 2, NaN], n) + newy = vec(Float64[yi for i in 1:3, yi in y]) x := newx y := newy seriestype := :straightline @@ -125,7 +124,7 @@ end @recipe function f(::Type{Val{:vline}}, x, y, z) n = length(y) - newx = vec(Float64[yi for i = 1:3, yi in y]) + newx = vec(Float64[yi for i in 1:3, yi in y]) x := newx y := repeat(Float64[1, 2, NaN], n) seriestype := :straightline @@ -136,7 +135,7 @@ end @recipe function f(::Type{Val{:hspan}}, x, y, z) n = div(length(y), 2) newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n) - newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...) + newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i in 1:n]...) linewidth --> 0 x := newx y := newy @@ -147,7 +146,7 @@ end @recipe function f(::Type{Val{:vspan}}, x, y, z) n = div(length(y), 2) - newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...) + newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i in 1:n]...) newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n) linewidth --> 0 x := newx @@ -179,7 +178,6 @@ end end @deps scatterpath path scatter - # --------------------------------------------------------------------------- # regression line and scatter @@ -202,10 +200,8 @@ end () end - @specialize - # --------------------------------------------------------------------------- # steps @@ -215,10 +211,10 @@ function make_steps(x::AbstractArray, st, even) n == 0 && return zeros(0) newx = zeros(2n - (even ? 0 : 1)) newx[1] = x[1] - for i = 2:n + for i in 2:n idx = 2i - 1 if st == :mid - newx[idx] = newx[idx-1] = (x[i] + x[i-1]) / 2 + newx[idx] = newx[idx - 1] = (x[i] + x[i - 1]) / 2 else newx[idx] = x[i] newx[idx - 1] = x[st == :pre ? i : i - 1] @@ -229,7 +225,6 @@ function make_steps(x::AbstractArray, st, even) end make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t) - @nospecialize # create a path from steps @@ -307,7 +302,6 @@ end end @deps steppost path scatter - # --------------------------------------------------------------------------- # sticks @@ -326,7 +320,7 @@ end end newx, newy = zeros(3n), zeros(3n) newz = z !== nothing ? zeros(3n) : nothing - for (i, (xi, yi, zi)) = enumerate(zip(x, y, z !== nothing ? z : 1:n)) + for (i, (xi, yi, zi)) in enumerate(zip(x, y, z !== nothing ? z : 1:n)) rng = (3i - 2):(3i) newx[rng] = [xi, xi, NaN] if z !== nothing @@ -343,7 +337,11 @@ end end fillrange := nothing seriestype := :path - if plotattributes[:linecolor] == :auto && plotattributes[:marker_z] !== nothing && plotattributes[:line_z] === nothing + if ( + plotattributes[:linecolor] == :auto && + plotattributes[:marker_z] !== nothing && + plotattributes[:line_z] === nothing + ) line_z := plotattributes[:marker_z] end @@ -368,7 +366,6 @@ end @specialize - # --------------------------------------------------------------------------- # bezier curves @@ -438,8 +435,7 @@ end # create a bar plot as a filled step function @recipe function f(::Type{Val{:bar}}, x, y, z) - procx, procy, xscale, yscale, baseline = - _preprocess_barlike(plotattributes, x, y) + procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y) nx, ny = length(procx), length(procy) axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis] cv = [discrete_value!(axis, xi)[1] for xi in procx] @@ -448,7 +444,9 @@ end elseif nx == ny + 1 0.5 * diff(cv) + cv[1:(end - 1)] else - error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))") + error( + "bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))", + ) end # compute half-width of bars @@ -473,7 +471,7 @@ end end xseg, yseg = Segments(), Segments() - for i = 1:ny + for i in 1:ny yi = procy[i] if !isnan(yi) center = procx[i] @@ -497,7 +495,7 @@ end # switch back if !isvertical(plotattributes) xseg, yseg = yseg, xseg - x, y = y, x + x, y = y, x end # reset orientation @@ -532,8 +530,8 @@ end m, n = size(z.surf) x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n) fz = zeros(m * n) - for i = 1:m # y - for j = 1:n # x + for i in 1:m # y + for j in 1:n # x k = (j - 1) * m + i inds = (6 * (k - 1) + 1):(6 * k - 1) x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]] @@ -580,7 +578,6 @@ function _scale_adjusted_values( end end - function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real} if (scale in _logScales) !isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3) @@ -589,7 +586,6 @@ function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real} end end - function _preprocess_binbarlike_weights( ::Type{T}, w, @@ -618,12 +614,10 @@ function _preprocess_binlike(plotattributes, x, y) edge, weights, xscale, yscale, baseline end - @nospecialize @recipe function f(::Type{Val{:barbins}}, x, y, z) - edge, weights, xscale, yscale, baseline = - _preprocess_binlike(plotattributes, x, y) + edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) if (plotattributes[:bar_width] === nothing) bar_width := diff(edge) end @@ -634,10 +628,8 @@ end end @deps barbins bar - @recipe function f(::Type{Val{:scatterbins}}, x, y, z) - edge, weights, xscale, yscale, baseline = - _preprocess_binlike(plotattributes, x, y) + edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) @series begin x := _bin_centers(edge) xerror := diff(edge) / 2 @@ -654,13 +646,7 @@ end @specialize -function _stepbins_path( - edge, - weights, - baseline::Real, - xscale::Symbol, - yscale::Symbol, -) +function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::Symbol) log_scale_x = xscale in _logScales log_scale_y = yscale in _logScales @@ -722,11 +708,9 @@ end @recipe function f(::Type{Val{:stepbins}}, x, y, z) @nospecialize - axis = - plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis] + axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis] - edge, weights, xscale, yscale, baseline = - _preprocess_binlike(plotattributes, x, y) + edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale) if !isvertical(plotattributes) @@ -778,12 +762,9 @@ function _auto_binning_nbins( # The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation nd = n_samples^(1 / (2 + N)) - nd = N == 2 ? - min( - n_samples^(1 / (2 + N)), - nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8), - ) : - nd # the >2-dimensional case does not have a nice solution to correlations + nd = + N == 2 ? + min(n_samples^(1 / (2 + N)), nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8)) : nd # the >2-dimensional case does not have a nice solution to correlations v = vs[dim] @@ -812,11 +793,8 @@ _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where { StatsBase.histrange(vs[dim], binning, :left) _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning)) -_hist_edge( - vs::NTuple{N,AbstractVector}, - dim::Integer, - binning::AbstractVector, -) where {N} = binning +_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = + binning _hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N,Any}) where {N} = map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,)) @@ -846,8 +824,8 @@ function _make_hist( edges = _hist_edges(localvs, binning) h = float( weights === nothing ? - StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) : - StatsBase.fit( + StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) : + StatsBase.fit( StatsBase.Histogram, localvs, StatsBase.Weights(weights), @@ -908,7 +886,6 @@ end end @deps scatterhist scatterbins - @recipe function f(h::StatsBase.Histogram{T,1,E}) where {T,E} seriestype --> :barbins @@ -918,8 +895,7 @@ end :step => :stepbins, :steppost => :stepbins, # :step can be mapped to :steppost in pre-processing ) - seriestype := - get(st_map, plotattributes[:seriestype], plotattributes[:seriestype]) + seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype]) if plotattributes[:seriestype] == :scatterbins # Workaround, error bars currently not set correctly by scatterbins @@ -933,7 +909,6 @@ end end end - @recipe function f(hv::AbstractVector{H}) where {H<:StatsBase.Histogram} for h in hv @series begin @@ -942,7 +917,6 @@ end end end - # --------------------------------------------------------------------------- # Histogram 2D @@ -969,7 +943,6 @@ end end Plots.@deps bins2d heatmap - @recipe function f(::Type{Val{:histogram2d}}, x, y, z) h = _make_hist( (x, y), @@ -985,13 +958,11 @@ Plots.@deps bins2d heatmap end @deps histogram2d bins2d - @recipe function f(h::StatsBase.Histogram{T,2,E}) where {T,E} seriestype --> :bins2d (h.edges[1], h.edges[2], Surface(h.weights)) end - # --------------------------------------------------------------------------- # pie @recipe function f(::Type{Val{:pie}}, x, y, z) @@ -1013,7 +984,6 @@ end end @deps pie shape - # --------------------------------------------------------------------------- # mesh 3d replacement for non-plotly backends @@ -1021,12 +991,15 @@ end # As long as no i,j,k are supplied this should work with PyPlot and GR seriestype := :surface if plotattributes[:connections] !== nothing - throw(ArgumentError("Giving triangles using the connections argument is only supported on Plotly backend.")) + throw( + ArgumentError( + "Giving triangles using the connections argument is only supported on Plotly backend.", + ), + ) end () end - # --------------------------------------------------------------------------- # scatter 3d @@ -1044,7 +1017,7 @@ end # --------------------------------------------------------------------------- # lens! - magnify a region of a plot -lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...) +lens!(args...; kwargs...) = plot!(args...; seriestype = :lens, kwargs...) export lens! @recipe function f(::Type{Val{:lens}}, plt::AbstractPlot) sp_index, inset_bbox = plotattributes[:inset_subplots] @@ -1072,11 +1045,12 @@ export lens! linecolor := :lightgray bbx_mag = (x1 + x2) / 2 bby_mag = (y1 + y2) / 2 - xi_lens, yi_lens = intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1)) - xi_mag, yi_mag = intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1)) + xi_lens, yi_lens = + intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1)) + xi_mag, yi_mag = + intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1)) # add lines - if xl1 < xi_lens < xl2 && - yl1 < yi_lens < yl2 + if xl1 < xi_lens < xl2 && yl1 < yi_lens < yl2 @series begin primary := false subplot := sp_index @@ -1121,14 +1095,14 @@ function intersection_point(xA, yA, xB, yB, h, w) else # left return xB - hw, yB - s * hw end - # top or bot? - elseif -hw <= hh/s <= hw + # top or bot? + elseif -hw <= hh / s <= hw if yA > yB # top - return xB + hh/s, yB + hh + return xB + hh / s, yB + hh else # bottom - return xB - hh/s, yB - hh + return xB - hh / s, yB - hh end end end @@ -1268,15 +1242,15 @@ function quiver_using_arrows(plotattributes::AKW) if !isa(plotattributes[:arrow], Arrow) plotattributes[:arrow] = arrow() end - is_3d = haskey(plotattributes,:z) && !isnothing(plotattributes[:z]) + is_3d = haskey(plotattributes, :z) && !isnothing(plotattributes[:z]) velocity = error_zipit(plotattributes[:quiver]) xorig, yorig = plotattributes[:x], plotattributes[:y] zorig = is_3d ? plotattributes[:z] : [] # for each point, we create an arrow of velocity vi, translated to the x/y coordinates x, y = zeros(0), zeros(0) - is_3d && ( z = zeros(0)) - for i = 1:max(length(xorig), length(yorig), is_3d ? 0 : length(zorig)) + is_3d && (z = zeros(0)) + for i in 1:max(length(xorig), length(yorig), is_3d ? 0 : length(zorig)) # get the starting position xi = _cycle(xorig, i) yi = _cycle(yorig, i) @@ -1326,7 +1300,7 @@ function quiver_using_hack(plotattributes::AKW) # for each point, we create an arrow of velocity vi, translated to the x/y coordinates pts = P2[] - for i = 1:max(length(xorig), length(yorig)) + for i in 1:max(length(xorig), length(yorig)) # get the starting position xi = _cycle(xorig, i) @@ -1355,10 +1329,7 @@ function quiver_using_hack(plotattributes::AKW) U2 *= arrow_w ppv = p + v - nanappend!( - pts, - P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1], - ) + nanappend!(pts, P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1]) end plotattributes[:x], plotattributes[:y] = RecipesPipeline.unzip(pts[2:end]) @@ -1377,7 +1348,6 @@ end end @deps quiver shape path - # -------------------------------------------------------------------- # 1 argument # -------------------------------------------------------------------- @@ -1409,7 +1379,7 @@ end @nospecialize # images - colors -@recipe function f(mat::AMat{T}) where {T <: Colorant} +@recipe function f(mat::AMat{T}) where {T<:Colorant} n, m = axes(mat) if is_seriestype_supported(:image) @@ -1439,9 +1409,9 @@ end # interpreted as having one element per shape for attr in union(_segmenting_array_attributes, _segmenting_vector_attributes) v = get(plotattributes, attr, nothing) - if v isa AVec || v isa AMat && size(v,2) == 1 + if v isa AVec || v isa AMat && size(v, 2) == 1 @warn "Column vector attribute `$attr` reinterpreted as row vector (one value per shape).\n" * - "Pass a row vector instead (e.g. using `permutedims`) to suppress this warning." + "Pass a row vector instead (e.g. using `permutedims`) to suppress this warning." plotattributes[attr] = permutedims(v) end end @@ -1455,13 +1425,12 @@ end end end - # -------------------------------------------------------------------- # 3 arguments # -------------------------------------------------------------------- # images - grays -@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T <: Gray} +@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T<:Gray} if is_seriestype_supported(:image) seriestype := :image yflip --> true @@ -1476,7 +1445,7 @@ end end # images - colors -@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T <: Colorant} +@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T<:Colorant} if is_seriestype_supported(:image) seriestype := :image yflip --> true @@ -1497,7 +1466,7 @@ end @recipe f(p::GeometryBasics.Point) = [p] # Special case for 4-tuples in :ohlc series -@recipe f(xyuv::AVec{<:Tuple{R1, R2, R3, R4}}) where {R1, R2, R3, R4} = +@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} = get(plotattributes, :seriestype, :path) == :ohlc ? OHLC[OHLC(t...) for t in xyuv] : RecipesPipeline.unzip(xyuv) @@ -1554,8 +1523,7 @@ end @recipe f( x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}, -) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = - x, OHLC[OHLC(t...) for t in ohlc] +) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc] @recipe function f(x::AVec, v::AVec{OHLC}) seriestype := :path @@ -1574,7 +1542,6 @@ end # TODO: everything below here should be either changed to a # series recipe or moved to PlotRecipes - # "Sparsity plot... heatmap of non-zero values of a matrix" # function spy{T<:Real}(z::AMat{T}; kw...) # mat = reshape(map(zi->float(zi!=0), z),1,:) @@ -1622,7 +1589,6 @@ end @specialize - Plots.findnz(A::AbstractSparseMatrix) = SparseArrays.findnz(A) # fallback function for finding non-zero elements of non-sparse matrices @@ -1662,7 +1628,6 @@ end x, real.(y), imag.(y) end - # Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246 @userplot PortfolioComposition diff --git a/src/shorthands.jl b/src/shorthands.jl index 74a7b26c..923ed5a4 100644 --- a/src/shorthands.jl +++ b/src/shorthands.jl @@ -241,7 +241,6 @@ julia> ohlc(y) """ @shorthands ohlc - """ contour(x,y,z) contour!(x,y,z) @@ -263,7 +262,6 @@ julia> contour(x, y, (x, y) -> x^2 + y^2) "An alias for `contour` with fill = true." @shorthands contourf - @shorthands contour3d """ @@ -408,17 +406,17 @@ julia> curves([1,2,3,4],[1,1,2,4]) @shorthands pie "Plot with seriestype :path3d" -plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d) -plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d) +plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d) +plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d) "Add title to an existing plot" -title!(s::AbstractString; kw...) = plot!(; title = s, kw...) +title!(s::AbstractString; kw...) = plot!(; title = s, kw...) "Add xlabel to an existing plot" -xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...) +xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...) "Add ylabel to an existing plot" -ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...) +ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...) "Set xlims for an existing plot" xlims!(lims::Tuple; kw...) = plot!(; xlims = lims, kw...) @@ -429,21 +427,20 @@ ylims!(lims::Tuple; kw...) = plot!(; ylims = lims, kw...) "Set zlims for an existing plot" zlims!(lims::Tuple; kw...) = plot!(; zlims = lims, kw...) -xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...) -ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...) -zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...) - +xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin, xmax), kw...) +ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin, ymax), kw...) +zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin, zmax), kw...) "Set xticks for an existing plot" -xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...) +xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...) "Set yticks for an existing plot" -yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...) +yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...) -xticks!( -ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...) -yticks!( -ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...) +xticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = + plot!(; xticks = (ticks, labels), kw...) +yticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = + plot!(; yticks = (ticks, labels), kw...) """ annotate!(anns...) @@ -463,22 +460,22 @@ julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))]) julia> annotate!([(4, 4, ("More text", 8, 45.0, :bottom, :red))]) ``` """ -annotate!(anns...; kw...) = plot!(; annotation = anns, kw...) +annotate!(anns...; kw...) = plot!(; annotation = anns, kw...) annotate!(anns::Tuple...; kw...) = plot!(; annotation = collect(anns), kw...) annotate!(anns::AVec{<:Tuple}; kw...) = plot!(; annotation = anns, kw...) "Flip the current plots' x axis" -xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...) +xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...) "Flip the current plots' y axis" -yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...) +yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...) "Specify x axis attributes for an existing plot" -xaxis!(args...; kw...) = plot!(; xaxis = args, kw...) +xaxis!(args...; kw...) = plot!(; xaxis = args, kw...) "Specify y axis attributes for an existing plot" -yaxis!(args...; kw...) = plot!(; yaxis = args, kw...) -xgrid!(args...; kw...) = plot!(; xgrid = args, kw...) -ygrid!(args...; kw...) = plot!(; ygrid = args, kw...) +yaxis!(args...; kw...) = plot!(; yaxis = args, kw...) +xgrid!(args...; kw...) = plot!(; xgrid = args, kw...) +ygrid!(args...; kw...) = plot!(; ygrid = args, kw...) @specialize diff --git a/src/subplots.jl b/src/subplots.jl index 35167349..5d1be3a8 100644 --- a/src/subplots.jl +++ b/src/subplots.jl @@ -1,6 +1,5 @@ - -function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend +function Subplot(::T; parent = RootLayout()) where {T<:AbstractBackend} Subplot{T}( parent, Series[], @@ -9,7 +8,7 @@ function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend defaultbox, DefaultsDict(KW(), _subplot_defaults), nothing, - nothing + nothing, ) end @@ -21,8 +20,7 @@ Return the bounding box of a subplot plotarea(sp::Subplot) = sp.plotarea plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox) - -Base.size(sp::Subplot) = (1,1) +Base.size(sp::Subplot) = (1, 1) Base.length(sp::Subplot) = 1 Base.getindex(sp::Subplot, r::Int, c::Int) = sp @@ -43,23 +41,23 @@ series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattribut function should_add_to_legend(series::Series) series.plotattributes[:primary] && - series.plotattributes[:label] != "" && - !( - series.plotattributes[:seriestype] in ( - :hexbin, - :bins2d, - :histogram2d, - :hline, - :vline, - :contour, - :contourf, - :contour3d, - :surface, - :wireframe, - :heatmap, - :image, + series.plotattributes[:label] != "" && + !( + series.plotattributes[:seriestype] in ( + :hexbin, + :bins2d, + :histogram2d, + :hline, + :vline, + :contour, + :contourf, + :contour3d, + :surface, + :wireframe, + :heatmap, + :image, + ) ) - ) end # ---------------------------------------------------------------------- diff --git a/src/themes.jl b/src/themes.jl index bb1489f9..a770bfb0 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -34,11 +34,8 @@ end @userplot ShowTheme -_color_functions = KW( - :protanopic => protanopic, - :deuteranopic => deuteranopic, - :tritanopic => tritanopic, -) +_color_functions = + KW(:protanopic => protanopic, :deuteranopic => deuteranopic, :tritanopic => tritanopic) _get_showtheme_args(thm::Symbol) = thm, identity _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func, identity) @@ -110,8 +107,8 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func subplot := 4 seriestype := :heatmap seriescolor := colorgradient - xticks := (-2π:2π:2π, string.(-2:2:2, "π")) - yticks := (-2π:2π:2π, string.(-2:2:2, "π")) + xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π")) + yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π")) x, y, z end @@ -119,8 +116,8 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func subplot := 5 seriestype := :surface seriescolor := colorgradient - xticks := (-2π:2π:2π, string.(-2:2:2, "π")) - yticks := (-2π:2π:2π, string.(-2:2:2, "π")) + xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π")) + yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π")) x, y, z end @@ -137,5 +134,4 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func line_z := z x, y, z end - end diff --git a/src/types.jl b/src/types.jl index 5a7427c5..24d441a2 100644 --- a/src/types.jl +++ b/src/types.jl @@ -6,7 +6,8 @@ const AVec = AbstractVector const AMat = AbstractMatrix const KW = Dict{Symbol,Any} const AKW = AbstractDict{Symbol,Any} -const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString} +const TicksArgs = + Union{AVec{T},Tuple{AVec{T},AVec{S}},Symbol} where {T<:Real,S<:AbstractString} struct PlotsDisplay <: AbstractDisplay end @@ -59,11 +60,10 @@ Extrema() = Extrema(Inf, -Inf) # ----------------------------------------------------------- -const SubplotMap = Dict{Any, Subplot} +const SubplotMap = Dict{Any,Subplot} # ----------------------------------------------------------- - mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T} backend::T # the backend type n::Int # number of series @@ -78,9 +78,18 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T} end function Plot() - Plot(backend(), 0, DefaultsDict(KW(), _plot_defaults), Series[], nothing, - Subplot[], SubplotMap(), EmptyLayout(), - Subplot[], false) + Plot( + backend(), + 0, + DefaultsDict(KW(), _plot_defaults), + Series[], + nothing, + Subplot[], + SubplotMap(), + EmptyLayout(), + Subplot[], + false, + ) end # ----------------------------------------------------------------------- @@ -89,7 +98,7 @@ Base.getindex(plt::Plot, i::Integer) = plt.subplots[i] Base.length(plt::Plot) = length(plt.subplots) Base.lastindex(plt::Plot) = length(plt) -Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c] +Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r, c] Base.size(plt::Plot) = size(plt.layout) Base.size(plt::Plot, i::Integer) = size(plt.layout)[i] Base.ndims(plt::Plot) = 2 diff --git a/src/utils.jl b/src/utils.jl index 9b7c12dd..244a14a0 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,11 +1,12 @@ # --------------------------------------------------------------- -treats_y_as_x(seriestype) = seriestype in (:vline, :vspan, :histogram, :barhist, :stephist, :scatterhist) +treats_y_as_x(seriestype) = + seriestype in (:vline, :vspan, :histogram, :barhist, :stephist, :scatterhist) -function replace_image_with_heatmap(z::Array{T}) where T<:Colorant +function replace_image_with_heatmap(z::Array{T}) where {T<:Colorant} n, m = size(z) colors = palette(vec(z)) - newz = reshape(1:n*m, n, m) + newz = reshape(1:(n * m), n, m) newz, colors end @@ -20,8 +21,7 @@ end Segments() = Segments(Float64) Segments(::Type{T}) where {T} = Segments(T[]) -Segments(p::Int) = Segments(NTuple{p, Float64}[]) - +Segments(p::Int) = Segments(NTuple{p,Float64}[]) # Segments() = Segments(zeros(0)) @@ -30,30 +30,32 @@ to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN) to_nan(::Type{NTuple{3,Float64}}) = (NaN, NaN, NaN) coords(segs::Segments{Float64}) = segs.pts -coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts] -coords(segs::Segments{NTuple{3,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts], Float64[p[3] for p in segs.pts] +coords(segs::Segments{NTuple{2,Float64}}) = + Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts] +coords(segs::Segments{NTuple{3,Float64}}) = Float64[p[1] for p in segs.pts], +Float64[p[2] for p in segs.pts], +Float64[p[3] for p in segs.pts] -function Base.push!(segments::Segments{T}, vs...) where T +function Base.push!(segments::Segments{T}, vs...) where {T} if !isempty(segments.pts) push!(segments.pts, to_nan(T)) end for v in vs - push!(segments.pts, convert(T,v)) + push!(segments.pts, convert(T, v)) end segments end -function Base.push!(segments::Segments{T}, vs::AVec) where T +function Base.push!(segments::Segments{T}, vs::AVec) where {T} if !isempty(segments.pts) push!(segments.pts, to_nan(T)) end for v in vs - push!(segments.pts, convert(T,v)) + push!(segments.pts, convert(T, v)) end segments end - struct SeriesSegment # indexes of this segement in series data vectors range::UnitRange @@ -76,7 +78,7 @@ function iter_segments(args...) NaNSegmentsIterator(tup, n1, n2) end -function series_segments(series::Series, seriestype::Symbol=:path; check=false) +function series_segments(series::Series, seriestype::Symbol = :path; check = false) x, y, z = series[:x], series[:y], series[:z] (x === nothing || isempty(x)) && return UnitRange{Int}[] @@ -85,13 +87,13 @@ function series_segments(series::Series, seriestype::Symbol=:path; check=false) if check scales = :xscale, :yscale, :zscale - for (n, s) ∈ enumerate(args) + for (n, s) in enumerate(args) scale = get(series, scales[n], :identity) if scale ∈ _logScales - for (i, v) ∈ enumerate(s) + for (i, v) in enumerate(s) if v <= 0 @warn "Invalid negative or zero value $v found at series index $i for $(scale) based $(scales[n])" - @debug "" exception=(DomainError(v), stacktrace()) + @debug "" exception = (DomainError(v), stacktrace()) break end end @@ -101,12 +103,12 @@ function series_segments(series::Series, seriestype::Symbol=:path; check=false) segments = if has_attribute_segments(series) Iterators.flatten(map(nan_segments) do r - if seriestype in (:scatter, :scatter3d) - (SeriesSegment(i:i, i) for i in r) - else - (SeriesSegment(i:i+1, i) for i in first(r):last(r)-1) - end - end) + if seriestype in (:scatter, :scatter3d) + (SeriesSegment(i:i, i) for i in r) + else + (SeriesSegment(i:(i + 1), i) for i in first(r):(last(r) - 1)) + end + end) else (SeriesSegment(r, 1) for r in nan_segments) end @@ -117,13 +119,15 @@ end function warn_on_attr_dim_mismatch(series, x, y, z, segments) isempty(segments) && return - seg_range = UnitRange(minimum(first(seg.range) for seg in segments), - maximum(last(seg.range) for seg in segments)) + seg_range = UnitRange( + minimum(first(seg.range) for seg in segments), + maximum(last(seg.range) for seg in segments), + ) for attr in _segmenting_vector_attributes v = get(series, attr, nothing) if v isa AVec && eachindex(v) != seg_range @warn "Indices $(eachindex(v)) of attribute `$attr` does not match data indices $seg_range." - if any(v -> !isnothing(v) && any(isnan, v), (x,y,z)) + if any(v -> !isnothing(v) && any(isnan, v), (x, y, z)) @info """Data contains NaNs or missing values, and indices of `$attr` vector do not match data indices. If you intend elements of `$attr` to apply to individual NaN-separated segements in the data, pass each segment in a separate vector instead, and use a row vector for `$attr`. Legend entries @@ -137,20 +141,24 @@ function warn_on_attr_dim_mismatch(series, x, y, z, segments) end # helpers to figure out if there are NaN values in a list of array types -anynan(i::Int, args::Tuple) = any(a -> try isnan(_cycle(a,i)) catch MethodError false end, args) -anynan(args::Tuple) = i -> anynan(i,args) +anynan(i::Int, args::Tuple) = any(a -> try + isnan(_cycle(a, i)) +catch MethodError + false +end, args) +anynan(args::Tuple) = i -> anynan(i, args) anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend) allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend) function Base.iterate(itr::NaNSegmentsIterator, nextidx::Int = itr.n1) - i = findfirst(!anynan(itr.args), nextidx:itr.n2) + i = findfirst(!anynan(itr.args), nextidx:(itr.n2)) i === nothing && return nextval = nextidx + i - 1 - j = findfirst(anynan(itr.args), nextval:itr.n2) + j = findfirst(anynan(itr.args), nextval:(itr.n2)) nextnan = j === nothing ? itr.n2 + 1 : nextval + j - 1 - nextval:nextnan-1, nextnan + nextval:(nextnan - 1), nextnan end Base.IteratorSize(::NaNSegmentsIterator) = Base.SizeUnknown() @@ -162,7 +170,6 @@ float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64 # ------------------------------------------------------------------------------------ - nop() = nothing notimpl() = error("This has not been implemented yet") @@ -172,12 +179,12 @@ isnothing(x) = false _cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj _cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj -_cycle(v::AVec, idx::Int) = v[mod(idx, axes(v,1))] -_cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[end, mod(idx, axes(v,2))] : v[:, mod(idx, axes(v,2))] +_cycle(v::AVec, idx::Int) = v[mod(idx, axes(v, 1))] +_cycle(v::AMat, idx::Int) = size(v, 1) == 1 ? v[end, mod(idx, axes(v, 2))] : v[:, mod(idx, axes(v, 2))] _cycle(v, idx::Int) = v -_cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices) -_cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v,i), indices) +_cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v, i), indices) +_cycle(v::AMat, indices::AVec{Int}) = map(i -> _cycle(v, i), indices) _cycle(v, indices::AVec{Int}) = fill(v, length(indices)) _cycle(cl::PlotUtils.AbstractColorList, idx::Int) = cl[mod1(idx, end)] @@ -198,17 +205,16 @@ maketuple(x::Tuple{T,S}) where {T,S} = x for i in 2:4 @eval begin RecipesPipeline.unzip( - v::Union{AVec{<:Tuple{Vararg{T,$i} where T}}, AVec{<:GeometryBasics.Point{$i}}}, - ) = $(Expr(:tuple, (:([t[$j] for t in v]) for j=1:i)...)) + v::Union{AVec{<:Tuple{Vararg{T,$i} where T}},AVec{<:GeometryBasics.Point{$i}}}, + ) = $(Expr(:tuple, (:([t[$j] for t in v]) for j in 1:i)...)) end end RecipesPipeline.unzip( - ::Union{AVec{<:GeometryBasics.Point{N}}, AVec{<:Tuple{Vararg{T,N} where T}}} -) where N = error("$N-dimensional unzip not implemented.") -RecipesPipeline.unzip(::Union{AVec{<:GeometryBasics.Point}, AVec{<:Tuple}}) = error( - "Can't unzip points of different dimensions." -) + ::Union{AVec{<:GeometryBasics.Point{N}},AVec{<:Tuple{Vararg{T,N} where T}}}, +) where {N} = error("$N-dimensional unzip not implemented.") +RecipesPipeline.unzip(::Union{AVec{<:GeometryBasics.Point},AVec{<:Tuple}}) = + error("Can't unzip points of different dimensions.") # given 2-element lims and a vector of data x, widen lims to account for the extrema of x function _expand_limits(lims, x) @@ -221,7 +227,7 @@ function _expand_limits(lims, x) nothing end -expand_data(v, n::Integer) = [_cycle(v, i) for i=1:n] +expand_data(v, n::Integer) = [_cycle(v, i) for i in 1:n] # if the type exists in a list, replace the first occurence. otherwise add it to the end function addOrReplace(v::AbstractVector, t::DataType, args...; kw...) @@ -253,28 +259,42 @@ function replaceAliases!(plotattributes::AKW, aliases::Dict{Symbol,Symbol}) end end -createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end] +createSegments(z) = collect(repeat(reshape(z, 1, :), 2, 1))[2:end] sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes))) function _heatmap_edges(v::AVec, isedges::Bool = false, ispolar::Bool = false) length(v) == 1 && return v[1] .+ [ispolar ? max(-v[1], -0.5) : -0.5, 0.5] - if isedges return v end + if isedges + return v + end # `isedges = true` means that v is a vector which already describes edges # and does not need to be extended. vmin, vmax = ignorenan_extrema(v) extra_min = ispolar ? min(v[1], (v[2] - v[1]) / 2) : (v[2] - v[1]) / 2 extra_max = (v[end] - v[end - 1]) / 2 - vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max) + vcat(vmin - extra_min, 0.5 * (v[1:(end - 1)] + v[2:end]), vmax + extra_max) end "create an (n+1) list of the outsides of heatmap rectangles" -function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false, ispolar::Bool = false) +function heatmap_edges( + v::AVec, + scale::Symbol = :identity, + isedges::Bool = false, + ispolar::Bool = false, +) f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale) - map(invf, _heatmap_edges(map(f,v), isedges, ispolar)) + map(invf, _heatmap_edges(map(f, v), isedges, ispolar)) end -function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int}, ispolar::Bool = false) +function heatmap_edges( + x::AVec, + xscale::Symbol, + y::AVec, + yscale::Symbol, + z_size::Tuple{Int,Int}, + ispolar::Bool = false, +) nx, ny = length(x), length(y) # ismidpoints = z_size == (ny, nx) # This fails some tests, but would actually be # the correct check, since (4, 3) != (3, 4) and a missleading plot is produced. @@ -285,12 +305,11 @@ function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size: Must be either `size(z) == (length(y), length(x))` (x & y define midpoints) or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""") end - x, y = heatmap_edges(x, xscale, isedges), - heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots + x, y = heatmap_edges(x, xscale, isedges), heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots return x, y end -function is_uniformly_spaced(v; tol=1e-6) +function is_uniformly_spaced(v; tol = 1e-6) dv = diff(v) maximum(dv) - minimum(dv) < tol * mean(abs.(dv)) end @@ -298,8 +317,8 @@ end function convert_to_polar(theta, r, r_extrema = ignorenan_extrema(r)) rmin, rmax = r_extrema r = (r .- rmin) ./ (rmax .- rmin) - x = r.*cos.(theta) - y = r.*sin.(theta) + x = r .* cos.(theta) + y = r .* sin.(theta) x, y end @@ -307,8 +326,8 @@ fakedata(sz::Int...) = fakedata(Random.seed!(PLOTS_SEED), sz...) function fakedata(rng::AbstractRNG, sz...) y = zeros(sz...) - for r in 2:size(y,1) - y[r,:] = 0.95 * vec(y[r-1,:]) + randn(rng, size(y,2)) + for r in 2:size(y, 1) + y[r, :] = 0.95 * vec(y[r - 1, :]) + randn(rng, size(y, 2)) end y end @@ -327,13 +346,14 @@ isscalar(::Any) = false is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2 -isvertical(plotattributes::AKW) = get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert) +isvertical(plotattributes::AKW) = + get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert) isvertical(series::Series) = isvertical(series.plotattributes) - ticksType(ticks::AVec{T}) where {T<:Real} = :ticks ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels -ticksType(ticks::Tuple{T,S}) where {T<:Union{AVec,Tuple},S<:Union{AVec,Tuple}} = :ticks_and_labels +ticksType(ticks::Tuple{T,S}) where {T<:Union{AVec,Tuple},S<:Union{AVec,Tuple}} = + :ticks_and_labels ticksType(ticks) = :invalid limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits @@ -357,9 +377,9 @@ function nansplit(v::AVec) push!(vs, v) break elseif idx > 1 - push!(vs, v[1:idx-1]) + push!(vs, v[1:(idx - 1)]) end - v = v[idx+1:end] + v = v[(idx + 1):end] end vs end @@ -376,7 +396,7 @@ end # returns the array of indices (znew) and a vector of unique values (vals) function indices_and_unique_values(z::AbstractArray) vals = sort(unique(z)) - vmap = Dict([(v,i) for (i,v) in enumerate(vals)]) + vmap = Dict([(v, i) for (i, v) in enumerate(vals)]) newz = map(zi -> vmap[zi], z) newz, vals end @@ -384,14 +404,14 @@ end handle_surface(z) = z handle_surface(z::Surface) = permutedims(z.surf) -ok(x::Number, y::Number, z::Number=0) = isfinite(x) && isfinite(y) && isfinite(z) +ok(x::Number, y::Number, z::Number = 0) = isfinite(x) && isfinite(y) && isfinite(z) ok(tup::Tuple) = ok(tup...) # compute one side of a fill range from a ribbon function make_fillrange_side(y::AVec, rib) frs = zeros(axes(y)) for (i, yi) in pairs(y) - frs[i] = yi + _cycle(rib,i) + frs[i] = yi + _cycle(rib, i) end frs end @@ -407,10 +427,10 @@ function make_fillrange_from_ribbon(kw::AKW) end #turn tuple of fillranges to one path -function concatenate_fillrange(x,y::Tuple) +function concatenate_fillrange(x, y::Tuple) rib1, rib2 = first(y), last(y) - yline = vcat(rib1,(rib2)[end:-1:1]) - xline = vcat(x,x[end:-1:1]) + yline = vcat(rib1, (rib2)[end:-1:1]) + xline = vcat(x, x[end:-1:1]) return xline, yline end @@ -452,9 +472,9 @@ function contour_levels(series::Series, clims) zmin, zmax = clims levels = series[:levels] if levels isa Integer - levels = range(zmin, stop=zmax, length=levels+2) + levels = range(zmin, stop = zmax, length = levels + 2) if !isfilledcontour(series) - levels = levels[2:end-1] + levels = levels[2:(end - 1)] end end levels @@ -479,7 +499,8 @@ for comp in (:line, :fill, :marker) end end - $get_compcolor(series, clims, i::Int=1) = $get_compcolor(series, clims[1], clims[2], i) + $get_compcolor(series, clims, i::Int = 1) = + $get_compcolor(series, clims[1], clims[2], i) function $get_compcolor(series, i::Int = 1) if series[$Symbol($comp_z)] === nothing @@ -489,7 +510,7 @@ for comp in (:line, :fill, :marker) end end - $get_compalpha(series, i::Int=1) = _cycle(series[$Symbol($compalpha)], i) + $get_compalpha(series, i::Int = 1) = _cycle(series[$Symbol($compalpha)], i) end end @@ -501,30 +522,30 @@ function get_colorgradient(series::Series) series[:linecolor] elseif series[:marker_z] !== nothing series[:markercolor] - elseif series[:line_z] !== nothing + elseif series[:line_z] !== nothing series[:linecolor] elseif series[:fill_z] !== nothing series[:fillcolor] end end -single_color(c, v=0.5) = c -single_color(grad::ColorGradient, v=0.5) = grad[v] +single_color(c, v = 0.5) = c +single_color(grad::ColorGradient, v = 0.5) = grad[v] get_gradient(c) = cgrad() get_gradient(cg::ColorGradient) = cg -get_gradient(cp::ColorPalette) = cgrad(cp, categorical=true) +get_gradient(cp::ColorPalette) = cgrad(cp, categorical = true) -get_linewidth(series, i::Int=1) = _cycle(series[:linewidth], i) -get_linestyle(series, i::Int=1) = _cycle(series[:linestyle], i) +get_linewidth(series, i::Int = 1) = _cycle(series[:linewidth], i) +get_linestyle(series, i::Int = 1) = _cycle(series[:linestyle], i) -function get_markerstrokecolor(series, i::Int=1) +function get_markerstrokecolor(series, i::Int = 1) msc = series[:markerstrokecolor] isa(msc, ColorGradient) ? msc : _cycle(msc, i) end -get_markerstrokealpha(series, i::Int=1) = _cycle(series[:markerstrokealpha], i) -get_markerstrokewidth(series, i::Int=1) = _cycle(series[:markerstrokewidth], i) +get_markerstrokealpha(series, i::Int = 1) = _cycle(series[:markerstrokealpha], i) +get_markerstrokewidth(series, i::Int = 1) = _cycle(series[:markerstrokewidth], i) const _segmenting_vector_attributes = ( :seriescolor, @@ -551,9 +572,10 @@ function has_attribute_segments(series::Series) # of its attributes series[:seriestype] == :shape && return false # check relevant attributes if they have multiple inputs - return any(series[attr] isa AbstractVector && length(series[attr]) > 1 - for attr in _segmenting_vector_attributes - ) || any(series[attr] isa AbstractArray for attr in _segmenting_array_attributes) + return any( + series[attr] isa AbstractVector && length(series[attr]) > 1 for + attr in _segmenting_vector_attributes + ) || any(series[attr] isa AbstractArray for attr in _segmenting_array_attributes) end function get_aspect_ratio(sp) @@ -577,7 +599,8 @@ get_size(sp::Subplot) = get_size(sp.plt) get_thickness_scaling(kw) = get(kw, :thickness_scaling, default(:thickness_scaling)) get_thickness_scaling(plt::Plot) = get_thickness_scaling(plt.attr) get_thickness_scaling(sp::Subplot) = get_thickness_scaling(sp.plt) -get_thickness_scaling(series::Series) = get_thickness_scaling(series.plotattributes[:subplot]) +get_thickness_scaling(series::Series) = + get_thickness_scaling(series.plotattributes[:subplot]) # --------------------------------------------------------------- makekw(; kw...) = KW(kw) @@ -595,8 +618,11 @@ allShapes(arg) = ( trueOrAllTrue(a -> isa(a, Shape), arg) ) allAlphas(arg) = trueOrAllTrue( - a -> (typeof(a) <: Real && a > 0 && a < 1) || - (typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg + a -> + (typeof(a) <: Real && a > 0 && a < 1) || ( + typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a))) + ), + arg, ) allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg) allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg) @@ -695,7 +721,7 @@ mutable struct DebugMode end const _debugMode = DebugMode(false) -debugplots(on=true) = _debugMode.on = on +debugplots(on = true) = _debugMode.on = on debugshow(io, x) = show(io, x) debugshow(io, x::AbstractArray) = print(io, summary(x)) @@ -747,16 +773,17 @@ function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} _series_updated(plt, series) end -setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z<:AbstractMatrix} = ( - setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i) -) +setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z<:AbstractMatrix} = + (setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i)) # ------------------------------------------------------- # indexing notation # Base.getindex(plt::Plot, i::Integer) = getxy(plt, i) -Base.setindex!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y} = (setxy!(plt, xy, i); plt) -Base.setindex!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} = (setxyz!(plt, xyz, i); plt) +Base.setindex!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y} = + (setxy!(plt, xy, i); plt) +Base.setindex!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} = + (setxyz!(plt, xyz, i); plt) # ------------------------------------------------------- # operate on individual series @@ -810,14 +837,15 @@ function extend_to_length!(v::AbstractVector, n) extend_by_data!(v, vmax .+ (1:(n - length(v)))) end extend_by_data!(v::AbstractVector, x) = isimmutable(v) ? vcat(v, x) : push!(v, x) -extend_by_data!(v::AbstractVector, x::AbstractVector) = isimmutable(v) ? vcat(v, x) : append!(v, x) +extend_by_data!(v::AbstractVector, x::AbstractVector) = + isimmutable(v) ? vcat(v, x) : append!(v, x) # ------------------------------------------------------- function attr!(series::Series; kw...) plotattributes = KW(kw) RecipesPipeline.preprocess_attributes!(plotattributes) - for (k,v) in plotattributes + for (k, v) in plotattributes if haskey(_series_defaults, k) series[k] = v else @@ -831,7 +859,7 @@ end function attr!(sp::Subplot; kw...) plotattributes = KW(kw) RecipesPipeline.preprocess_attributes!(plotattributes) - for (k,v) in plotattributes + for (k, v) in plotattributes if haskey(_subplot_defaults, k) sp[k] = v else @@ -861,8 +889,8 @@ Base.append!(plt::Plot, i::Integer, t::Tuple) = append!(plt, i, t...) # push y[i] to the ith series function Base.push!(plt::Plot, y::AVec) ny = length(y) - for i in 1:plt.n - push!(plt, i, y[mod1(i,ny)]) + for i in 1:(plt.n) + push!(plt, i, y[mod1(i, ny)]) end plt end @@ -875,8 +903,8 @@ Base.push!(plt::Plot, x::Real, y::AVec) = push!(plt, [x], y) function Base.push!(plt::Plot, x::AVec, y::AVec) nx = length(x) ny = length(y) - for i in 1:plt.n - push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)]) + for i in 1:(plt.n) + push!(plt, i, x[mod1(i, nx)], y[mod1(i, ny)]) end plt end @@ -886,8 +914,8 @@ function Base.push!(plt::Plot, x::AVec, y::AVec, z::AVec) nx = length(x) ny = length(y) nz = length(z) - for i in 1:plt.n - push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)], z[mod1(i,nz)]) + for i in 1:(plt.n) + push!(plt, i, x[mod1(i, nx)], y[mod1(i, ny)], z[mod1(i, nz)]) end plt end @@ -909,15 +937,14 @@ mm2inch(mm::Real) = float(mm / MM_PER_INCH) px2mm(px::Real) = float(px * MM_PER_PX) mm2px(mm::Real) = float(mm / MM_PER_PX) - "Smallest x in plot" -xmin(plt::Plot) = ignorenan_minimum( - [ignorenan_minimum(series.plotattributes[:x]) for series in plt.series_list] -) +xmin(plt::Plot) = ignorenan_minimum([ + ignorenan_minimum(series.plotattributes[:x]) for series in plt.series_list +]) "Largest x in plot" -xmax(plt::Plot) = ignorenan_maximum( - [ignorenan_maximum(series.plotattributes[:x]) for series in plt.series_list] -) +xmax(plt::Plot) = ignorenan_maximum([ + ignorenan_maximum(series.plotattributes[:x]) for series in plt.series_list +]) "Extrema of x-values in plot" ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt)) @@ -1040,11 +1067,14 @@ function straightline_data(series, expansion_factor = 1) xdata, ydata = fill(NaN, n), fill(NaN, n) for i in 1:k inds = (3 * i - 2):(3 * i - 1) - xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds], expansion_factor) + xdata[inds], ydata[inds] = + straightline_data(xl, yl, x[inds], y[inds], expansion_factor) end xdata, ydata else - error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n") + error( + "Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n", + ) end end @@ -1066,7 +1096,10 @@ function straightline_data(xl, yl, x, y, expansion_factor = 1) b = y[1] - (y[1] - y[2]) * x[1] / (x[1] - x[2]) a = (y[1] - y[2]) / (x[1] - x[2]) # get the data values - xdata = [clamp(x[1] + (x[1] - x[2]) * (ylim - y[1]) / (y[1] - y[2]), xl...) for ylim in yl] + xdata = [ + clamp(x[1] + (x[1] - x[2]) * (ylim - y[1]) / (y[1] - y[2]), xl...) for + ylim in yl + ] xdata, a .* xdata .+ b end @@ -1107,49 +1140,51 @@ function shape_data(series, expansion_factor = 1) return x, y end -construct_categorical_data(x::AbstractArray, axis::Axis) = ( - map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x) -) +construct_categorical_data(x::AbstractArray, axis::Axis) = + (map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x)) -_fmt_paragraph(paragraph::AbstractString;kwargs...) = _fmt_paragraph( - IOBuffer(), paragraph, 0; kwargs... -) +_fmt_paragraph(paragraph::AbstractString; kwargs...) = + _fmt_paragraph(IOBuffer(), paragraph, 0; kwargs...) function _fmt_paragraph( - io::IOBuffer, remaining_text::AbstractString, column_count::Integer; - fillwidth=60, leadingspaces=0 + io::IOBuffer, + remaining_text::AbstractString, + column_count::Integer; + fillwidth = 60, + leadingspaces = 0, ) - kwargs = (fillwidth=fillwidth, leadingspaces=leadingspaces) + kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces) - m = match(r"(.*?) (.*)",remaining_text) + m = match(r"(.*?) (.*)", remaining_text) if isa(m, Nothing) if column_count + length(remaining_text) ≤ fillwidth print(io, remaining_text) String(take!(io)) else - print(io, "\n"*" "^leadingspaces*remaining_text) + print(io, "\n" * " "^leadingspaces * remaining_text) String(take!(io)) end else if column_count + length(m[1]) ≤ fillwidth - print(io,"$(m[1]) ") + print(io, "$(m[1]) ") _fmt_paragraph(io, m[2], column_count + length(m[1]) + 1; kwargs...) else - print(io,"\n"*" "^leadingspaces*"$(m[1]) ") + print(io, "\n" * " "^leadingspaces * "$(m[1]) ") _fmt_paragraph(io, m[2], leadingspaces; kwargs...) end end end -_document_argument(S::AbstractString) = _fmt_paragraph( - "`$S`: "*_arg_desc[Symbol(S)], leadingspaces=6+length(S) -) +_document_argument(S::AbstractString) = + _fmt_paragraph("`$S`: " * _arg_desc[Symbol(S)], leadingspaces = 6 + length(S)) function mesh3d_triangles(x, y, z, cns) - if typeof(cns) <: Tuple{Array, Array, Array} + if typeof(cns) <: Tuple{Array,Array,Array} ci, cj, ck = cns if !(length(ci) == length(cj) == length(ck)) - throw(ArgumentError("Argument connections must consist of equally sized arrays.")) + throw( + ArgumentError("Argument connections must consist of equally sized arrays."), + ) end else throw(ArgumentError("Argument connections has to be a tuple of three arrays.")) @@ -1157,11 +1192,14 @@ function mesh3d_triangles(x, y, z, cns) X = zeros(eltype(x), 4length(ci)) Y = zeros(eltype(y), 4length(cj)) Z = zeros(eltype(z), 4length(ck)) - @inbounds for I ∈ 1:length(ci) + @inbounds for I in 1:length(ci) i = ci[I] + 1 # connections are 0-based j = cj[I] + 1 k = ck[I] + 1 - m = 4(I - 1) + 1; n = m + 1; o = m + 2; p = m + 3 + m = 4(I - 1) + 1 + n = m + 1 + o = m + 2 + p = m + 3 X[m] = X[p] = x[i] Y[m] = Y[p] = y[i] Z[m] = Z[p] = z[i] diff --git a/test/imgcomp.jl b/test/imgcomp.jl index 879a87ea..589dbd11 100644 --- a/test/imgcomp.jl +++ b/test/imgcomp.jl @@ -3,13 +3,13 @@ import Plots._current_plots_version # replace `f(args...)` with `f(rng, args...)` for `f ∈ (rand, randn)` function replace_rand!(ex) end function replace_rand!(ex::Expr) - for arg in ex.args - replace_rand!(arg) - end - if ex.head === :call && ex.args[1] ∈ (:rand, :randn, :(Plots.fakedata)) - pushfirst!(ex.args, ex.args[1]) - ex.args[2] = :rng - end + for arg in ex.args + replace_rand!(arg) + end + if ex.head === :call && ex.args[1] ∈ (:rand, :randn, :(Plots.fakedata)) + pushfirst!(ex.args, ex.args[1]) + ex.args[2] = :rng + end end function fix_rand!(ex) replace_rand!(ex) @@ -59,7 +59,7 @@ function image_comparison_facts( sigma = [1, 1], # number of pixels to "blur" tol = 1e-2, ) # acceptable error (percent) - for i = 1:length(Plots._examples) + for i in 1:length(Plots._examples) i in skip && continue if only === nothing || i in only @test image_comparison_tests(pkg, i, debug = debug, sigma = sigma, tol = tol) |> diff --git a/test/integration_dates.jl b/test/integration_dates.jl index 081d69fb..48aa5b94 100644 --- a/test/integration_dates.jl +++ b/test/integration_dates.jl @@ -1,13 +1,13 @@ using Plots, Test, Dates @testset "Limits" begin - y=[1.0*i*i for i in 1:10] - x=[Date(2019,11,i) for i in 1:10] + y = [1.0 * i * i for i in 1:10] + x = [Date(2019, 11, i) for i in 1:10] - rx=[x[3],x[5]] + rx = [x[3], x[5]] - p = plot(x,y, widen = false) - vspan!(p, rx, label="", alpha=0.2) + p = plot(x, y, widen = false) + vspan!(p, rx, label = "", alpha = 0.2) ref_ylims = (y[1], y[end]) ref_xlims = (x[1].instant.periods.value, x[end].instant.periods.value) @@ -23,13 +23,13 @@ using Plots, Test, Dates end # testset @testset "Date xlims" begin - y=[1.0*i*i for i in 1:10] - x=[Date(2019,11,i) for i in 1:10] - span = (Date(2019,10,31), Date(2019,11,11)) + y = [1.0 * i * i for i in 1:10] + x = [Date(2019, 11, i) for i in 1:10] + span = (Date(2019, 10, 31), Date(2019, 11, 11)) - ref_xlims = map(date->date.instant.periods.value, span) + ref_xlims = map(date -> date.instant.periods.value, span) - p = plot(x,y, xlims=span, widen = false) + p = plot(x, y, xlims = span, widen = false) @test Plots.xlims(p) == ref_xlims #@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI")) @@ -42,13 +42,13 @@ end # testset end # testset @testset "DateTime xlims" begin - y=[1.0*i*i for i in 1:10] - x=[DateTime(2019,11,i,11) for i in 1:10] - span = (DateTime(2019,10,31,11,59,59), DateTime(2019,11,11,12,01,15)) + y = [1.0 * i * i for i in 1:10] + x = [DateTime(2019, 11, i, 11) for i in 1:10] + span = (DateTime(2019, 10, 31, 11, 59, 59), DateTime(2019, 11, 11, 12, 01, 15)) - ref_xlims = map(date->date.instant.periods.value, span) + ref_xlims = map(date -> date.instant.periods.value, span) - p = plot(x,y, xlims=span, widen = false) + p = plot(x, y, xlims = span, widen = false) @test Plots.xlims(p) == ref_xlims #@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI")) @static if haskey(ENV, "APPVEYOR") diff --git a/test/runtests.jl b/test/runtests.jl index f29e1153..24931870 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -18,12 +18,12 @@ using RecipesBase @test Plots.plotly_local_file_path[] === nothing temp = Plots.use_local_dependencies[] withenv("PLOTS_HOST_DEPENDENCY_LOCAL" => true) do - Plots.__init__() - @test Plots.plotly_local_file_path[] isa String - @test isfile(Plots.plotly_local_file_path[]) - @test Plots.use_local_dependencies[] = true - @test_nowarn Plots._init_ijulia_plotting() -end + Plots.__init__() + @test Plots.plotly_local_file_path[] isa String + @test isfile(Plots.plotly_local_file_path[]) + @test Plots.use_local_dependencies[] = true + @test_nowarn Plots._init_ijulia_plotting() + end Plots.plotly_local_file_path[] = nothing Plots.use_local_dependencies[] = temp end # testset @@ -39,12 +39,13 @@ include("test_recipes.jl") include("test_hdf5plots.jl") include("test_pgfplotsx.jl") -reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...) +reference_dir(args...) = + joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...) function reference_file(backend, i, version) refdir = reference_dir("Plots", string(backend)) fn = "ref$i.png" - versions = sort(VersionNumber.(readdir(refdir)), rev=true) + versions = sort(VersionNumber.(readdir(refdir)), rev = true) reffn = joinpath(refdir, string(version), fn) for v in versions @@ -62,13 +63,16 @@ reference_path(backend, version) = reference_dir("Plots", string(backend), strin if !isdir(reference_dir()) mkpath(reference_dir()) - LibGit2.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git", reference_dir()) + LibGit2.clone( + "https://github.com/JuliaPlots/PlotReferenceImages.jl.git", + reference_dir(), + ) end include("imgcomp.jl") # don't actually show the plots Random.seed!(PLOTS_SEED) -default(show=false, reuse=true) +default(show = false, reuse = true) is_ci() = get(ENV, "CI", "false") == "true" const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" : "1e-5")) @@ -98,7 +102,6 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" ## @testset "Backends" begin - @testset "GR" begin ENV["PLOTS_TEST"] = "true" ENV["GKSwstype"] = "100" @@ -108,7 +111,11 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" @static if haskey(ENV, "APPVEYOR") @info "Skipping GR image comparison tests on AppVeyor" else - image_comparison_facts(:gr, tol=PLOTS_IMG_TOL, skip=Plots._backend_skips[:gr]) + image_comparison_facts( + :gr, + tol = PLOTS_IMG_TOL, + skip = Plots._backend_skips[:gr], + ) end end @@ -148,7 +155,6 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" @test isa(p, Plots.Plot) == true @test_broken isa(display(p), Nothing) == true end - end @testset "Axes" begin @@ -158,10 +164,10 @@ end @test Plots.discrete_value!(axis, "HI") == (0.5, 1) @test Plots.discrete_value!(axis, :yo) == (1.5, 2) @test Plots.ignorenan_extrema(axis) == (0.5, 1.5) - @test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1) + @test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1) - Plots.discrete_value!(axis, ["x$i" for i = 1:5]) - Plots.discrete_value!(axis, ["x$i" for i = 0:2]) + Plots.discrete_value!(axis, ["x$i" for i in 1:5]) + Plots.discrete_value!(axis, ["x$i" for i in 0:2]) @test Plots.ignorenan_extrema(axis) == (0.5, 7.5) end @@ -171,14 +177,16 @@ end @test backend() == Plots.UnicodePlotsBackend() @testset "Plot" begin - plots = [histogram([1, 0, 0, 0, 0, 0]), - plot([missing]), - plot([missing, missing]), - plot(fill(missing, 10)), - plot([missing; 1:4]), - plot([fill(missing, 10); 1:4]), - plot([1 1; 1 missing]), - plot(["a" "b"; missing "d"], [1 2; 3 4])] + plots = [ + histogram([1, 0, 0, 0, 0, 0]), + plot([missing]), + plot([missing, missing]), + plot(fill(missing, 10)), + plot([missing; 1:4]), + plot([fill(missing, 10); 1:4]), + plot([1 1; 1 missing]), + plot(["a" "b"; missing "d"], [1 2; 3 4]), + ] for plt in plots display(plt) end @@ -186,13 +194,12 @@ end end @testset "Bar" begin - p = bar([3,2,1], [1,2,3]); - @test isa(p, Plots.Plot) - @test isa(display(p), Nothing) == true + p = bar([3, 2, 1], [1, 2, 3]) + @test isa(p, Plots.Plot) + @test isa(display(p), Nothing) == true end end - @testset "EmptyAnim" begin anim = @animate for i in [] end @@ -208,17 +215,25 @@ end @test segments([NaN]) == [] @test segments(nan10) == [] @test segments([nan10; 1:5]) == [11:15] - @test segments([1:5;nan10]) == [1:5] + @test segments([1:5; nan10]) == [1:5] @test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30] @test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10] @test segments([nan10; 1:15], [1:15; nan10]) == [11:15] end @testset "Utils" begin - zipped = ([(1, 2)], [("a", "b")], [(1, "a"),(2, "b")], - [(1, 2),(3, 4)], [(1, 2, 3),(3, 4, 5)], [(1, 2, 3, 4),(3, 4, 5, 6)], - [(1, 2.0),(missing, missing)], [(1, missing),(missing, "a")], - [(missing, missing)], [(missing, missing, missing),("a", "b", "c")]) + zipped = ( + [(1, 2)], + [("a", "b")], + [(1, "a"), (2, "b")], + [(1, 2), (3, 4)], + [(1, 2, 3), (3, 4, 5)], + [(1, 2, 3, 4), (3, 4, 5, 6)], + [(1, 2.0), (missing, missing)], + [(1, missing), (missing, "a")], + [(missing, missing)], + [(missing, missing, missing), ("a", "b", "c")], + ) for z in zipped @test isequal(collect(zip(Plots.unzip(z)...)), z) @test isequal(collect(zip(Plots.unzip(GeometryBasics.Point.(z))...)), z) @@ -227,5 +242,7 @@ end op2 = Plots.process_clims((1, 2.0)) data = randn(100, 100) @test op1(data) == op2(data) - @test Plots.process_clims(nothing) == Plots.process_clims(missing) == Plots.process_clims(:auto) + @test Plots.process_clims(nothing) == + Plots.process_clims(missing) == + Plots.process_clims(:auto) end diff --git a/test/test_axes.jl b/test/test_axes.jl index f65cd745..4d714c86 100644 --- a/test/test_axes.jl +++ b/test/test_axes.jl @@ -9,8 +9,8 @@ using Plots, Test end @testset "Magic axis" begin - @test plot(1, axis=nothing)[1][:xaxis][:ticks] == [] - @test plot(1, axis=nothing)[1][:yaxis][:ticks] == [] + @test plot(1, axis = nothing)[1][:xaxis][:ticks] == [] + @test plot(1, axis = nothing)[1][:yaxis][:ticks] == [] end # testset @testset "Categorical ticks" begin @@ -23,34 +23,34 @@ end # testset end @testset "Ticks getter functions" begin - ticks1 = ([1,2,3], ("a","b","c")) - ticks2 = ([4,5], ("e","f")) - p1 = plot(1:5, 1:5, 1:5, xticks=ticks1, yticks=ticks1, zticks=ticks1) - p2 = plot(1:5, 1:5, 1:5, xticks=ticks2, yticks=ticks2, zticks=ticks2) + ticks1 = ([1, 2, 3], ("a", "b", "c")) + ticks2 = ([4, 5], ("e", "f")) + p1 = plot(1:5, 1:5, 1:5, xticks = ticks1, yticks = ticks1, zticks = ticks1) + p2 = plot(1:5, 1:5, 1:5, xticks = ticks2, yticks = ticks2, zticks = ticks2) p = plot(p1, p2) @test xticks(p) == yticks(p) == zticks(p) == [ticks1, ticks2] @test xticks(p[1]) == yticks(p[1]) == zticks(p[1]) == ticks1 end @testset "Axis limits" begin - pl = plot(1:5, xlims=:symmetric, widen = false) + 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) + @test Plots.xlims(pl) == Plots.widen(1, 3) - pl = plot([1.05,2.0,2.95], ylims=:round) + pl = plot([1.05, 2.0, 2.95], ylims = :round) @test Plots.ylims(pl) == (1, 3) - pl = plot(1:3, xlims=(1,5)) + pl = plot(1:3, xlims = (1, 5)) @test Plots.xlims(pl) == (1, 5) - pl = plot(1:3, xlims=(1,5), widen=true) + pl = plot(1:3, xlims = (1, 5), widen = true) @test Plots.xlims(pl) == Plots.widen(1, 5) end @testset "3D Axis" begin - ql = quiver([1, 2], [2, 1], [3, 4], quiver = ([1, -1], [0, 0], [1, -0.5]), arrow=true) + ql = quiver([1, 2], [2, 1], [3, 4], quiver = ([1, -1], [0, 0], [1, -0.5]), arrow = true) @test ql[1][:projection] == "3d" end diff --git a/test/test_axis_letter.jl b/test/test_axis_letter.jl index 691034b8..e0b6462c 100644 --- a/test/test_axis_letter.jl +++ b/test/test_axis_letter.jl @@ -9,12 +9,15 @@ using Plots, Test value(m::MyType) = m.val data = MyType.(sort(randn(20))) # A recipe that puts the axis letter in the title - @recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:MyType} + @recipe function f(::Type{T}, m::T) where {T<:AbstractArray{<:MyType}} title --> string(plotattributes[:letter]) value.(m) end - @testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist], o in [:vertical, :horizontal] - @test f(data, orientation=o).subplots[1].attr[:title] == (o == :vertical ? "x" : "y") + @testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist], + o in [:vertical, :horizontal] + + @test f(data, orientation = o).subplots[1].attr[:title] == + (o == :vertical ? "x" : "y") end @testset "$f" for f in [hline, hspan] @test f(data).subplots[1].attr[:title] == "y" diff --git a/test/test_components.jl b/test/test_components.jl index aae50da3..31b643e3 100644 --- a/test/test_components.jl +++ b/test/test_components.jl @@ -52,7 +52,7 @@ using Plots, Test @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] + myshapes = [ellipse(x, rand(), rand(), rand()) for x in 1:4] @test coords(myshapes) isa Tuple{Vector{Vector{S}},Vector{Vector{T}}} where {T,S} local p @test_nowarn p = plot(myshapes) @@ -116,7 +116,7 @@ end end @testset "Series Annotations" begin - square = Shape([(0., 0.), (1., 0.), (1., 1.), (0., 1.)]) + square = Shape([(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)]) @test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin p = plot( [1, 2, 3], @@ -136,24 +136,25 @@ end @test sa.scalefactor == (1, 4) end spl = scatter( - 4.53 .* [1/1 1/2 1/3 1/4 1/5], + 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"]]), ) - for i ∈ 1:5 - @test only(spl.series_list[i].plotattributes[:series_annotations].strs).str == "1/$i" + for i in 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))) + p = plot([1, 2], annotations = (1.5, 2, text("foo", :left))) 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)) + p = plot([1, 2], annotations = ((0.1, 0.5), :auto)) pos, txt = only(p.subplots[end][:annotations]) - @test pos == (.1, .5) + @test pos == (0.1, 0.5) @test txt.str == "(a)" end diff --git a/test/test_hdf5plots.jl b/test/test_hdf5plots.jl index 2c106025..a948c677 100644 --- a/test/test_hdf5plots.jl +++ b/test/test_hdf5plots.jl @@ -1,21 +1,20 @@ using Plots, HDF5 - @testset "HDF5_Plots" begin - fname = "tmpplotsave.hdf5" - hdf5() + fname = "tmpplotsave.hdf5" + hdf5() - x = 1:10 - psrc=plot(x, x.*x); #Create some plot - Plots.hdf5plot_write(psrc, fname) + x = 1:10 + psrc = plot(x, x .* x) #Create some plot + Plots.hdf5plot_write(psrc, fname) - #Read back file: - gr() #Choose some fast backend likely to work in test environment. - pread = Plots.hdf5plot_read(fname) + #Read back file: + gr() #Choose some fast backend likely to work in test environment. + pread = Plots.hdf5plot_read(fname) - #Make sure data made it through: - @test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x] - @test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y] + #Make sure data made it through: + @test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x] + @test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y] - #display(pread) #Don't display. Regression env might not support + #display(pread) #Don't display. Regression env might not support end #testset diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl index 18fd68e5..21144db4 100644 --- a/test/test_pgfplotsx.jl +++ b/test/test_pgfplotsx.jl @@ -2,420 +2,407 @@ using Plots, Test pgfplotsx() function create_plot(args...; kwargs...) - pgfx_plot = plot(args...; kwargs...) - return pgfx_plot, repr("application/x-tex", pgfx_plot) + pgfx_plot = plot(args...; kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) end function create_plot!(args...; kwargs...) - pgfx_plot = plot!(args...; kwargs...) - return pgfx_plot, repr("application/x-tex", pgfx_plot) + pgfx_plot = plot!(args...; kwargs...) + return pgfx_plot, repr("application/x-tex", pgfx_plot) end @testset "PGFPlotsX" begin - pgfx_plot = plot(1:5) - Plots._update_plot_object(pgfx_plot) - @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument - @test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing - axis = Plots.pgfx_axes(pgfx_plot.o)[1] - @test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 1 - @test !haskey(axis.contents[1].options.dict, "fill") + pgfx_plot = plot(1:5) + Plots._update_plot_object(pgfx_plot) + @test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument + @test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing + axis = Plots.pgfx_axes(pgfx_plot.o)[1] + @test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 1 + @test !haskey(axis.contents[1].options.dict, "fill") - @testset "Legends" begin - legends_plot = plot(rand(5, 2), lab = ["1" ""]) - scatter!(legends_plot, rand(5)) - Plots._update_plot_object(legends_plot) - axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents - leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents) - series = filter(x -> x isa PGFPlotsX.Plot, axis_contents) - @test length(leg_entries) == 2 - @test !haskey(series[1].options.dict, "forget plot") - @test haskey(series[2].options.dict, "forget plot") - @test !haskey(series[3].options.dict, "forget plot") - end # testset + @testset "Legends" begin + legends_plot = plot(rand(5, 2), lab = ["1" ""]) + scatter!(legends_plot, rand(5)) + Plots._update_plot_object(legends_plot) + axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents + leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents) + series = filter(x -> x isa PGFPlotsX.Plot, axis_contents) + @test length(leg_entries) == 2 + @test !haskey(series[1].options.dict, "forget plot") + @test haskey(series[2].options.dict, "forget plot") + @test !haskey(series[3].options.dict, "forget plot") + end # testset - @testset "3D docs example" begin - n = 100 - ts = range(0, stop = 8π, length = n) - x = ts .* map(cos, ts) - y = (0.1ts) .* map(sin, ts) - z = 1:n - pl = plot( - x, - y, - z, - zcolor = reverse(z), - m = (10, 0.8, :blues, Plots.stroke(0)), - leg = false, - cbar = true, - w = 5, - ) - pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w = 10) - Plots._update_plot_object(pgfx_plot) - if @test_nowarn( - haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true - ) - @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing - end - end # testset - @testset "Color docs example" begin - y = rand(100) - plot( - 0:10:100, - rand(11, 4), - lab = "lines", - w = 3, - palette = :grays, - fill = 0, - α = 0.6, - ) - pl = scatter!( - y, - zcolor = abs.(y .- 0.5), - m = (:hot, 0.8, Plots.stroke(1, :green)), - ms = 10 * abs.(y .- 0.5) .+ 4, - lab = ["grad", "", "ient"], - ) - Plots._update_plot_object(pl) - axis = Plots.pgfx_axes(pl.o)[1] - @test count(x -> x isa PGFPlotsX.LegendEntry, axis.contents) == 6 - @test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 108 # each marker is its own plot, fillranges create 2 plot-objects - marker = axis.contents[15] - @test marker isa PGFPlotsX.Plot - @test marker.options["mark"] == "*" - @test marker.options["mark options"]["color"] == - RGBA{Float64}(colorant"green", 0.8) - @test marker.options["mark options"]["line width"] == 0.75 # 1px is 0.75pt - end # testset - @testset "Plot in pieces" begin - pic = plot(rand(100) / 3, reg = true, fill = (0, :green)) - scatter!(pic, rand(100), markersize = 6, c = :orange) - Plots._update_plot_object(pic) - axis_contents = Plots.pgfx_axes(pic.o)[1].contents - leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents) - series = filter(x -> x isa PGFPlotsX.Plot, axis_contents) - @test length(leg_entries) == 2 - @test length(series) == 4 - @test haskey(series[1].options.dict, "forget plot") - @test !haskey(series[2].options.dict, "forget plot") - @test haskey(series[3].options.dict, "forget plot") - @test !haskey(series[4].options.dict, "forget plot") - end # testset - @testset "Marker types" begin - markers = filter((m -> begin - m in Plots.supported_markers() - end), Plots._shape_keys) - markers = reshape(markers, 1, length(markers)) - n = length(markers) - x = (range(0, stop = 10, length = n + 2))[2:(end-1)] - y = repeat(reshape(reverse(x), 1, :), n, 1) - scatter( - x, - y, - m = (8, :auto), - lab = map(string, markers), - bg = :linen, - xlim = (0, 10), - ylim = (0, 10), - ) - end # testset - @testset "Layout" begin - plot( - Plots.fakedata(100, 10), - layout = 4, - palette = [:grays :blues :hot :rainbow], - bg_inside = [:orange :pink :darkblue :black], - ) - end # testset - @testset "Polar plots" begin - Θ = range(0, stop = 1.5π, length = 100) - r = abs.(0.1 * randn(100) + sin.(3Θ)) - plot(Θ, r, proj = :polar, m = 2) - end # testset - @testset "Drawing shapes" begin - verts = [ - (-1.0, 1.0), - (-1.28, 0.6), - (-0.2, -1.4), - (0.2, -1.4), - (1.28, 0.6), - (1.0, 1.0), - (-1.0, 1.0), - (-0.2, -0.6), - (0.0, -0.2), - (-0.4, 0.6), - (1.28, 0.6), - (0.2, -1.4), - (-0.2, -1.4), - (0.6, 0.2), - (-0.2, 0.2), - (0.0, -0.2), - (0.2, 0.2), - (-0.2, -0.6), - ] - x = 0.1:0.2:0.9 - y = 0.7 * rand(5) .+ 0.15 - plot( - x, - y, - line = (3, :dash, :lightblue), - marker = (Shape(verts), 30, RGBA(0, 0, 0, 0.2)), - bg = :pink, - fg = :darkblue, - xlim = (0, 1), - ylim = (0, 1), - leg = false, - ) - end # testset - @testset "Histogram 2D" begin - histogram2d(randn(10000), randn(10000), nbins = 20) - end # testset - @testset "Heatmap-like" begin - xs = [string("x", i) for i = 1:10] - ys = [string("y", i) for i = 1:4] - z = float((1:4) * reshape(1:10, 1, :)) - pgfx_plot = heatmap(xs, ys, z, aspect_ratio = 1) - Plots._update_plot_object(pgfx_plot) - if @test_nowarn( - haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true - ) - @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing - @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" - end + @testset "3D docs example" begin + n = 100 + ts = range(0, stop = 8π, length = n) + x = ts .* map(cos, ts) + y = (0.1ts) .* map(sin, ts) + z = 1:n + pl = plot( + x, + y, + z, + zcolor = reverse(z), + m = (10, 0.8, :blues, Plots.stroke(0)), + leg = false, + cbar = true, + w = 5, + ) + pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w = 10) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn( + haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true + ) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing + end + end # testset + @testset "Color docs example" begin + y = rand(100) + plot( + 0:10:100, + rand(11, 4), + lab = "lines", + w = 3, + palette = :grays, + fill = 0, + α = 0.6, + ) + pl = scatter!( + y, + zcolor = abs.(y .- 0.5), + m = (:hot, 0.8, Plots.stroke(1, :green)), + ms = 10 * abs.(y .- 0.5) .+ 4, + lab = ["grad", "", "ient"], + ) + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + @test count(x -> x isa PGFPlotsX.LegendEntry, axis.contents) == 6 + @test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 108 # each marker is its own plot, fillranges create 2 plot-objects + marker = axis.contents[15] + @test marker isa PGFPlotsX.Plot + @test marker.options["mark"] == "*" + @test marker.options["mark options"]["color"] == RGBA{Float64}(colorant"green", 0.8) + @test marker.options["mark options"]["line width"] == 0.75 # 1px is 0.75pt + end # testset + @testset "Plot in pieces" begin + pic = plot(rand(100) / 3, reg = true, fill = (0, :green)) + scatter!(pic, rand(100), markersize = 6, c = :orange) + Plots._update_plot_object(pic) + axis_contents = Plots.pgfx_axes(pic.o)[1].contents + leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents) + series = filter(x -> x isa PGFPlotsX.Plot, axis_contents) + @test length(leg_entries) == 2 + @test length(series) == 4 + @test haskey(series[1].options.dict, "forget plot") + @test !haskey(series[2].options.dict, "forget plot") + @test haskey(series[3].options.dict, "forget plot") + @test !haskey(series[4].options.dict, "forget plot") + end # testset + @testset "Marker types" begin + markers = filter((m -> begin + m in Plots.supported_markers() + end), Plots._shape_keys) + markers = reshape(markers, 1, length(markers)) + n = length(markers) + x = (range(0, stop = 10, length = n + 2))[2:(end - 1)] + y = repeat(reshape(reverse(x), 1, :), n, 1) + scatter( + x, + y, + m = (8, :auto), + lab = map(string, markers), + bg = :linen, + xlim = (0, 10), + ylim = (0, 10), + ) + end # testset + @testset "Layout" begin + plot( + Plots.fakedata(100, 10), + layout = 4, + palette = [:grays :blues :hot :rainbow], + bg_inside = [:orange :pink :darkblue :black], + ) + end # testset + @testset "Polar plots" begin + Θ = range(0, stop = 1.5π, length = 100) + r = abs.(0.1 * randn(100) + sin.(3Θ)) + plot(Θ, r, proj = :polar, m = 2) + end # testset + @testset "Drawing shapes" begin + verts = [ + (-1.0, 1.0), + (-1.28, 0.6), + (-0.2, -1.4), + (0.2, -1.4), + (1.28, 0.6), + (1.0, 1.0), + (-1.0, 1.0), + (-0.2, -0.6), + (0.0, -0.2), + (-0.4, 0.6), + (1.28, 0.6), + (0.2, -1.4), + (-0.2, -1.4), + (0.6, 0.2), + (-0.2, 0.2), + (0.0, -0.2), + (0.2, 0.2), + (-0.2, -0.6), + ] + x = 0.1:0.2:0.9 + y = 0.7 * rand(5) .+ 0.15 + plot( + x, + y, + line = (3, :dash, :lightblue), + marker = (Shape(verts), 30, RGBA(0, 0, 0, 0.2)), + bg = :pink, + fg = :darkblue, + xlim = (0, 1), + ylim = (0, 1), + leg = false, + ) + end # testset + @testset "Histogram 2D" begin + histogram2d(randn(10000), randn(10000), nbins = 20) + end # testset + @testset "Heatmap-like" begin + xs = [string("x", i) for i in 1:10] + ys = [string("y", i) for i in 1:4] + z = float((1:4) * reshape(1:10, 1, :)) + pgfx_plot = heatmap(xs, ys, z, aspect_ratio = 1) + Plots._update_plot_object(pgfx_plot) + if @test_nowarn( + haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true + ) + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing + @test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1" + end - pgfx_plot = wireframe(xs, ys, z, aspect_ratio = 1) - # TODO: clims are wrong - end # testset - @testset "Contours" begin - x = 1:0.5:20 - y = 1:0.5:10 - f(x, y) = begin - (3x + y^2) * abs(sin(x) + cos(y)) - end - X = repeat(reshape(x, 1, :), length(y), 1) - Y = repeat(y, 1, length(x)) - Z = map(f, X, Y) - p2 = contour(x, y, Z) - p1 = contour(x, y, f, fill = true) - plot(p1, p2) - # TODO: colorbar for filled contours - end # testset - @testset "Varying colors" begin - t = range(0, stop = 1, length = 100) - θ = (6π) .* t - x = t .* cos.(θ) - y = t .* sin.(θ) - p1 = plot(x, y, line_z = t, linewidth = 3, legend = false) - p2 = scatter( - x, - y, - marker_z = ((x, y) -> begin + pgfx_plot = wireframe(xs, ys, z, aspect_ratio = 1) + # TODO: clims are wrong + end # testset + @testset "Contours" begin + x = 1:0.5:20 + y = 1:0.5:10 + f(x, y) = begin + (3x + y^2) * abs(sin(x) + cos(y)) + end + X = repeat(reshape(x, 1, :), length(y), 1) + Y = repeat(y, 1, length(x)) + Z = map(f, X, Y) + p2 = contour(x, y, Z) + p1 = contour(x, y, f, fill = true) + plot(p1, p2) + # TODO: colorbar for filled contours + end # testset + @testset "Varying colors" begin + t = range(0, stop = 1, length = 100) + θ = (6π) .* t + x = t .* cos.(θ) + y = t .* sin.(θ) + p1 = plot(x, y, line_z = t, linewidth = 3, legend = false) + p2 = scatter(x, y, marker_z = ((x, y) -> begin x + y - end), - color = :bwr, - legend = false, - ) - plot(p1, p2) - end # testset - @testset "Framestyles" begin - scatter( - fill(randn(10), 6), - fill(randn(10), 6), - framestyle = [:box :semi :origin :zerolines :grid :none], - title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], - color = permutedims(1:6), - layout = 6, - label = "", - markerstrokewidth = 0, - ticks = -2:2, - ) - # TODO: support :semi - end # testset - @testset "Quiver" begin - x = (-2pi):0.2:(2*pi) - y = sin.(x) + end), color = :bwr, legend = false) + plot(p1, p2) + end # testset + @testset "Framestyles" begin + scatter( + fill(randn(10), 6), + fill(randn(10), 6), + framestyle = [:box :semi :origin :zerolines :grid :none], + title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"], + color = permutedims(1:6), + layout = 6, + label = "", + markerstrokewidth = 0, + ticks = -2:2, + ) + # TODO: support :semi + end # testset + @testset "Quiver" begin + x = (-2pi):0.2:(2 * pi) + y = sin.(x) - u = ones(length(x)) - v = cos.(x) - arrow_plot = plot(x, y, quiver = (u, v), arrow = true) - # TODO: could adjust limits to fit arrows if too long, but how? - # TODO: get latex available on CI - # mktempdir() do path - # @test_nowarn savefig(arrow_plot, path*"arrow.pdf") - # end - end # testset - @testset "Annotations" begin - y = rand(10) - pgfx_plot = plot( - y, - annotations = (3, y[3], Plots.text("this is \\#3", :left)), - leg = false, - ) - Plots._update_plot_object(pgfx_plot) - axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents - nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) - @test length(nodes) == 1 - mktempdir() do path - file_path = joinpath(path, "annotations.tex") - @test_nowarn savefig(pgfx_plot, file_path) - open(file_path) do io - lines = readlines(io) - @test count(s -> occursin("node", s), lines) == 1 - end - end - annotate!([ - (5, y[5], Plots.text("this is \\#5", 16, :red, :center)), - (10, y[10], Plots.text("this is \\#10", :right, 20, "courier")), - ]) - Plots._update_plot_object(pgfx_plot) - axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents - nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) - @test length(nodes) == 3 - mktempdir() do path - file_path = joinpath(path, "annotations.tex") - @test_nowarn savefig(pgfx_plot, file_path) - open(file_path) do io - lines = readlines(io) - @test count(s -> occursin("node", s), lines) == 3 - end - end - annotation_plot = scatter!( - range(2, stop = 8, length = 6), - rand(6), - marker = (50, 0.2, :orange), - series_annotations = [ - "series", - "annotations", - "map", - "to", - "series", - Plots.text("data", :green), - ], - ) - Plots._update_plot_object(annotation_plot) - axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents - nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) - @test length(nodes) == 9 - mktempdir() do path - file_path = joinpath(path, "annotations.tex") - @test_nowarn savefig(annotation_plot, file_path) - open(file_path) do io - lines = readlines(io) - @test count(s -> occursin("node", s), lines) == 9 - end - # test .tikz extension - file_path = joinpath(path, "annotations.tikz") - @test_nowarn savefig(annotation_plot, file_path) - @test_nowarn open(file_path) do io - end - end - end # testset - @testset "Ribbon" begin - aa = rand(10) - bb = rand(10) - cc = rand(10) - conf = [aa - cc bb - cc] - ribbon_plot = - plot(collect(1:10), fill(1, 10), ribbon = (conf[:, 1], conf[:, 2])) - Plots._update_plot_object(ribbon_plot) - axis = Plots.pgfx_axes(ribbon_plot.o)[1] - plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents) - @test length(plots) == 3 - @test haskey(plots[1].options.dict, "fill") - @test haskey(plots[2].options.dict, "fill") - @test !haskey(plots[3].options.dict, "fill") - @test ribbon_plot.o !== nothing - @test ribbon_plot.o.the_plot !== nothing - end # testset - @testset "Markers and Paths" begin - pl = plot( - 5 .- ones(9), - markershape = [:utriangle, :rect], - markersize = 8, - color = [:red, :black], - ) - Plots._update_plot_object(pl) - axis = Plots.pgfx_axes(pl.o)[1] - plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents) - @test length(plots) == 9 - end # testset - @testset "Groups and Subplots" begin - group = rand(map((i->begin - "group $(i)" - end), 1:4), 100) - pl = plot(rand(100), layout = @layout([a b; c]), group = group, linetype = [:bar :scatter :steppre], linecolor = :match) - Plots._update_plot_object(pl) - axis = Plots.pgfx_axes(pl.o)[1] - legend_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis.contents) - @test length(legend_entries) == 2 - end + u = ones(length(x)) + v = cos.(x) + arrow_plot = plot(x, y, quiver = (u, v), arrow = true) + # TODO: could adjust limits to fit arrows if too long, but how? + # TODO: get latex available on CI + # mktempdir() do path + # @test_nowarn savefig(arrow_plot, path*"arrow.pdf") + # end + end # testset + @testset "Annotations" begin + y = rand(10) + pgfx_plot = + plot(y, annotations = (3, y[3], Plots.text("this is \\#3", :left)), leg = false) + Plots._update_plot_object(pgfx_plot) + axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents + nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) + @test length(nodes) == 1 + mktempdir() do path + file_path = joinpath(path, "annotations.tex") + @test_nowarn savefig(pgfx_plot, file_path) + open(file_path) do io + lines = readlines(io) + @test count(s -> occursin("node", s), lines) == 1 + end + end + annotate!([ + (5, y[5], Plots.text("this is \\#5", 16, :red, :center)), + (10, y[10], Plots.text("this is \\#10", :right, 20, "courier")), + ]) + Plots._update_plot_object(pgfx_plot) + axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents + nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) + @test length(nodes) == 3 + mktempdir() do path + file_path = joinpath(path, "annotations.tex") + @test_nowarn savefig(pgfx_plot, file_path) + open(file_path) do io + lines = readlines(io) + @test count(s -> occursin("node", s), lines) == 3 + end + end + annotation_plot = scatter!( + range(2, stop = 8, length = 6), + rand(6), + marker = (50, 0.2, :orange), + series_annotations = [ + "series", + "annotations", + "map", + "to", + "series", + Plots.text("data", :green), + ], + ) + Plots._update_plot_object(annotation_plot) + axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents + nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) + @test length(nodes) == 9 + mktempdir() do path + file_path = joinpath(path, "annotations.tex") + @test_nowarn savefig(annotation_plot, file_path) + open(file_path) do io + lines = readlines(io) + @test count(s -> occursin("node", s), lines) == 9 + end + # test .tikz extension + file_path = joinpath(path, "annotations.tikz") + @test_nowarn savefig(annotation_plot, file_path) + @test_nowarn open(file_path) do io + end + end + end # testset + @testset "Ribbon" begin + aa = rand(10) + bb = rand(10) + cc = rand(10) + conf = [aa - cc bb - cc] + ribbon_plot = plot(collect(1:10), fill(1, 10), ribbon = (conf[:, 1], conf[:, 2])) + Plots._update_plot_object(ribbon_plot) + axis = Plots.pgfx_axes(ribbon_plot.o)[1] + plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents) + @test length(plots) == 3 + @test haskey(plots[1].options.dict, "fill") + @test haskey(plots[2].options.dict, "fill") + @test !haskey(plots[3].options.dict, "fill") + @test ribbon_plot.o !== nothing + @test ribbon_plot.o.the_plot !== nothing + end # testset + @testset "Markers and Paths" begin + pl = plot( + 5 .- ones(9), + markershape = [:utriangle, :rect], + markersize = 8, + color = [:red, :black], + ) + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents) + @test length(plots) == 9 + end # testset + @testset "Groups and Subplots" begin + group = rand(map((i -> begin + "group $(i)" + end), 1:4), 100) + pl = plot( + rand(100), + layout = @layout([a b; c]), + group = group, + linetype = [:bar :scatter :steppre], + linecolor = :match, + ) + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + legend_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis.contents) + @test length(legend_entries) == 2 + end end # testset @testset "Extra kwargs" begin - pl = plot(1:5, test = "me") - @test pl[1][1].plotattributes[:extra_kwargs][:test] == "me" - pl = plot(1:5, test = "me", extra_kwargs = :subplot) - @test pl[1].attr[:extra_kwargs][:test] == "me" - pl = plot(1:5, test = "me", extra_kwargs = :plot) - @test pl.attr[:extra_plot_kwargs][:test] == "me" - pl = plot( - 1:5, - extra_kwargs = Dict( - :plot => Dict(:test => "me"), - :series => Dict(:and => "me too"), - ), - ) - @test pl.attr[:extra_plot_kwargs][:test] == "me" - @test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too" - pl = plot( - plot(1:5, title = "Line"), - scatter( - 1:5, - title = "Scatter", - extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")), - ), - ) - Plots._update_plot_object(pl) - axes = Plots.pgfx_axes(pl.o) - @test !haskey(axes[1].options.dict, "axis line shift") - @test haskey(axes[2].options.dict, "axis line shift") - pl = plot( - x -> x, - -1:1; - add = raw"\node at (0,0.5) {\huge hi};", - extra_kwargs = :subplot, - ) - @test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};") - Plots._update_plot_object(pl) - axes = Plots.pgfx_axes(pl.o) - @test filter(x -> x isa String, axes[1].contents)[1] == - raw"\node at (0,0.5) {\huge hi};" - plot!(pl) - @test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};") - Plots._update_plot_object(pl) - axes = Plots.pgfx_axes(pl.o) - @test filter(x -> x isa String, axes[1].contents)[1] == - raw"\node at (0,0.5) {\huge hi};" + pl = plot(1:5, test = "me") + @test pl[1][1].plotattributes[:extra_kwargs][:test] == "me" + pl = plot(1:5, test = "me", extra_kwargs = :subplot) + @test pl[1].attr[:extra_kwargs][:test] == "me" + pl = plot(1:5, test = "me", extra_kwargs = :plot) + @test pl.attr[:extra_plot_kwargs][:test] == "me" + pl = plot( + 1:5, + extra_kwargs = Dict( + :plot => Dict(:test => "me"), + :series => Dict(:and => "me too"), + ), + ) + @test pl.attr[:extra_plot_kwargs][:test] == "me" + @test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too" + pl = plot( + plot(1:5, title = "Line"), + scatter( + 1:5, + title = "Scatter", + extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")), + ), + ) + Plots._update_plot_object(pl) + axes = Plots.pgfx_axes(pl.o) + @test !haskey(axes[1].options.dict, "axis line shift") + @test haskey(axes[2].options.dict, "axis line shift") + pl = + plot(x -> x, -1:1; add = raw"\node at (0,0.5) {\huge hi};", extra_kwargs = :subplot) + @test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};") + Plots._update_plot_object(pl) + axes = Plots.pgfx_axes(pl.o) + @test filter(x -> x isa String, axes[1].contents)[1] == + raw"\node at (0,0.5) {\huge hi};" + plot!(pl) + @test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};") + Plots._update_plot_object(pl) + axes = Plots.pgfx_axes(pl.o) + @test filter(x -> x isa String, axes[1].contents)[1] == + raw"\node at (0,0.5) {\huge hi};" end # testset @testset "Titlefonts" begin - pl = plot(1:5, title = "Test me", titlefont = (2, :left)) - @test pl[1][:title] == "Test me" - @test pl[1][:titlefontsize] == 2 - @test pl[1][:titlefonthalign] == :left - Plots._update_plot_object(pl) - ax_opt = Plots.pgfx_axes(pl.o)[1].options - @test ax_opt["title"] == "Test me" - @test(haskey(ax_opt.dict, "title style")) isa Test.Pass - pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left)) - @test pl[:plot_title] == "Test me" - @test pl[:plot_titlefontsize] == 2 - @test pl[:plot_titlefonthalign] == :left - pl = heatmap( - rand(3, 3), - colorbar_title = "Test me", - colorbar_titlefont = (12, :right), - ) - @test pl[1][:colorbar_title] == "Test me" - @test pl[1][:colorbar_titlefontsize] == 12 - @test pl[1][:colorbar_titlefonthalign] == :right + pl = plot(1:5, title = "Test me", titlefont = (2, :left)) + @test pl[1][:title] == "Test me" + @test pl[1][:titlefontsize] == 2 + @test pl[1][:titlefonthalign] == :left + Plots._update_plot_object(pl) + ax_opt = Plots.pgfx_axes(pl.o)[1].options + @test ax_opt["title"] == "Test me" + @test(haskey(ax_opt.dict, "title style")) isa Test.Pass + pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left)) + @test pl[:plot_title] == "Test me" + @test pl[:plot_titlefontsize] == 2 + @test pl[:plot_titlefonthalign] == :left + pl = heatmap(rand(3, 3), colorbar_title = "Test me", colorbar_titlefont = (12, :right)) + @test pl[1][:colorbar_title] == "Test me" + @test pl[1][:colorbar_titlefontsize] == 12 + @test pl[1][:colorbar_titlefonthalign] == :right end # testset diff --git a/test/test_pipeline.jl b/test/test_pipeline.jl index cf6c38e2..ac6876f8 100644 --- a/test/test_pipeline.jl +++ b/test/test_pipeline.jl @@ -11,8 +11,8 @@ using RecipesPipeline end @testset "get_axis_limits" begin - x = [.1, 5] - p1 = plot(x, [5, .1], yscale=:log10) + x = [0.1, 5] + p1 = plot(x, [5, 0.1], yscale = :log10) p2 = plot!(identity) @test all(RecipesPipeline.get_axis_limits(p1, :x) .== x) @test all(RecipesPipeline.get_axis_limits(p2, :x) .== x) diff --git a/test/test_recipes.jl b/test/test_recipes.jl index a228d2a6..418e4465 100644 --- a/test/test_recipes.jl +++ b/test/test_recipes.jl @@ -3,27 +3,27 @@ using OffsetArrays @testset "lens!" begin pl = plot(1:5) - lens!(pl, [1,2], [1,2], inset = (1, bbox(0.0,0.0,0.2,0.2)), colorbar = false) + lens!(pl, [1, 2], [1, 2], inset = (1, bbox(0.0, 0.0, 0.2, 0.2)), colorbar = false) @test length(pl.series_list) == 4 @test pl[2][:colorbar] == :none end # testset @testset "vline, vspan" begin vl = vline([1], widen = false) - @test Plots.xlims(vl) == (1,2) - @test Plots.ylims(vl) == (1,2) - vl = vline([1], xlims=(0,2), widen = false) - @test Plots.xlims(vl) == (0,2) - vl = vline([1], ylims=(-3,5), widen = false) - @test Plots.ylims(vl) == (-3,5) + @test Plots.xlims(vl) == (1, 2) + @test Plots.ylims(vl) == (1, 2) + vl = vline([1], xlims = (0, 2), widen = false) + @test Plots.xlims(vl) == (0, 2) + vl = vline([1], ylims = (-3, 5), widen = false) + @test Plots.ylims(vl) == (-3, 5) - vsp = vspan([1,3], widen = false) - @test Plots.xlims(vsp) == (1,3) - @test Plots.ylims(vsp) == (0,1) # TODO: might be problematic on log-scales - vsp = vspan([1,3], xlims=(-2,5), widen = false) - @test Plots.xlims(vsp) == (-2,5) - vsp = vspan([1,3], ylims=(-2,5), widen = false) - @test Plots.ylims(vsp) == (-2,5) + vsp = vspan([1, 3], widen = false) + @test Plots.xlims(vsp) == (1, 3) + @test Plots.ylims(vsp) == (0, 1) # TODO: might be problematic on log-scales + vsp = vspan([1, 3], xlims = (-2, 5), widen = false) + @test Plots.xlims(vsp) == (-2, 5) + vsp = vspan([1, 3], ylims = (-2, 5), widen = false) + @test Plots.ylims(vsp) == (-2, 5) end # testset @testset "offset axes" begin @@ -46,4 +46,4 @@ end prevha = ha end end -end \ No newline at end of file +end diff --git a/test/test_shorthands.jl b/test/test_shorthands.jl index 891c0c14..116548ca 100644 --- a/test/test_shorthands.jl +++ b/test/test_shorthands.jl @@ -4,45 +4,45 @@ using Plots, Test @testset "Set Lims" begin p = plot(rand(10)) - xlims!((1,20)) - @test xlims(p) == (1,20) + xlims!((1, 20)) + @test xlims(p) == (1, 20) - ylims!((-1,1)) - @test ylims(p) == (-1,1) + ylims!((-1, 1)) + @test ylims(p) == (-1, 1) - zlims!((-1,1)) - @test zlims(p) == (-1,1) + zlims!((-1, 1)) + @test zlims(p) == (-1, 1) - xlims!(-1,11) - @test xlims(p) == (-1,11) + xlims!(-1, 11) + @test xlims(p) == (-1, 11) - ylims!((-10,10)) - @test ylims(p) == (-10,10) + ylims!((-10, 10)) + @test ylims(p) == (-10, 10) - zlims!((-10,10)) - @test zlims(p) == (-10,10) + zlims!((-10, 10)) + @test zlims(p) == (-10, 10) end @testset "Set Ticks" begin - p = plot([0,2,3,4,5,6,7,8,9,10]) + p = plot([0, 2, 3, 4, 5, 6, 7, 8, 9, 10]) xticks = 2:6 xticks!(xticks) - @test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == xticks + @test Plots.get_subplot(current(), 1).attr[:xaxis][:ticks] == xticks yticks = 0.2:0.1:0.7 yticks!(yticks) - @test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == yticks + @test Plots.get_subplot(current(), 1).attr[:yaxis][:ticks] == yticks - xticks = [5,6,7.5] - xlabels = ["a","b","c"] + xticks = [5, 6, 7.5] + xlabels = ["a", "b", "c"] xticks!(xticks, xlabels) - @test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == (xticks, xlabels) + @test Plots.get_subplot(current(), 1).attr[:xaxis][:ticks] == (xticks, xlabels) - yticks = [.5,.6,.75] - ylabels = ["z","y","x"] + yticks = [0.5, 0.6, 0.75] + ylabels = ["z", "y", "x"] yticks!(yticks, ylabels) - @test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == (yticks, ylabels) + @test Plots.get_subplot(current(), 1).attr[:yaxis][:ticks] == (yticks, ylabels) end end