diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 00000000..68dbe39c --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,24 @@ +name: CompatHelper + +on: + schedule: + - cron: '00 * * * *' + +jobs: + CompatHelper: + runs-on: ${{ matrix.os }} + strategy: + matrix: + julia-version: [1.2.0] + julia-arch: [x86] + os: [ubuntu-latest] + steps: + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.julia-version }} + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.travis.yml b/.travis.yml index fc303b0f..1bd6d03c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,21 @@ os: - linux # - osx julia: - - 1.1 + - 1 + - 1.2 - nightly - + matrix: allow_failures: - - julia: nightly + - julia: nightly + +addons: + apt: + packages: + - at-spi2-core + - libgtk-3-dev + - xauth + - xvfb sudo: required before_install: @@ -18,3 +27,8 @@ before_install: notifications: email: true + +script: + - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi + - if [[ `uname` = "Linux" ]]; then TESTCMD="xvfb-run julia"; else TESTCMD="julia"; fi + - $TESTCMD -e 'using Pkg; Pkg.build(); Pkg.test(coverage=true)' diff --git a/NEWS.md b/NEWS.md index 08a760c3..33ae2e4c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,14 +3,38 @@ #### notes on release changes, ongoing development, and future planned work -- Minor version 0.17 is the last one to support Julia 0.6!! -- Minor version 0.11 is the last one to support Julia 0.5!! - - Critical bugfixes only - - `backports` branch is for Julia 0.5 - ---- ## (current master) +## 0.28.3 +- support generalized array interface +- save to pdf, svg and eps in plotlyjs +- fix for clims in line_z +- optimize heatmap logic in gr + +## 0.26.3 +- fix `vline` with dates +- fix PyPlot logscale bug +- avoid annotation clipping for PyPlot +- allow plotting of Any vectors and 3D plotting again in convertToAnyVector +- specify legend title font in GR and PyPlot +- delete `pushtomaster.sh` +- use `=== nothing` + +## 0.26.2 +- improve empty animation build error +- fix GR axis flip for heatmaps and images +- fix ribbons specified as tuples +- add Char recipe +- fix Plotly plots with single-element series +- rewrite PlotlyJS backend + +## 0.26.1 +- handle `Char`s as input data +- fix html saving for Plotly +- expand ~ in paths on UNIX systems +- convertToAnyVector clean-up +- fix color_palette grouping issue + ## 0.26.0 - use FFMPEG.jl - add missing method for convertToAnyVector diff --git a/Project.toml b/Project.toml index d61e259e..bc1fc4e5 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Plots" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" author = ["Tom Breloff (@tbreloff)"] -version = "0.26.0" +version = "0.28.4" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -31,27 +31,39 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] -FixedPointNumbers = "≥ 0.3.0" -GR = "≥ 0.31.0" -PlotThemes = "≥ 0.1.3" -PlotUtils = "≥ 0.4.1" -RecipesBase = "≥ 0.6.0" -StatsBase = "≥ 0.14.0" -julia = "≥ 1.0.0" +Contour = "0.5" +FFMPEG = "0.2" +FixedPointNumbers = "0.6, 0.7" +GR = "0.44" +GeometryTypes = "0.7" +JSON = "0.21" +Measures = "0.3" +NaNMath = "0.3" +PGFPlotsX = "1.2.0" +PlotThemes = "1" +PlotUtils = "0.6.1" +RecipesBase = "0.6, 0.7" +Reexport = "0.2" +Requires = "0.5, 1.0" +Showoff = "0.3.1" +StatsBase = "0.32" +julia = "1" [extras] FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb" +Gtk = "4c0ca9eb-093a-5379-98c5-f87ac0bbbf44" ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" +PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" -BinaryProvider = "b99e7846-7c00-51b0-8f62-c81ae34c0232" [targets] -test = ["BinaryProvider", "Pkg", "Test", "Random", "StatsPlots", "VisualRegressionTests", "LaTeXStrings", "Images", "ImageMagick", "RDatasets", "FileIO", "UnicodePlots"] +test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LaTeXStrings", "LibGit2", "PGFPlotsX", "Random", "RDatasets", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] diff --git a/appveyor.yml b/appveyor.yml index 3490f07b..b0bbcfc0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,6 +2,7 @@ environment: matrix: # - julia_version: 0.7 - julia_version: 1 + - julia_version: 1.2 - julia_version: nightly platform: diff --git a/deps/generateprecompiles.jl b/deps/generateprecompiles.jl new file mode 100644 index 00000000..5bf3d6be --- /dev/null +++ b/deps/generateprecompiles.jl @@ -0,0 +1,51 @@ +# To figure out what should be precompiled, run this script, then move +# precompile_Plots.jl in precompiles_path (see below) to src/precompile.jl + +# This script works by using SnoopCompile to log compilations that take place +# while running the examples on the GR backend. So SnoopCompile must be +# installed, and StatsPlots, RDatasets, and FileIO are also required for +# certain examples. + +# If precompilation fails with an UndefVarError for a module, probably what is +# happening is that the module appears in the precompile statements, but is +# only visible to one of Plots' dependencies, and not Plots itself. Adding the +# module to the blacklist below will remove these precompile statements. + +# Anonymous functions may appear in precompile statements as functions with +# hashes in their name. Those of the form "#something##kw" have to do with +# compiling functions with keyword arguments, and are named reproducibly, so +# can be kept. Others generally will not work. Currently, SnoopCompile includes +# some anonymous functions that not reproducible, but SnoopCompile PR #30 +# (which looks about to be merged) will ensure that anonymous functions are +# actually defined before attempting to precompile them. Alternatively, we can +# keep only the keyword argument related anonymous functions by changing the +# regex that SnoopCompile uses to detect anonymous functions to +# r"#{1,2}[^\"#]+#{1,2}\d+" (see anonrex in SnoopCompile.jl). To exclude all +# precompile statements involving anonymous functions, "#" can also be added to +# the blacklist below. + +using SnoopCompile + +log_path = joinpath(tempdir(), "compiles.log") +precompiles_path = joinpath(tempdir(), "precompile") + +# run examples with GR backend, logging what needs to be compiled +SnoopCompile.@snoopc log_path begin + using Plots + Plots.test_examples(:gr, disp=true) +end + +# precompile calls containing the following strings are dropped +blacklist = [ + # functions defined in examples + "PlotExampleModule", + # the following are not visible to Plots, only its dependencies + "CategoricalArrays", + "FixedPointNumbers", + "SparseArrays", + r"#{1,2}[^\"#]+#{1,2}\d+", +] + +data = SnoopCompile.read(log_path) +pc = SnoopCompile.parcel(reverse!(data[2]), blacklist=blacklist) +SnoopCompile.write(precompiles_path, pc) diff --git a/pushtomaster.sh b/pushtomaster.sh deleted file mode 100755 index 01d219c0..00000000 --- a/pushtomaster.sh +++ /dev/null @@ -1,4 +0,0 @@ -git checkout master -git merge --ff-only dev -git push origin master -git checkout dev diff --git a/src/Plots.jl b/src/Plots.jl index 4fd536b5..6b64f9c0 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -1,6 +1,6 @@ module Plots -_current_plots_version = v"0.25.0" +const _current_plots_version = VersionNumber(split(first(filter(line -> occursin("version", line), readlines(normpath(@__DIR__, "..", "Project.toml")))), "\"")[2]) using Reexport @@ -222,4 +222,7 @@ end const CURRENT_BACKEND = CurrentBackend(:none) +include("precompile.jl") +_precompile_() + end # module diff --git a/src/animation.jl b/src/animation.jl index b6d45f36..7e5f9a8e 100644 --- a/src/animation.jl +++ b/src/animation.jl @@ -60,31 +60,39 @@ end file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end] -gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...) -mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn, false; kw...) -mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false; kw...) +gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim, fn; kw...) +mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim, fn, false; kw...) +mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim, fn, false; kw...) +ffmpeg_framerate(fps) = "$fps" +ffmpeg_framerate(fps::Rational) = "$(fps.num)/$(fps.den)" -function buildanimation(animdir::AbstractString, fn::AbstractString, +function buildanimation(anim::Animation, fn::AbstractString, is_animated_gif::Bool=true; - fps::Integer = 20, loop::Integer = 0, + fps::Real = 20, loop::Integer = 0, variable_palette::Bool=false, show_msg::Bool=true) - fn = abspath(fn) + if length(anim.frames) == 0 + throw(ArgumentError("Cannot build empty animations")) + end + + fn = abspath(expanduser(fn)) + animdir = anim.dir + framerate = ffmpeg_framerate(fps) 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 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`) + ffmpeg_exe(`-v 0 -framerate $framerate -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`) else # generate a colorpalette first so ffmpeg does not have to guess it ffmpeg_exe(`-v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`) # then apply the palette to get better results - ffmpeg_exe(` -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`) + ffmpeg_exe(` -v 0 -framerate $framerate -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`) end else - ffmpeg_exe(`-v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`) + ffmpeg_exe(`-v 0 -framerate $framerate -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`) end show_msg && @info("Saved animation to ", fn) @@ -96,13 +104,18 @@ end # write out html to view the gif function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif) ext = file_extension(agif.filename) - write(io, if ext == "gif" - "" + if ext == "gif" + html = "" elseif ext in ("mov", "mp4") - "" + mimetype = ext == "mov" ? "video/quicktime" : "video/mp4" + html = "" else error("Cannot show animation with extension $ext: $agif") - end) + end + + write(io, html) return nothing end diff --git a/src/arg_desc.jl b/src/arg_desc.jl index 120d1c36..7b7e5283 100644 --- a/src/arg_desc.jl +++ b/src/arg_desc.jl @@ -42,6 +42,7 @@ const _arg_desc = KW( :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`.", @@ -50,7 +51,7 @@ const _arg_desc = KW( :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) (Note: Not currently implemented)", :background_color => "Color Type. Base color for all backgrounds.", @@ -95,9 +96,16 @@ const _arg_desc = KW( :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", +: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` or NTuple{2,Number}. Fixes the limits of the colorbar.", :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 or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.", :projection => "Symbol or String. '3d' or 'polar'", :aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units.", diff --git a/src/args.jl b/src/args.jl index 6f719bae..75577482 100644 --- a/src/args.jl +++ b/src/args.jl @@ -272,6 +272,7 @@ const _series_defaults = KW( :arrow => nothing, # allows for adding arrows to line/path... call `arrow(args...)` :normalize => false, # do we want a normalized histogram? :weights => nothing, # optional weights for histograms (1D and 2D) + :show_empty_bins => false, # should empty bins in 2D histogram be colored as zero (otherwise they are transparent) :contours => false, # add contours to 3d surface and wireframe plots :contour_labels => false, :match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196 @@ -336,6 +337,12 @@ const _subplot_defaults = KW( :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) :projection => :none, # can also be :polar or :3d :aspect_ratio => :none, # choose from :none or :equal @@ -450,6 +457,7 @@ const _initial_axis_defaults = deepcopy(_axis_defaults) # to be able to reset font sizes to initial values const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize], :legendfontsize => _subplot_defaults[:legendfontsize], + :legendtitlefontsize => _subplot_defaults[:legendtitlefontsize], :tickfontsize => _axis_defaults[:tickfontsize], :guidefontsize => _axis_defaults[:guidefontsize]) @@ -574,6 +582,7 @@ add_aliases(:xerror, :xerr, :xerrorbar) add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar) add_aliases(:quiver, :velocity, :quiver2d, :gradient, :vectorfield) add_aliases(:normalize, :norm, :normed, :normalized) +add_aliases(:show_empty_bins, :showemptybins, :showempty, :show_empty) add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio) add_aliases(:match_dimensions, :transpose, :transpose_z) add_aliases(:subplot, :sp, :subplt, :splt) @@ -685,15 +694,15 @@ function processLineArg(plotattributes::KW, 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.alpha == nothing || (plotattributes[:linealpha] = arg.alpha) - arg.style == nothing || (plotattributes[:linestyle] = arg.style) + arg.width === nothing || (plotattributes[:linewidth] = arg.width) + 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.alpha == nothing || (plotattributes[:fillalpha] = arg.alpha) + 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 @@ -724,15 +733,15 @@ function processMarkerArg(plotattributes::KW, 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.alpha == nothing || (plotattributes[:markerstrokealpha] = arg.alpha) - arg.style == nothing || (plotattributes[:markerstrokestyle] = arg.style) + arg.width === nothing || (plotattributes[:markerstrokewidth] = arg.width) + 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.alpha == nothing || (plotattributes[:markeralpha] = arg.alpha) + 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 elseif allAlphas(arg) @@ -757,9 +766,9 @@ end function processFillArg(plotattributes::KW, 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.alpha == nothing || (plotattributes[:fillalpha] = arg.alpha) + 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 @@ -793,10 +802,10 @@ function processGridArg!(plotattributes::KW, 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.alpha == nothing || (plotattributes[Symbol(letter, :gridalpha)] = arg.alpha) - arg.style == nothing || (plotattributes[Symbol(letter, :gridstyle)] = arg.style) + 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 elseif allAlphas(arg) @@ -822,10 +831,10 @@ function processMinorGridArg!(plotattributes::KW, 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 @@ -930,6 +939,15 @@ function preprocessArgs!(plotattributes::KW) end end + # vline accesses the y argument but actually maps it to the x axis. + # Hence, we have to swap formatters + if get(plotattributes, :seriestype, :path) == :vline + xformatter = get(plotattributes, :xformatter, :auto) + yformatter = get(plotattributes, :yformatter, :auto) + plotattributes[:xformatter] = yformatter + plotattributes[:yformatter] = xformatter + end + # handle grid args common to all axes args = pop!(plotattributes, :grid, ()) for arg in wraptuple(args) @@ -961,7 +979,7 @@ function preprocessArgs!(plotattributes::KW) end end # fonts - for fontname in (:titlefont, :legendfont) + for fontname in (:titlefont, :legendfont, :legendtitlefont) args = pop!(plotattributes, fontname, ()) for arg in wraptuple(args) processFontArg!(plotattributes, fontname, arg) @@ -1080,7 +1098,7 @@ function extractGroupArgs(v::AVec, args...; legendEntry = string) if n > 100 @warn("You created n=$n groups... Is that intended?") end - groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels] + groupIds = Vector{Int}[filter(i -> v[i] == glab, eachindex(v)) for glab in groupLabels] GroupBy(map(legendEntry, groupLabels), groupIds) end @@ -1088,7 +1106,7 @@ legendEntryFromTuple(ns::Tuple) = join(ns, ' ') # this is when given a tuple of vectors of values to group by function extractGroupArgs(vs::Tuple, args...) - isempty(vs) && return GroupBy([""], [1:size(args[1],1)]) + isempty(vs) && return GroupBy([""], [axes(args[1],1)]) v = map(tuple, vs...) extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple) end @@ -1098,7 +1116,7 @@ legendEntryFromTuple(ns::NamedTuple) = join(["$k = $v" for (k, v) in pairs(ns)], ", ") function extractGroupArgs(vs::NamedTuple, args...) - isempty(vs) && return GroupBy([""], [1:size(args[1],1)]) + isempty(vs) && return GroupBy([""], [axes(args[1],1)]) v = map(NamedTuple{keys(vs)}∘tuple, values(vs)...) extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple) end @@ -1121,7 +1139,7 @@ end function _filter_input_data!(plotattributes::KW) idxfilter = pop!(plotattributes, :idxfilter, nothing) - if idxfilter != nothing + if idxfilter !== nothing filter_data!(plotattributes, idxfilter) end end @@ -1207,7 +1225,8 @@ convertLegendValue(v::AbstractArray) = map(convertLegendValue, v) # anything else is returned as-is function slice_arg(v::AMat, idx::Int) c = mod1(idx, size(v,2)) - size(v,1) == 1 ? v[1,c] : v[:,c] + 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 @@ -1237,7 +1256,7 @@ end # v = plotattributes[k] # plotattributes[k] = if v == :match # match_color -# elseif v == nothing +# elseif v === nothing # plot_color(RGBA(0,0,0,0)) # else # v @@ -1246,7 +1265,7 @@ end function color_or_nothing!(plotattributes::KW, k::Symbol) v = plotattributes[k] - plotattributes[k] = if v == nothing || v == false + plotattributes[k] = if v === nothing || v == false RGBA{Float64}(0,0,0,0) elseif v != :match plot_color(v) @@ -1271,8 +1290,10 @@ const _match_map = KW( :bottom_margin => :margin, :titlefontfamily => :fontfamily_subplot, :legendfontfamily => :fontfamily_subplot, + :legendtitlefontfamily => :fontfamily_subplot, :titlefontcolor => :foreground_color_subplot, :legendfontcolor => :foreground_color_subplot, + :legendtitlefontcolor => :foreground_color_subplot, :tickfontcolor => :foreground_color_text, :guidefontcolor => :foreground_color_guide, ) @@ -1563,11 +1584,11 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot) # update alphas for asym in (:linealpha, :markeralpha, :fillalpha) - if plotattributes[asym] == nothing + if plotattributes[asym] === nothing plotattributes[asym] = plotattributes[:seriesalpha] end end - if plotattributes[:markerstrokealpha] == nothing + if plotattributes[:markerstrokealpha] === nothing plotattributes[:markerstrokealpha] = plotattributes[:markeralpha] end @@ -1602,13 +1623,13 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot) end # if marker_z, fill_z or line_z are set, ensure we have a gradient - if plotattributes[:marker_z] != nothing + if plotattributes[:marker_z] !== nothing ensure_gradient!(plotattributes, :markercolor, :markeralpha) end - if plotattributes[:line_z] != nothing + if plotattributes[:line_z] !== nothing ensure_gradient!(plotattributes, :linecolor, :linealpha) end - if plotattributes[:fill_z] != nothing + if plotattributes[:fill_z] !== nothing ensure_gradient!(plotattributes, :fillcolor, :fillalpha) end diff --git a/src/axes.jl b/src/axes.jl index 8ef97f7e..baebcaac 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -67,7 +67,7 @@ function process_axis_arg!(plotattributes::KW, arg, letter = "") elseif T <: AVec plotattributes[Symbol(letter,:ticks)] = arg - elseif arg == nothing + elseif arg === nothing plotattributes[Symbol(letter,:ticks)] = [] elseif T <: Bool || arg in _allShowaxisArgs @@ -166,7 +166,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing) # or DateTime) is chosen based on the time span between amin and amax # rather than on the input format # TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime - if ticks == nothing && scale == :identity + if ticks === nothing && scale == :identity if axis[:formatter] == dateformatter # optimize_datetime_ticks returns ticks and labels(!) based on # integers/floats corresponding to the DateTime type. Thus, the axes @@ -184,7 +184,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing) end # get a list of well-laid-out ticks - if ticks == nothing + if ticks === nothing scaled_ticks = optimize_ticks( sf(amin), sf(amax); @@ -218,6 +218,8 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing) map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :plain)) elseif formatter == :scientific Showoff.showoff(unscaled_ticks, :scientific) + elseif formatter == :latex + 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) @@ -295,7 +297,7 @@ function get_minor_ticks(sp, axis, ticks) #Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits if length(ticks) > 2 ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1]) - elseif axis[:scale] == :none + elseif axis[:scale] in (:none, :identity) ratio = 1 else return nothing @@ -309,7 +311,9 @@ function get_minor_ticks(sp, axis, ticks) minorticks = typeof(ticks[1])[] for (i,hi) in enumerate(ticks[2:end]) lo = ticks[i] - append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n)) + if isfinite(lo) && hi > lo + append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n)) + end end minorticks[amin .<= minorticks .<= amax] end @@ -382,7 +386,7 @@ function expand_extrema!(sp::Subplot, plotattributes::KW) data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf)) end expand_extrema!(axis, data) - elseif data != nothing + elseif data !== nothing # 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) @@ -399,10 +403,10 @@ function expand_extrema!(sp::Subplot, plotattributes::KW) # expand for fillrange fr = plotattributes[:fillrange] - if fr == nothing && plotattributes[:seriestype] == :bar + if fr === nothing && plotattributes[:seriestype] == :bar fr = 0.0 end - if fr != nothing && !all3D(plotattributes) + if fr !== nothing && !all3D(plotattributes) axis = sp.attr[vert ? :yaxis : :xaxis] if typeof(fr) <: Tuple for fri in fr @@ -419,7 +423,7 @@ function expand_extrema!(sp::Subplot, plotattributes::KW) data = plotattributes[dsym] bw = plotattributes[:bar_width] - if bw == nothing + if bw === nothing bw = plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data)))) end axis = sp.attr[Symbol(dsym, :axis)] @@ -573,10 +577,10 @@ end # add the discrete value for each item. return the continuous values and the indices function discrete_value!(axis::Axis, v::AVec) - n = length(v) - cvec = zeros(n) - discrete_indices = zeros(Int, n) - for i=1:n + n = eachindex(v) + cvec = zeros(axes(v)) + discrete_indices = similar(Array{Int}, axes(v)) + for i in n cvec[i], discrete_indices[i] = discrete_value!(axis, v[i]) end cvec, discrete_indices @@ -584,10 +588,10 @@ end # add the discrete value for each item. return the continuous values and the indices function discrete_value!(axis::Axis, v::AMat) - n,m = size(v) - cmat = zeros(n,m) - discrete_indices = zeros(Int, n, m) - for i=1:n, j=1:m + 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]) end cmat, discrete_indices @@ -633,13 +637,13 @@ function axis_drawing_info(sp::Subplot) if sp[:framestyle] != :none # xaxis + y1, y2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) + end if xaxis[:showaxis] if sp[:framestyle] != :grid - y1, y2 = if sp[:framestyle] in (:origin, :zerolines) - 0.0, 0.0 - else - xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) - end push!(xaxis_segs, (xmin, y1), (xmax, y1)) # don't show the 0 tick label for the origin framestyle if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1 @@ -652,55 +656,48 @@ function axis_drawing_info(sp::Subplot) if !(xaxis[:ticks] in (:none, nothing, false)) f = scalefunc(yaxis[:scale]) invf = invscalefunc(yaxis[:scale]) - ticks_in = xaxis[:tick_direction] == :out ? -1 : 1 - t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in) - t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in) - t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in) + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.012 * (f(ymax) - f(ymin))) + (-t, t) + else + ticks_in = xaxis[:tick_direction] == :out ? -1 : 1 + t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end for xtick in xticks[1] if xaxis[:showaxis] - tick_start, tick_stop = if sp[:framestyle] == :origin - (0, t3) - else - xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1) - end push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick end - # sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid end - end - if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid] - f = scalefunc(yaxis[:scale]) - invf = invscalefunc(yaxis[:scale]) - ticks_in = xaxis[:tick_direction] == :out ? -1 : 1 - t1 = invf(f(ymin) + 0.01 * (f(ymax) - f(ymin)) * ticks_in) - t2 = invf(f(ymax) - 0.01 * (f(ymax) - f(ymin)) * ticks_in) - t3 = invf(f(0) + 0.01 * (f(ymax) - f(ymin)) * ticks_in) - for xminortick in xminorticks - if xaxis[:showaxis] - tick_start, tick_stop = if sp[:framestyle] == :origin - (0, t3) - else - xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1) - end - push!(xtick_segs, (xminortick, tick_start), (xminortick, tick_stop)) # bottom tick + if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid] + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.006 * (f(ymax) - f(ymin))) + (-t, t) + else + t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end + for xtick in xminorticks + if xaxis[:showaxis] + push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick + end + xaxis[:minorgrid] && push!(xminorgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid end - # sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick - xaxis[:minorgrid] && push!(xminorgrid_segs, (xminortick, ymin), (xminortick, ymax)) # vertical grid end end # yaxis + x1, x2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax) + end if yaxis[:showaxis] if sp[:framestyle] != :grid - x1, x2 = if sp[:framestyle] in (:origin, :zerolines) - 0.0, 0.0 - else - xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax) - end push!(yaxis_segs, (x1, ymin), (x1, ymax)) # don't show the 0 tick label for the origin framestyle if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1 @@ -713,46 +710,297 @@ function axis_drawing_info(sp::Subplot) if !(yaxis[:ticks] in (:none, nothing, false)) f = scalefunc(xaxis[:scale]) invf = invscalefunc(xaxis[:scale]) - ticks_in = yaxis[:tick_direction] == :out ? -1 : 1 - t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in) - t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in) - t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in) + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.012 * (f(xmax) - f(xmin))) + (-t, t) + else + ticks_in = yaxis[:tick_direction] == :out ? -1 : 1 + t = invf(f(x1) + 0.012 * (f(x2) - f(x1)) * ticks_in) + (x1, t) + end for ytick in yticks[1] if yaxis[:showaxis] - tick_start, tick_stop = if sp[:framestyle] == :origin - (0, t3) - else - xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1) - end push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick end - # sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid end - end - if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid] - f = scalefunc(xaxis[:scale]) - invf = invscalefunc(xaxis[:scale]) - ticks_in = yaxis[:tick_direction] == :out ? -1 : 1 - t1 = invf(f(xmin) + 0.01 * (f(xmax) - f(xmin)) * ticks_in) - t2 = invf(f(xmax) - 0.01 * (f(xmax) - f(xmin)) * ticks_in) - t3 = invf(f(0) + 0.01 * (f(xmax) - f(xmin)) * ticks_in) - for ytick in yminorticks - if yaxis[:showaxis] - tick_start, tick_stop = if sp[:framestyle] == :origin - (0, t3) - else - xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1) - end - push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick + if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid] + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.006 * (f(xmax) - f(xmin))) + (-t, t) + else + t = invf(f(x1) + 0.006 * (f(x2) - f(x1)) * ticks_in) + (x1, t) + end + for ytick in yminorticks + if yaxis[:showaxis] + push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick + end + yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid end - # sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick - yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid end end end xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs end + + +function axis_drawing_info_3d(sp::Subplot) + xaxis, yaxis, zaxis = sp[:xaxis], sp[:yaxis], sp[:zaxis] + xmin, xmax = axis_limits(sp, :x) + ymin, ymax = axis_limits(sp, :y) + zmin, zmax = axis_limits(sp, :z) + xticks = get_ticks(sp, xaxis) + yticks = get_ticks(sp, yaxis) + zticks = get_ticks(sp, zaxis) + xminorticks = get_minor_ticks(sp, xaxis, xticks) + yminorticks = get_minor_ticks(sp, yaxis, yticks) + zminorticks = get_minor_ticks(sp, zaxis, zticks) + xaxis_segs = Segments(3) + yaxis_segs = Segments(3) + zaxis_segs = Segments(3) + xtick_segs = Segments(3) + ytick_segs = Segments(3) + ztick_segs = Segments(3) + xgrid_segs = Segments(3) + ygrid_segs = Segments(3) + zgrid_segs = Segments(3) + xminorgrid_segs = Segments(3) + yminorgrid_segs = Segments(3) + zminorgrid_segs = Segments(3) + xborder_segs = Segments(3) + yborder_segs = Segments(3) + zborder_segs = Segments(3) + + if sp[:framestyle] != :none + + # xaxis + y1, y2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) + end + z1, z2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(xaxis[:mirror], zaxis[:flip]) ? (zmax, zmin) : (zmin, zmax) + end + if xaxis[:showaxis] + if sp[:framestyle] != :grid + push!(xaxis_segs, (xmin, y1, z1), (xmax, y1, z1)) + # don't show the 0 tick label for the origin framestyle + if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1 + showticks = xticks[1] .!= 0 + xticks = (xticks[1][showticks], xticks[2][showticks]) + end + end + sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2, z2), (xmax, y2, z2)) # top spine + end + if !(xaxis[:ticks] in (:none, nothing, false)) + f = scalefunc(yaxis[:scale]) + invf = invscalefunc(yaxis[:scale]) + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.012 * (f(ymax) - f(ymin))) + (-t, t) + else + ticks_in = xaxis[:tick_direction] == :out ? -1 : 1 + t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end + + for xtick in xticks[1] + if xaxis[:showaxis] + push!(xtick_segs, (xtick, tick_start, z1), (xtick, tick_stop, z1)) # bottom tick + end + if xaxis[:grid] + if sp[:framestyle] in (:origin, :zerolines) + push!(xgrid_segs, (xtick, ymin, 0.0), (xtick, ymax, 0.0)) + push!(xgrid_segs, (xtick, 0.0, zmin), (xtick, 0.0, zmax)) + else + push!(xgrid_segs, (xtick, y1, z1), (xtick, y2, z1)) + push!(xgrid_segs, (xtick, y2, z1), (xtick, y2, z2)) + end + end + end + + if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid] + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.006 * (f(ymax) - f(ymin))) + (-t, t) + else + t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end + for xtick in xminorticks + if xaxis[:showaxis] + push!(xtick_segs, (xtick, tick_start, z1), (xtick, tick_stop, z1)) # bottom tick + end + if xaxis[:minorgrid] + if sp[:framestyle] in (:origin, :zerolines) + push!(xminorgrid_segs, (xtick, ymin, 0.0), (xtick, ymax, 0.0)) + push!(xminorgrid_segs, (xtick, 0.0, zmin), (xtick, 0.0, zmax)) + else + push!(xminorgrid_segs, (xtick, y1, z1), (xtick, y2, z1)) + push!(xminorgrid_segs, (xtick, y2, z1), (xtick, y2, z2)) + end + end + end + end + end + + + # yaxis + x1, x2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(yaxis[:mirror], xaxis[:flip]) ? (xmin, xmax) : (xmax, xmin) + end + z1, z2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(yaxis[:mirror], zaxis[:flip]) ? (zmax, zmin) : (zmin, zmax) + end + if yaxis[:showaxis] + if sp[:framestyle] != :grid + push!(yaxis_segs, (x1, ymin, z1), (x1, ymax, z1)) + # don't show the 0 tick label for the origin framestyle + if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1 + showticks = yticks[1] .!= 0 + yticks = (yticks[1][showticks], yticks[2][showticks]) + end + end + sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin, z2), (x2, ymax, z2)) # right spine + end + if !(yaxis[:ticks] in (:none, nothing, false)) + f = scalefunc(xaxis[:scale]) + invf = invscalefunc(xaxis[:scale]) + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.012 * (f(xmax) - f(xmin))) + (-t, t) + else + ticks_in = yaxis[:tick_direction] == :out ? -1 : 1 + t = invf(f(x1) + 0.012 * (f(x2) - f(x1)) * ticks_in) + (x1, t) + end + + for ytick in yticks[1] + if yaxis[:showaxis] + push!(ytick_segs, (tick_start, ytick, z1), (tick_stop, ytick, z1)) # left tick + end + if yaxis[:grid] + if sp[:framestyle] in (:origin, :zerolines) + push!(ygrid_segs, (xmin, ytick, 0.0), (xmax, ytick, 0.0)) + push!(ygrid_segs, (0.0, ytick, zmin), (0.0, ytick, zmax)) + else + push!(ygrid_segs, (x1, ytick, z1), (x2, ytick, z1)) + push!(ygrid_segs, (x2, ytick, z1), (x2, ytick, z2)) + end + end + end + + if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid] + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.006 * (f(xmax) - f(xmin))) + (-t, t) + else + t = invf(f(x1) + 0.006 * (f(x2) - f(x1)) * ticks_in) + (x1, t) + end + for ytick in yminorticks + if yaxis[:showaxis] + push!(ytick_segs, (tick_start, ytick, z1), (tick_stop, ytick, z1)) # left tick + end + if yaxis[:minorgrid] + if sp[:framestyle] in (:origin, :zerolines) + push!(yminorgrid_segs, (xmin, ytick, 0.0), (xmax, ytick, 0.0)) + push!(yminorgrid_segs, (0.0, ytick, zmin), (0.0, ytick, zmax)) + else + push!(yminorgrid_segs, (x1, ytick, z1), (x2, ytick, z1)) + push!(yminorgrid_segs, (x2, ytick, z1), (x2, ytick, z2)) + end + end + end + end + end + + + # zaxis + x1, x2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(zaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax) + end + y1, y2 = if sp[:framestyle] in (:origin, :zerolines) + 0.0, 0.0 + else + xor(zaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) + end + if zaxis[:showaxis] + if sp[:framestyle] != :grid + push!(zaxis_segs, (x1, y1, zmin), (x1, y1, zmax)) + # don't show the 0 tick label for the origin framestyle + if sp[:framestyle] == :origin && !(zticks in (:none, nothing,false)) && length(zticks) > 1 + showticks = zticks[1] .!= 0 + zticks = (zticks[1][showticks], zticks[2][showticks]) + end + end + sp[:framestyle] in (:semi, :box) && push!(zborder_segs, (x2, y2, zmin), (x2, y2, zmax)) + end + if !(zaxis[:ticks] in (:none, nothing, false)) + f = scalefunc(xaxis[:scale]) + invf = invscalefunc(xaxis[:scale]) + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.012 * (f(ymax) - f(ymin))) + (-t, t) + else + ticks_in = zaxis[:tick_direction] == :out ? -1 : 1 + t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end + + for ztick in zticks[1] + if zaxis[:showaxis] + push!(ztick_segs, (x1, tick_start, ztick), (x1, tick_stop, ztick)) # left tick + end + if zaxis[:grid] + if sp[:framestyle] in (:origin, :zerolines) + push!(zgrid_segs, (xmin, 0.0, ztick), (xmax, 0.0, ztick)) + push!(ygrid_segs, (0.0, ymin, ztick), (0.0, ymax, ztick)) + else + push!(ygrid_segs, (x1, y1, ztick), (x1, y2, ztick)) + push!(ygrid_segs, (x1, y2, ztick), (x2, y2, ztick)) + end + end + end + + if !(zaxis[:minorticks] in (:none, nothing, false)) || zaxis[:minorgrid] + tick_start, tick_stop = if sp[:framestyle] == :origin + t = invf(f(0) + 0.006 * (f(ymax) - f(ymin))) + (-t, t) + else + t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in) + (y1, t) + end + for ztick in zminorticks + if zaxis[:showaxis] + push!(ztick_segs, (x1, tick_start, ztick), (x1, tick_stop, ztick)) # left tick + end + if zaxis[:minorgrid] + if sp[:framestyle] in (:origin, :zerolines) + push!(zminorgrid_segs, (xmin, 0.0, ztick), (xmax, 0.0, ztick)) + push!(zminorgrid_segs, (0.0, ymin, ztick), (0.0, ymax, ztick)) + else + push!(zminorgrid_segs, (x1, y1, ztick), (x1, y2, ztick)) + push!(zminorgrid_segs, (x1, y2, ztick), (x2, y2, ztick)) + end + end + end + end + end + end + + xticks, yticks, zticks, xaxis_segs, yaxis_segs, zaxis_segs, xtick_segs, ytick_segs, ztick_segs, xgrid_segs, ygrid_segs, zgrid_segs, xminorgrid_segs, yminorgrid_segs, zminorgrid_segs, xborder_segs, yborder_segs, zborder_segs +end diff --git a/src/backends.jl b/src/backends.jl index a95b2dd2..143a929e 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -37,7 +37,6 @@ macro init_backend(s) _backendType[Symbol($str)] = $T _backendSymbol[$T] = Symbol($str) _backend_packages[Symbol($str)] = Symbol($package_str) - # include("backends/" * $str * ".jl") end) end @@ -77,7 +76,7 @@ text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(l # account for the size/length/rotation of tick labels function tick_padding(sp::Subplot, axis::Axis) ticks = get_ticks(sp, axis) - if ticks == nothing + if ticks === nothing 0mm else vals, labs = ticks @@ -229,7 +228,7 @@ const _base_supported_args = [ :subplot_index, :discrete_values, :projection, - + :show_empty_bins ] function merge_with_base_supported(v::AVec) @@ -252,6 +251,7 @@ end @init_backend PlotlyJS @init_backend GR @init_backend PGFPlots +@init_backend PGFPlotsX @init_backend InspectDR @init_backend HDF5 @@ -296,9 +296,6 @@ end _initialize_backend(pkg::GRBackend) = nothing -_initialize_backend(pkg::PlotlyBackend) = nothing - - # ------------------------------------------------------------------------------ # gr @@ -357,6 +354,16 @@ is_marker_supported(::GRBackend, shape::Shape) = true # ------------------------------------------------------------------------------ # plotly +function _initialize_backend(pkg::PlotlyBackend) + try + @eval Main begin + import ORCA + end + catch + @info "For saving to png with the Plotly backend ORCA has to be installed." + end +end + const _plotly_attr = merge_with_base_supported([ :annotations, :background_color_legend, :background_color_inside, :background_color_outside, @@ -661,3 +668,57 @@ const _inspectdr_marker = Symbol[ ] const _inspectdr_scale = [:identity, :ln, :log2, :log10] +# ------------------------------------------------------------------------------ +# pgfplotsx + +const _pgfplotsx_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, + :label, + :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, + :match_dimensions, + :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, + :fill_z, :line_z, :marker_z, :levels, + :ribbon, :quiver, + :orientation, + :overwrite_figure, + :polar, + :aspect_ratio, + :normalize, :weights, + :inset_subplots, + :bar_width, + :arrow, + :framestyle, + :tick_direction, + :camera, + :contour_labels, +]) +const _pgfplotsx_seriestype = + [:path, :scatter, :straightline, + :path3d, :scatter3d, :surface, :wireframe, + :heatmap, :contour, :contour3d, + :shape, + :steppre, :stepmid, :steppost, :ysticks, :xsticks] +const _pgfplotsx_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] +const _pgfplotsx_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :ltriangle, :rtriangle, :cross, :xcross, :star5, :pentagon, :hline, :vline, Shape] +const _pgfplotsx_scale = [:identity, :ln, :log2, :log10] +is_marker_supported(::PGFPlotsXBackend, shape::Shape) = true diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 0fa3d210..7db386aa 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -69,6 +69,19 @@ 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)) ) +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 ) +end +gr_color(c, ::Type) = gr_color(RGBA(c), RGB) + function gr_getcolorind(c) gr_set_transparency(float(alpha(c))) convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c))) @@ -142,12 +155,54 @@ function gr_polyline(x, y, func = GR.polyline; arrowside = :none, arrowstyle = : end end +function gr_polyline3d(x, y, z, func = GR.polyline3d; arrowside = :none, arrowstyle = :simple) + iend = 0 + n = length(x) + while iend < n-1 + # set istart to the first index that is finite + istart = -1 + for j = iend+1:n + if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j]) + istart = j + break + end + end + + if istart > 0 + # iend is the last finite index + iend = -1 + for j = istart+1:n + if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j]) + iend = j + else + break + end + end + end + + # 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], z[istart:iend]) + if arrowside in (:head,:both) + gr_set_arrowstyle(arrowstyle) + GR.drawarrow(x[iend-1], y[iend-1], z[iend-1], x[iend], y[iend], z[iend]) + end + if arrowside in (:tail,:both) + gr_set_arrowstyle(arrowstyle) + GR.drawarrow(x[istart+1], y[istart+1], z[istart+1], x[istart], y[istart], z[istart]) + end + else + break + end + end +end + gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s)) function gr_inqtext(x, y, s) if length(s) >= 2 && s[1] == '$' && s[end] == '$' GR.inqmathtex(x, y, s[2:end-1]) - elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s) + elseif findfirst(isequal('\\'), s) !== nothing || occursin("10^{", s) GR.inqtextext(x, y, s) else GR.inqtext(x, y, s) @@ -159,7 +214,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s)) function gr_text(x, y, s) if length(s) >= 2 && s[1] == '$' && s[end] == '$' GR.mathtex(x, y, s[2:end-1]) - elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s) + elseif findfirst(isequal('\\'), s) !== nothing || occursin("10^{", s) GR.textext(x, y, s) else GR.text(x, y, s) @@ -184,7 +239,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) if xaxis[:grid] gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid]) gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:gridalpha]) - for i in 1:length(α) + for i in eachindex(α) GR.polyline([sinf[i], 0], [cosf[i], 0]) end end @@ -193,7 +248,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) if yaxis[:grid] gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid]) gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:gridalpha]) - for i in 1:length(rtick_values) + for i in eachindex(rtick_values) r = (rtick_values[i] - rmin) / (rmax - rmin) if r <= 1.0 && r >= 0.0 GR.drawarc(-r, r, -r, r, 0, 359) @@ -210,7 +265,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) #draw angular ticks if xaxis[:showaxis] GR.drawarc(-1, 1, -1, 1, 0, 359) - for i in 1:length(α) + 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")) end @@ -218,7 +273,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot) #draw radial ticks if yaxis[:showaxis] - for i in 1:length(rtick_values) + for i in eachindex(rtick_values) r = (rtick_values[i] - rmin) / (rmax - rmin) if r <= 1.0 && r >= 0.0 x, y = GR.wctondc(0.05, r) @@ -236,18 +291,6 @@ 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_lims(sp::Subplot, axis::Axis, adjust::Bool, expand = nothing) - if expand != nothing - expand_extrema!(axis, expand) - end - lims = axis_limits(sp, axis[:letter]) - if adjust - GR.adjustrange(lims...) - else - lims - end -end - function gr_fill_viewport(vp::AVec{Float64}, c) GR.savestate() @@ -260,19 +303,6 @@ function gr_fill_viewport(vp::AVec{Float64}, c) GR.restorestate() end - -normalize_zvals(args...) = nothing -function normalize_zvals(zv::AVec, clims::NTuple{2, <:Real}) - vmin, vmax = ignorenan_extrema(zv) - isfinite(clims[1]) && (vmin = clims[1]) - isfinite(clims[2]) && (vmax = clims[2]) - if vmin == vmax - zeros(length(zv)) - else - clamp.((zv .- vmin) ./ (vmax .- vmin), 0, 1) - end -end - # --------------------------------------------------------- # draw ONE Shape @@ -305,7 +335,7 @@ function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize shapes = series[:markershape] if shapes != :none - for i=1:length(x) + for i=eachindex(x) msi = _cycle(msize, i) shape = _cycle(shapes, i) cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor @@ -370,6 +400,12 @@ function gr_nans_to_infs!(z) end end +function gr_w3tondc(x, y, z) + xw, yw, zw = GR.wc3towc(x, y, z) + x, y = GR.wctondc(xw, yw) + return x, y +end + # -------------------------------------------------------------------------------------- # viewport plot area @@ -388,16 +424,8 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi viewport[2] = viewport_canvas[2] * (right(bb) / w) viewport[3] = viewport_canvas[4] * (1.0 - bottom(bb) / h) viewport[4] = viewport_canvas[4] * (1.0 - top(bb) / h) - if is3d(sp) - vp = viewport[:] - extent = min(vp[2] - vp[1], vp[4] - vp[3]) - viewport[1] = 0.5 * (vp[1] + vp[2] - extent) - viewport[2] = 0.5 * (vp[1] + vp[2] + extent) - viewport[3] = 0.5 * (vp[3] + vp[4] - extent) - viewport[4] = 0.5 * (vp[3] + vp[4] + extent) - end if hascolorbar(sp) - viewport[2] -= gr_colorbar_ratio + viewport[2] -= gr_colorbar_ratio * (1 + is3d(sp) / 2) end viewport end @@ -481,7 +509,7 @@ function _cbar_unique(values, propname) out = last(values) if any(x != out for x in values) @warn "Multiple series with different $propname share a colorbar. " * - "Colorbar may not refelct all series correctly." + "Colorbar may not reflect all series correctly." end out end @@ -567,13 +595,13 @@ function gr_legend_pos(sp::Subplot, w, h) 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] + 0.11 + ymirror * gr_yaxis_width(sp) + xpos = viewport_plotarea[2] + 0.11 + ymirror * gr_axis_width(sp, sp[:yaxis]) else xpos = viewport_plotarea[2] - 0.05 - w end elseif occursin("left", str) if occursin("outer", str) - xpos = viewport_plotarea[1] - 0.05 - w - !ymirror * gr_yaxis_width(sp) + xpos = viewport_plotarea[1] - 0.05 - w - !ymirror * gr_axis_width(sp, sp[:yaxis]) else xpos = viewport_plotarea[1] + 0.11 end @@ -582,13 +610,13 @@ function gr_legend_pos(sp::Subplot, w, h) end if occursin("top", str) if s == :outertop - ypos = viewport_plotarea[4] + 0.02 + h + xmirror * gr_xaxis_height(sp) + ypos = viewport_plotarea[4] + 0.02 + h + xmirror * gr_axis_height(sp, sp[:xaxis]) else ypos = viewport_plotarea[4] - 0.06 end elseif occursin("bottom", str) if s == :outerbottom - ypos = viewport_plotarea[3] - 0.05 - !xmirror * gr_xaxis_height(sp) + ypos = viewport_plotarea[3] - 0.05 - !xmirror * gr_axis_height(sp, sp[:xaxis]) else ypos = viewport_plotarea[3] + h + 0.06 end @@ -629,11 +657,11 @@ function gr_get_color(series::Series) series[:fillcolor] elseif st in (:contour, :wireframe) series[:linecolor] - elseif series[:marker_z] != nothing + elseif series[:marker_z] !== nothing series[:markercolor] - elseif series[:line_z] != nothing + elseif series[:line_z] !== nothing series[:linecolor] - elseif series[:fill_z] != nothing + elseif series[:fill_z] !== nothing series[:fillcolor] end end @@ -747,26 +775,24 @@ function gr_get_ticks_size(ticks, rot) return w, h end -function gr_xaxis_height(sp) - xaxis = sp[:xaxis] - xticks, yticks = axis_drawing_info(sp)[1:2] - gr_set_font(tickfont(xaxis)) - h = (xticks in (nothing, false, :none) ? 0 : last(gr_get_ticks_size(xticks, xaxis[:rotation]))) - if xaxis[:guide] != "" - gr_set_font(guidefont(xaxis)) - h += last(gr_text_size(xaxis[:guide])) +function gr_axis_height(sp, axis) + ticks = get_ticks(sp, axis) + gr_set_font(tickfont(axis)) + h = (ticks in (nothing, false, :none) ? 0 : last(gr_get_ticks_size(ticks, axis[:rotation]))) + if axis[:guide] != "" + gr_set_font(guidefont(axis)) + h += last(gr_text_size(axis[:guide])) end return h end -function gr_yaxis_width(sp) - yaxis = sp[:yaxis] - xticks, yticks = axis_drawing_info(sp)[1:2] - gr_set_font(tickfont(yaxis)) - w = (xticks in (nothing, false, :none) ? 0 : first(gr_get_ticks_size(yticks, yaxis[:rotation]))) - if yaxis[:guide] != "" - gr_set_font(guidefont(yaxis)) - w += last(gr_text_size(yaxis[:guide])) +function gr_axis_width(sp, axis) + ticks = get_ticks(sp, axis) + gr_set_font(tickfont(axis)) + w = (ticks in (nothing, false, :none) ? 0 : first(gr_get_ticks_size(ticks, axis[:rotation]))) + if axis[:guide] != "" + gr_set_font(guidefont(axis)) + w += last(gr_text_size(axis[:guide])) end return w end @@ -790,48 +816,132 @@ function _update_min_padding!(sp::Subplot{GRBackend}) h = 1mm + gr_plot_size[2] * l * px toppad += h end - # Add margin for x and y ticks - xticks, yticks = axis_drawing_info(sp)[1:2] - if !(xticks in (nothing, false, :none)) - flip, mirror = gr_set_xticks_font(sp) - l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation])) - h = 1mm + gr_plot_size[2] * l * px - if mirror - toppad += h - else - bottompad += h + + if 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) + # Add margin for x and y ticks + h = 0mm + if !(xticks in (nothing, false, :none)) + gr_set_font( + tickfont(xaxis), + halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], + valign = (xaxis[:mirror] ? :bottom : :top), + rotation = xaxis[:rotation] + ) + l = 0.01 + last(gr_get_ticks_size(xticks, xaxis[:rotation])) + h = max(h, 1mm + gr_plot_size[2] * l * px) end - end - if !(yticks in (nothing, false, :none)) - flip, mirror = gr_set_yticks_font(sp) - l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation])) - w = 1mm + gr_plot_size[1] * l * px - if mirror - rightpad += w - else - leftpad += w + if !(yticks in (nothing, false, :none)) + gr_set_font( + tickfont(yaxis), + halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], + valign = (yaxis[:mirror] ? :bottom : :top), + rotation = yaxis[:rotation] + ) + l = 0.01 + last(gr_get_ticks_size(yticks, yaxis[:rotation])) + h = max(h, 1mm + gr_plot_size[2] * l * px) end - end - # Add margin for x label - if sp[:xaxis][:guide] != "" - gr_set_font(guidefont(sp[:xaxis])) - l = last(gr_text_size(sp[:xaxis][:guide])) - h = 1mm + gr_plot_size[2] * l * px - if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true) - toppad += h - else - bottompad += h + if h > 0mm + if xaxis[:mirror] || yaxis[:mirror] + toppad += h + end + if !xaxis[:mirror] || !yaxis[:mirror] + bottompad += h + end end - end - # Add margin for y label - if sp[:yaxis][:guide] != "" - gr_set_font(guidefont(sp[:yaxis])) - l = last(gr_text_size(sp[:yaxis][:guide])) - w = 1mm + gr_plot_size[2] * l * px - if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true) - rightpad += w - else - leftpad += w + + if !(zticks in (nothing, false, :none)) + gr_set_font( + tickfont(zaxis), + halign = (zaxis[:mirror] ? :left : :right), + valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2], + rotation = zaxis[:rotation] + ) + l = 0.01 + first(gr_get_ticks_size(zticks, zaxis[:rotation])) + w = 1mm + gr_plot_size[1] * l * px + if zaxis[:mirror] + rightpad += w + else + leftpad += w + end + end + + # Add margin for x or y label + h = 0mm + if xaxis[:guide] != "" + gr_set_font(guidefont(sp[:xaxis])) + l = last(gr_text_size(sp[:xaxis][:guide])) + h = max(h, 1mm + gr_plot_size[2] * l * px) + end + if yaxis[:guide] != "" + gr_set_font(guidefont(sp[:yaxis])) + l = last(gr_text_size(sp[:yaxis][:guide])) + h = max(h, 1mm + gr_plot_size[2] * l * px) + end + if h > 0mm + if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) + toppad += h + else + bottompad += h + end + end + # Add margin for z label + if zaxis[:guide] != "" + gr_set_font(guidefont(sp[:zaxis])) + l = last(gr_text_size(sp[:zaxis][:guide])) + w = 1mm + gr_plot_size[2] * l * px + if zaxis[:guide_position] == :right || (zaxis[:guide_position] == :auto && zaxis[:mirror] == true) + rightpad += w + else + leftpad += w + end + end + else + # Add margin for x and y ticks + xticks, yticks = get_ticks(sp, sp[:xaxis]), get_ticks(sp, sp[:yaxis]) + if !(xticks in (nothing, false, :none)) + flip, mirror = gr_set_xticks_font(sp) + l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation])) + h = 1mm + gr_plot_size[2] * l * px + if mirror + toppad += h + else + bottompad += h + end + end + if !(yticks in (nothing, false, :none)) + flip, mirror = gr_set_yticks_font(sp) + l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation])) + w = 1mm + gr_plot_size[1] * l * px + if mirror + rightpad += w + else + leftpad += w + end + end + + # Add margin for x label + if sp[:xaxis][:guide] != "" + gr_set_font(guidefont(sp[:xaxis])) + l = last(gr_text_size(sp[:xaxis][:guide])) + h = 1mm + gr_plot_size[2] * l * px + if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true) + toppad += h + else + bottompad += h + end + end + # Add margin for y label + if sp[:yaxis][:guide] != "" + gr_set_font(guidefont(sp[:yaxis])) + l = last(gr_text_size(sp[:yaxis][:guide])) + w = 1mm + gr_plot_size[2] * l * px + if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true) + rightpad += w + else + leftpad += w + end end end if sp[:colorbar_title] != "" @@ -840,6 +950,11 @@ function _update_min_padding!(sp::Subplot{GRBackend}) sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad]) end +function is_equally_spaced(v) + d = collect(v[2:end] .- v[1:end-1]) + all(d .≈ d[1]) +end + function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) _update_min_padding!(sp) @@ -874,26 +989,21 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # has to be done now due to a potential adjustment to the plotarea given an outer legend. legendn = 0 legendw = 0 - legendi = 0 if sp[:legend] != :none GR.savestate() GR.selntran(0) GR.setscale(0) - gr_set_font(legendfont(sp)) - if sp[:legendtitle] != nothing + if sp[:legendtitle] !== nothing + gr_set_font(legendtitlefont(sp)) tbx, tby = gr_inqtext(0, 0, string(sp[:legendtitle])) legendw = tbx[3] - tbx[1] legendn += 1 end + gr_set_font(legendfont(sp)) for series in series_list(sp) should_add_to_legend(series) || continue legendn += 1 - if typeof(series[:label]) <: Array - legendi += 1 - lab = series[:label][legendi] - else - lab = series[:label] - end + lab = series[:label] tbx, tby = gr_inqtext(0, 0, string(lab)) legendw = max(legendw, tbx[3] - tbx[1]) end @@ -908,7 +1018,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) leg_str = string(sp[:legend]) if occursin("outer", leg_str) if occursin("right", leg_str) - viewport_plotarea[2] -= legendw + 0.11 + viewport_plotarea[2] -= legendw + 0.12 elseif occursin("left", leg_str) viewport_plotarea[1] += legendw + 0.11 elseif occursin("top", leg_str) @@ -920,13 +1030,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # fill in the plot area background bg = plot_color(sp[:background_color_inside]) - gr_fill_viewport(viewport_plotarea, bg) + is3d(sp) || gr_fill_viewport(viewport_plotarea, bg) # reduced from before... set some flags based on the series in this subplot # TODO: can these be generic flags? outside_ticks = false - # calculate the colorbar limits once for a subplot - clims = get_clims(sp) cbar = GRColorbar() draw_axes = sp[:framestyle] != :none @@ -940,11 +1048,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) outside_ticks = true for ax in (sp[:xaxis], sp[:yaxis]) v = series[ax[:letter]] - if length(v) > 1 && diff(collect(extrema(diff(v))))[1] > 1e-6*std(v) - @warn("GR: heatmap only supported with equally spaced data.") - end end - x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale]) + x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z])) xy_lims = x[1], x[end], y[1], y[end] expand_extrema!(sp[:xaxis], x) expand_extrema!(sp[:yaxis], y) @@ -1000,39 +1105,228 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) GR.setlinewidth(sp.plt[:thickness_scaling]) if is3d(sp) - # TODO do we really need a different clims computation here from the one - # computed above using get_clims(sp)? - zmin, zmax = gr_lims(sp, zaxis, true) - clims3d = sp[:clims] - if is_2tuple(clims3d) - isfinite(clims3d[1]) && (zmin = clims3d[1]) - isfinite(clims3d[2]) && (zmax = clims3d[2]) - end + zmin, zmax = axis_limits(sp, :z) GR.setspace(zmin, zmax, round.(Int, sp[:camera])...) - xtick = GR.tick(xmin, xmax) / 2 - ytick = GR.tick(ymin, ymax) / 2 - ztick = GR.tick(zmin, zmax) / 2 - ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1]) + xticks, yticks, zticks, xaxis_segs, yaxis_segs, zaxis_segs, xtick_segs, ytick_segs, ztick_segs, xgrid_segs, ygrid_segs, zgrid_segs, xminorgrid_segs, yminorgrid_segs, zminorgrid_segs, xborder_segs, yborder_segs, zborder_segs = axis_drawing_info_3d(sp) + + # fill the plot area + gr_set_fill(sp[:background_color_inside]) + 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 = unzip(GR.wc3towc.(plot_area_x, plot_area_y, plot_area_z)) + GR.fillarea(x_bg, y_bg) + + # draw the grid lines if xaxis[:grid] gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid]) gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:gridalpha]) - GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0) + gr_polyline3d(coords(xgrid_segs)...) end if yaxis[:grid] gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid]) gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:gridalpha]) - GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0) + gr_polyline3d(coords(ygrid_segs)...) end if zaxis[:grid] gr_set_line(zaxis[:gridlinewidth], zaxis[:gridstyle], zaxis[:foreground_color_grid]) gr_set_transparency(zaxis[:foreground_color_grid], zaxis[:gridalpha]) - GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2) + gr_polyline3d(coords(zgrid_segs)...) end - gr_set_line(1, :solid, xaxis[:foreground_color_axis]) - gr_set_transparency(xaxis[:foreground_color_axis]) - GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize) - GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize) + + if xaxis[:minorgrid] + gr_set_line(xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], xaxis[:foreground_color_minor_grid]) + gr_set_transparency(xaxis[:foreground_color_minor_grid], xaxis[:minorgridalpha]) + gr_polyline3d(coords(xminorgrid_segs)...) + end + if yaxis[:minorgrid] + gr_set_line(yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], yaxis[:foreground_color_minor_grid]) + gr_set_transparency(yaxis[:foreground_color_minor_grid], yaxis[:minorgridalpha]) + gr_polyline3d(coords(yminorgrid_segs)...) + end + if zaxis[:minorgrid] + gr_set_line(zaxis[:minorgridlinewidth], zaxis[:minorgridstyle], zaxis[:foreground_color_minor_grid]) + gr_set_transparency(zaxis[:foreground_color_minor_grid], zaxis[:minorgridalpha]) + gr_polyline3d(coords(zminorgrid_segs)...) + end + gr_set_transparency(1.0) + + # axis lines + if xaxis[:showaxis] + gr_set_line(1, :solid, xaxis[:foreground_color_border]) + GR.setclip(0) + gr_polyline3d(coords(xaxis_segs)...) + end + if yaxis[:showaxis] + gr_set_line(1, :solid, yaxis[:foreground_color_border]) + GR.setclip(0) + gr_polyline3d(coords(yaxis_segs)...) + end + if zaxis[:showaxis] + gr_set_line(1, :solid, zaxis[:foreground_color_border]) + GR.setclip(0) + gr_polyline3d(coords(zaxis_segs)...) + end + GR.setclip(1) + + # axis ticks + if xaxis[:showaxis] + if sp[:framestyle] in (:zerolines, :grid) + gr_set_line(1, :solid, xaxis[:foreground_color_grid]) + gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:tick_direction] == :out ? xaxis[:gridalpha] : 0) + else + gr_set_line(1, :solid, xaxis[:foreground_color_axis]) + end + GR.setclip(0) + gr_polyline3d(coords(xtick_segs)...) + end + if yaxis[:showaxis] + if sp[:framestyle] in (:zerolines, :grid) + gr_set_line(1, :solid, yaxis[:foreground_color_grid]) + gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:tick_direction] == :out ? yaxis[:gridalpha] : 0) + else + gr_set_line(1, :solid, yaxis[:foreground_color_axis]) + end + GR.setclip(0) + gr_polyline3d(coords(ytick_segs)...) + end + if zaxis[:showaxis] + if sp[:framestyle] in (:zerolines, :grid) + gr_set_line(1, :solid, zaxis[:foreground_color_grid]) + gr_set_transparency(zaxis[:foreground_color_grid], zaxis[:tick_direction] == :out ? zaxis[:gridalpha] : 0) + else + gr_set_line(1, :solid, zaxis[:foreground_color_axis]) + end + GR.setclip(0) + gr_polyline3d(coords(ztick_segs)...) + end + GR.setclip(1) + + # tick marks + if !(xticks in (:none, nothing, false)) && xaxis[:showaxis] + # x labels + gr_set_font( + tickfont(xaxis), + halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], + valign = (xaxis[:mirror] ? :bottom : :top), + rotation = xaxis[:rotation] + ) + yt = if sp[:framestyle] == :origin + 0 + elseif xor(xaxis[:mirror], yaxis[:flip]) + ymax + else + ymin + end + zt = if sp[:framestyle] == :origin + 0 + elseif xor(xaxis[:mirror], zaxis[:flip]) + zmax + else + zmin + end + for (cv, dv) in zip(xticks...) + xi, yi = gr_w3tondc(cv, yt, zt) + if xaxis[:ticks] in (:auto, :native) + if xaxis[:formatter] in (:scientific, :auto) + # ensure correct dispatch in gr_text for automatic log ticks + if xaxis[:scale] in _logScales + dv = string(dv, "\\ ") + end + dv = convert_sci_unicode(dv) + end + end + xi += (yaxis[:mirror] ? 1 : -1) * 1e-2 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0) + yi += (xaxis[:mirror] ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0) + gr_text(xi, yi, string(dv)) + end + end + + if !(yticks in (:none, nothing, false)) && yaxis[:showaxis] + # y labels + gr_set_font( + tickfont(yaxis), + halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], + valign = (yaxis[:mirror] ? :bottom : :top), + rotation = yaxis[:rotation] + ) + xt = if sp[:framestyle] == :origin + 0 + elseif xor(yaxis[:mirror], xaxis[:flip]) + xmin + else + xmax + end + zt = if sp[:framestyle] == :origin + 0 + elseif xor(yaxis[:mirror], zaxis[:flip]) + zmax + else + zmin + end + for (cv, dv) in zip(yticks...) + xi, yi = gr_w3tondc(xt, cv, zt) + if yaxis[:ticks] in (:auto, :native) + if xaxis[:formatter] in (:scientific, :auto) + # ensure correct dispatch in gr_text for automatic log ticks + if yaxis[:scale] in _logScales + dv = string(dv, "\\ ") + end + dv = convert_sci_unicode(dv) + end + end + gr_text(xi + (yaxis[:mirror] ? -1 : 1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi + (yaxis[:mirror] ? 1 : -1) * 5e-3 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), string(dv)) + end + end + + if !(zticks in (:none, nothing, false)) && zaxis[:showaxis] + # z labels + gr_set_font( + tickfont(zaxis), + halign = (zaxis[:mirror] ? :left : :right), + valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2], + rotation = zaxis[:rotation] + ) + xt = if sp[:framestyle] == :origin + 0 + elseif xor(zaxis[:mirror], xaxis[:flip]) + xmax + else + xmin + end + yt = if sp[:framestyle] == :origin + 0 + elseif xor(zaxis[:mirror], yaxis[:flip]) + ymax + else + ymin + end + for (cv, dv) in zip(zticks...) + xi, yi = gr_w3tondc(xt, yt, cv) + if zaxis[:ticks] in (:auto, :native) + if zaxis[:formatter] in (:scientific, :auto) + # ensure correct dispatch in gr_text for automatic log ticks + if zaxis[:scale] in _logScales + dv = string(dv, "\\ ") + end + dv = convert_sci_unicode(dv) + end + end + gr_text(xi + (zaxis[:mirror] ? 1 : -1) * 1e-2 * (zaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, string(dv)) + end + end + # + # # border + # intensity = sp[:framestyle] == :semi ? 0.5 : 1.0 + # if sp[:framestyle] in (:box, :semi) + # gr_set_line(intensity, :solid, xaxis[:foreground_color_border]) + # gr_set_transparency(xaxis[:foreground_color_border], intensity) + # gr_polyline3d(coords(xborder_segs)...) + # gr_set_line(intensity, :solid, yaxis[:foreground_color_border]) + # gr_set_transparency(yaxis[:foreground_color_border], intensity) + # gr_polyline3d(coords(yborder_segs)...) + # end elseif ispolar(sp) r = gr_set_viewport_polar() @@ -1121,9 +1415,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # @show cv dv ymin xi yi flip mirror (flip $ mirror) if xaxis[:ticks] in (:auto, :native) # ensure correct dispatch in gr_text for automatic log ticks - if xaxis[:scale] in _logScales - dv = string(dv, "\\ ") - elseif xaxis[:formatter] in (:scientific, :auto) + if xaxis[:formatter] in (:scientific, :auto) + if xaxis[:scale] in _logScales + dv = string(dv, "\\ ") + end dv = convert_sci_unicode(dv) end end @@ -1140,9 +1435,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # @show cv dv xmin xi yi if yaxis[:ticks] in (:auto, :native) # ensure correct dispatch in gr_text for automatic log ticks - if yaxis[:scale] in _logScales - dv = string(dv, "\\ ") - elseif yaxis[:formatter] in (:scientific, :auto) + if yaxis[:formatter] in (:scientific, :auto) + if yaxis[:scale] in _logScales + dv = string(dv, "\\ ") + end dv = convert_sci_unicode(dv) end end @@ -1182,12 +1478,54 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) gr_text(xpos, viewport_subplot[4], sp[:title]) end if is3d(sp) - gr_set_font(guidefont(xaxis)) - GR.titles3d(xaxis[:guide], yaxis[:guide], zaxis[:guide]) - else - xticks, yticks = axis_drawing_info(sp)[1:2] if xaxis[:guide] != "" - h = 0.01 + gr_xaxis_height(sp) + gr_set_font( + guidefont(xaxis), + halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], + valign = (xaxis[:mirror] ? :bottom : :top), + rotation = xaxis[:rotation] + ) + yg = xor(xaxis[:mirror], yaxis[:flip]) ? ymax : ymin + zg = xor(xaxis[:mirror], zaxis[:flip]) ? zmax : zmin + xg = (xmin + xmax) / 2 + xndc, yndc = gr_w3tondc(xg, yg, zg) + h = gr_axis_height(sp, xaxis) + gr_text(xndc - h, yndc - h, xaxis[:guide]) + end + + if yaxis[:guide] != "" + gr_set_font( + guidefont(yaxis), + halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], + valign = (yaxis[:mirror] ? :bottom : :top), + rotation = yaxis[:rotation] + ) + xg = xor(yaxis[:mirror], xaxis[:flip]) ? xmin : xmax + yg = (ymin + ymax) / 2 + zg = xor(yaxis[:mirror], zaxis[:flip]) ? zmax : zmin + xndc, yndc = gr_w3tondc(xg, yg, zg) + h = gr_axis_height(sp, yaxis) + gr_text(xndc + h, yndc - h, yaxis[:guide]) + end + + if zaxis[:guide] != "" + gr_set_font( + guidefont(zaxis), + halign = (:left, :hcenter, :right)[sign(zaxis[:rotation]) + 2], + valign = (zaxis[:mirror] ? :bottom : :top), + rotation = zaxis[:rotation] + ) + xg = xor(zaxis[:mirror], xaxis[:flip]) ? xmax : xmin + yg = xor(zaxis[:mirror], yaxis[:flip]) ? ymax : ymin + zg = (zmin + zmax) / 2 + xndc, yndc = gr_w3tondc(xg, yg, zg) + w = gr_axis_width(sp, zaxis) + GR.setcharup(-1, 0) + gr_text(xndc - w, yndc, zaxis[:guide]) + end + else + if xaxis[:guide] != "" + h = 0.01 + gr_axis_height(sp, xaxis) gr_set_font(guidefont(xaxis)) if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true) GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) @@ -1199,7 +1537,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end if yaxis[:guide] != "" - w = 0.02 + gr_yaxis_width(sp) + w = 0.02 + gr_axis_width(sp, yaxis) gr_set_font(guidefont(yaxis)) GR.setcharup(-1, 0) if yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true) @@ -1239,6 +1577,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) x, y, z = series[:x], series[:y], series[:z] frng = series[:fillrange] + clims = get_clims(sp, series) + # add custom frame shapes to markershape? series_annotations_shapes!(series) # ------------------------------------------------------- @@ -1247,7 +1587,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) if typeof(z) <: Surface z = vec(transpose_z(series, z.surf, false)) elseif ispolar(sp) - if frng != nothing + if frng !== nothing _, frng = convert_to_polar(x, frng, (rmin, rmax)) end x, y = convert_to_polar(x, y, (rmin, rmax)) @@ -1258,11 +1598,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end if st in (:path, :scatter, :straightline) - if x != nothing && length(x) > 1 + if x !== nothing && length(x) > 1 lz = series[:line_z] segments = iter_segments(series) # do area fill - if frng != nothing + if frng !== nothing GR.setfillintstyle(GR.INTSTYLE_SOLID) fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng)) for (i, rng) in enumerate(segments) @@ -1301,7 +1641,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) plot_color(series[:linecolor]) in (black,[black]) end h = gr_contour_levels(series, clims) - if series[:fillrange] != nothing + if series[:fillrange] !== nothing if series[:fillcolor] != series[:linecolor] && !is_lc_black @warn("GR: filled contour only supported with black contour lines") end @@ -1335,26 +1675,45 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) elseif st == :heatmap zmin, zmax = clims if !ispolar(sp) - xmin, xmax, ymin, ymax = xy_lims - m, n = length(x), length(y) - xinds = sort(1:m, rev = xaxis[:flip]) - yinds = sort(1:n, rev = yaxis[:flip]) - z = reshape(reshape(z, m, n)[xinds, yinds], m*n) GR.setspace(zmin, zmax, 0, 90) - grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad() - colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z] - rgba = map(c -> UInt32( round(UInt, alpha(c) * 255) << 24 + - round(UInt, blue(c) * 255) << 16 + - round(UInt, green(c) * 255) << 8 + - round(UInt, red(c) * 255) ), colors) - w, h = length(x), length(y) - GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba) + x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z])) + w, h = length(x) - 1, length(y) - 1 + z_normalized = map(x -> GR.jlgr.normalize_color(x, zmin, zmax), z) + if is_uniformly_spaced(x) && is_uniformly_spaced(y) + # For uniformly spaced data use GR.drawimage, which can be + # much faster than GR.nonuniformcellarray, especially for + # pdf output, and also supports alpha values. + # Note that drawimage draws uniformly spaced data correctly + # even on log scales, where it is visually non-uniform. + colors = plot_color.(series[:fillcolor][z_normalized], series[:fillalpha]) + colors[isnan.(z_normalized)] .= RGBA(0,0,0,0) + rgba = gr_color.(colors) + GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba) + else + (something(series[:fillalpha],1) < 1 || any(_gr_gradient_alpha .< 1)) && @warn( + "GR: transparency not supported in non-uniform heatmaps. Alpha values ignored.") + z_normalized = map(x -> isnan(x) ? 256/255 : x, z_normalized) # results in color index = 1256 -> transparent + colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized] + GR.nonuniformcellarray(x, y, w, h, colors) + end else - h, w = length(x), length(y) - z = reshape(z, h, w) - colors = Int32[round(Int32, 1000 + _i * 255) for _i in z'] - GR.setwindow(-1, 1, -1, 1) - GR.polarcellarray(0, 0, 0, 360, 0, 1, w, h, colors) + phimin, phimax = 0.0, 360.0 # nonuniform polar array is not yet supported in GR.jl + nx, ny = length(series[:x]), length(series[:y]) + z_normalized = map(x -> GR.jlgr.normalize_color(x, zmin, zmax), z) + colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized] + xmin, xmax, ymin, ymax = xy_lims + rmax = data_lims[4] + GR.setwindow(-rmax, rmax, -rmax, rmax) + if ymin > 0 + @warn "'ymin[1] > 0' (rmin) is not yet supported." + end + if series[:y][end] != ny + @warn "Right now only the maximum value of y (r) is taken into account." + end + # GR.polarcellarray(0, 0, phimin, phimax, ymin, ymax, nx, ny, colors) + GR.polarcellarray(0, 0, phimin, phimax, 0, ymax, nx, ny, colors) + # Right now only the maximum value of y (r) is taken into account. + # This is certainly not perfect but nonuniform polar array is not yet supported in GR.jl end elseif st in (:path3d, :scatter3d) @@ -1454,19 +1813,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) elseif st == :image z = transpose_z(series, series[:z].surf, true)' w, h = size(z) - xinds = sort(1:w, rev = xaxis[:flip]) - yinds = sort(1:h, rev = yaxis[:flip]) - z = z[xinds, yinds] xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y]) - if eltype(z) <: Colors.AbstractGray - grey = round.(UInt8, clamp.(float(z) * 255, 0, 255)) - rgba = map(c -> UInt32( 0xff000000 + UInt(c)<<16 + UInt(c)<<8 + UInt(c) ), grey) - else - rgba = map(c -> 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)) ), z) - end + rgba = gr_color.(z) GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba) end @@ -1481,7 +1829,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end # draw the colorbar - hascolorbar(sp) && gr_draw_colorbar(cbar, sp, clims) + hascolorbar(sp) && gr_draw_colorbar(cbar, sp, get_clims(sp)) # add the legend if sp[:legend] != :none @@ -1490,7 +1838,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) GR.setscale(0) gr_set_font(legendfont(sp)) w = legendw - i = legendi n = legendn if w > 0 dy = _gr_point_mult[1] * sp[:legendfontsize] * 1.75 @@ -1502,20 +1849,21 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) gr_set_line(1, :solid, sp[:foreground_color_legend]) GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n) i = 0 - if sp[:legendtitle] != nothing + if sp[:legendtitle] !== nothing GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF) - gr_set_textcolor(sp[:legendfontcolor]) - gr_set_transparency(sp[:legendfontcolor]) + gr_set_font(legendtitlefont(sp)) gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle])) ypos -= dy + gr_set_font(legendfont(sp)) end for series in series_list(sp) + clims = get_clims(sp, series) should_add_to_legend(series) || continue st = series[:seriestype] lc = get_linecolor(series, clims) gr_set_line(get_linewidth(series), get_linestyle(series), lc) #, series[:linealpha]) - 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-0.07, xpos-0.01 @@ -1532,7 +1880,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) if st in (:path, :straightline) gr_set_transparency(lc, get_linealpha(series)) - if series[:fillrange] == nothing || series[:ribbon] != nothing + if series[:fillrange] === nothing || series[:ribbon] !== nothing GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos]) else GR.polyline([xpos - 0.07, xpos - 0.01], [ypos+0.4dy, ypos+0.4dy]) @@ -1543,14 +1891,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) gr_draw_markers(series, xpos - .035, ypos, clims, 6) end - if typeof(series[:label]) <: Array - i += 1 - lab = series[:label][i] - else - lab = series[:label] - end + lab = series[:label] GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) - gr_set_textcolor(sp[:legendfontcolor]) + gr_set_textcolor(plot_color(sp[:legendfontcolor])) gr_text(xpos, ypos, string(lab)) ypos -= dy end @@ -1573,7 +1916,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) for ann in sp[:annotations] x, y, val = locate_annotation(sp, ann...) x, y = if is3d(sp) - # GR.wc3towc(x, y, z) + gr_w3tondc(x, y, z) else GR.wctondc(x, y) end diff --git a/src/backends/inspectdr.jl b/src/backends/inspectdr.jl index c1e5c5b8..e9ad4cc4 100644 --- a/src/backends/inspectdr.jl +++ b/src/backends/inspectdr.jl @@ -121,9 +121,9 @@ function _create_backend_figure(plt::Plot{InspectDRBackend}) gplot = _inspectdr_getgui(plt.o) #:overwrite_figure: want to reuse current figure - if plt[:overwrite_figure] && mplot != nothing + if plt[:overwrite_figure] && mplot !== nothing mplot.subplots = [] #Reset - if gplot != nothing #Ensure still references current plot + if gplot !== nothing #Ensure still references current plot gplot.src = mplot end else #want new one: diff --git a/src/backends/orca.jl b/src/backends/orca.jl new file mode 100644 index 00000000..9bc4471c --- /dev/null +++ b/src/backends/orca.jl @@ -0,0 +1,24 @@ +function plotlybase_syncplot(plt::Plot) + plt.o = ORCA.PlotlyBase.Plot() + traces = ORCA.PlotlyBase.GenericTrace[] + for series_dict in plotly_series(plt) + plotly_type = pop!(series_dict, :type) + push!(traces, ORCA.PlotlyBase.GenericTrace(plotly_type; series_dict...)) + end + ORCA.PlotlyBase.addtraces!(plt.o, traces...) + layout = plotly_layout(plt) + w, h = plt[:size] + ORCA.PlotlyBase.relayout!(plt.o, layout, width = w, height = h) + return plt.o +end + +const _orca_mimeformats = Dict( + "application/pdf" => "pdf", + "image/png" => "png", + "image/svg+xml" => "svg", + "image/eps" => "eps", +) + +for (mime, fmt) in _orca_mimeformats + @eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyBackend}) = ORCA.PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = $fmt) +end diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index 8f849c07..378473c5 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -96,7 +96,7 @@ pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot]) function pgf_fillstyle(plotattributes, i = 1) cstr,a = pgf_color(get_fillcolor(plotattributes, i)) fa = get_fillalpha(plotattributes, i) - if fa != nothing + if fa !== nothing a = fa end "fill = $cstr, fill opacity=$a" @@ -128,16 +128,18 @@ 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))) - """ - mark = $(get(_pgfplots_markers, shape, "*")), - mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)), - mark options = { - color = $cstr_stroke, draw opacity = $a_stroke, - fill = $cstr, fill opacity = $a, - line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)), - rotate = $(shape == :dtriangle ? 180 : 0), - $(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid")) - }""" + return string( + "mark = $(get(_pgfplots_markers, shape, "*")),\n", + "mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),\n", + plotattributes[:seriestype] == :scatter ? "only marks,\n" : "", + "mark options = { + color = $cstr_stroke, draw opacity = $a_stroke, + fill = $cstr, fill opacity = $a, + 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) @@ -178,11 +180,11 @@ function pgf_series(sp::Subplot, series::Series) end # PGFPlots can't handle non-Vector? - args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector - collect(a) - else - a - end, args) + # args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector + # collect(a) + # else + # a + # end, args) if st in (:contour, :histogram2d) style = [] @@ -216,12 +218,12 @@ function pgf_series(sp::Subplot, series::Series) # add to legend? if i == 1 && sp[:legend] != :none && should_add_to_legend(series) - if plotattributes[:fillrange] != nothing + if plotattributes[:fillrange] !== nothing push!(style, "forget plot") push!(series_collection, pgf_fill_legend_hack(plotattributes, args)) else kw[:legendentry] = plotattributes[:label] - if st == :shape # || plotattributes[:fillrange] != nothing + if st == :shape # || plotattributes[:fillrange] !== nothing push!(style, "area legend") end end @@ -238,7 +240,7 @@ function pgf_series(sp::Subplot, series::Series) kw[:style] = join(style, ',') # add fillrange - if series[:fillrange] != nothing && st != :shape + if series[:fillrange] !== nothing && st != :shape push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...)) end @@ -476,8 +478,18 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend}) if haskey(_pgfplots_legend_pos, legpos) kw[:legendPos] = _pgfplots_legend_pos[legpos] end - cstr, a = pgf_color(plot_color(sp[:background_color_legend])) - push!(style, string("legend style = {", pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid"), ",", "fill = $cstr,", "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), "}")) + 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", ), ",", + "fill = $cstr,", + "fill opacity = $bg_alpha,", + "text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),", + "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), + "}", + )) if any(s[:seriestype] == :contour for s in series_list(sp)) kw[:view] = "{0}{90}" diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl new file mode 100644 index 00000000..367f181a --- /dev/null +++ b/src/backends/pgfplotsx.jl @@ -0,0 +1,862 @@ +using Contour: Contour +using UUIDs +Base.@kwdef mutable struct PGFPlotsXPlot + is_created::Bool = false + was_shown::Bool = false + the_plot::PGFPlotsX.TikzDocument = PGFPlotsX.TikzDocument() + 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}") + # pgfplots libraries + 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!(pgfx_plot.the_plot, + raw""" + \pgfplotsset{ + /pgfplots/layers/axis on top/.define layer set={ + background, axis background,pre main,main,axis grid,axis ticks,axis lines,axis tick labels, + axis descriptions,axis foreground + }{/pgfplots/layers/standard}, + } + """ + ) + pgfx_plot + end +end + +## end user utility functions +function pgfx_axes(pgfx_plot::PGFPlotsXPlot) + gp = pgfx_plot.the_plot.elements[1].elements[1] + return gp isa PGFPlotsX.GroupPlot ? gp.contents : gp +end + +function pgfx_preamble(pgfx_plot::Plot{PGFPlotsXBackend}) + old_flag = pgfx_plot.attr[:tex_output_standalone] + pgfx_plot.attr[:tex_output_standalone] = true + fulltext = String(repr("application/x-tex", pgfx_plot)) + preamble = fulltext[1:first(findfirst("\\begin{document}", fulltext)) - 1] + pgfx_plot.attr[:tex_output_standalone] = old_flag + preamble +end +## + +function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat, Surface}) + a = Array(s) + xn = Vector{eltype(x)}(undef, length(a)) + yn = Vector{eltype(y)}(undef, length(a)) + zn = Vector{eltype(s)}(undef, length(a)) + for (n, (i, j)) in enumerate(Tuple.(CartesianIndices(a))) + xn[n] = x[j] + yn[n] = y[i] + zn[n] = a[i,j] + end + return xn, yn, zn +end + +function Base.push!(pgfx_plot::PGFPlotsXPlot, item) + push!(pgfx_plot.the_plot, item) +end + +function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend}) + if !pgfx_plot.is_created + the_plot = PGFPlotsX.TikzPicture(PGFPlotsX.Options()) + rows, cols = size(plt.layout.grid) + 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) + push!(the_plot.options, + "/tikz/background rectangle/.style" => PGFPlotsX.Options( + "fill" => cstr, + "draw opacity" => a, + ), + "show background rectangle" => nothing, + ) + end + + # the combination of groupplot and polaraxis is broken in pgfplots + if !any( sp -> ispolar(sp), plt.subplots ) + pl_height, pl_width = plt.attr[:size] + push!( the_plot, PGFPlotsX.GroupPlot( + PGFPlotsX.Options( + "group style" => PGFPlotsX.Options( + "group size" => string(cols)*" by "*string(rows), + "horizontal sep" => string(maximum(sp -> sp.minpad[1], plt.subplots)), + "vertical sep" => string(maximum(sp -> sp.minpad[2], plt.subplots)), + ), + "height" => pl_height > 0 ? string(pl_height * px) : "{}", + "width" => pl_width > 0 ? string(pl_width * px) : "{}", + ) + ) + ) + end + for sp in plt.subplots + bb = bbox(sp) + sp_width = width(bb) + sp_height = height(bb) + cstr = plot_color(sp[:background_color_legend]) + a = alpha(cstr) + fg_alpha = alpha(plot_color(sp[:foreground_color_legend])) + title_cstr = plot_color(sp[:titlefontcolor]) + title_a = alpha(title_cstr) + axis_opt = PGFPlotsX.Options( + "title" => sp[:title], + "title style" => PGFPlotsX.Options( + "font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)), + "color" => title_cstr, + "draw opacity" => title_a, + "rotate" => sp[:titlefontrotation] + ), + "legend style" => PGFPlotsX.Options( + pgfx_linestyle(pgfx_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid") => nothing, + "fill" => cstr, + "fill opacity" => a, + "text opacity" => alpha(plot_color(sp[:legendfontcolor])), + "font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)) + ), + "axis background/.style" => PGFPlotsX.Options( + "fill" => sp[:background_color_inside] + ), + "axis on top" => nothing, + ) + sp_width > 0*mm ? push!(axis_opt, "width" => string(sp_width)) : nothing + sp_height > 0*mm ? push!(axis_opt, "height" => string(sp_height)) : nothing + # legend position + if sp[:legend] isa Tuple + x, y = sp[:legend] + push!(axis_opt["legend style"], "at={($x, $y)}" ) + else + push!(axis_opt, "legend pos" => get(_pgfplotsx_legend_pos, sp[:legend], "outer north east"), + ) + end + for letter in (:x, :y, :z) + if letter != :z || is3d(sp) + pgfx_axis!(axis_opt, sp, letter) + end + end + # Search series for any gradient. In case one series uses a gradient set + # the colorbar and colomap. + # The reasoning behind doing this on the axis level is that pgfplots + # colorbar seems to only works on axis level and needs the proper colormap for + # correctly displaying it. + # It's also possible to assign the colormap to the series itself but + # then the colormap needs to be added twice, once for the axis and once for the + # series. + # As it is likely that all series within the same axis use the same + # colormap this should not cause any problem. + for series in series_list(sp) + for col in (:markercolor, :fillcolor, :linecolor) + if typeof(series.plotattributes[col]) == ColorGradient + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, """\\pgfplotsset{ + colormap={plots$(sp.attr[:subplot_index])}{$(pgfx_colormap(series.plotattributes[col]))}, + }""") + push!(axis_opt, + "colorbar" => nothing, + "colormap name" => "plots$(sp.attr[:subplot_index])", + ) + # goto is needed to break out of col and series for + @goto colorbar_end + end + end + end + @label colorbar_end + + push!(axis_opt, "colorbar style" => PGFPlotsX.Options( + "title" => sp[:colorbar_title], + "point meta max" => get_clims(sp)[2], + "point meta min" => get_clims(sp)[1] + ) + ) + if is3d(sp) + azim, elev = sp[:camera] + push!( axis_opt, "view" => (azim, elev) ) + end + axisf = if sp[:projection] == :polar + # push!(axis_opt, "xmin" => 90) + # push!(axis_opt, "xmax" => 450) + PGFPlotsX.PolarAxis + else + PGFPlotsX.Axis + end + axis = axisf( + axis_opt + ) + for (series_index, series) in enumerate(series_list(sp)) + opt = series.plotattributes + st = series[:seriestype] + series_opt = PGFPlotsX.Options( + "color" => single_color(opt[:linecolor]), + ) + if is3d(series) || st == :heatmap + series_func = PGFPlotsX.Plot3 + else + series_func = PGFPlotsX.Plot + end + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing + push!(series_opt, "area legend" => nothing) + end + if st == :heatmap + push!(axis.options, + "view" => "{0}{90}", + ) + end + # treat segments + segments = if st in (:wireframe, :heatmap, :contour, :surface, :contour3d) + iter_segments(surface_to_vecs(series[:x], series[:y], series[:z])...) + else + iter_segments(series) + end + for (i, rng) in enumerate(segments) + segment_opt = PGFPlotsX.Options() + segment_opt = merge( segment_opt, pgfx_linestyle(opt, i) ) + if opt[:markershape] != :none + marker = opt[:markershape] + if marker isa Shape + x = marker.x + y = marker.y + scale_factor = 0.025 + mark_size = opt[:markersize] * scale_factor + path = join(["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)], " -- ") + c = get_markercolor(series, i) + a = get_markeralpha(series, i) + PGFPlotsX.push_preamble!(pgfx_plot.the_plot, + """ + \\pgfdeclareplotmark{PlotsShape$(series_index)}{ + \\filldraw + $path; + } + """ + ) + end + segment_opt = merge( segment_opt, pgfx_marker(opt, i) ) + end + if st == :shape || + isfilledcontour(series) + segment_opt = merge( segment_opt, pgfx_fillstyle(opt, i) ) + end + # add fillrange + if series[:fillrange] !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing + pgfx_fillrange_series!( axis, series, series_func, i, _cycle(series[:fillrange], rng), rng) + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + pgfx_filllegend!(series_opt, opt) + end + end + # series + # + coordinates = pgfx_series_coordinates!( sp, series, segment_opt, opt, rng ) + segment_plot = series_func( + merge(series_opt, segment_opt), + coordinates, + ) + push!(axis, segment_plot) + # add ribbons? + ribbon = series[:ribbon] + if ribbon !== nothing + pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + end + # add to legend? + if i == 1 && opt[:label] != "" && sp[:legend] != :none && should_add_to_legend(series) + leg_opt = PGFPlotsX.Options() + if ribbon !== nothing + pgfx_filllegend!(axis.contents[end-3].options, opt) + end + legend = PGFPlotsX.LegendEntry(leg_opt, opt[:label], false) + push!( axis, legend ) + end + # add series annotations + anns = series[:series_annotations] + for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y]) + pgfx_add_annotation!(axis, xi, yi, PlotText(str, fnt), pgfx_thickness_scaling(series)) + end + end + # add subplot annotations + anns = sp.attr[:annotations] + for (xi,yi,txt) in anns + pgfx_add_annotation!(axis, xi, yi, txt, pgfx_thickness_scaling(sp)) + end + end + if ispolar(sp) + axes = the_plot + else + axes = the_plot.elements[1] + end + push!( axes, axis ) + if length(plt.o.the_plot.elements) > 0 + plt.o.the_plot.elements[1] = the_plot + else + push!(plt.o, the_plot) + end + end + pgfx_plot.is_created = true + end + return pgfx_plot +end +## seriestype specifics +@inline function pgfx_series_coordinates!(sp, series, segment_opt, opt, rng) + st = series[:seriestype] + # function args + args = if st in (:contour, :contour3d) + opt[:x], opt[:y], Array(opt[:z])' + elseif st in (:heatmap, :surface, :wireframe) + surface_to_vecs(opt[:x], opt[:y], opt[:z]) + elseif is3d(st) + opt[:x], opt[:y], opt[:z] + elseif st == :straightline + straightline_data(series) + elseif st == :shape + shape_data(series) + elseif ispolar(sp) + theta, r = opt[:x], opt[:y] + rad2deg.(theta), r + else + opt[:x], opt[:y] + end + seg_args = if st in (:contour, :contour3d) + args + else + (arg[rng] for arg in args) + end + if opt[:quiver] !== nothing + push!(segment_opt, "quiver" => PGFPlotsX.Options( + "u" => "\\thisrow{u}", + "v" => "\\thisrow{v}", + pgfx_arrow(opt[:arrow]) => nothing + ), + ) + x, y = collect(seg_args) + return PGFPlotsX.Table([:x => x, :y => y, :u => opt[:quiver][1], :v => opt[:quiver][2]]) + else + if isfilledcontour(series) + st = :filledcontour + end + pgfx_series_coordinates!(Val(st), segment_opt, opt, seg_args) + end +end +function pgfx_series_coordinates!(st_val::Union{Val{:path}, Val{:path3d}, Val{:straightline}}, segment_opt, opt, args) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:scatter}, Val{:scatter3d}}, segment_opt, opt, args) + push!( segment_opt, "only marks" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:heatmap}, segment_opt, opt, args) + push!(segment_opt, + "matrix plot*" => nothing, + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]), + ) + return PGFPlotsX.Table(args...) +end + +function pgfx_series_coordinates!(st_val::Val{:steppre}, segment_opt, opt, args) + push!( segment_opt, "const plot mark right" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:stepmid}, segment_opt, opt, args) + push!( segment_opt, "const plot mark mid" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:steppost}, segment_opt, opt, args) + push!( segment_opt, "const plot" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:ysticks},Val{:sticks}}, segment_opt, opt, args) + push!( segment_opt, "ycomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:xsticks}, segment_opt, opt, args) + push!( segment_opt, "xcomb" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:surface}, segment_opt, opt, args) + push!( segment_opt, "surf" => nothing, + "mesh/rows" => length(opt[:x]), + "mesh/cols" => length(opt[:y]), + ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:volume}, segment_opt, opt, args) + push!( segment_opt, "patch" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:wireframe}, segment_opt, opt, args) + push!( segment_opt, "mesh" => nothing, + "mesh/rows" => length(opt[:x]) + ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Val{:shape}, segment_opt, opt, args) + push!( segment_opt, "area legend" => nothing ) + return PGFPlotsX.Coordinates(args...) +end +function pgfx_series_coordinates!(st_val::Union{Val{:contour}, Val{:contour3d}}, segment_opt, opt, args) + push!(segment_opt, + "contour prepared" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + ) + return PGFPlotsX.Table(Contour.contours(args..., opt[:levels])) +end +function pgfx_series_coordinates!(st_val::Val{:filledcontour}, segment_opt, opt, args) + xs, ys, zs = collect(args) + push!(segment_opt, + "contour filled" => PGFPlotsX.Options( + "labels" => opt[:contour_labels], + ), + "point meta" => "explicit", + "shader" => "flat" + ) + if opt[:levels] isa Number + push!(segment_opt["contour filled"], + "number" => opt[:levels], + ) + elseif opt[:levels] isa AVec + push!(segment_opt["contour filled"], + "levels" => opt[:levels], + ) + end + + cs = join([ + join(["($x, $y) [$(zs[j, i])]" for (j, x) in enumerate(xs)], " ") for (i, y) in enumerate(ys)], "\n\n" + ) + """ + coordinates { + $cs + }; + """ +end +## +const _pgfplotsx_linestyles = KW( + :solid => "solid", + :dash => "dashed", + :dot => "dotted", + :dashdot => "dashdotted", + :dashdotdot => "dashdotdotted", +) + +const _pgfplotsx_markers = KW( + :none => "none", + :cross => "+", + :xcross => "x", + :+ => "+", + :x => "x", + :utriangle => "triangle*", + :dtriangle => "triangle*", + :rtriangle => "triangle*", + :ltriangle => "triangle*", + :circle => "*", + :rect => "square*", + :star5 => "star", + :star6 => "asterisk", + :diamond => "diamond*", + :pentagon => "pentagon*", + :hline => "-", + :vline => "|" +) + +const _pgfplotsx_legend_pos = KW( + :bottomleft => "south west", + :bottomright => "south east", + :topright => "north east", + :topleft => "north west", + :outertopright => "outer north east", +) + +const _pgfx_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none] +const _pgfx_framestyle_defaults = Dict(:semi => :box) + +# we use the anchors to define orientations for example to align left +# one needs to use the right edge as anchor +const _pgfx_annotation_halign = KW( + :center => "", + :left => "right", + :right => "left" +) +## -------------------------------------------------------------------------------------- +# Generates a colormap for pgfplots based on a ColorGradient +pgfx_arrow(::Nothing) = "every arrow/.append style={-}" +function pgfx_arrow( arr::Arrow ) + components = String[] + head = String[] + push!(head, "{stealth[length = $(arr.headlength)pt, width = $(arr.headwidth)pt") + if arr.style == :open + push!(head, ", open") + end + push!(head, "]}") + head = join(head, "") + if arr.side == :both || arr.side == :tail + push!( components, head ) + end + push!(components, "-") + if arr.side == :both || arr.side == :head + push!( components, head ) + end + components = join( components, "" ) + return "every arrow/.append style={$(components)}" +end + +function pgfx_filllegend!( series_opt, opt ) + io = IOBuffer() + PGFPlotsX.print_tex(io, pgfx_fillstyle(opt)) + style = strip(String(take!(io)),['[',']', ' ']) + push!( series_opt, "legend image code/.code" => """{ + \\draw[$style] (0cm,-0.1cm) rectangle (0.6cm,0.1cm); + }""" ) +end + +function pgfx_colormap(grad::ColorGradient) + join(map(grad.colors) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) + end,"\n") +end +function pgfx_colormap(grad::Vector{<:Colorant}) + join(map(grad) do c + @sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c)) + end,"\n") +end + +function pgfx_framestyle(style::Symbol) + if style in _pgfx_framestyles + return style + else + default_style = get(_pgfx_framestyle_defaults, style, :axes) + @warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.") + default_style + end +end + +pgfx_thickness_scaling(plt::Plot) = plt[:thickness_scaling] +pgfx_thickness_scaling(sp::Subplot) = pgfx_thickness_scaling(sp.plt) +pgfx_thickness_scaling(series) = pgfx_thickness_scaling(series[:subplot]) + +function pgfx_fillstyle(plotattributes, i = 1) + cstr = get_fillcolor(plotattributes, i) + a = get_fillalpha(plotattributes, i) + if a === nothing + a = alpha(single_color(cstr)) + end + PGFPlotsX.Options("fill" => cstr, "fill opacity" => a) +end + +function pgfx_linestyle(linewidth::Real, color, α = 1, linestyle = "solid") + cstr = plot_color(color, α) + a = alpha(cstr) + return PGFPlotsX.Options( + "color" => cstr, + "draw opacity" => a, + "line width" => linewidth, + get(_pgfplotsx_linestyles, linestyle, "solid") => nothing + ) +end + +function pgfx_linestyle(plotattributes, i = 1) + lw = pgfx_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i) + lc = single_color(get_linecolor(plotattributes, i)) + la = get_linealpha(plotattributes, i) + ls = get_linestyle(plotattributes, i) + return pgfx_linestyle(lw, lc, la, ls) +end + +function pgfx_font(fontsize, thickness_scaling = 1, font = "\\selectfont") + fs = fontsize * thickness_scaling + return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}") +end + +function pgfx_marker(plotattributes, i = 1) + shape = _cycle(plotattributes[:markershape], i) + cstr = plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)) + a = alpha(cstr) + cstr_stroke = plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)) + a_stroke = alpha(cstr_stroke) + mark_size = pgfx_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i) + return PGFPlotsX.Options( + "mark" => shape isa Shape ? "PlotsShape$i" : get(_pgfplotsx_markers, shape, "*"), + "mark size" => "$mark_size pt", + "mark options" => PGFPlotsX.Options( + "color" => cstr_stroke, + "draw opacity" => a_stroke, + "fill" => cstr, + "fill opacity" => a, + "line width" => pgfx_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i), + "rotate" => if shape == :dtriangle + 180 + elseif shape == :rtriangle + 270 + elseif shape == :ltriangle + 90 + else + 0 + end, + get(_pgfplotsx_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid") => nothing + ) + ) +end + +function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1) + # Construct the style string. + cstr = val.font.color + a = alpha(cstr) + push!(o, ["\\node", + PGFPlotsX.Options( + get(_pgfx_annotation_halign, val.font.halign, "") => nothing, + "color" => cstr, + "draw opacity" => convert(Float16, a), + "rotate" => val.font.rotation, + "font" => pgfx_font(val.font.pointsize, thickness_scaling) + ), + " at (axis cs:$x, $y) {$(val.str)};" + ]) +end + +function pgfx_add_ribbons!( axis, series, segment_plot, series_func, series_index ) + ribbon_y = series[:ribbon] + opt = series.plotattributes + if ribbon_y isa AVec + ribbon_n = length(opt[:y]) ÷ length(ribbon_y) + ribbon_yp = ribbon_ym = repeat(ribbon_y, outer = ribbon_n) + elseif ribbon_y isa Tuple + ribbon_ym, ribbon_yp = ribbon_y + ribbon_nm = length(opt[:y]) ÷ length(ribbon_ym) + ribbon_ym = repeat(ribbon_ym, outer = ribbon_nm) + ribbon_np = length(opt[:y]) ÷ length(ribbon_yp) + ribbon_yp = repeat(ribbon_yp, outer = ribbon_np) + else + ribbon_yp = ribbon_ym = ribbon_y + end + # upper ribbon + rib_uuid = uuid4() + ribbon_name_plus = "plots_rib_p$rib_uuid" + ribbon_opt_plus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_plus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha], + "forget plot" => nothing + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .+ ribbon_yp) + ribbon_plot_plus = series_func( + ribbon_opt_plus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # lower ribbon + ribbon_name_minus = "plots_rib_m$rib_uuid" + ribbon_opt_minus = merge(segment_plot.options, PGFPlotsX.Options( + "name path" => ribbon_name_minus, + "color" => opt[:fillcolor], + "draw opacity" => opt[:fillalpha], + "forget plot" => nothing + )) + coordinates_plus = PGFPlotsX.Coordinates(opt[:x], opt[:y] .- ribbon_ym) + ribbon_plot_plus = series_func( + ribbon_opt_minus, + coordinates_plus + ) + push!(axis, ribbon_plot_plus) + # fill + push!(axis, series_func( + merge(pgfx_fillstyle(opt, series_index), PGFPlotsX.Options("forget plot" => nothing)), + "fill between [of=$(ribbon_name_plus) and $(ribbon_name_minus)]" + )) + return axis +end + +function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng) + fillrange_opt = PGFPlotsX.Options( + "line width" => "0", + "draw opacity" => "0", + ) + fillrange_opt = merge( fillrange_opt, pgfx_fillstyle(series, i) ) + fillrange_opt = merge( fillrange_opt, pgfx_marker(series, i) ) + push!( fillrange_opt, "forget plot" => nothing ) + opt = series.plotattributes + args = 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...))) + return axis +end + +function pgfx_fillrange_args(fillrange, x, y) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; _cycle(fillrange, n:-1:1); y[1]] + return PGFPlotsX.Coordinates(x_fill, y_fill) +end + +function pgfx_fillrange_args(fillrange, x, y, z) + n = length(x) + x_fill = [x; x[n:-1:1]; x[1]] + y_fill = [y; y[n:-1:1]; x[1]] + z_fill = [z; _cycle(fillrange, n:-1:1); z[1]] + return PGFPlotsX.Coordiantes(x_fill, y_fill, z_fill) +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], + ) + + # set to supported framestyle + framestyle = pgfx_framestyle(sp[:framestyle] == false ? :none : sp[:framestyle]) + + # axis label position + labelpos = "" + if letter == :x && axis[:guide_position] == :top + labelpos = "at={(0.5,1)},above," + elseif letter == :y && axis[:guide_position] == :right + labelpos = "at={(1,0.5)},below," + end + + # Add label font + cstr = plot_color(axis[:guidefontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "label style") => PGFPlotsX.Options( + labelpos => nothing, + "font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:guidefontrotation], + ) + ) + + # flip/reverse? + axis[:flip] && push!(opt, "$letter dir" => "reverse") + + # scale + 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)") + end + + # ticks on or off + if axis[:ticks] in (nothing, false, :none) || framestyle == :none + push!(opt, "$(letter)majorticks" => "false") + end + + # grid on or off + if axis[:grid] && framestyle != :none + push!(opt, "$(letter)majorgrids" => "true") + else + push!(opt, "$(letter)majorgrids" => "false") + end + + # limits + 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] + ) + + 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!(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]) + base, power = split(label, "^") + power = string("{", power, "}") + tick_labels[i] = string(base, "^", power) + end + push!(opt, string(letter, "ticklabels") => string("{\$", join(tick_labels,"\$,\$"), "\$}")) + elseif axis[:showaxis] + 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!(opt, string(letter, "ticklabels") => string("{", join(tick_labels,","), "}")) + else + push!(opt, string(letter, "ticklabels") => "{}") + end + push!(opt, string(letter, "tick align") => (axis[:tick_direction] == :out ? "outside" : "inside")) + cstr = plot_color(axis[:tickfontcolor]) + α = alpha(cstr) + push!(opt, string(letter, "ticklabel style") => PGFPlotsX.Options( + "font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)), + "color" => cstr, + "draw opacity" => α, + "rotate" => axis[:tickfontrotation] + ) + ) + push!(opt, string(letter, " grid style") => pgfx_linestyle(pgfx_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]) + ) + end + + # framestyle + if framestyle in (:axes, :origin) + axispos = framestyle == :axes ? "left" : "middle" + if axis[:draw_arrow] + push!(opt, string("axis ", letter, " line") => axispos) + else + # the * after line disables the arrow at the axis + push!(opt, string("axis ", letter, " line*") => axispos) + end + end + + if framestyle == :zerolines + push!(opt, string("extra ", letter, " ticks") => "0") + push!(opt, string("extra ", letter, " tick labels") => "") + push!(opt, string("extra ", letter, " tick style") => PGFPlotsX.Options( + "grid" => "major", + "major grid style" => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + ) + end + + if !axis[:showaxis] + push!(opt, "separate axis lines") + end + if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none) + push!(opt, string(letter, " axis line style") => "{draw opacity = 0}") + else + push!(opt, string(letter, " axis line style") => pgfx_linestyle(pgfx_thickness_scaling(sp), axis[:foreground_color_border], 1.0) + ) + end +end +# -------------------------------------------------------------------------------------- +# display calls this and then _display, its called 3 times for plot(1:5) +# 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{PGFPlotsXBackend}) + # TODO: make padding more intelligent + # order: right, top, left, bottom + sp.minpad = (22mm + sp[:right_margin], + 12mm + sp[:top_margin], + 2mm + sp[:left_margin], + 10mm + sp[:bottom_margin]) +end + +function _create_backend_figure(plt::Plot{PGFPlotsXBackend}) + plt.o = PGFPlotsXPlot() +end + +function _series_added(plt::Plot{PGFPlotsXBackend}, series::Series) + plt.o.is_created = false +end + +function _update_plot_object(plt::Plot{PGFPlotsXBackend}) + plt.o(plt) +end + +for mime in ("application/pdf", "image/png", "image/svg+xml") + @eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend}) + show(io, mime, plt.o.the_plot) + end +end + +function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend}) + PGFPlotsX.print_tex(io, plt.o.the_plot, include_preamble = plt.attr[:tex_output_standalone]) +end + +function _display(plt::Plot{PGFPlotsXBackend}) + display(PGFPlotsX.PGFPlotsXDisplay(), plt.o.the_plot) +end diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 977d338f..e63cddba 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -26,7 +26,6 @@ const plotly_remote_file_path = "https://cdn.plot.ly/plotly-latest.min.js" # end using UUIDs -push!(_initialized_backends, :plotly) # ---------------------------------------------------------------- const _plotly_legend_pos = KW( @@ -346,12 +345,12 @@ function plotly_layout(plt::Plot) end function plotly_layout_json(plt::Plot) - JSON.json(plotly_layout(plt)) + JSON.json(plotly_layout(plt), 4) end function plotly_colorscale(grad::ColorGradient, α) - [[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)] + [[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in eachindex(grad.colors)] end plotly_colorscale(c::Colorant,α) = plotly_colorscale(_as_gradient(c),α) function plotly_colorscale(c::AbstractVector{<:RGBA}, α) @@ -392,7 +391,7 @@ end # 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=1:length(xs) + for i=eachindex(xs) shape = Shape(xs[i], ys[i]) xs[i], ys[i] = coords(shape) end @@ -402,7 +401,7 @@ end function plotly_data(series::Series, letter::Symbol, data) axis = series[:subplot][Symbol(letter, :axis)] - data = if axis[:ticks] == :native && data != nothing + data = if axis[:ticks] == :native && data !== nothing plotly_native_data(axis, data) else data @@ -414,7 +413,8 @@ function plotly_data(series::Series, letter::Symbol, data) plotly_data(data) end end -plotly_data(v) = v != nothing ? collect(v) : v +plotly_data(v) = v !== nothing ? collect(v) : v +plotly_data(v::AbstractArray) = v plotly_data(surf::Surface) = surf.surf plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v) @@ -453,7 +453,7 @@ function plotly_series(plt::Plot, series::Series) st = series[:seriestype] sp = series[:subplot] - clims = get_clims(sp) + clims = get_clims(sp, series) if st == :shape return plotly_series_shapes(plt, series, clims) @@ -468,7 +468,7 @@ function plotly_series(plt::Plot, series::Series) plotattributes_out[:showlegend] = should_add_to_legend(series) if st == :straightline - x, y = straightline_data(series) + x, y = straightline_data(series, 100) z = series[:z] else x, y, z = series[:x], series[:y], series[:z] @@ -528,7 +528,7 @@ function plotly_series(plt::Plot, series::Series) else plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) plotattributes_out[:opacity] = series[:fillalpha] - if series[:fill_z] != nothing + if series[:fill_z] !== nothing plotattributes_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z]) end plotattributes_out[:showscale] = hascolorbar(sp) @@ -583,7 +583,7 @@ function plotly_series_shapes(plt::Plot, series::Series, clims) ) x, y = (plotly_data(series, letter, data) - for (letter, data) in zip((:x, :y), shape_data(series)) + for (letter, data) in zip((:x, :y), shape_data(series, 100)) ) for (i,rng) in enumerate(segments) @@ -610,11 +610,11 @@ function plotly_series_shapes(plt::Plot, series::Series, clims) plotly_hover!(plotattributes_out, _cycle(series[:hover], i)) plotattributes_outs[i] = plotattributes_out end - if series[:fill_z] != nothing + if series[:fill_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill)) - elseif series[:line_z] != nothing + elseif series[:line_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line)) - elseif series[:marker_z] != nothing + elseif series[:marker_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker)) end plotattributes_outs @@ -630,11 +630,9 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z (isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple)) segments = iter_segments(series) - plotattributes_outs = Vector{KW}(undef, (hasfillrange ? 2 : 1 ) * length(segments)) + plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments)) for (i,rng) in enumerate(segments) - !isscatter && length(rng) < 2 && continue - plotattributes_out = deepcopy(plotattributes_base) plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false plotattributes_out[:legendgroup] = series[:label] @@ -734,11 +732,11 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z end end - if series[:line_z] != nothing + if series[:line_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line)) - elseif series[:fill_z] != nothing + elseif series[:fill_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill)) - elseif series[:marker_z] != nothing + elseif series[:marker_z] !== nothing push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker)) end @@ -783,7 +781,7 @@ function plotly_hover!(plotattributes_out::KW, hover) # hover text if hover in (:none, false) plotattributes_out[:hoverinfo] = "none" - elseif hover != nothing + elseif hover !== nothing plotattributes_out[:hoverinfo] = "text" plotattributes_out[:text] = hover end @@ -799,13 +797,16 @@ function plotly_series(plt::Plot) end # get json string for a list of dictionaries, each representing the series params -plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt)) +plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt), 4) # ---------------------------------------------------------------- +html_head(plt::Plot{PlotlyBackend}) = plotly_html_head(plt) +html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt) + const ijulia_initialized = Ref(false) -function html_head(plt::Plot{PlotlyBackend}) +function plotly_html_head(plt::Plot) local_file = ("file://" * plotly_local_file_path) plotly = use_local_dependencies[] ? local_file : plotly_remote_file_path if isijulia() && !ijulia_initialized[] @@ -821,12 +822,10 @@ function html_head(plt::Plot{PlotlyBackend}) """) ijulia_initialized[] = true end - # IJulia just needs one initialization - isijulia() && return "" return "" end -function html_body(plt::Plot{PlotlyBackend}, style = nothing) +function plotly_html_body(plt, style = nothing) if style == nothing style = "width:100%;height:100%;" end @@ -839,7 +838,7 @@ function html_body(plt::Plot{PlotlyBackend}, style = nothing) """ end -function js_body(plt::Plot{PlotlyBackend}, divid) +function js_body(plt::Plot, divid) """ gd = (function() { var WIDTH_IN_PERCENT_OF_PARENT = 100; @@ -866,7 +865,7 @@ end # ---------------------------------------------------------------- -function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend}) +function plotly_show_js(io::IO, plot::Plot) data = [] for series in plot.series_list append!(data, plotly_series(plot, series)) @@ -875,7 +874,19 @@ function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{Plotly JSON.print(io, Dict(:data => data, :layout => layout)) end +# ---------------------------------------------------------------- + +function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend}) + plotly_show_js(io, plot) +end + + +function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend}) + write(io, standalone_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 83952c71..5893ece3 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -1,78 +1,44 @@ # https://github.com/sglyon/PlotlyJS.jl -# -------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ - -function _create_backend_figure(plt::Plot{PlotlyJSBackend}) - if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot) - PlotlyJS.SyncPlot(PlotlyJS.Plot(), options = current().o.options) - else - PlotlyJS.plot() +function plotlyjs_syncplot(plt::Plot{PlotlyJSBackend}) + plt[:overwrite_figure] && closeall() + plt.o = PlotlyJS.plot() + traces = PlotlyJS.GenericTrace[] + for series_dict in plotly_series(plt) + plotly_type = pop!(series_dict, :type) + push!(traces, PlotlyJS.GenericTrace(plotly_type; series_dict...)) end + PlotlyJS.addtraces!(plt.o, traces...) + layout = plotly_layout(plt) + w, h = plt[:size] + PlotlyJS.relayout!(plt.o, layout, width = w, height = h) + return plt.o end +# ------------------------------------------------------------------------------ -function _series_added(plt::Plot{PlotlyJSBackend}, series::Series) - syncplot = plt.o - pdicts = plotly_series(plt, series) - for pdict in pdicts - typ = pop!(pdict, :type) - gt = PlotlyJS.GenericTrace(typ; pdict...) - PlotlyJS.addtraces!(syncplot, gt) - end +const _plotlyjs_mimeformats = Dict( + "application/pdf" => "pdf", + "image/png" => "png", + "image/svg+xml" => "svg", + "image/eps" => "eps", +) + +for (mime, fmt) in _plotlyjs_mimeformats + @eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt) end -function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series) - xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y)) - kw = KW(xsym => (series.plotattributes[:x],), ysym => (series.plotattributes[:y],)) - z = series[:z] - if z != nothing - kw[:z] = (isa(z,Surface) ? transpose_z(series, series[:z].surf, false) : z,) - end - PlotlyJS.restyle!( - plt.o, - findfirst(isequal(series), plt.series_list), - kw - ) -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) +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, standalone_html(plt)) -function _update_plot_object(plt::Plot{PlotlyJSBackend}) - pdict = plotly_layout(plt) - syncplot = plt.o - w,h = plt[:size] - PlotlyJS.relayout!(syncplot, pdict, width = w, height = h) -end - - -# ---------------------------------------------------------------- - -_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = show(io, MIME("text/html"), plt.o) -_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="svg") -_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="png") -_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="pdf") -_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="eps") - -function _show(io::IO, m::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) - show(io, m, plt.o) -end - - -function write_temp_html(plt::Plot{PlotlyJSBackend}) - filename = string(tempname(), ".html") - savefig(plt, filename) - filename -end - -function _display(plt::Plot{PlotlyJSBackend}) - if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes") - display(plt.o) - else - standalone_html_window(plt) - end -end +_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt)) @require WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" begin function WebIO.render(plt::Plot{PlotlyJSBackend}) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index eec1e6ca..19137b13 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -187,7 +187,7 @@ end # end function get_locator_and_formatter(vals::AVec) - pyticker."FixedLocator"(1:length(vals)), pyticker."FixedFormatter"(vals) + pyticker."FixedLocator"(eachindex(vals)), pyticker."FixedFormatter"(vals) end function add_pyfixedformatter(cbar, vals::AVec) @@ -216,7 +216,7 @@ end # --------------------------------------------------------------------------- function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series) - if series[:x] != nothing + if series[:x] !== nothing x, y = series[:x], series[:y] nx, ny = length(x), length(y) if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny @@ -399,7 +399,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # handle zcolor and get c/cmap needs_colorbar = hascolorbar(sp) - vmin, vmax = clims = get_clims(sp) + vmin, vmax = clims = get_clims(sp, series) # Dict to store extra kwargs if st == :wireframe @@ -434,7 +434,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) if maximum(series[:linewidth]) > 0 segments = iter_segments(series) # TODO: check LineCollection alternative for speed - # if length(segments) > 1 && (any(typeof(series[attr]) <: AbstractVector for attr in (:fillcolor, :fillalpha)) || series[:fill_z] != nothing) && !(typeof(series[:linestyle]) <: AbstractVector) + # if length(segments) > 1 && (any(typeof(series[attr]) <: AbstractVector for attr in (:fillcolor, :fillalpha)) || series[:fill_z] !== nothing) && !(typeof(series[:linestyle]) <: AbstractVector) # # multicolored line segments # n = length(segments) # # segments = Array(Any,n) @@ -478,7 +478,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # end a = series[:arrow] - if a != nothing && !is3d(st) # TODO: handle 3d later + if a !== nothing && !is3d(st) # TODO: handle 3d later if typeof(a) != Arrow @warn("Unexpected type for arrow: $(typeof(a))") else @@ -508,7 +508,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) if series[:markershape] != :none && st in (:path, :scatter, :path3d, :scatter3d, :steppre, :steppost, :bar) - markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] != nothing + markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] !== nothing # py_color(plot_color.(get_markercolor.(series, clims, eachindex(x)), get_markeralpha.(series, eachindex(x)))) [py_color(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))) for i in eachindex(x)] else @@ -535,7 +535,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) shapes = series[:markershape] msc = py_markerstrokecolor(series) lw = py_thickness_scale(plt, series[:markerstrokewidth]) - for i=1:length(y) + for i=eachindex(y) extrakw[:c] = _cycle(markercolor, i) push!(handle, ax."scatter"(_cycle(x,i), _cycle(y,i); @@ -564,7 +564,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) delete!(extrakw, :c) - for i=1:length(y) + for i=eachindex(y) cur_marker = py_marker(_cycle(shapes,i)) if ( cur_marker == prev_marker ) @@ -672,7 +672,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) push!(handles, handle) # contour fills - if series[:fillrange] != nothing + if series[:fillrange] !== nothing handle = ax."contourf"(x, y, z, levelargs...; label = series[:label], zorder = series[:series_plotindex] + 0.5, @@ -691,7 +691,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end z = transpose_z(series, z) if st == :surface - if series[:fill_z] != nothing + if series[:fill_z] !== nothing # the surface colors are different than z-value extrakw[:facecolors] = py_shading(series[:fillcolor], transpose_z(series, series[:fill_z].surf)) extrakw[:shade] = false @@ -756,7 +756,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) cmap = py_colormap(cgrad([:black, :white])), vmin = 0.0, vmax = 1.0, - extent = (xmin, xmax, ymax, ymin) + extent = (xmin-0.5, xmax+0.5, ymax+0.5, ymin-0.5) ) push!(handles, handle) @@ -830,7 +830,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # handle area filling fillrange = series[:fillrange] - if fillrange != nothing && st != :contour + if fillrange !== nothing && st != :contour for (i, rng) in enumerate(iter_segments(series)) f, dim1, dim2 = if isvertical(series) :fill_between, x[rng], y[rng] @@ -871,7 +871,7 @@ end function py_set_ticks(ax, ticks, letter) ticks == :auto && return axis = getproperty(ax, Symbol(letter,"axis")) - if ticks == :none || ticks == nothing || ticks == false + if ticks == :none || ticks === nothing || ticks == false kw = KW() for dir in (:top,:bottom,:left,:right) kw[dir] = kw[Symbol(:label,dir)] = false @@ -927,7 +927,7 @@ function py_set_scale(ax, sp::Subplot, axis::Axis) elseif scale == :log10 10 end - kw[Symbol(:linthresh,letter)] = NaNMath.min(1e-16, py_compute_axis_minval(sp, axis)) + kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) "symlog" end func(arg; kw...) @@ -978,7 +978,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) # update subplots for sp in plt.subplots ax = sp.o - if ax == nothing + if ax === nothing continue end @@ -1013,17 +1013,17 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) kw = KW() if !isempty(sp[:zaxis][:discrete_values]) && colorbar_series[:seriestype] == :heatmap locator, formatter = get_locator_and_formatter(sp[:zaxis][:discrete_values]) - # kw[:values] = 1:length(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 + f = if colorbar_series[:line_z] !== nothing py_linecolormap - elseif colorbar_series[:fill_z] != nothing + elseif colorbar_series[:fill_z] !== nothing py_fillcolormap else py_markercolormap @@ -1186,7 +1186,7 @@ end # to fit ticks, tick labels, guides, colorbars, etc. function _update_min_padding!(sp::Subplot{PyPlotBackend}) ax = sp.o - ax == nothing && return sp.minpad + ax === nothing && return sp.minpad plotbb = py_bbox(ax) # TODO: this should initialize to the margin from sp.attr @@ -1228,7 +1228,7 @@ end function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val) ax = sp.o - ax."annotate"(val, xy = (x,y), zorder = 999) + ax."annotate"(val, xy = (x,y), zorder = 999, annotation_clip = false) end @@ -1242,7 +1242,8 @@ function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText) 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 + zorder = 999, + annotation_clip = false ) end @@ -1289,15 +1290,15 @@ py_legend_bbox(pos) = pos function py_add_legend(plt::Plot, sp::Subplot, ax) leg = sp[:legend] - clims = get_clims(sp) if leg != :none # gotta do this to ensure both axes are included labels = [] handles = [] for series in series_list(sp) if should_add_to_legend(series) + clims = get_clims(sp, series) # add a line/marker and a label - push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing + 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)), @@ -1335,10 +1336,13 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) frame = leg."get_frame"() frame."set_linewidth"(py_thickness_scale(plt, 1)) leg."set_zorder"(1000) - sp[:legendtitle] != nothing && leg."set_title"(sp[:legendtitle]) + 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])) + end for txt in leg."get_texts"() - PyPlot.plt."setp"(txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily]) + PyPlot.plt."setp"(txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily], fontsize = py_thickness_scale(plt, sp[:legendfontsize])) end end end @@ -1352,7 +1356,7 @@ end function _update_plot_object(plt::Plot{PyPlotBackend}) for sp in plt.subplots ax = sp.o - ax == nothing && return + ax === nothing && return figw, figh = sp.plt[:size] figw, figh = figw*px, figh*px pcts = bbox_to_pcts(sp.plotarea, figw, figh) diff --git a/src/components.jl b/src/components.jl index 097aee19..de10f663 100644 --- a/src/components.jl +++ b/src/components.jl @@ -187,7 +187,7 @@ end function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape)) sx, sy = coords(shape) cx, cy = c - for i=1:length(sx) + for i=eachindex(sx) sx[i] = (sx[i] - cx) * x + cx sy[i] = (sy[i] - cy) * y + cy end @@ -202,7 +202,7 @@ end "translate a Shape in space" function translate!(shape::Shape, x::Real, y::Real = x) sx, sy = coords(shape) - for i=1:length(sx) + for i=eachindex(sx) sx[i] += x sy[i] += y end @@ -230,7 +230,7 @@ end function rotate!(shape::Shape, Θ::Real, c = center(shape)) x, y = coords(shape) cx, cy = c - for i=1:length(x) + for i=eachindex(x) xi = rotate_x(x[i], y[i], Θ, cx, cy) yi = rotate_y(x[i], y[i], Θ, cx, cy) x[i], y[i] = xi, yi @@ -529,7 +529,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels) # end # @show msw msh - if anns != nothing && anns.baseshape != nothing + if anns !== nothing && anns.baseshape !== nothing # we use baseshape to overwrite the markershape attribute # with a list of custom shapes for each msw,msh = anns.scalefactor @@ -568,7 +568,7 @@ mutable struct EachAnn end function Base.iterate(ea::EachAnn, i = 1) - if ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y) + if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y) return nothing end @@ -794,7 +794,7 @@ end @deprecate curve_points coords -coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, range(range..., stop=n, length=50)) +coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, Base.range(range..., length=n)) # build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards. # may create a loop if necessary. Assumes the view is [0,1] diff --git a/src/examples.jl b/src/examples.jl index 6dd1b7f4..c0ac5a38 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -165,7 +165,7 @@ PlotExample("Marker types", ), PlotExample("Bar", - "x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)", + "`x` is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)", [:(begin bar(randn(99)) end)] @@ -238,12 +238,12 @@ build with the method `text(string, attr...)`, which wraps font and color attrib """, [:(begin y = rand(10) -plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false) -annotate!([(5, y[5], text("this is #5",16,:red,:center)), - (10, y[10], text("this is #10",:right,20,"courier"))]) +plot(y, annotations = (3,y[3], Plots.text("this is #3",:left)), leg=false) +annotate!([(5, y[5], Plots.text("this is #5",16,:red,:center)), + (10, y[10], Plots.text("this is #10",:right,20,"courier"))]) scatter!(range(2, stop=8, length=6), rand(6), marker=(50,0.2,:orange), series_annotations = ["series","annotations","map","to","series", - text("data",:green)]) + Plots.text("data",:green)]) end)] ), @@ -305,7 +305,8 @@ PlotExample("3D", PlotExample("DataFrames", "Plot using DataFrame column symbols.", - [:(begin + [:(using StatsPlots), # can't be inside begin block because @df gets expanded first + :(begin import RDatasets iris = RDatasets.dataset("datasets", "iris") @df iris scatter(:SepalLength, :SepalWidth, group=:Species, @@ -354,7 +355,8 @@ PlotExample("Layouts, margins, label rotation, title location", PlotExample("Boxplot and Violin series recipes", "", - [:(begin + [:(using StatsPlots), # can't be inside begin block because @df gets expanded first + :(begin import RDatasets singers = RDatasets.dataset("lattice", "singer") @df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue)) @@ -454,6 +456,49 @@ see: http://stackoverflow.com/a/37732384/5075246 end)] ), +PlotExample("Ribbons", + """ + Ribbons can be added to lines via the `ribbon` keyword; + you can pass a tuple of arrays (upper and lower bounds), + a single Array (for symmetric ribbons), a Function, or a number. + """, + [:(begin + plot( + plot(0:10; ribbon = (LinRange(0, 2, 10), LinRange(0, 1, 10))), + plot(0:10; ribbon = 0:0.5:5), + plot(0:10; ribbon = sqrt), + plot(0:10; ribbon = 1), + ) + end)] +), + +PlotExample("Histogram2D (complex values)", + "", + [:(begin + n = 10_000 + x = exp.(0.1randn(n) .+ randn(n).*(im)) + histogram2d(x, nbins=(20,40), show_empty_bins=true, + normed=true, aspect_ratio=1) + end)] +), + +PlotExample("Unconnected lines using `missing` or `NaN`", +""" +Missing values and non-finite values, including `NaN`, are not plotted. +Instead, lines are separated into segments at these values. +""", + [:(begin + x,y = [1,2,2,1,1], [1,2,1,2,1] + plot( + plot([rand(5); NaN; rand(5); NaN; rand(5)]), + plot([1,missing,2,3], marker=true), + plot([x; NaN; x.+2], [y; NaN; y.+1], arrow=2), + plot([1, 2+3im, Inf, 4im, 3, -Inf*im, 0, 3+3im], marker=true), + legend=false + ) + end)] +), + ] # Some constants for PlotDocs and PlotReferenceImages @@ -461,7 +506,7 @@ _animation_examples = [2, 30] _backend_skips = Dict( :gr => [25, 30], :pyplot => [25, 30], - :plotlyjs => [2, 21, 25, 30, 31], + :plotlyjs => [2, 21, 24, 25, 30, 31], :pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30], ) @@ -475,7 +520,12 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true) @info("Testing plot: $pkgname:$idx:$(_examples[idx].header)") backend(pkgname) backend() - map(eval, _examples[idx].exprs) + + # prevent leaking variables (esp. functions) directly into Plots namespace + m = Module(:PlotExampleModule) + Base.eval(m, :(using Plots)) + map(exprs -> Base.eval(m, exprs), _examples[idx].exprs) + plt = current() if disp gui(plt) @@ -495,8 +545,8 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth skip = [], only = nothing) Plots._debugMode.on = debug plts = Dict() - for i in 1:length(_examples) - only != nothing && !(i in only) && continue + for i in eachindex(_examples) + only !== nothing && !(i in only) && continue i in skip && continue try plt = test_examples(pkgname, i, debug=debug, disp=disp) @@ -505,7 +555,7 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth # TODO: put error info into markdown? @warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex") end - if sleep != nothing + if sleep !== nothing Base.sleep(sleep) end end diff --git a/src/ijulia.jl b/src/ijulia.jl index a54c0ca9..1f0ef219 100644 --- a/src/ijulia.jl +++ b/src/ijulia.jl @@ -20,7 +20,10 @@ 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"] = JSON.lower(plt.o) + out["application/vnd.plotly.v1+json"] = Dict( + :data => plotly_series(plt), + :layout => plotly_layout(plt) + ) out end diff --git a/src/init.jl b/src/init.jl index bffc99f2..c6213001 100644 --- a/src/init.jl +++ b/src/init.jl @@ -28,12 +28,53 @@ function __init__() insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay()) end) - @require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl")) - @require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl")) - @require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl")) - @require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" include(joinpath(@__DIR__, "backends", "plotlyjs.jl")) - @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl")) - @require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl")) + @require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin + fn = joinpath(@__DIR__, "backends", "hdf5.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" begin + fn = joinpath(@__DIR__, "backends", "inspectdr.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" begin + fn = joinpath(@__DIR__, "backends", "pgfplots.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require ORCA = "47be7bcc-f1a6-5447-8b36-7eeeff7534fd" begin + fn = joinpath(@__DIR__, "backends", "orca.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin + fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin + fn = joinpath(@__DIR__, "backends", "plotlyjs.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin + fn = joinpath(@__DIR__, "backends", "pyplot.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end + + @require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" begin + fn = joinpath(@__DIR__, "backends", "unicodeplots.jl") + include(fn) + @require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn) + end @require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin if IJulia.inited diff --git a/src/layouts.jl b/src/layouts.jl index 83ae259d..1bc5367b 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -107,7 +107,6 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol) if mix.len != 0mm f = (letter == :x ? width : height) totlen = f(plotarea(sp)) - @show totlen pct += mix.len / totlen end if pct != 0 @@ -218,6 +217,7 @@ bottompad(layout::AbstractLayout) = 0mm # this is the parent of the top-level layout struct RootLayout <: AbstractLayout end +Base.show(io::IO, layout::RootLayout) = Base.show_default(io, layout) Base.parent(::RootLayout) = nothing parent_bbox(::RootLayout) = defaultbox bbox(::RootLayout) = defaultbox @@ -469,7 +469,7 @@ function layout_args(plotattributes::KW) end function layout_args(plotattributes::KW, n_override::Integer) - layout, n = layout_args(get(plotattributes, :layout, n_override)) + 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.") end @@ -481,12 +481,27 @@ function layout_args(n::Integer) GridLayout(nr, nc), n end -function layout_args(sztup::NTuple{2,I}) where I<:Integer +function layout_args(sztup::NTuple{2, Integer}) nr, nc = sztup GridLayout(nr, nc), nr*nc end -function layout_args(sztup::NTuple{3,I}) where I<:Integer +layout_args(n_override::Integer, n::Integer) = layout_args(n) +layout_args(n, sztup::NTuple{2, Integer}) = layout_args(sztup) + +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}) + nr = sztup[1] + nc = ceil(Int, n / nr) + GridLayout(nr, nc), n +end + +function layout_args(sztup::NTuple{3, Integer}) n, nr, nc = sztup nr, nc = compute_gridsize(n, nr, nc) GridLayout(nr, nc), n @@ -499,6 +514,8 @@ function layout_args(layout::GridLayout) layout, n end +layout_args(n_override::Integer, layout::GridLayout) = layout_args(layout) + layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh") diff --git a/src/output.jl b/src/output.jl index 95a9c158..ac29815c 100644 --- a/src/output.jl +++ b/src/output.jl @@ -72,6 +72,7 @@ const _savemap = Dict( "eps" => eps, "tex" => tex, "html" => html, + "tikz" => tex, ) function getExtension(fn::AbstractString) @@ -103,7 +104,7 @@ type is inferred from the file extension. All backends support png and pdf file types, some also support svg, ps, eps, html and tex. """ function savefig(plt::Plot, fn::AbstractString) - + fn = abspath(expanduser(fn)) # get the extension local ext try @@ -201,6 +202,8 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml end end +Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) = showjuno(io, MIME("text/html"), plt) + # default text/plain for all backends _show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt) @@ -229,15 +232,16 @@ closeall() = closeall(backend()) # Atom PlotPane # --------------------------------------------------------- function showjuno(io::IO, m, plt) - sz = plt[:size] + sz = collect(plt[:size]) dpi = plt[:dpi] thickness_scaling = plt[:thickness_scaling] jsize = get(io, :juno_plotsize, [400, 500]) + jratio = get(io, :juno_dpi_ratio, 1) scale = minimum(jsize[i] / sz[i] for i in 1:2) - plt[:size] = (s * scale for s in sz) - plt[:dpi] = Plots.DPI + plt[:size] = [s * scale for s in sz] + plt[:dpi] = jratio*Plots.DPI plt[:thickness_scaling] *= scale prepare_output(plt) @@ -258,4 +262,6 @@ function _showjuno(io::IO, m::MIME"image/svg+xml", plt) end end +Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot) = showable(MIME"text/html"(), plt) + _showjuno(io::IO, m, plt) = _show(io, m, plt) diff --git a/src/pipeline.jl b/src/pipeline.jl index 433997c2..4966b7f8 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -12,7 +12,7 @@ function _expand_seriestype_array(plotattributes::KW, args) if typeof(sts) <: AbstractArray delete!(plotattributes, :seriestype) rd = Vector{RecipeData}(undef, size(sts, 1)) - for r in 1:size(sts, 1) + for r in axes(sts, 1) dc = copy(plotattributes) dc[:seriestype] = sts[r:r,:] rd[r] = RecipeData(dc, args) @@ -126,7 +126,7 @@ function _preprocess_userrecipe(kw::KW) end # convert a ribbon into a fillrange - if get(kw, :ribbon, nothing) != nothing + if get(kw, :ribbon, nothing) !== nothing make_fillrange_from_ribbon(kw) end return @@ -136,7 +136,7 @@ function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW) # handle error bars by creating new recipedata data... these will have # the same recipedata index as the recipedata they are copied from for esym in (:xerror, :yerror) - if get(kw, esym, nothing) != nothing + if get(kw, esym, nothing) !== nothing # we make a copy of the KW and apply an errorbar recipe errkw = copy(kw) errkw[:seriestype] = esym @@ -227,7 +227,7 @@ function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW}) # handle inset subplots insets = plt[:inset_subplots] - if insets != nothing + if insets !== nothing if !(typeof(insets) <: AVec) insets = [insets] end diff --git a/src/plot.jl b/src/plot.jl index 2c2ecd48..4352403a 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -4,7 +4,7 @@ mutable struct CurrentPlot end const CURRENT_PLOT = CurrentPlot(nothing) -isplotnull() = CURRENT_PLOT.nullableplot == nothing +isplotnull() = CURRENT_PLOT.nullableplot === nothing """ current() diff --git a/src/precompile.jl b/src/precompile.jl index 22c11ca0..a171ac36 100644 --- a/src/precompile.jl +++ b/src/precompile.jl @@ -1,3 +1,873 @@ function _precompile_() ccall(:jl_generating_output, Cint, ()) == 1 || return nothing + isdefined(Plots, Symbol("#@layout")) && precompile(Tuple{getfield(Plots, Symbol("#@layout")), LineNumberNode, Module, Expr}) + isdefined(Plots, Symbol("#kw##_make_hist")) && precompile(Tuple{getfield(Plots, Symbol("#kw##_make_hist")), NamedTuple{(:normed, :weights), Tuple{Bool, Array{Int64, 1}}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}}, Symbol}) + isdefined(Plots, Symbol("#kw##_make_hist")) && precompile(Tuple{getfield(Plots, Symbol("#kw##_make_hist")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64}) + isdefined(Plots, Symbol("#kw##_make_hist")) && precompile(Tuple{getfield(Plots, Symbol("#kw##_make_hist")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Tuple{Int64, Int64}}) + isdefined(Plots, Symbol("#kw##_make_hist")) && precompile(Tuple{getfield(Plots, Symbol("#kw##_make_hist")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}}, Symbol}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:flip,), Tuple{Bool}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:foreground_color_grid, :grid, :gridalpha, :gridstyle, :gridlinewidth), Tuple{ColorTypes.RGBA{Float64}, Bool, Float64, Symbol, Int64}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:formatter,), Tuple{Symbol}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:grid, :lims), Tuple{Bool, Tuple{Int64, Int64}}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:grid, :lims, :flip), Tuple{Bool, Tuple{Int64, Int64}, Bool}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:grid, :ticks), Tuple{Bool, Nothing}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:grid,), Tuple{Bool}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:grid,), Tuple{Bool}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:guide,), Tuple{String}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:lims, :flip, :ticks, :guide), Tuple{Tuple{Int64, Int64}, Bool, Base.StepRange{Int64, Int64}, String}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:lims,), Tuple{Tuple{Int64, Float64}}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:rotation,), Tuple{Int64}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:scale, :guide), Tuple{Symbol, String}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:ticks,), Tuple{Base.UnitRange{Int64}}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##attr!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##attr!")), NamedTuple{(:ticks,), Tuple{Nothing}}, typeof(Plots.attr!), Plots.Axis}) + isdefined(Plots, Symbol("#kw##contour")) && precompile(Tuple{getfield(Plots, Symbol("#kw##contour")), NamedTuple{(:fill,), Tuple{Bool}}, typeof(Plots.contour), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int}) + isdefined(Plots, Symbol("#kw##gr_polyline")) && precompile(Tuple{getfield(Plots, Symbol("#kw##gr_polyline")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Array{Float64, 1}, Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##gr_polyline")) && precompile(Tuple{getfield(Plots, Symbol("#kw##gr_polyline")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Array{Int64, 1}, Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##gr_polyline")) && precompile(Tuple{getfield(Plots, Symbol("#kw##gr_polyline")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Base.UnitRange{Int64}, Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##gr_set_font")) && precompile(Tuple{getfield(Plots, Symbol("#kw##gr_set_font")), NamedTuple{(:halign, :valign, :rotation), Tuple{Symbol, Symbol, Int64}}, typeof(Plots.gr_set_font), Plots.Font}) + isdefined(Plots, Symbol("#kw##gr_set_font")) && precompile(Tuple{getfield(Plots, Symbol("#kw##gr_set_font")), NamedTuple{(:halign, :valign, :rotation), Tuple{Symbol, Symbol, Int64}}, typeof(Plots.gr_set_font), Plots.Font}) + isdefined(Plots, Symbol("#kw##heatmap")) && precompile(Tuple{getfield(Plots, Symbol("#kw##heatmap")), NamedTuple{(:aspect_ratio,), Tuple{Int64}}, typeof(Plots.heatmap), Array{String, 1}, Int}) + isdefined(Plots, Symbol("#kw##histogram")) && precompile(Tuple{getfield(Plots, Symbol("#kw##histogram")), NamedTuple{(:bins, :weights), Tuple{Symbol, Array{Int64, 1}}}, typeof(Plots.histogram), Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##histogram2d")) && precompile(Tuple{getfield(Plots, Symbol("#kw##histogram2d")), NamedTuple{(:nbins, :show_empty_bins, :normed, :aspect_ratio), Tuple{Tuple{Int64, Int64}, Bool, Bool, Int64}}, typeof(Plots.histogram2d), Array{Base.Complex{Float64}, 1}}) + isdefined(Plots, Symbol("#kw##histogram2d")) && precompile(Tuple{getfield(Plots, Symbol("#kw##histogram2d")), NamedTuple{(:nbins,), Tuple{Int64}}, typeof(Plots.histogram2d), Array{Float64, 1}, Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##hline!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##hline!")), NamedTuple{(:line,), Tuple{Tuple{Int64, Symbol, Float64, Array{Symbol, 2}}}}, typeof(Plots.hline!), Array{Float64, 2}}) + isdefined(Plots, Symbol("#kw##pie")) && precompile(Tuple{getfield(Plots, Symbol("#kw##pie")), NamedTuple{(:title, :l), Tuple{String, Float64}}, typeof(Plots.pie), Array{String, 1}, Int}) + isdefined(Plots, Symbol("#kw##portfoliocomposition")) && precompile(Tuple{getfield(Plots, Symbol("#kw##portfoliocomposition")), NamedTuple{(:labels,), Tuple{Array{String, 2}}}, typeof(Plots.portfoliocomposition), Array{Float64, 2}, Int}) + isdefined(Plots, Symbol("#kw##scatter!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##scatter!")), NamedTuple{(:marker, :series_annotations), Tuple{Tuple{Int64, Float64, Symbol}, Array{Any, 1}}}, typeof(Plots.scatter!), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int}) + isdefined(Plots, Symbol("#kw##scatter!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##scatter!")), NamedTuple{(:markersize, :c), Tuple{Int64, Symbol}}, typeof(Plots.scatter!), Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##scatter!")) && precompile(Tuple{getfield(Plots, Symbol("#kw##scatter!")), NamedTuple{(:zcolor, :m, :ms, :lab), Tuple{Array{Float64, 1}, Tuple{Symbol, Float64, Plots.Stroke}, Array{Float64, 1}, String}}, typeof(Plots.scatter!), Array{Float64, 1}}) + isdefined(Plots, Symbol("#kw##scatter")) && precompile(Tuple{getfield(Plots, Symbol("#kw##scatter")), NamedTuple{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks), Tuple{Array{Symbol, 2}, Array{String, 2}, Base.ReshapedArray{Int64, 2, Base.UnitRange{Int64}, Tuple{}}, Int64, String, Int64, Base.UnitRange{Int64}}}, typeof(Plots.scatter), Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}) + isdefined(Plots, Symbol("#kw##scatter")) && precompile(Tuple{getfield(Plots, Symbol("#kw##scatter")), NamedTuple{(:m, :lab, :bg, :xlim, :ylim), Tuple{Tuple{Int64, Symbol}, Array{String, 2}, Symbol, Tuple{Int64, Int64}, Tuple{Int64, Int64}}}, typeof(Plots.scatter), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int}) + isdefined(Plots, Symbol("#kw##test_examples")) && precompile(Tuple{getfield(Plots, Symbol("#kw##test_examples")), NamedTuple{(:disp,), Tuple{Bool}}, typeof(Plots.test_examples), Symbol}) + precompile(Tuple{typeof(Plots.__init__)}) + precompile(Tuple{typeof(Plots._add_defaults!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Int64}) + precompile(Tuple{typeof(Plots._add_defaults!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Int64}) + precompile(Tuple{typeof(Plots._add_errorbar_kw), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_errorbar_kw), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_markershape), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_markershape), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_smooth_kw), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_smooth_kw), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_the_series), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._add_the_series), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{Array{Float64, 1}, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{Array{T, 1} where T, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{Function, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{Function, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{String, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, Array{Union{Base.Missing, Int64}, 1}}) + precompile(Tuple{typeof(Plots._apply_type_recipe), Base.Dict{Symbol, Any}, typeof(identity)}) + precompile(Tuple{typeof(Plots._backend_instance), Symbol}) + precompile(Tuple{typeof(Plots._backend_instance), Symbol}) + precompile(Tuple{typeof(Plots._bin_centers), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots._binbarlike_baseline), Float64, Symbol}) + precompile(Tuple{typeof(Plots._cbar_unique), Array{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, 1}, String}) + precompile(Tuple{typeof(Plots._cbar_unique), Array{Int64, 1}, String}) + precompile(Tuple{typeof(Plots._cbar_unique), Array{Nothing, 1}, String}) + precompile(Tuple{typeof(Plots._cbar_unique), Array{PlotUtils.ColorGradient, 1}, String}) + precompile(Tuple{typeof(Plots._cbar_unique), Array{Symbol, 1}, String}) + precompile(Tuple{typeof(Plots._create_backend_figure), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._cycle), Array{Any, 1}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Array{Float64, 1}, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots._cycle), Array{Float64, 1}, Base.StepRange{Int64, Int64}}) + precompile(Tuple{typeof(Plots._cycle), Array{Float64, 1}, Base.UnitRange{Int64}}) + precompile(Tuple{typeof(Plots._cycle), Array{Float64, 1}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Array{Plots.Subplot{T} where T<:RecipesBase.AbstractBackend, 1}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Array{String, 1}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Base.OneTo{Int64}, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots._cycle), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Base.StepRange{Int64, Int64}, Int64}) + precompile(Tuple{typeof(Plots._cycle), ColorTypes.RGBA{Float64}, Int64}) + precompile(Tuple{typeof(Plots._cycle), Float64, Int64}) + precompile(Tuple{typeof(Plots._cycle), Int64, Base.StepRange{Int64, Int64}}) + precompile(Tuple{typeof(Plots._cycle), Int64, Int64}) + precompile(Tuple{typeof(Plots._cycle), Nothing, Int64}) + precompile(Tuple{typeof(Plots._cycle), Plots.Shape, Int64}) + precompile(Tuple{typeof(Plots._cycle), Symbol, Int64}) + precompile(Tuple{typeof(Plots._display), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._display), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._do_plot_show), Plots.Plot{Plots.GRBackend}, Bool}) + precompile(Tuple{typeof(Plots._do_plot_show), Plots.Plot{Plots.GRBackend}, Bool}) + precompile(Tuple{typeof(Plots._do_plot_show), Plots.Plot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots._do_plot_show), Plots.Plot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Base.Complex{Float64}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Int64}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Plots.OHLC{T} where T<:Real, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{String, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Array{Union{Base.Missing, Int64}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.StepRange{Int64, Int64}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Array{T, 1} where T, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Array{T, 1} where T, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Base.Complex{Float64}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Function, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Function, 1}, Int64}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Int64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Plots.OHLC{T} where T<:Real, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{String, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{String, 1}, Array{String, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Array{Union{Base.Missing, Int64}, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.StepRange{Int64, Int64}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Plots.PortfolioComposition}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, Plots.Spy}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy, typeof(Base.log), Int64}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.GroupBy}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.PortfolioComposition}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{Plots.Spy}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{typeof(Base.log), Int64}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._expand_seriestype_array), Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._expand_subplot_extrema), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots._expand_subplot_extrema), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots._filter_input_data!), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._heatmap_edges), Array{Float64, 1}, Bool}) + precompile(Tuple{typeof(Plots._hist_edge), Tuple{Array{Float64, 1}}, Int64, Symbol}) + precompile(Tuple{typeof(Plots._hist_edges), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64}) + precompile(Tuple{typeof(Plots._hist_edges), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Tuple{Int64, Int64}}) + precompile(Tuple{typeof(Plots._hist_edges), Tuple{Array{Float64, 1}}, Symbol}) + precompile(Tuple{typeof(Plots._override_seriestype_check), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots._pick_default_backend)}) + precompile(Tuple{typeof(Plots._pick_default_backend)}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Base.Complex{Float64}, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Int64}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Plots.OHLC{T} where T<:Real, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{String, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Union{Base.Missing, Int64}, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRange{Int64, Int64}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.PortfolioComposition}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.Spy}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{typeof(Base.log), Int64}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._plot_setup), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._plot_setup), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._plots_defaults)}) + precompile(Tuple{typeof(Plots._prepare_annotations), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._prepare_annotations), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._prepare_subplot), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._prepare_subplot), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._prepare_subplot), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}, Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Base.Complex{Float64}, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Int64}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Plots.OHLC{T} where T<:Real, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{String, 1}, Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Array{Union{Base.Missing, Int64}, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.StepRange{Int64, Int64}, Array{Float64, 2}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Base.UnitRange{Int64}}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Plots.PortfolioComposition}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{Plots.Spy}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{typeof(Base.log), Int64}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_args), Base.Dict{Symbol, Any}, Tuple{}, Array{RecipesBase.RecipeData, 1}}) + precompile(Tuple{typeof(Plots._preprocess_barlike), Base.Dict{Symbol, Any}, Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots._preprocess_barlike), Base.Dict{Symbol, Any}, Array{Int64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots._preprocess_barlike), Base.Dict{Symbol, Any}, Base.OneTo{Int64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots._preprocess_binlike), Base.Dict{Symbol, Any}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots._preprocess_userrecipe), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._preprocess_userrecipe), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._process_plotrecipe), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._process_plotrecipe), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._process_seriesrecipe), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._process_seriesrecipe), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._process_seriesrecipe), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._process_userrecipe), Plots.Plot{Plots.GRBackend}, Array{Base.Dict{Symbol, Any}, 1}, RecipesBase.RecipeData}) + precompile(Tuple{typeof(Plots._process_userrecipe), Plots.Plot{Plots.GRBackend}, Array{Base.Dict{Symbol, Any}, 1}, RecipesBase.RecipeData}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Base.Complex{Float64}, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Int64}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Plots.OHLC{T} where T<:Real, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{String, 1}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Union{Base.Missing, Int64}, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRange{Int64, Int64}, Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Base.UnitRange{Int64}}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.PortfolioComposition}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.Spy}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{typeof(Base.log), Int64}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._process_userrecipes), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Tuple{}}) + precompile(Tuple{typeof(Plots._replace_linewidth), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._replace_linewidth), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._replace_markershape), Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots._replace_markershape), Plots.Shape}) + precompile(Tuple{typeof(Plots._scale_adjusted_values), Type{Float64}, Array{Float64, 1}, Symbol}) + precompile(Tuple{typeof(Plots._series_index), Base.Dict{Symbol, Any}, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._show), Base.IOStream, Base.Multimedia.MIME{Symbol("image/png")}, Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._show), Base.IOStream, Base.Multimedia.MIME{Symbol("image/png")}, Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._subplot_setup), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._subplot_setup), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}}) + precompile(Tuple{typeof(Plots._transform_ticks), Base.StepRange{Int64, Int64}}) + precompile(Tuple{typeof(Plots._transform_ticks), Base.UnitRange{Int64}}) + precompile(Tuple{typeof(Plots._transform_ticks), Nothing}) + precompile(Tuple{typeof(Plots._transform_ticks), Symbol}) + precompile(Tuple{typeof(Plots._update_axis), Plots.Axis, Base.Dict{Symbol, Any}, Symbol, Int64}) + precompile(Tuple{typeof(Plots._update_axis), Plots.Axis, Base.Dict{Symbol, Any}, Symbol, Int64}) + precompile(Tuple{typeof(Plots._update_axis), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Symbol, Int64}) + precompile(Tuple{typeof(Plots._update_axis), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Symbol, Int64}) + precompile(Tuple{typeof(Plots._update_axis_colors), Plots.Axis}) + precompile(Tuple{typeof(Plots._update_axis_colors), Plots.Axis}) + precompile(Tuple{typeof(Plots._update_axis_links), Plots.Plot{Plots.GRBackend}, Plots.Axis, Symbol}) + precompile(Tuple{typeof(Plots._update_axis_links), Plots.Plot{Plots.GRBackend}, Plots.Axis, Symbol}) + precompile(Tuple{typeof(Plots._update_clims), Float64, Float64, Float64, Float64}) + precompile(Tuple{typeof(Plots._update_clims), Float64, Float64, Int64, Int64}) + precompile(Tuple{typeof(Plots._update_min_padding!), Plots.GridLayout}) + precompile(Tuple{typeof(Plots._update_min_padding!), Plots.GridLayout}) + precompile(Tuple{typeof(Plots._update_min_padding!), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_min_padding!), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_plot_args), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._update_plot_args), Plots.Plot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots._update_series_attributes!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_series_attributes!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_series_attributes!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_subplot_args), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Int64, Bool}) + precompile(Tuple{typeof(Plots._update_subplot_args), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Int64, Bool}) + precompile(Tuple{typeof(Plots._update_subplot_args), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}, Int64, Bool}) + precompile(Tuple{typeof(Plots._update_subplot_colors), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_subplot_colors), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_subplot_colors), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots._update_subplot_periphery), Plots.Subplot{Plots.GRBackend}, Array{Any, 1}}) + precompile(Tuple{typeof(Plots._update_subplot_periphery), Plots.Subplot{Plots.GRBackend}, Array{Any, 1}}) + precompile(Tuple{typeof(Plots.addExtension), String, String}) + precompile(Tuple{typeof(Plots.add_layout_pct!), Base.Dict{Symbol, Any}, Expr, Int64, Int64}) + precompile(Tuple{typeof(Plots.add_layout_pct!), Base.Dict{Symbol, Any}, Expr, Int64, Int64}) + precompile(Tuple{typeof(Plots.aliasesAndAutopick), Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Symbol}, Array{Symbol, 1}, Int64}) + precompile(Tuple{typeof(Plots.aliasesAndAutopick), Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Symbol}, Array{Symbol, 1}, Int64}) + precompile(Tuple{typeof(Plots.all3D), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.allAlphas), Int64}) + precompile(Tuple{typeof(Plots.allStyles), Int64}) + precompile(Tuple{typeof(Plots.allStyles), Symbol}) + precompile(Tuple{typeof(Plots.annotate!), Array{Tuple{Int64, Float64, Plots.PlotText}, 1}}) + precompile(Tuple{typeof(Plots.annotations), Array{Any, 1}}) + precompile(Tuple{typeof(Plots.arrow), Int64}) + precompile(Tuple{typeof(Plots.attr!), Plots.Axis}) + precompile(Tuple{typeof(Plots.attr!), Plots.Axis}) + precompile(Tuple{typeof(Plots.attr), Plots.EmptyLayout, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.attr), Plots.EmptyLayout, Symbol}) + precompile(Tuple{typeof(Plots.autopick), Array{ColorTypes.RGBA{Float64}, 1}, Int64}) + precompile(Tuple{typeof(Plots.autopick_ignore_none_auto), Array{Symbol, 1}, Int64}) + precompile(Tuple{typeof(Plots.axis_drawing_info), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.axis_drawing_info), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.axis_drawing_info_3d), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.axis_drawing_info_3d), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.GRBackend}, Symbol, Bool, Bool}) + precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.GRBackend}, Symbol, Bool, Bool}) + precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots.backend), Plots.GRBackend}) + precompile(Tuple{typeof(Plots.backend), Symbol}) + precompile(Tuple{typeof(Plots.backend), Symbol}) + precompile(Tuple{typeof(Plots.backend)}) + precompile(Tuple{typeof(Plots.backend)}) + precompile(Tuple{typeof(Plots.bar), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.bbox!), Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.bbox!), Plots.Subplot{Plots.GRBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.bottom), Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.bottompad), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.build_layout), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.build_layout), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.build_layout), Plots.GridLayout, Int64, Array{Plots.Plot{T} where T<:RecipesBase.AbstractBackend, 1}}) + precompile(Tuple{typeof(Plots.build_layout), Plots.GridLayout, Int64, Array{Plots.Plot{T} where T<:RecipesBase.AbstractBackend, 1}}) + precompile(Tuple{typeof(Plots.build_layout), Plots.GridLayout, Int64}) + precompile(Tuple{typeof(Plots.build_layout), Plots.GridLayout, Int64}) + precompile(Tuple{typeof(Plots.calc_num_subplots), Plots.EmptyLayout}) + precompile(Tuple{typeof(Plots.calc_num_subplots), Plots.GridLayout}) + precompile(Tuple{typeof(Plots.color_or_nothing!), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.color_or_nothing!), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.colorbar_style), Plots.Series}) + precompile(Tuple{typeof(Plots.colorbar_style), Plots.Series}) + precompile(Tuple{typeof(Plots.command_idx), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.compute_gridsize), Int64, Int64, Int64}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{Float64, 1}, Array{Float64, 1}, Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{Float64, 1}, Array{Float64, 1}, Plots.Surface{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{Float64, 1}, typeof(identity), Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{Float64, 1}, typeof(identity), Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{String, 1}, Array{Float64, 1}, Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Array{String, 1}, Array{String, 1}, Plots.Surface{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots.compute_xyz), Nothing, Array{Float64, 1}, Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Nothing, Array{Union{Base.Missing, Float64}, 1}, Nothing}) + precompile(Tuple{typeof(Plots.compute_xyz), Nothing, Nothing, Nothing}) + precompile(Tuple{typeof(Plots.contour), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int}) + precompile(Tuple{typeof(Plots.contour_levels), Plots.Series, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.convertLegendValue), Bool}) + precompile(Tuple{typeof(Plots.convertLegendValue), Symbol}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Array{Array{Float64, 1}, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Array{Array{T, 1} where T, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Array{Float64, 2}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Array{Function, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Array{Function, 1}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convertToAnyVector), Int64, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.convert_sci_unicode), String}) + precompile(Tuple{typeof(Plots.convert_sci_unicode), String}) + precompile(Tuple{typeof(Plots.convert_to_polar), Array{Float64, 1}, Array{Float64, 1}, Tuple{Int64, Float64}}) + precompile(Tuple{typeof(Plots.create_grid), Expr}) + precompile(Tuple{typeof(Plots.create_grid), Expr}) + precompile(Tuple{typeof(Plots.create_grid), Symbol}) + precompile(Tuple{typeof(Plots.create_grid_curly), Expr}) + precompile(Tuple{typeof(Plots.create_grid_curly), Expr}) + precompile(Tuple{typeof(Plots.create_grid_vcat), Expr}) + precompile(Tuple{typeof(Plots.create_grid_vcat), Expr}) + precompile(Tuple{typeof(Plots.default), Symbol}) + precompile(Tuple{typeof(Plots.default_should_widen), Plots.Axis}) + precompile(Tuple{typeof(Plots.default_should_widen), Plots.Axis}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, Array{Any, 1}}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, Array{String, 1}}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, Array{Union{Base.Missing, Float64}, 1}}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, Base.Missing}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, Char}) + precompile(Tuple{typeof(Plots.discrete_value!), Plots.Axis, String}) + precompile(Tuple{typeof(Plots.ensure_gradient!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.ensure_gradient!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.ensure_gradient!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Base.OneTo{Int64}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Base.OneTo{Int64}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Base.UnitRange{Int64}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Float64}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Float64}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Int64}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Int64}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Plots.Surface{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Plots.Surface{Array{Float64, 2}}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Subplot{Plots.GRBackend}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.extendSeriesData), Array{Float64, 1}, Float64}) + precompile(Tuple{typeof(Plots.extractGroupArgs), Array{String, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.fakedata), Int64, Int64}) + precompile(Tuple{typeof(Plots.fakedata), Int64, Int64}) + precompile(Tuple{typeof(Plots.fg_color), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.fg_color), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.filter_data!), Base.Dict{Symbol, Any}, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.filter_data), Array{Float64, 1}, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.filter_data), Base.OneTo{Int64}, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.filter_data), Nothing, Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.font), Int64, Int}) + precompile(Tuple{typeof(Plots.font), String, Int}) + precompile(Tuple{typeof(Plots.font), String, Int}) + precompile(Tuple{typeof(Plots.font), Symbol, Int}) + precompile(Tuple{typeof(Plots.frame), Plots.Animation, Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.frame), Plots.Animation}) + precompile(Tuple{typeof(Plots.get_axis), Plots.Subplot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots.get_axis), Plots.Subplot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Series}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Series}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.GRBackend}, Plots.Series}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.GRBackend}, Plots.Series}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.get_fillalpha), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_fillalpha), Plots.Series}) + precompile(Tuple{typeof(Plots.get_fillcolor), Plots.Series, Float64, Float64, Int64}) + precompile(Tuple{typeof(Plots.get_fillcolor), Plots.Series, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.get_fillcolor), Plots.Series, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.get_linealpha), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_linealpha), Plots.Series}) + precompile(Tuple{typeof(Plots.get_linecolor), Plots.Series, Float64, Float64, Int64}) + precompile(Tuple{typeof(Plots.get_linecolor), Plots.Series, Float64, Float64, Int64}) + precompile(Tuple{typeof(Plots.get_linecolor), Plots.Series, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.get_linecolor), Plots.Series, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.get_linecolor), Plots.Series, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.get_linestyle), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_linestyle), Plots.Series}) + precompile(Tuple{typeof(Plots.get_linewidth), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_linewidth), Plots.Series}) + precompile(Tuple{typeof(Plots.get_markeralpha), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_markercolor), Plots.Series, Float64, Float64, Int64}) + precompile(Tuple{typeof(Plots.get_markercolor), Plots.Series, Float64, Float64, Int64}) + precompile(Tuple{typeof(Plots.get_markerstrokealpha), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_markerstrokecolor), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.get_minor_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Tuple{Array{Float64, 1}, Array{Any, 1}}}) + precompile(Tuple{typeof(Plots.get_minor_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Tuple{Array{Float64, 1}, Array{String, 1}}}) + precompile(Tuple{typeof(Plots.get_minor_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Tuple{Array{Float64, 1}, Array{String, 1}}}) + precompile(Tuple{typeof(Plots.get_series_color), ColorTypes.RGBA{Float64}, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), ColorTypes.RGBA{Float64}, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), ColorTypes.RGBA{Float64}, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), Int64, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), PlotUtils.ColorGradient, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), PlotUtils.ColorGradient, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), Symbol, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), Symbol, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_series_color), Symbol, Plots.Subplot{Plots.GRBackend}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.get_subplot), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.get_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis}) + precompile(Tuple{typeof(Plots.get_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis}) + precompile(Tuple{typeof(Plots.get_xy), Array{Plots.OHLC{T} where T<:Real, 1}, Base.OneTo{Int64}}) + precompile(Tuple{typeof(Plots.get_xy), Plots.OHLC{Float64}, Int64, Float64}) + precompile(Tuple{typeof(Plots.getxy), Plots.Plot{Plots.GRBackend}, Int64}) + precompile(Tuple{typeof(Plots.gr_axis_height), Plots.Subplot{Plots.GRBackend}, Plots.Axis}) + precompile(Tuple{typeof(Plots.gr_axis_width), Plots.Subplot{Plots.GRBackend}, Plots.Axis}) + precompile(Tuple{typeof(Plots.gr_color), ColorTypes.RGBA{Float64}, Type{ColorTypes.RGB{Float64}}}) + precompile(Tuple{typeof(Plots.gr_colorbar_colors), Plots.Series, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_contour_levels), Plots.Series, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_display), Plots.Plot{Plots.GRBackend}, String}) + precompile(Tuple{typeof(Plots.gr_display), Plots.Plot{Plots.GRBackend}, String}) + precompile(Tuple{typeof(Plots.gr_display), Plots.Subplot{Plots.GRBackend}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_display), Plots.Subplot{Plots.GRBackend}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_draw_colorbar), Plots.GRColorbar, Plots.Subplot{Plots.GRBackend}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Float64, Float64, Int64, Plots.Shape}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Float64, Float64, Int64, Symbol}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Float64, Float64, Plots.Shape}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Float64, Float64, Symbol}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Float64, Int64, Plots.Shape}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Float64, Int64, Symbol}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Int64, Int64, Plots.Shape}) + precompile(Tuple{typeof(Plots.gr_draw_marker), Int64, Int64, Int64, Symbol}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Int64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Int64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Int64, 1}, Array{Int64, 1}, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Int64, 1}, Array{Int64, 1}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Base.OneTo{Int64}, Array{Float64, 1}, Tuple{Float64, Float64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Base.OneTo{Int64}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Base.OneTo{Int64}, Array{Float64, 1}, Tuple{Float64, Float64}}) + precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Float64, Float64, Tuple{Float64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.gr_fill_viewport), Array{Float64, 1}, ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_get_color), Plots.Series}) + precompile(Tuple{typeof(Plots.gr_get_color), Plots.Series}) + precompile(Tuple{typeof(Plots.gr_get_ticks_size), Tuple{Array{Float64, 1}, Array{Any, 1}}, Int64}) + precompile(Tuple{typeof(Plots.gr_get_ticks_size), Tuple{Array{Float64, 1}, Array{String, 1}}, Int64}) + precompile(Tuple{typeof(Plots.gr_get_ticks_size), Tuple{Array{Float64, 1}, Array{String, 1}}, Int64}) + precompile(Tuple{typeof(Plots.gr_inqtext), Int64, Int64, String}) + precompile(Tuple{typeof(Plots.gr_inqtext), Int64, Int64, String}) + precompile(Tuple{typeof(Plots.gr_legend_pos), Plots.Subplot{Plots.GRBackend}, Float64, Float64}) + precompile(Tuple{typeof(Plots.gr_polaraxes), Int64, Float64, Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_polyline), Array{Float64, 1}, Array{Float64, 1}, typeof(identity)}) + precompile(Tuple{typeof(Plots.gr_polyline), Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_set_fill), ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_fillcolor), ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_font), Plots.Font}) + precompile(Tuple{typeof(Plots.gr_set_font), Plots.Font}) + precompile(Tuple{typeof(Plots.gr_set_gradient), PlotUtils.ColorGradient}) + precompile(Tuple{typeof(Plots.gr_set_gradient), Plots.Series}) + precompile(Tuple{typeof(Plots.gr_set_gradient), Plots.Series}) + precompile(Tuple{typeof(Plots.gr_set_line), Float64, Symbol, ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_line), Int64, Symbol, ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_line), Int64, Symbol, PlotUtils.ColorGradient}) + precompile(Tuple{typeof(Plots.gr_set_linecolor), PlotUtils.ColorGradient}) + precompile(Tuple{typeof(Plots.gr_set_markercolor), ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_textcolor), ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.gr_set_transparency), ColorTypes.RGBA{Float64}, Float64}) + precompile(Tuple{typeof(Plots.gr_set_transparency), ColorTypes.RGBA{Float64}, Nothing}) + precompile(Tuple{typeof(Plots.gr_set_viewport_cmap), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_set_viewport_polar)}) + precompile(Tuple{typeof(Plots.gr_set_xticks_font), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_set_xticks_font), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_set_yticks_font), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_set_yticks_font), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.gr_text), Float64, Float64, String}) + precompile(Tuple{typeof(Plots.gr_text), Float64, Float64, String}) + precompile(Tuple{typeof(Plots.gr_text_size), String, Int64}) + precompile(Tuple{typeof(Plots.gr_text_size), String, Int64}) + precompile(Tuple{typeof(Plots.gr_text_size), String}) + precompile(Tuple{typeof(Plots.gr_update_colorbar!), Plots.GRColorbar, Plots.Series}) + precompile(Tuple{typeof(Plots.gr_update_colorbar!), Plots.GRColorbar, Plots.Series}) + precompile(Tuple{typeof(Plots.gr_viewport_from_bbox), Plots.Subplot{Plots.GRBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_viewport_from_bbox), Plots.Subplot{Plots.GRBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.gr_w3tondc), Float64, Float64, Float64}) + precompile(Tuple{typeof(Plots.gui), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.guidefont), Plots.Axis}) + precompile(Tuple{typeof(Plots.guidefont), Plots.Axis}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64}, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Plots.Shape, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.handleColors!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.has_attribute_segments), Plots.Series}) + precompile(Tuple{typeof(Plots.has_attribute_segments), Plots.Series}) + precompile(Tuple{typeof(Plots.hascolorbar), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.hascolorbar), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.hasgrid), Symbol, Symbol}) + precompile(Tuple{typeof(Plots.heatmap_edges), Array{Float64, 1}, Symbol, Array{Float64, 1}, Symbol, Tuple{Int64, Int64}}) + precompile(Tuple{typeof(Plots.heatmap_edges), Array{Float64, 1}, Symbol, Bool}) + precompile(Tuple{typeof(Plots.heatmap_edges), Array{Float64, 1}, Symbol, Bool}) + precompile(Tuple{typeof(Plots.heatmap_edges), Array{Float64, 1}, Symbol}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol, Tuple{Int64, Int64}}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol, Bool}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol, Bool}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol, Bool}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol}) + precompile(Tuple{typeof(Plots.heatmap_edges), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Symbol}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Array{Float64, 2}}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Base.StepRange{Int64, Int64}}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Plots.Axis}) + precompile(Tuple{typeof(Plots.ignorenan_extrema), Plots.Axis}) + precompile(Tuple{typeof(Plots.ignorenan_maximum), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.ignorenan_maximum), Base.OneTo{Int64}}) + precompile(Tuple{typeof(Plots.ignorenan_minimum), Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.ignorenan_minimum), Base.OneTo{Int64}}) + precompile(Tuple{typeof(Plots.inline), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.is3d), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.is3d), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.is3d), Symbol}) + precompile(Tuple{typeof(Plots.is_2tuple), Int64}) + precompile(Tuple{typeof(Plots.is_2tuple), Symbol}) + precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Int64, Float64}}) + precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Int64, Int64}}) + precompile(Tuple{typeof(Plots.is_attr_supported), Plots.GRBackend, Symbol}) + precompile(Tuple{typeof(Plots.is_attr_supported), Symbol}) + precompile(Tuple{typeof(Plots.is_marker_supported), Plots.GRBackend, Symbol}) + precompile(Tuple{typeof(Plots.is_marker_supported), Plots.Shape}) + precompile(Tuple{typeof(Plots.is_marker_supported), Plots.Stroke}) + precompile(Tuple{typeof(Plots.is_marker_supported), Symbol}) + precompile(Tuple{typeof(Plots.is_marker_supported), Symbol}) + precompile(Tuple{typeof(Plots.is_scale_supported), Plots.GRBackend, Symbol}) + precompile(Tuple{typeof(Plots.is_seriestype_supported), Plots.GRBackend, Symbol}) + precompile(Tuple{typeof(Plots.is_seriestype_supported), Symbol}) + precompile(Tuple{typeof(Plots.is_seriestype_supported), Symbol}) + precompile(Tuple{typeof(Plots.is_style_supported), Plots.GRBackend, Symbol}) + precompile(Tuple{typeof(Plots.is_uniformly_spaced), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iscontour), Plots.Series}) + precompile(Tuple{typeof(Plots.iscontour), Plots.Series}) + precompile(Tuple{typeof(Plots.isijulia)}) + precompile(Tuple{typeof(Plots.ispolar), Plots.Series}) + precompile(Tuple{typeof(Plots.ispolar), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.isvertical), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.isvertical), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.iter_segments), Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iter_segments), Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iter_segments), Array{Int64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iter_segments), Base.OneTo{Int64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iter_segments), Base.UnitRange{Int64}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.iter_segments), Plots.Series}) + precompile(Tuple{typeof(Plots.iter_segments), Plots.Series}) + precompile(Tuple{typeof(Plots.labelfunc), Symbol, Plots.GRBackend}) + precompile(Tuple{typeof(Plots.layout_args), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.layout_args), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.layout_args), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.layout_args), Int64, Int64}) + precompile(Tuple{typeof(Plots.layout_args), Int64, Plots.GridLayout}) + precompile(Tuple{typeof(Plots.layout_args), Int64, Tuple{Int64, Int64}}) + precompile(Tuple{typeof(Plots.layout_args), Int64}) + precompile(Tuple{typeof(Plots.layout_args), Plots.GridLayout}) + precompile(Tuple{typeof(Plots.leftpad), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.legendfont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.legendfont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.legendtitlefont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.legendtitlefont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.like_histogram), Symbol}) + precompile(Tuple{typeof(Plots.like_surface), Symbol}) + precompile(Tuple{typeof(Plots.link_axes!), Array{RecipesBase.AbstractLayout, 1}, Symbol}) + precompile(Tuple{typeof(Plots.link_axes!), Array{RecipesBase.AbstractLayout, 1}, Symbol}) + precompile(Tuple{typeof(Plots.link_axes!), Plots.Axis, Plots.Axis}) + precompile(Tuple{typeof(Plots.link_axes!), Plots.Axis, Plots.Axis}) + precompile(Tuple{typeof(Plots.link_axes!), Plots.GridLayout, Symbol}) + precompile(Tuple{typeof(Plots.link_axes!), Plots.GridLayout, Symbol}) + precompile(Tuple{typeof(Plots.link_axes!), Plots.Subplot{Plots.GRBackend}, Symbol}) + precompile(Tuple{typeof(Plots.link_subplots), Array{RecipesBase.AbstractLayout, 1}, Symbol}) + precompile(Tuple{typeof(Plots.locate_annotation), Plots.Subplot{Plots.GRBackend}, Int64, Float64, Plots.PlotText}) + precompile(Tuple{typeof(Plots.make_fillrange_from_ribbon), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.make_fillrange_side), Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.make_fillrange_side), Array{Float64, 1}, Int64}) + precompile(Tuple{typeof(Plots.make_steps), Array{Float64, 1}, Symbol}) + precompile(Tuple{typeof(Plots.make_steps), Array{Int64, 1}, Symbol}) + precompile(Tuple{typeof(Plots.make_steps), Base.OneTo{Int64}, Symbol}) + precompile(Tuple{typeof(Plots.make_steps), Nothing, Symbol}) + precompile(Tuple{typeof(Plots.nanappend!), Array{Float64, 1}, Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.nobigs), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.ohlc), Array{Plots.OHLC{T} where T<:Real, 1}}) + precompile(Tuple{typeof(Plots.optimal_ticks_and_labels), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Base.StepRange{Int64, Int64}}) + precompile(Tuple{typeof(Plots.optimal_ticks_and_labels), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Base.UnitRange{Int64}}) + precompile(Tuple{typeof(Plots.optimal_ticks_and_labels), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Nothing}) + precompile(Tuple{typeof(Plots.optimal_ticks_and_labels), Plots.Subplot{Plots.GRBackend}, Plots.Axis, Nothing}) + precompile(Tuple{typeof(Plots.pie_labels), Plots.Subplot{Plots.GRBackend}, Plots.Series}) + precompile(Tuple{typeof(Plots.plotarea!), Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.plotarea!), Plots.Subplot{Plots.GRBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.png), Plots.Plot{Plots.GRBackend}, String}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Float64, 2}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Int32, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Union{Base.Missing, Int64}, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Union{Base.Missing, Number}, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Array{Union{Base.Missing, Number}, 1}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Base.LinRange{Float64}}) + precompile(Tuple{typeof(Plots.prepareSeriesData), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}) + precompile(Tuple{typeof(Plots.prepare_output), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.prepare_output), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.preprocessArgs!), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.preprocessArgs!), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Bool}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Float64}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processGridArg!), Base.Dict{Symbol, Any}, Bool, Symbol}) + precompile(Tuple{typeof(Plots.processGridArg!), Base.Dict{Symbol, Any}, Float64, Symbol}) + precompile(Tuple{typeof(Plots.processGridArg!), Base.Dict{Symbol, Any}, Int64, Symbol}) + precompile(Tuple{typeof(Plots.processGridArg!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Float64}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processLineArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Bool}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64}}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Float64}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Float64}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Int64}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Plots.Shape}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Plots.Stroke}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.processMarkerArg), Base.Dict{Symbol, Any}, Symbol}) + precompile(Tuple{typeof(Plots.process_annotation), Plots.Subplot{Plots.GRBackend}, Int64, Float64, Plots.PlotText, Plots.Font}) + precompile(Tuple{typeof(Plots.process_annotation), Plots.Subplot{Plots.GRBackend}, Int64, Float64, Plots.PlotText}) + precompile(Tuple{typeof(Plots.process_axis_arg!), Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64}, Symbol}) + precompile(Tuple{typeof(Plots.process_axis_arg!), Base.Dict{Symbol, Any}, String, Symbol}) + precompile(Tuple{typeof(Plots.process_axis_arg!), Base.Dict{Symbol, Any}, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.process_axis_arg!), Base.Dict{Symbol, Any}, Tuple{Int64, Int64}, Symbol}) + precompile(Tuple{typeof(Plots.process_fillrange), Int64, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_fillrange), Nothing, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_ribbon), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_ribbon), Int64, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_ribbon), Nothing, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_ribbon), Tuple{Base.LinRange{Float64}, Base.LinRange{Float64}}, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.process_ribbon), typeof(identity), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.recompute_lengths), Array{Measures.Measure, 1}}) + precompile(Tuple{typeof(Plots.recompute_lengths), Array{Measures.Measure, 1}}) + precompile(Tuple{typeof(Plots.replaceAlias!), Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Symbol}}) + precompile(Tuple{typeof(Plots.replaceAliases!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Symbol}}) + precompile(Tuple{typeof(Plots.reset_extrema!), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.reset_extrema!), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.right), Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}}) + precompile(Tuple{typeof(Plots.rightpad), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.rowsize), Expr}) + precompile(Tuple{typeof(Plots.rowsize), Symbol}) + precompile(Tuple{typeof(Plots.series_annotations), Array{Any, 1}}) + precompile(Tuple{typeof(Plots.series_annotations), Nothing}) + precompile(Tuple{typeof(Plots.series_annotations), Plots.SeriesAnnotations}) + precompile(Tuple{typeof(Plots.series_annotations_shapes!), Plots.Series, Symbol}) + precompile(Tuple{typeof(Plots.series_annotations_shapes!), Plots.Series, Symbol}) + precompile(Tuple{typeof(Plots.setxy!), Plots.Plot{Plots.GRBackend}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64}) + precompile(Tuple{typeof(Plots.shape_data), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.shape_data), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.should_add_to_legend), Plots.Series}) + precompile(Tuple{typeof(Plots.should_add_to_legend), Plots.Series}) + precompile(Tuple{typeof(Plots.showaxis), Symbol, Symbol}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Array{Any, 1}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Array{Any, 1}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Bool, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Bool, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Float64, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Float64, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Measures.Length{:mm, Float64}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Measures.Length{:mm, Float64}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Nothing, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Nothing, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, String, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, String, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Symbol, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Symbol, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Tuple{Int64, Int64}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Tuple{Int64, Int64}, Int64, Bool}) + precompile(Tuple{typeof(Plots.slice_arg), Array{ColorTypes.RGBA{Float64}, 2}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Array{Measures.Length{:mm, Float64}, 2}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Array{String, 2}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Array{Symbol, 2}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Base.ReshapedArray{Int64, 2, Base.UnitRange{Int64}, Tuple{}}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Base.StepRange{Int64, Int64}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Base.UnitRange{Int64}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Bool, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), ColorTypes.RGBA{Float64}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Float64, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Int64, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Nothing, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), String, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Symbol, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Tuple{Int64, Float64}, Int64}) + precompile(Tuple{typeof(Plots.slice_arg), Tuple{Int64, Int64}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Array{Int64, 1}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Array{String, 1}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Array{Symbol, 2}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, ColorTypes.RGB{Float64}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Float64, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Int64, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Plots.GridLayout, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Plots.Plot{Plots.GRBackend}, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, String, Int64}) + precompile(Tuple{typeof(Plots.splittable_kw), Symbol, Symbol, Int64}) + precompile(Tuple{typeof(Plots.straightline_data), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.straightline_data), Plots.Series, Int64}) + precompile(Tuple{typeof(Plots.straightline_data), Tuple{Int64, Int64}, Tuple{Float64, Float64}, Array{Float64, 1}, Array{Float64, 1}, Int64}) + precompile(Tuple{typeof(Plots.stroke), Int64, Int}) + precompile(Tuple{typeof(Plots.supported_markers), Plots.GRBackend}) + precompile(Tuple{typeof(Plots.supported_markers)}) + precompile(Tuple{typeof(Plots.supported_styles), Plots.GRBackend}) + precompile(Tuple{typeof(Plots.supported_styles)}) + precompile(Tuple{typeof(Plots.text), String, Int64, Symbol, Symbol}) + precompile(Tuple{typeof(Plots.text), String, Symbol, Int64, Int}) + precompile(Tuple{typeof(Plots.text), String, Symbol}) + precompile(Tuple{typeof(Plots.tickfont), Plots.Axis}) + precompile(Tuple{typeof(Plots.tickfont), Plots.Axis}) + precompile(Tuple{typeof(Plots.title!), String}) + precompile(Tuple{typeof(Plots.titlefont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.titlefont), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.toppad), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.tovec), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.transpose_z), Plots.Series, Array{Float64, 2}, Bool}) + precompile(Tuple{typeof(Plots.trueOrAllTrue), typeof(Plots.is3d), Symbol}) + precompile(Tuple{typeof(Plots.trueOrAllTrue), typeof(identity), Array{Symbol, 2}}) + precompile(Tuple{typeof(Plots.unzip), Array{Tuple{Float64, Float64, Float64}, 1}}) + precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.GridLayout, Array{Measures.Length{:mm, Float64}, 1}}) + precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.GridLayout, Array{Measures.Length{:mm, Float64}, 1}}) + precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.GridLayout}) + precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.GridLayout}) + precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.Subplot{Plots.GRBackend}, Array{Measures.Length{:mm, Float64}, 1}}) + precompile(Tuple{typeof(Plots.update_inset_bboxes!), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.update_inset_bboxes!), Plots.Plot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.vline!), Array{Int64, 1}}) + precompile(Tuple{typeof(Plots.wand_edges), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported_args), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported_args), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported_scales), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.warnOnUnsupported_scales), Plots.GRBackend, Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.widen), Float64, Float64, Symbol}) + precompile(Tuple{typeof(Plots.wrap_surfaces), Base.Dict{Symbol, Any}}) + precompile(Tuple{typeof(Plots.wraptuple), Array{Any, 1}}) + precompile(Tuple{typeof(Plots.wraptuple), Array{Float64, 1}}) + precompile(Tuple{typeof(Plots.wraptuple), Bool}) + precompile(Tuple{typeof(Plots.wraptuple), Float64}) + precompile(Tuple{typeof(Plots.wraptuple), Int64}) + precompile(Tuple{typeof(Plots.wraptuple), Nothing}) + precompile(Tuple{typeof(Plots.wraptuple), Plots.SeriesAnnotations}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Array{Float64, 1}, Array{Float64, 1}}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Array{Symbol, 2}, Int64, Float64, Plots.Stroke}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Array{Symbol, 2}, Int64}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Float64, Array{Symbol, 2}, Int64}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Float64, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Array{Symbol, 2}}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Float64, Symbol, Plots.Stroke}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Float64, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Symbol, Float64, Array{Symbol, 2}}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Symbol, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Int64, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Plots.Shape, Int64, ColorTypes.RGBA{Float64}}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{String, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{String, Tuple{Int64, Int64}, Base.StepRange{Int64, Int64}, Symbol}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Symbol, Float64, Plots.Stroke}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Symbol, Int64}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Symbol, Symbol, Int64, Symbol, Float64}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{Symbol, Symbol, Symbol, Int64, Float64}}) + precompile(Tuple{typeof(Plots.wraptuple), Tuple{}}) + precompile(Tuple{typeof(Plots.xgrid!), Plots.Plot{Plots.GRBackend}, Symbol, Int}) + precompile(Tuple{typeof(Plots.xlims), Int64}) + precompile(Tuple{typeof(Plots.xlims), Int64}) + precompile(Tuple{typeof(Plots.xlims), Plots.Subplot{Plots.GRBackend}}) + precompile(Tuple{typeof(Plots.yaxis!), String, Symbol}) + precompile(Tuple{typeof(Plots.ylims), Int64}) + precompile(Tuple{typeof(Plots.ylims), Int64}) + precompile(Tuple{typeof(Plots.ylims), Plots.Subplot{Plots.GRBackend}}) end diff --git a/src/recipes.jl b/src/recipes.jl index 9be74970..06215cd2 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -239,7 +239,7 @@ end @recipe function f(::Type{Val{:sticks}}, x, y, z) n = length(x) fr = plotattributes[:fillrange] - if fr == nothing + if fr === nothing sp = plotattributes[:subplot] yaxis = sp[:yaxis] fr = if yaxis[:scale] == :identity @@ -291,13 +291,13 @@ end # create segmented bezier curves in place of line segments @recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30) - args = z != nothing ? (x,y,z) : (x,y) + args = z !== nothing ? (x,y,z) : (x,y) newx, newy = zeros(0), zeros(0) fr = plotattributes[:fillrange] - newfr = fr != nothing ? zeros(0) : nothing - newz = z != nothing ? zeros(0) : nothing + newfr = fr !== nothing ? zeros(0) : nothing + newz = z !== nothing ? zeros(0) : nothing # lz = plotattributes[:line_z] - # newlz = lz != nothing ? zeros(0) : nothing + # newlz = lz !== nothing ? zeros(0) : nothing # for each line segment (point series with no NaNs), convert it into a bezier curve # where the points are the control points of the curve @@ -306,13 +306,13 @@ end ts = range(0, stop = 1, length = npoints) nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts)) nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts)) - if z != nothing + if z !== nothing nanappend!(newz, map(t -> bezier_value(_cycle(z,rng), t), ts)) end - if fr != nothing + if fr !== nothing nanappend!(newfr, map(t -> bezier_value(_cycle(fr,rng), t), ts)) end - # if lz != nothing + # if lz !== nothing # lzrng = _cycle(lz, rng) # the line_z's for this segment # push!(newlz, 0.0) # append!(newlz, map(t -> lzrng[1+floor(Int, t * (length(rng)-1))], ts)) @@ -321,16 +321,16 @@ end x := newx y := newy - if z == nothing + if z === nothing seriestype := :path else seriestype := :path3d z := newz end - if fr != nothing + if fr !== nothing fillrange := newfr end - # if lz != nothing + # if lz !== nothing # # line_z := newlz # linecolor := (isa(plotattributes[:linecolor], ColorGradient) ? plotattributes[:linecolor] : cgrad()) # end @@ -357,19 +357,19 @@ end # compute half-width of bars bw = plotattributes[:bar_width] - hw = if bw == nothing + hw = if bw === nothing if nx > 1 0.5*_bar_width*ignorenan_minimum(filter(x->x>0, diff(procx))) else 0.5 * _bar_width end else - Float64[0.5_cycle(bw,i) for i=1:length(procx)] + Float64[0.5_cycle(bw,i) for i=eachindex(procx)] end # make fillto a vector... default fills to 0 fillto = plotattributes[:fillrange] - if fillto == nothing + if fillto === nothing fillto = 0 end if (yscale in _logScales) && !all(_is_positive, fillto) @@ -491,7 +491,7 @@ end @recipe function f(::Type{Val{:barbins}}, x, y, z) edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y) - if (plotattributes[:bar_width] == nothing) + if (plotattributes[:bar_width] === nothing) bar_width := diff(edge) end x := _bin_centers(edge) @@ -533,7 +533,7 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S last_w = eltype(weights)(NaN) - while it_tuple_e != nothing && it_tuple_w != nothing + while it_tuple_e !== nothing && it_tuple_w !== nothing b, it_state_e = it_tuple_e w, it_state_w = it_tuple_w @@ -667,7 +667,7 @@ end function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N localvs = _filternans(vs) edges = _hist_edges(localvs, binning) - h = float( weights == nothing ? + h = float( weights === nothing ? StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) : StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left) ) @@ -746,12 +746,14 @@ end edge_x, edge_y, weights = x, y, z.surf float_weights = float(weights) - if float_weights === weights - float_weights = deepcopy(float_weights) - end - for (i, c) in enumerate(float_weights) - if c == 0 - float_weights[i] = NaN + if !plotattributes[:show_empty_bins] + if float_weights === weights + float_weights = deepcopy(float_weights) + end + for (i, c) in enumerate(float_weights) + if c == 0 + float_weights[i] = NaN + end end end @@ -996,7 +998,7 @@ function get_xy(o::OHLC, x, xdiff) end # get the joined vector -function get_xy(v::AVec{OHLC}, x = 1:length(v)) +function get_xy(v::AVec{OHLC}, x = eachindex(v)) xdiff = 0.3ignorenan_mean(abs.(diff(x))) x_out, y_out = zeros(0), zeros(0) for (i,ohlc) in enumerate(v) @@ -1054,8 +1056,8 @@ end @assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix seriestype := :spy mat = g.args[1] - n,m = size(mat) - Plots.SliceIt, 1:m, 1:n, Surface(mat) + n,m = axes(mat) + Plots.SliceIt, m, n, Surface(mat) end @recipe function f(::Type{Val{:spy}}, x,y,z) @@ -1101,6 +1103,11 @@ timeformatter(t) = string(Dates.Time(Dates.Nanosecond(t))) @recipe f(::Type{Dates.Time}, t::Dates.Time) = (t -> Dates.value(t), timeformatter) @recipe f(::Type{P}, t::P) where P <: Dates.Period = (t -> Dates.value(t), t -> string(P(t))) +# ------------------------------------------------- +# Characters + +@recipe f(::Type{<:AbstractChar}, ::AbstractChar) = (string, string) + # ------------------------------------------------- # Complex Numbers @@ -1178,7 +1185,7 @@ end seriestype := :shape # create a filled polygon for each item - for c=1:size(weights,2) + for c=axes(weights,2) sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1])) sy = vcat(returns, reverse(returns)) @series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx) @@ -1199,9 +1206,9 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f @recipe function f(a::AreaPlot) data = cumsum(a.args[end], dims=2) - x = length(a.args) == 1 ? (1:size(data, 1)) : a.args[1] + x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1] seriestype := :line - for i in 1:size(data, 2) + for i in axes(data, 2) @series begin fillrange := i > 1 ? data[:,i-1] : 0 x, data[:,i] diff --git a/src/series.jl b/src/series.jl index 023c7c4b..be5fc439 100644 --- a/src/series.jl +++ b/src/series.jl @@ -7,46 +7,76 @@ # note: returns meta information... mainly for use with automatic labeling from DataFrames for now const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}} -const DataPoint = Union{Number, AbstractString, Missing} -const SeriesData = Union{AVec{<:DataPoint}, Function, Surface, Volume} +const MaybeNumber = Union{Number, Missing} +const MaybeString = Union{AbstractString, Missing} +const DataPoint = Union{MaybeNumber, MaybeString} prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting") prepareSeriesData(::Nothing) = nothing -prepareSeriesData(s::SeriesData) = handlemissings(s) - -handlemissings(v) = v -handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: Number = replace(v, missing => NaN) -handlemissings(v::AbstractArray{Union{T,Missing}}) where T <: AbstractString = replace(v, missing => "") -handlemissings(s::Surface) = Surface(handlemissings(s.surf)) -handlemissings(v::Volume) = Volume(handlemissings(v.v), v.x_extents, v.y_extents, v.z_extents) +prepareSeriesData(f::Function) = f +prepareSeriesData(a::AbstractArray{<:MaybeNumber}) = replace!( + x -> ismissing(x) || isinf(x) ? NaN : x, + map(float,a)) +prepareSeriesData(a::AbstractArray{<:MaybeString}) = replace(x -> ismissing(x) ? "" : x, a) +prepareSeriesData(s::Surface{<:AMat{<:MaybeNumber}}) = Surface(prepareSeriesData(s.surf)) +prepareSeriesData(s::Surface) = s # non-numeric Surface, such as an image +prepareSeriesData(v::Volume) = Volume(prepareSeriesData(v.v), v.x_extents, v.y_extents, v.z_extents) # default: assume x represents a single series -convertToAnyVector(x) = Any[prepareSeriesData(x)] +convertToAnyVector(x, plotattributes) = Any[prepareSeriesData(x)] # fixed number of blank series -convertToAnyVector(n::Integer) = Any[zeros(0) for i in 1:n] +convertToAnyVector(n::Integer, plotattributes) = Any[zeros(0) for i in 1:n] # vector of data points is a single series -convertToAnyVector(v::AVec{<:DataPoint}) = Any[prepareSeriesData(v)] +convertToAnyVector(v::AVec{<:DataPoint}, plotattributes) = Any[prepareSeriesData(v)] # list of things (maybe other vectors, functions, or something else) -convertToAnyVector(v::AVec) = vcat((convertToAnyVector(vi) for vi in v)...) +function convertToAnyVector(v::AVec, plotattributes) + if all(x -> x isa MaybeNumber, v) + convertToAnyVector(Vector{MaybeNumber}(v), plotattributes) + elseif all(x -> x isa MaybeString, v) + convertToAnyVector(Vector{MaybeString}(v), plotattributes) + else + vcat((convertToAnyVector(vi, plotattributes) for vi in v)...) + end +end # Matrix is split into columns -convertToAnyVector(v::AMat{<:DataPoint}) = Any[prepareSeriesData(v[:,i]) for i in 1:size(v,2)] +function convertToAnyVector(v::AMat{<:DataPoint}, plotattributes) + if all3D(plotattributes) + Any[prepareSeriesData(Surface(v))] + else + Any[prepareSeriesData(v[:, i]) for i in axes(v, 2)] + end +end + +# -------------------------------------------------------------------- +# Fillranges & ribbons + + +process_fillrange(range::Number, plotattributes) = [range] +process_fillrange(range, plotattributes) = convertToAnyVector(range, plotattributes) + +process_ribbon(ribbon::Number, plotattributes) = [ribbon] +process_ribbon(ribbon, plotattributes) = convertToAnyVector(ribbon, plotattributes) +# ribbon as a tuple: (lower_ribbons, upper_ribbons) +process_ribbon(ribbon::Tuple{Any,Any}, plotattributes) = collect(zip(convertToAnyVector(ribbon[1], plotattributes), + convertToAnyVector(ribbon[2], plotattributes))) + # -------------------------------------------------------------------- # TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array # result in that array being shared. push!, etc will add too many items to that array -compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1) -compute_x(x::Nothing, y, z) = 1:size(y,1) +compute_x(x::Nothing, y::Nothing, z) = axes(z,1) +compute_x(x::Nothing, y, z) = axes(y,1) compute_x(x::Function, y, z) = map(x, y) compute_x(x, y, z) = copy(x) # compute_y(x::Void, y::Function, z) = error() -compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2) +compute_y(x::Nothing, y::Nothing, z) = axes(z,2) compute_y(x, y::Function, z) = map(y, x) compute_y(x, y, z) = copy(y) @@ -96,25 +126,17 @@ struct SliceIt end z = z.data end - xs = convertToAnyVector(x) - ys = convertToAnyVector(y) - zs = convertToAnyVector(z) + xs = convertToAnyVector(x, plotattributes) + ys = convertToAnyVector(y, plotattributes) + zs = convertToAnyVector(z, plotattributes) fr = pop!(plotattributes, :fillrange, nothing) - fillranges = if typeof(fr) <: Number - [fr] - else - convertToAnyVector(fr) - end + fillranges = process_fillrange(fr, plotattributes) mf = length(fillranges) rib = pop!(plotattributes, :ribbon, nothing) - ribbons = if typeof(rib) <: Number - [rib] - else - convertToAnyVector(rib) - end + ribbons = process_ribbon(rib, plotattributes) mr = length(ribbons) # @show zs @@ -260,9 +282,9 @@ all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :hea # return a surface if this is a 3d plot, otherwise let it be sliced up @recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat,Missing} if all3D(plotattributes) - n,m = size(mat) + n,m = axes(mat) wrap_surfaces(plotattributes) - SliceIt, 1:m, 1:n, Surface(mat) + SliceIt, m, n, Surface(mat) else SliceIt, nothing, mat, nothing end @@ -272,9 +294,9 @@ end @recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix if all3D(plotattributes) mat = fmt.data - n,m = size(mat) + n,m = axes(mat) wrap_surfaces(plotattributes) - SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter) + SliceIt, m, n, Formatted(Surface(mat), fmt.formatter) else SliceIt, nothing, fmt, nothing end @@ -297,35 +319,35 @@ function clamp_greys!(mat::AMat{T}) where T<:Gray end @recipe function f(mat::AMat{T}) where T<:Gray - n, m = size(mat) + n, m = axes(mat) if is_seriestype_supported(:image) seriestype := :image yflip --> true - SliceIt, 1:m, 1:n, Surface(clamp_greys!(mat)) + SliceIt, m, n, Surface(clamp_greys!(mat)) else seriestype := :heatmap yflip --> true cbar --> false fillcolor --> ColorGradient([:black, :white]) - SliceIt, 1:m, 1:n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.)) + SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.)) end end # # images - colors @recipe function f(mat::AMat{T}) where T<:Colorant - n, m = size(mat) + n, m = axes(mat) if is_seriestype_supported(:image) seriestype := :image yflip --> true - SliceIt, 1:m, 1:n, Surface(mat) + SliceIt, m, n, Surface(mat) else seriestype := :heatmap yflip --> true cbar --> false z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat) - SliceIt, 1:m, 1:n, Surface(z) + SliceIt, m, n, Surface(z) end end @@ -344,23 +366,29 @@ end @recipe function f(shapes::AMat{Shape}) seriestype --> :shape - for j in 1:size(shapes,2) + for j in axes(shapes,2) @series coords(vec(shapes[:,j])) end end +# Dicts: each entry is a data point (x,y)=(key,value) +@recipe f(d::AbstractDict) = collect(keys(d)), collect(values(d)) # function without range... use the current range of the x-axis @recipe function f(f::FuncOrFuncs{F}) where F<:Function plt = plotattributes[:plot_object] - xmin, xmax = try - axis_limits(plt[1], :x) - catch - xinv = invscalefunc(get(plotattributes, :xscale, :identity)) - xm = tryrange(f, xinv.([-5,-1,0,0.01])) - xm, tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01]))) + xmin, xmax = if haskey(plotattributes, :xlims) + plotattributes[:xlims] + else + try + axis_limits(plt[1], :x) + catch + xinv = invscalefunc(get(plotattributes, :xscale, :identity)) + xm = tryrange(f, xinv.([-5,-1,0,0.01])) + xm, tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01]))) + end end f, xmin, xmax @@ -491,20 +519,25 @@ end # # special handling... xmin/xmax with parametric function(s) @recipe function f(f::Function, xmin::Number, xmax::Number) xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)] - xs = _scaled_adapted_grid(f, xscale, yscale, xmin, xmax) - xs, f + _scaled_adapted_grid(f, xscale, yscale, xmin, xmax) end @recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)] - xs = Any[_scaled_adapted_grid(f, xscale, yscale, xmin, xmax) for f in fs] - xs, fs + xs = Array{Any}(undef, length(fs)) + ys = Array{Any}(undef, length(fs)) + for (i, (x, y)) in enumerate(_scaled_adapted_grid(f, xscale, yscale, xmin, xmax) for f in fs) + xs[i] = x + ys[i] = y + end + xs, ys end @recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u) @recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n) function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax) (xf, xinv), (yf, yinv) = ((scalefunc(s),invscalefunc(s)) for s in (xscale,yscale)) - xinv.(adapted_grid(yf∘f∘xinv, xf.((xmin, xmax)))) + xs, ys = adapted_grid(yf∘f∘xinv, xf.((xmin, xmax))) + xinv.(xs), yinv.(ys) end # @@ -550,7 +583,7 @@ end # end splittable_kw(key, val, lengthGroup) = false -splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && size(val,1) == lengthGroup +splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && length(axes(val,1)) == lengthGroup splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup)) splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup) @@ -564,7 +597,7 @@ end function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1]) y_mat = Array{promote_type(eltype(y), typeof(def_val))}(undef, length(keys(x_ind)), length(groupby.groupLabels)) fill!(y_mat, def_val) - for i in 1:length(groupby.groupLabels) + for i in eachindex(groupby.groupLabels) xi = x[groupby.groupIds[i]] yi = y[groupby.groupIds[i]] y_mat[getindex.(Ref(x_ind), xi), i] = yi @@ -597,7 +630,7 @@ group_as_matrix(t) = false if length(g.args) == 1 x = zeros(Int, lengthGroup) for indexes in groupby.groupIds - x[indexes] = 1:length(indexes) + x[indexes] = eachindex(indexes) end last_args = g.args else @@ -605,7 +638,7 @@ group_as_matrix(t) = false last_args = g.args[2:end] end x_u = unique(sort(x)) - x_ind = Dict(zip(x_u, 1:length(x_u))) + x_ind = Dict(zip(x_u, eachindex(x_u))) for (key,val) in plotattributes if splittable_kw(key, val, lengthGroup) :($key) := groupedvec2mat(x_ind, x, val, groupby) diff --git a/src/themes.jl b/src/themes.jl index 592d0a78..4f47039b 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -4,39 +4,19 @@ Specify the colour theme for plots. """ function theme(s::Symbol; kw...) - defaults = _get_defaults(s) + defaults = copy(PlotThemes._themes[s].defaults) _theme(s, defaults; kw...) end -function _get_defaults(s::Symbol) - thm = PlotThemes._themes[s] - if :defaults in fieldnames(typeof(thm)) - return thm.defaults - else # old PlotTheme type - defaults = KW( - :bg => thm.bg_secondary, - :bginside => thm.bg_primary, - :fg => thm.lines, - :fgtext => thm.text, - :fgguide => thm.text, - :fglegend => thm.text, - :palette => thm.palette, - ) - if thm.gradient != nothing - push!(defaults, :gradient => thm.gradient) - end - return defaults - end -end - function _theme(s::Symbol, defaults::KW; kw...) # Reset to defaults to overwrite active theme reset_defaults() # Set the theme's gradient as default - if haskey(defaults, :gradient) + if haskey(defaults, :colorgradient) PlotUtils.clibrary(:misc) PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s)) + pop!(defaults, :colorgradient) else PlotUtils.clibrary(:Plots) PlotUtils.default_cgrad(default = :sequential, sequential = :inferno) @@ -44,8 +24,8 @@ function _theme(s::Symbol, defaults::KW; kw...) # maybe overwrite the theme's gradient kw = KW(kw) - if haskey(kw, :gradient) - kwgrad = pop!(kw, :gradient) + if haskey(kw, :colorgradient) + kwgrad = pop!(kw, :colorgradient) for clib in clibraries() if kwgrad in cgradients(clib) PlotUtils.clibrary(clib) @@ -74,11 +54,11 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func @recipe function showtheme(st::ShowTheme) thm, cfunc = _get_showtheme_args(st.args...) - defaults = _get_defaults(thm) + defaults = PlotThemes._themes[thm].defaults # get the gradient - gradient_colors = get(defaults, :gradient, cgrad(:inferno).colors) - gradient = cgrad(cfunc.(RGB.(gradient_colors))) + gradient_colors = get(defaults, :colorgradient, cgrad(:inferno).colors) + colorgradient = cgrad(cfunc.(RGB.(gradient_colors))) # get the palette palette = get(defaults, :palette, get_color_palette(:auto, plot_color(:white), 17)) @@ -86,7 +66,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func # apply the theme for k in keys(defaults) - k in (:gradient, :palette) && continue + k in (:colorgradient, :palette) && continue def = defaults[k] arg = get(_keyAliases, k, k) plotattributes[arg] = if typeof(def) <: Colorant @@ -139,27 +119,30 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func @series begin subplot := 4 seriestype := :heatmap - seriescolor := gradient - ticks := -5:5:5 + seriescolor := colorgradient + xticks := (-2π:2π:2π, string.(-2:2:2, "π")) + yticks := (-2π:2π:2π, string.(-2:2:2, "π")) x, y, z end @series begin subplot := 5 seriestype := :surface - seriescolor := gradient + seriescolor := colorgradient + xticks := (-2π:2π:2π, string.(-2:2:2, "π")) + yticks := (-2π:2π:2π, string.(-2:2:2, "π")) x, y, z end n = 100 ts = range(0, stop = 10π, length = n) - x = ts .* cos.(ts) + x = (0.1ts) .* cos.(ts) y = (0.1ts) .* sin.(ts) z = 1:n @series begin subplot := 6 - seriescolor := gradient + seriescolor := colorgradient linewidth := 3 line_z := z x, y, z diff --git a/src/utils.jl b/src/utils.jl index 666c878d..04ec2cae 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -26,7 +26,7 @@ function histogramHack(; kw...) plotattributes[:x] = midpoints plotattributes[:y] = float(counts) plotattributes[:seriestype] = :bar - plotattributes[:fillrange] = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange] + plotattributes[:fillrange] = plotattributes[:fillrange] === nothing ? 0.0 : plotattributes[:fillrange] plotattributes end @@ -38,12 +38,12 @@ function barHack(; kw...) plotattributes = KW(kw) midpoints = plotattributes[:x] heights = plotattributes[:y] - fillrange = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange] + fillrange = plotattributes[:fillrange] === nothing ? 0.0 : plotattributes[:fillrange] # estimate the edges dists = diff(midpoints) * 0.5 edges = zeros(length(midpoints)+1) - for i in 1:length(edges) + for i in eachindex(edges) if i == 1 edge = midpoints[1] - dists[1] elseif i == length(edges) @@ -56,7 +56,7 @@ function barHack(; kw...) x = Float64[] y = Float64[] - for i in 1:length(heights) + for i in eachindex(heights) e1, e2 = edges[i:i+1] append!(x, [e1, e1, e2, e2]) append!(y, [fillrange, heights[i], heights[i], fillrange]) @@ -81,7 +81,7 @@ function sticksHack(; kw...) # these are the line vertices x = Float64[] y = Float64[] - fillrange = plotattributesLine[:fillrange] == nothing ? 0.0 : plotattributesLine[:fillrange] + fillrange = plotattributesLine[:fillrange] === nothing ? 0.0 : plotattributesLine[:fillrange] # calculate the vertices yScatter = plotattributesScatter[:y] @@ -115,7 +115,6 @@ function regressionXY(x, y) end function replace_image_with_heatmap(z::Array{T}) where T<:Colorant - @show T, size(z) n, m = size(z) # idx = 0 colors = ColorGradient(vec(z)) @@ -146,16 +145,18 @@ end Segments() = Segments(Float64) Segments(::Type{T}) where {T} = Segments(T[]) -Segments(p::Int) = Segments(NTuple{2,Float64}[]) +Segments(p::Int) = Segments(NTuple{p, Float64}[]) # Segments() = Segments(zeros(0)) to_nan(::Type{Float64}) = NaN 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] function Base.push!(segments::Segments{T}, vs...) where T if !isempty(segments.pts) @@ -183,24 +184,26 @@ end mutable struct SegmentsIterator args::Tuple - n::Int + n1::Int + n2::Int end function iter_segments(args...) tup = Plots.wraptuple(args) - n = maximum(map(length, tup)) - SegmentsIterator(tup, n) + n1 = minimum(map(firstindex, tup)) + n2 = maximum(map(lastindex, tup)) + SegmentsIterator(tup, n1, n2) end function iter_segments(series::Series) x, y, z = series[:x], series[:y], series[:z] - if x == nothing + if x === nothing return UnitRange{Int}[] elseif has_attribute_segments(series) if series[:seriestype] in (:scatter, :scatter3d) - return [[i] for i in 1:length(y)] + return [[i] for i in eachindex(y)] else - return [i:(i + 1) for i in 1:(length(y) - 1)] + return [i:(i + 1) for i in firstindex(y):lastindex(y)-1] end else segs = UnitRange{Int}[] @@ -218,13 +221,13 @@ 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::SegmentsIterator, nextidx::Int = 1) - i = findfirst(!anynan(itr.args), nextidx:itr.n) +function Base.iterate(itr::SegmentsIterator, nextidx::Int = itr.n1) + i = findfirst(!anynan(itr.args), nextidx:itr.n2) i === nothing && return nothing nextval = nextidx + i - 1 - j = findfirst(anynan(itr.args), nextval:itr.n) - nextnan = j === nothing ? itr.n + 1 : nextval + j - 1 + j = findfirst(anynan(itr.args), nextval:itr.n2) + nextnan = j === nothing ? itr.n2 + 1 : nextval + j - 1 nextval:nextnan-1, nextnan end @@ -343,8 +346,11 @@ const _scale_base = Dict{Symbol, Real}( :ln => ℯ, ) -function _heatmap_edges(v::AVec) +function _heatmap_edges(v::AVec, isedges::Bool = false) length(v) == 1 && return v[1] .+ [-0.5, 0.5] + 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 = (v[2] - v[1]) / 2 extra_max = (v[end] - v[end - 1]) / 2 @@ -352,9 +358,30 @@ function _heatmap_edges(v::AVec) end "create an (n+1) list of the outsides of heatmap rectangles" -function heatmap_edges(v::AVec, scale::Symbol = :identity) +function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false) f, invf = scalefunc(scale), invscalefunc(scale) - map(invf, _heatmap_edges(map(f,v))) + map(invf, _heatmap_edges(map(f,v), isedges)) +end + +function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int}) + 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. + ismidpoints = prod(z_size) == (ny * nx) + isedges = z_size == (ny - 1, nx - 1) + if !ismidpoints && !isedges + error("""Length of x & y does not match the size of z. + 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) + return x, y +end + +function is_uniformly_spaced(v; tol=1e-6) + dv = diff(v) + maximum(dv) - minimum(dv) < tol * mean(abs.(dv)) end function convert_to_polar(theta, r, r_extrema = ignorenan_extrema(r)) @@ -478,7 +505,7 @@ function make_fillrange_from_ribbon(kw::KW) rib1, rib2 = -first(rib), last(rib) # kw[:ribbon] = nothing kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2) - (get(kw, :fillalpha, nothing) == nothing) && (kw[:fillalpha] = 0.5) + (get(kw, :fillalpha, nothing) === nothing) && (kw[:fillalpha] = 0.5) end #turn tuple of fillranges to one path @@ -524,14 +551,9 @@ zlims(sp_idx::Int = 1) = zlims(current(), sp_idx) function get_clims(sp::Subplot) zmin, zmax = Inf, -Inf - z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface) for series in series_list(sp) - 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, ignorenan_extrema(vals.surf)...) - elseif (vals != nothing) && (eltype(vals) <: Union{Missing, Real}) - zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...) - end + if series[:colorbar_entry] + zmin, zmax = _update_clims(zmin, zmax, get_clims(series)...) end end clims = sp[:clims] @@ -539,10 +561,37 @@ function get_clims(sp::Subplot) isfinite(clims[1]) && (zmin = clims[1]) isfinite(clims[2]) && (zmax = clims[2]) end - return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1) + return zmin <= zmax ? (zmin, zmax) : (NaN, NaN) end -_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax) +function get_clims(sp::Subplot, series::Series) + zmin, zmax = if series[:colorbar_entry] + get_clims(sp) + else + get_clims(series) + end + clims = sp[:clims] + if is_2tuple(clims) + isfinite(clims[1]) && (zmin = clims[1]) + isfinite(clims[2]) && (zmax = clims[2]) + end + return zmin <= zmax ? (zmin, zmax) : (NaN, NaN) +end + +function get_clims(series::Series) + zmin, zmax = Inf, -Inf + z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface) + 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, ignorenan_extrema(vals.surf)...) + elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real}) + zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...) + end + end + return zmin <= zmax ? (zmin, zmax) : (NaN, NaN) +end + +_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax) @enum ColorbarStyle cbar_gradient cbar_fill cbar_lines @@ -602,7 +651,7 @@ for comp in (:line, :fill, :marker) function $get_compcolor(series, cmin::Real, cmax::Real, i::Int = 1) c = series[$Symbol($compcolor)] z = series[$Symbol($comp_z)] - if z == nothing + if z === nothing isa(c, ColorGradient) ? c : plot_color(_cycle(c, i)) else grad = isa(c, ColorGradient) ? c : cgrad() @@ -613,7 +662,7 @@ for comp in (:line, :fill, :marker) $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 + if series[$Symbol($comp_z)] === nothing $get_compcolor(series, 0, 1, i) else $get_compcolor(series, get_clims(series[:subplot]), i) @@ -650,11 +699,11 @@ function has_attribute_segments(series::Series) for letter in (:x, :y, :z) # If we have NaNs in the data they define the segments and # SegmentsIterator is used - series[letter] != nothing && NaN in collect(series[letter]) && return false + series[letter] !== nothing && NaN in collect(series[letter]) && return false end series[:seriestype] == :shape && return false # ... else we check relevant attributes if they have multiple inputs - return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z)) + return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :linestyle, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z)) end # --------------------------------------------------------------- @@ -1060,6 +1109,15 @@ legendfont(sp::Subplot) = font( sp[:legendfontcolor], ) +legendtitlefont(sp::Subplot) = font( + sp[:legendtitlefontfamily], + sp[:legendtitlefontsize], + sp[:legendtitlefontvalign], + sp[:legendtitlefonthalign], + sp[:legendtitlefontrotation], + sp[:legendtitlefontcolor], +) + tickfont(ax::Axis) = font( ax[:tickfontfamily], ax[:tickfontsize], @@ -1106,20 +1164,20 @@ function convert_sci_unicode(label::AbstractString) label end -function straightline_data(series) +function straightline_data(series, expansion_factor = 1) sp = series[:subplot] xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp)) x, y = series[:x], series[:y] n = length(x) if n == 2 - return straightline_data(xl, yl, x, y) + return straightline_data(xl, yl, x, y, expansion_factor) else k, r = divrem(n, 3) if r == 0 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]) + xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds], expansion_factor) end return xdata, ydata else @@ -1128,7 +1186,7 @@ function straightline_data(series) end end -function straightline_data(xl, yl, x, y) +function straightline_data(xl, yl, x, y, expansion_factor = 1) x_vals, y_vals = if y[1] == y[2] if x[1] == x[2] error("Two identical points cannot be used to describe a straight line.") @@ -1149,29 +1207,28 @@ function straightline_data(xl, yl, x, y) end # expand the data outside the axis limits, by a certain factor too improve # plotly(js) and interactive behaviour - factor = 100 - x_vals = x_vals .+ (x_vals[2] - x_vals[1]) .* factor .* [-1, 1] - y_vals = y_vals .+ (y_vals[2] - y_vals[1]) .* factor .* [-1, 1] + x_vals = x_vals .+ (x_vals[2] - x_vals[1]) .* expansion_factor .* [-1, 1] + y_vals = y_vals .+ (y_vals[2] - y_vals[1]) .* expansion_factor .* [-1, 1] return x_vals, y_vals end -function shape_data(series) +function shape_data(series, expansion_factor = 1) sp = series[:subplot] xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp)) x, y = series[:x], series[:y] factor = 100 for i in eachindex(x) if x[i] == -Inf - x[i] = xl[1] - factor * (xl[2] - xl[1]) + x[i] = xl[1] - expansion_factor * (xl[2] - xl[1]) elseif x[i] == Inf - x[i] = xl[2] + factor * (xl[2] - xl[1]) + x[i] = xl[2] + expansion_factor * (xl[2] - xl[1]) end end for i in eachindex(y) if y[i] == -Inf - y[i] = yl[1] - factor * (yl[2] - yl[1]) + y[i] = yl[1] - expansion_factor * (yl[2] - yl[1]) elseif y[i] == Inf - y[i] = yl[2] + factor * (yl[2] - yl[1]) + y[i] = yl[2] + expansion_factor * (yl[2] - yl[1]) end end return x, y diff --git a/test/imgcomp.jl b/test/imgcomp.jl index 206b8d50..e7151573 100644 --- a/test/imgcomp.jl +++ b/test/imgcomp.jl @@ -1,34 +1,6 @@ import Plots._current_plots_version -# Taken from MakieGallery -""" -Downloads the reference images from ReferenceImages for a specific version -""" -function download_reference(version = v"0.0.1") - download_dir = abspath(@__DIR__, "reference_images") - isdir(download_dir) || mkpath(download_dir) - tarfile = joinpath(download_dir, "reference_images.zip") - url = "https://github.com/JuliaPlots/PlotReferenceImages.jl/archive/v$(version).tar.gz" - refpath = joinpath(download_dir, "PlotReferenceImages.jl-$(version)") - if !isdir(refpath) # if not yet downloaded - @info "downloading reference images for version $version" - download(url, tarfile) - BinaryProvider.unpack(tarfile, download_dir) - # check again after download - if !isdir(refpath) - error("Something went wrong while downloading reference images. Plots can't be compared to references") - else - rm(tarfile, force = true) - end - else - @info "using reference images for version $version (already downloaded)" - end - refpath -end - -const ref_image_dir = download_reference() - -function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2) +function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = !is_ci(), sigma = [1,1], tol = 1e-2) Plots._debugMode.on = debug example = Plots._examples[idx] Plots.theme(:default) @@ -39,36 +11,9 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is # ensure consistent results Random.seed!(1234) - # reference image directory setup - refdir = joinpath(ref_image_dir, "Plots", string(pkg)) fn = "ref$idx.png" - - # firgure out version info - vns = filter(x->x[1] != '.', readdir(refdir)) - versions = sort(VersionNumber.(vns), rev = true) - versions = filter(v -> v <= _current_plots_version, versions) - # @show refdir fn versions - - newdir = joinpath(refdir, string(_current_plots_version)) - newfn = joinpath(newdir, fn) - - # figure out which reference file we should compare to, by finding the highest versioned file - reffn = nothing - for v in versions - tmpfn = joinpath(refdir, string(v), fn) - if isfile(tmpfn) - reffn = tmpfn - break - end - end - - # now we have the fn (if any)... do the comparison - # @show reffn - if reffn == nothing - reffn = newfn - end - # @show reffn - # return + reffn = reference_file(pkg, idx, _current_plots_version) + newfn = joinpath(reference_path(pkg, _current_plots_version), fn) # test function func = (fn, idx) -> begin @@ -78,13 +23,6 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is png(fn) end - # try - # run(`mkdir -p $newdir`) - # catch err - # display(err) - # end - # # reffn = joinpath(refdir, "ref$idx.png") - # the test vtest = VisualTest(func, reffn, idx) test_images(vtest, popup=popup, sigma=sigma, tol=tol, newfn = newfn) @@ -98,7 +36,7 @@ function image_comparison_facts(pkg::Symbol; tol = 1e-2) # acceptable error (percent) for i in 1:length(Plots._examples) i in skip && continue - if only == nothing || i in only + if only === nothing || i in only @test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, tol=tol) |> success == true end end diff --git a/test/runtests.jl b/test/runtests.jl index 0b73b148..16ad485f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,40 +1,74 @@ +import ImageMagick using VisualRegressionTests using Plots using Random -using BinaryProvider using Test using FileIO +using Gtk +using LibGit2 using GeometryTypes +include("test_pgfplotsx.jl") + +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) + + reffn = joinpath(refdir, string(version), fn) + for v in versions + tmpfn = joinpath(refdir, string(v), fn) + if isfile(tmpfn) + reffn = tmpfn + break + end + end + + return reffn +end + +reference_path(backend, version) = reference_dir("Plots", string(backend), string(version)) + +if !isdir(reference_dir()) + mkpath(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!(1234) default(show=false, reuse=true) -img_tol = isinteractive() ? 1e-2 : 10e-2 +is_ci() = get(ENV, "CI", "false") == "true" +img_tol = is_ci() ? 10e-2 : 10e-2 -@testset "GR" begin - ENV["PLOTS_TEST"] = "true" - ENV["GKSwstype"] = "100" - @test gr() == Plots.GRBackend() - @test backend() == Plots.GRBackend() +@testset "Backends" begin - @static if Sys.islinux() - image_comparison_facts(:gr, tol=img_tol, skip = [25, 30]) + @testset "GR" begin + ENV["PLOTS_TEST"] = "true" + ENV["GKSwstype"] = "100" + @test gr() == Plots.GRBackend() + @test backend() == Plots.GRBackend() + + @static if Sys.islinux() + image_comparison_facts(:gr, tol=img_tol, skip = Plots._backend_skips[:gr]) + end end -end + @testset "UnicodePlots" begin + @test unicodeplots() == Plots.UnicodePlotsBackend() + @test backend() == Plots.UnicodePlotsBackend() -@testset "UnicodePlots" begin - @test unicodeplots() == Plots.UnicodePlotsBackend() - @test backend() == Plots.UnicodePlotsBackend() + # lets just make sure it runs without error + p = plot(rand(10)) + @test isa(p, Plots.Plot) == true + @test isa(display(p), Nothing) == true + p = bar(randn(10)) + @test isa(p, Plots.Plot) == true + @test isa(display(p), Nothing) == true + end - # lets just make sure it runs without error - p = plot(rand(10)) - @test isa(p, Plots.Plot) == true - @test isa(display(p), Nothing) == true - p = bar(randn(10)) - @test isa(p, Plots.Plot) == true - @test isa(display(p), Nothing) == true end @testset "Axes" begin @@ -61,6 +95,14 @@ end for plt in plots display(plt) end + @test_nowarn plot(x->x^2,0,2) +end + +@testset "EmptyAnim" begin + anim = @animate for i in [] + end + + @test_throws ArgumentError gif(anim) end @testset "Segments" begin @@ -90,6 +132,6 @@ end [(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(Point.(z))...)), z) + @test isequal(collect(zip(Plots.unzip(GeometryTypes.Point.(z))...)), z) end end diff --git a/test/test_pgfplotsx.jl b/test/test_pgfplotsx.jl new file mode 100644 index 00000000..91456fe3 --- /dev/null +++ b/test/test_pgfplotsx.jl @@ -0,0 +1,166 @@ +using Plots, Test +pgfplotsx() + +function create_plot( args...; kwargs... ) + 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) +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") + + @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=(:heat, 0.8, Plots.stroke(1, :green)), ms=10 * abs.(y .- 0.5) .+ 4, lab="grad") + Plots._update_plot_object(pl) + axis = Plots.pgfx_axes(pl.o)[1] + @test count( x->x isa PGFPlotsX.LegendEntry, axis.contents ) == 5 + @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"] == 1 + end # testset + @testset "Plot in pieces" begin + plot(rand(100) / 3, reg=true, fill=(0, :green)) + scatter!(rand(100), markersize=6, c=:orange) + 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 :heat :lightrainbow], 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 + + 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=:bluesreds, 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) + plot(y, annotations=(3, y[3], Plots.text("this is \\#3", :left)), leg=false) + annotate!([(5, y[5], Plots.text("this is \\#5", 16, :red, :center)), (10, y[10], Plots.text("this is \\#10", :right, 20, "courier"))]) + 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)]) + # mktempdir() do path + # @test_nowarn savefig(annotation_plot, path*"annotation.pdf") + # 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) == 4 + @test !haskey(plots[1].options.dict, "fill") + @test !haskey(plots[2].options.dict, "fill") + @test !haskey(plots[3].options.dict, "fill") + @test haskey(plots[4].options.dict, "fill") + @test ribbon_plot.o !== nothing + @test ribbon_plot.o.the_plot !== nothing + # mktempdir() do path + # @test_nowarn savefig(ribbon_plot, path*"ribbon.svg") + # end + end # testset + end # testset