Merge remote-tracking branch 'upstream/master' into HEAD

This commit is contained in:
t-bltg 2021-07-03 15:23:43 +02:00
commit 6cc37ff049
64 changed files with 6957 additions and 4710 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
# Set default behaviour to automatically normalize line endings.
* text=auto
# Force bash scripts to always use lf line endings so that if a repo is accessed
# in Unix via a file share from Windows, the scripts will work.
*.sh text eol=lf

View File

@ -7,7 +7,7 @@ assignees: ''
--- ---
Please search existing issues to avoid duplicates. <!-- Please search existing issues to avoid duplicates. -->
## Details ## Details
@ -28,5 +28,5 @@ inspectdr | | |
### Versions ### Versions
Plots.jl version: Plots.jl version:
Backend version: Backend version (`]st -m <backend(s)>`):
Output of `versioninfo()`: Output of `versioninfo()`:

View File

@ -2,23 +2,16 @@ name: CompatHelper
on: on:
schedule: schedule:
- cron: '00 * * * *' - cron: '00 00 * * *'
jobs: jobs:
CompatHelper: CompatHelper:
runs-on: ${{ matrix.os }} runs-on: ubuntu-latest
strategy:
matrix:
julia-version: [1.2.0]
julia-arch: [x86]
os: [ubuntu-latest]
steps: steps:
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}
- name: Pkg.add("CompatHelper") - name: Pkg.add("CompatHelper")
run: julia -e 'using Pkg; Pkg.add("CompatHelper")' run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
- name: CompatHelper.main() - name: CompatHelper.main()
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} # optional
run: julia -e 'using CompatHelper; CompatHelper.main()' run: julia -e 'using CompatHelper; CompatHelper.main()'

89
.github/workflows/SnoopCompile.yml vendored Normal file
View File

@ -0,0 +1,89 @@
name: SnoopCompile
on:
push:
branches:
# - 'master' # NOTE: to run the bot only on pushes to master
defaults:
run:
shell: bash
jobs:
SnoopCompile:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
GKS_ENCODING: "utf8"
GKSwstype: "100"
PLOTS_TEST: "true"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version: # NOTE: the versions below should match those in your botconfig
- '1'
os: # NOTE: should match the os setting of your botconfig
- ubuntu-latest
arch:
- x64
steps:
# Setup environment
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.version }}
- name: Install dependencies
run: |
julia --project -e 'using Pkg; Pkg.instantiate();'
julia -e 'using Pkg; Pkg.add( PackageSpec(name = "CompileBot", version = "1") ); Pkg.develop(PackageSpec(; path=pwd())); using CompileBot; CompileBot.addtestdep();'
# TESTCMD
- name: Default TESTCMD
run: echo "TESTCMD=julia" >> $GITHUB_ENV
- name: Ubuntu TESTCMD
if: startsWith(matrix.os,'ubuntu')
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
# Generate precompile files
- name: Generating precompile files
run: $TESTCMD --project -e 'include("deps/SnoopCompile/snoop_bot.jl")' # NOTE: must match path
# Run benchmarks
- name: Running Benchmark
run: $TESTCMD --project -e 'include("deps/SnoopCompile/snoop_bench.jl")' # NOTE: optional, if have benchmark file
- name: Upload all
uses: actions/upload-artifact@v2.0.1
with:
path: ./
Create_PR:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
needs: SnoopCompile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Download all
uses: actions/download-artifact@v2
- name: CompileBot postprocess
run: julia -e 'using Pkg; Pkg.add( PackageSpec(name = "CompileBot", version = "1") ); using CompileBot; CompileBot.postprocess();'
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Update precompile_*.jl file
title: "[AUTO] Update precompiles"
labels: SnoopCompile
branch: "Test_SnoopCompile_AutoPR_${{ github.ref }}"
Skip:
if: "contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
steps:
- name: Skip CI 🚫
run: echo skip ci

View File

@ -1,9 +1,12 @@
name: TagBot name: TagBot
on: on:
schedule: issue_comment:
- cron: 0 * * * * types:
- created
workflow_dispatch:
jobs: jobs:
TagBot: TagBot:
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: JuliaRegistries/TagBot@v1 - uses: JuliaRegistries/TagBot@v1

34
.github/workflows/benchmark.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Run benchmarks
on:
pull_request:
jobs:
Benchmark:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
GKS_ENCODING: "utf8"
GKSwstype: "100"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: 1
## Setup
- name: Ubuntu TESTCMD
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
- name: Install Plots dependencies
uses: julia-actions/julia-buildpkg@latest
- name: Install Benchmarking dependencies
run: julia -e 'using Pkg; pkg"add PkgBenchmark BenchmarkCI@0.1"'
- name: Run benchmarks
run: $TESTCMD -e 'using BenchmarkCI; BenchmarkCI.judge()'
- name: Print judgement
run: julia -e 'using BenchmarkCI; BenchmarkCI.displayjudgement()'
- name: Post results
run: julia -e 'using BenchmarkCI; BenchmarkCI.postjudge()'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

89
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,89 @@
name: ci
on:
push:
pull_request:
defaults:
run:
shell: bash
jobs:
CI:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
GKS_ENCODING: "utf8"
GKSwstype: "100"
name: Julia ${{ matrix.version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.version == 'nightly' }}
strategy:
fail-fast: false
matrix:
version:
- '1'
- 'nightly'
os:
- ubuntu-latest
- windows-latest
- macos-latest
arch:
- x64
# - x86
steps:
# Setup environment
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.version }}
- name: Cache artifacts
uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
## maybe required if we ever want to run graphical tests for plotly
# OS Dependencies
# - name: Ubuntu OS dependencies
# if: startsWith(matrix.os,'ubuntu')
# run: |
# ./test/install_wkhtmltoimage.sh
# TESTCMD
- name: Default TESTCMD
run: echo "TESTCMD=julia" >> $GITHUB_ENV
- name: Ubuntu TESTCMD
if: startsWith(matrix.os,'ubuntu')
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
# Julia Dependencies
- name: Install Julia dependencies
uses: julia-actions/julia-buildpkg@latest
# Run tests
- name: Run Graphical test
run: |
$TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true);'
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots");'
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes");'
- name: Codecov
uses: julia-actions/julia-uploadcodecov@latest
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Skip:
if: "contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
steps:
- name: Skip CI 🚫
run: echo skip ci

50
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: docs
on:
push:
branches:
- master
tags: '*'
jobs:
Build_docs:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
repository: JuliaPlots/PlotDocs.jl
- uses: julia-actions/setup-julia@v1
- name: Cache artifacts
uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y qt5-default \
ttf-mscorefonts-installer \
poppler-utils \
pdf2svg \
texlive-latex-base \
texlive-binaries \
texlive-pictures \
texlive-latex-extra \
texlive-luatex \
ghostscript-x \
libgconf2-4
sudo fc-cache -vr
- name: build documentation
env:
PYTHON: ""
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
run: |
xvfb-run julia --color=yes --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.add(PackageSpec(name="Plots", rev=split(ENV["GITHUB_REF"], "/", limit=3)[3])); Pkg.instantiate()'
xvfb-run julia --color=yes --project=docs/ -e 'withenv("GITHUB_REPOSITORY" => "JuliaPlots/PlotDocs.jl") do; include("docs/make.jl"); end'

5
.gitignore vendored
View File

@ -4,9 +4,12 @@
.DS_Store .DS_Store
examples/.ipynb_checkpoints/* examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/* examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js deps/plotly-*
deps/build.log deps/build.log
deps/deps.jl deps/deps.jl
Manifest.toml Manifest.toml
dev/ dev/
test/tmpplotsave.hdf5 test/tmpplotsave.hdf5
/.benchmarkci
/benchmark/*.json
.vscode/

View File

@ -1,44 +0,0 @@
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
- linux
# - osx
julia:
- 1.0
- 1
- nightly
matrix:
allow_failures:
- julia: nightly
addons:
apt:
packages:
- at-spi2-core
- libgtk-3-dev
- xauth
- xvfb
env:
- GKS_ENCODING="utf8"
cache:
directories:
- $HOME/.julia/artifacts
sudo: required
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
notifications:
email: true
after_success:
- julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(process_folder())'
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)'

697
.zenodo.json Normal file
View File

@ -0,0 +1,697 @@
{
"title": "Plots.jl",
"license": "MIT",
"creators": [
{
"affiliation": "Elemental Cognition",
"name": "Tom Breloff"
}
],
"contributors":[
{
"affiliation": "TU Wien",
"name": "Daniel Schwabeneder",
"orcid": "0000-0002-0412-0777",
"type": "ProjectLeader"
},
{
"affiliation": "GLOBE Institute",
"name": "Michael Krabbe Borregaard",
"type": "ProjectLeader"
},
{
"affiliation": "Leibniz Universit\u00e4t Hannover",
"name": "Simon Christ",
"orcid": "0000-0002-5866-1472",
"type": "ProjectLeader"
},
{
"affiliation": "Forschungszentrum J\u00fclich",
"name": "Josef Heinen",
"orcid": "0000-0001-6509-1925",
"type": "ProjectMember"
},
{
"name": "Yuval",
"type": "Other"
},
{
"name": "Andrew Palugniok",
"type": "ProjectMember"
},
{
"affiliation": "@beacon-biosignals",
"name": "Simon Danisch",
"type": "Other"
},
{
"affiliation": "Veos Digital (https://veos.digital/)",
"name": "Pietro Vertechi",
"type": "ProjectMember"
},
{
"affiliation": "Korea Advanced Inst. of Science and Technology (KAIST)",
"name": "Zhanibek Omarov",
"type": "ProjectMember",
"orcid": "0000-0002-8783-8791"
},
{
"name": "Thatcher Chamberlin",
"type": "Other"
},
{
"name": "@ma-laforge",
"type": "ProjectMember"
},
{
"affiliation": "Massachusetts Institute of Technology",
"name": "Christopher Rackauckas",
"orcid": "0000-0001-5850-0663",
"type": "Other"
},
{
"affiliation": "Max Planck Institute for Physics",
"name": "Oliver Schulz",
"type": "Other"
},
{
"affiliation": "@JuliaComputing",
"name": "Sebastian Pfitzner",
"type": "Other"
},
{
"name": "Takafumi Arakaki",
"type": "Other"
},
{
"affiliation": "University of Manitoba",
"name": "Amin Yahyaabadi",
"type": "Other"
},
{
"name": "Jack Devine",
"type": "Other"
},
{
"name": "Sebastian Pech",
"type": "Other"
},
{
"affiliation": "@JuliaComputing",
"name": "Patrick Kofod Mogensen",
"type": "Other",
"orcid": "0000-0002-4910-1932"
},
{
"name": "Samuel S. Watson",
"type": "Other"
},
{
"affiliation": "UC Davis",
"name": "Naoki Saito",
"orcid": "0000-0001-5234-4719",
"type": "Other"
},
{
"affiliation": "University of Southern California (USC)",
"name": "Benoit Pasquier",
"orcid": "0000-0002-3838-5976",
"type": "Other"
},
{
"affiliation": "NTNU Trondheim",
"name": "Ronny Bergmann",
"orcid": "0000-0001-8342-7218",
"type": "Other"
},
{
"name": "Andy Nowacki",
"affiliation": "University of Leeds",
"orcid": "0000-0001-7669-7383",
"type": "Other"
},
{
"name": "Ian Butterworth",
"type": "Other"
},
{
"affiliation": "Lund University",
"name": "David Gustavsson",
"type": "Other"
},
{
"name": "Anshul Singhvi",
"type": "Other"
},
{
"name": "david-macmahon",
"type": "Other"
},
{
"name": "Fredrik Ekre",
"type": "Other"
},
{
"name": "Maaz Bin Tahir Saeed",
"type": "Other"
},
{
"name": "Kristoffer Carlsson",
"type": "Other"
},
{
"name": "Will Kearney",
"type": "Other"
},
{
"name": "Niklas Korsbo",
"type": "Other"
},
{
"name": "Miles Lucas",
"type": "Other"
},
{
"name": "@Godisemo",
"type": "Other"
},
{
"name": "Florian Oswald",
"type": "Other"
},
{
"name": "Diego Javier Zea",
"type": "Other"
},
{
"name": "@WillRam",
"type": "Other"
},
{
"name": "Fedor Bezrukov",
"type": "Other"
},
{
"name": "Spencer Lyon",
"type": "Other"
},
{
"name": "Darwin Darakananda",
"type": "Other"
},
{
"name": "Lukas Hauertmann",
"type": "Other"
},
{
"name": "Huckleberry Febbo",
"type": "Other"
},
{
"name": "@H-M-H",
"type": "Other"
},
{
"name": "Josh Day",
"type": "Other"
},
{
"name": "@wfgra",
"type": "Other"
},
{
"name": "Sheehan Olver",
"type": "Other"
},
{
"name": "Jerry Ling",
"type": "Other"
},
{
"name": "Jks Liu",
"type": "Other"
},
{
"name": "Seth Axen",
"type": "Other"
},
{
"name": "@o01eg",
"type": "Other"
},
{
"name": "Sebastian Micluța-Câmpeanu",
"type": "Other"
},
{
"name": "Tim Holy",
"type": "Other"
},
{
"name": "Tony Kelman",
"type": "Other"
},
{
"name": "Antoine Levitt",
"type": "Other"
},
{
"name": "Iblis Lin",
"type": "Other"
},
{
"name": "Harry Scholes",
"type": "Other"
},
{
"name": "@djsegal",
"type": "Other"
},
{
"name": "Goran Nakerst",
"type": "Other"
},
{
"name": "Felix Hagemann",
"type": "Other"
},
{
"name": "Matthieu Gomez",
"type": "Other"
},
{
"name": "@biggsbiggsby",
"type": "Other"
},
{
"name": "Jonathan Anderson",
"type": "Other"
},
{
"name": "Michael Kraus",
"type": "Other"
},
{
"name": "Carlo Lucibello",
"type": "Other"
},
{
"name": "Robin Deits",
"type": "Other"
},
{
"name": "Misha Mkhasenko",
"type": "Other"
},
{
"name": "Benoît Legat",
"type": "Other"
},
{
"name": "Steven G. Johnson",
"type": "Other"
},
{
"name": "John Verzani",
"type": "Other"
},
{
"name": "Mattias Fält",
"type": "Other"
},
{
"name": "Rashika Karki",
"type": "Other"
},
{
"name": "Morten Piibeleht",
"type": "Other"
},
{
"name": "Filippo Vicentini",
"type": "Other"
},
{
"name": "David Anthoff",
"type": "Other"
},
{
"name": "Leon Wabeke",
"type": "Other"
},
{
"name": "Yusuke Kominami",
"type": "Other"
},
{
"name": "Oscar Dowson",
"type": "Other"
},
{
"name": "Max G",
"type": "Other"
},
{
"name": "Fabian Greimel",
"type": "Other"
},
{
"name": "Jérémy",
"type": "Other"
},
{
"name": "Pearl Li",
"type": "Other"
},
{
"name": "David P. Sanders",
"type": "Other"
},
{
"name": "Asbjørn Nilsen Riseth",
"type": "Other"
},
{
"name": "Jan Weidner",
"type": "Other"
},
{
"name": "@jakkor2",
"type": "Other"
},
{
"name": "Pablo Zubieta",
"type": "Other"
},
{
"name": "Hamza Yusuf Çakır",
"type": "Other"
},
{
"name": "John Rinehart",
"type": "Other"
},
{
"name": "Martin Biel",
"type": "Other"
},
{
"name": "Moritz Schauer",
"type": "Other"
},
{
"name": "Moesè Giodano",
"type": "Other"
},
{
"name": "@olegshtch",
"type": "Other"
},
{
"name": "Leon Shen",
"type": "Other"
},
{
"name": "Jeff Fessler",
"type": "Other"
},
{
"name": "@hustf",
"type": "Other"
},
{
"name": "Asim H Dar",
"type": "Other"
},
{
"name": "@8uurg",
"type": "Other"
},
{
"name": "Abel Siqueira",
"type": "Other"
},
{
"name": "Adrian Dawid",
"type": "Other"
},
{
"name": "Alberto Lusiani",
"type": "Other"
},
{
"name": "Balázs Mezei",
"type": "Other"
},
{
"name": "Ben Ide",
"type": "Other"
},
{
"name": "Benjamin Lungwitz",
"type": "Other"
},
{
"affiliation": "University of Graz",
"name": "Bernd Riederer",
"type": "Other",
"orcid": "0000-0001-8390-0087"
},
{
"name": "Christina Lee",
"type": "Other"
},
{
"name": "Christof Stocker",
"type": "Other"
},
{
"name": "Christoph Finkensiep",
"type": "Other"
},
{
"name": "@Cornelius-G",
"type": "Other"
},
{
"name": "Daniel Høegh",
"type": "Other"
},
{
"name": "Denny Biasiolli",
"type": "Other"
},
{
"name": "Dieter Castel",
"type": "Other"
},
{
"name": "Elliot Saba",
"type": "Other"
},
{
"name": "Fengyang Wang",
"type": "Other"
},
{
"name": "Fons van der Plas",
"type": "Other"
},
{
"name": "Fredrik Bagge Carlson",
"type": "Other"
},
{
"name": "Graham Smith",
"type": "Other"
},
{
"name": "Hayato Ikoma",
"type": "Other"
},
{
"name": "Hessam Mehr",
"type": "Other"
},
{
"name": "@InfiniteChai",
"type": "Other"
},
{
"name": "Jack Dunn",
"type": "Other"
},
{
"name": "Jeff Bezanson",
"type": "Other"
},
{
"name": "Jeff Eldredge",
"type": "Other"
},
{
"name": "Jinay Jain",
"type": "Other"
},
{
"name": "Johan Blåbäck",
"type": "Other"
},
{
"name": "@jmert",
"type": "Other"
},
{
"name": "Lakshya Khatri",
"type": "Other"
},
{
"name": "Lia Siegelmann",
"type": "Other"
},
{
"name": "@marekkukan-tw",
"type": "Other"
},
{
"affiliation": "ETH Zurich",
"name": "Mauro Werder",
"type": "Other",
"orcid": "0000-0003-0137-9377"
},
{
"name": "Maxim Grechkin",
"type": "Other"
},
{
"name": "Michael Cawte",
"type": "Other"
},
{
"name": "@milesfrain",
"type": "Other"
},
{
"name": "Nicholas Bauer",
"type": "Other"
},
{
"name": "Nicolau Leal Werneck",
"type": "Other"
},
{
"name": "@nilshg",
"type": "Other"
},
{
"name": "Oliver Evans",
"type": "Other"
},
{
"name": "Peter Gagarinov",
"type": "Other"
},
{
"name": "Páll Haraldsson",
"type": "Other"
},
{
"name": "Rik Huijzer",
"type": "Other"
},
{
"name": "Romain Franconville",
"type": "Other"
},
{
"name": "Ronan Pigott",
"type": "Other"
},
{
"name": "Roshan Shariff",
"type": "Other"
},
{
"name": "Scott Thomas",
"type": "Other"
},
{
"name": "Sebastian Rollén",
"type": "Other"
},
{
"name": "Seth Bromberger",
"type": "Other"
},
{
"name": "Siva Swaminathan",
"type": "Other"
},
{
"name": "Tim DuBois",
"type": "Other"
},
{
"name": "Travis DePrato",
"type": "Other"
},
{
"name": "Will Thompson",
"type": "Other"
},
{
"name": "Yakir Luc Gagnon",
"type": "Other"
},
{
"name": "Benjamin Chislett",
"type": "Other"
},
{
"name": "@hhaensel",
"type": "Other"
},
{
"name": "@improbable22",
"type": "Other"
},
{
"name": "Johannes Fleck",
"type": "Other"
},
{
"name": "Peter Czaban",
"type": "Other"
},
{
"name": "@innerlee",
"type": "Other"
},
{
"name": "Mats Cronqvist",
"type": "Other"
},
{
"name": "Shi Pengcheng",
"type": "Other"
},
{
"name": "@wg030",
"type": "Other"
},
{
"affiliation": "University of Cambridge",
"name": "Will Tebbutt",
"type": "Other"
},
{
"name": "@t-bltg",
"type": "Other"
}
{
"name": "Fred Callaway",
"type": "Other"
}
],
"upload_type": "software"
}

View File

@ -1,7 +1,7 @@
name = "Plots" name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"] author = ["Tom Breloff (@tbreloff)"]
version = "1.2.2" version = "1.16.8"
[deps] [deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
@ -10,12 +10,12 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e" Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
@ -25,6 +25,7 @@ RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
RecipesPipeline = "01d81517-befc-4cb6-b9ec-a95719d0359c" RecipesPipeline = "01d81517-befc-4cb6-b9ec-a95719d0359c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Requires = "ae029012-a4dd-5104-9daa-d747884805df" Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Scratch = "6c6a2e73-6563-6170-7368-637461726353"
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
@ -33,27 +34,28 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat] [compat]
Contour = "0.5" Contour = "0.5"
FFMPEG = "0.2, 0.3" FFMPEG = "0.2, 0.3, 0.4"
FixedPointNumbers = "0.6, 0.7, 0.8" FixedPointNumbers = "0.6, 0.7, 0.8"
GR = "0.46, 0.47, 0.48, 0.49" GR = "0.53, 0.54, 0.55, 0.57"
GeometryTypes = "0.7, 0.8" GeometryBasics = "0.2, 0.3.1"
JSON = "0.21" JSON = "0.21, 1"
Latexify = "0.14, 0.15"
Measures = "0.3" Measures = "0.3"
NaNMath = "0.3" NaNMath = "0.3"
PGFPlotsX = "1.2.0"
PlotThemes = "2" PlotThemes = "2"
PlotUtils = "1" PlotUtils = "1"
RecipesBase = "1" RecipesBase = "1"
RecipesPipeline = "0.1.3" RecipesPipeline = "0.3"
Reexport = "0.2" Reexport = "0.2, 1.0"
Requires = "0.5, 1" Requires = "1"
Showoff = "0.3.1" Scratch = "1"
Showoff = "0.3.1, 1.0"
StatsBase = "0.32, 0.33" StatsBase = "0.32, 0.33"
julia = "1" julia = "1.5"
[extras] [extras]
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb"
Gtk = "4c0ca9eb-093a-5379-98c5-f87ac0bbbf44" Gtk = "4c0ca9eb-093a-5379-98c5-f87ac0bbbf44"
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
@ -61,13 +63,15 @@ Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
[targets] [targets]
test = ["FileIO", "GeometryTypes", "Gtk", "ImageMagick", "Images", "LibGit2", "OffsetArrays", "PGFPlotsX", "HDF5", "Random", "RDatasets", "StaticArrays", "StatsPlots", "Test", "UnicodePlots", "VisualRegressionTests"] test = ["Distributions", "FileIO", "Gtk", "ImageMagick", "Images", "LibGit2", "OffsetArrays", "PGFPlotsX", "PlotlyJS", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]

View File

@ -1,10 +1,7 @@
# Plots # Plots
[travis-img]: https://img.shields.io/travis/JuliaPlots/Plots.jl?logo=travis [gh-ci-img]: https://github.com/JuliaPlots/Plots.jl/workflows/ci/badge.svg?branch=master
[travis-url]: https://travis-ci.org/JuliaPlots/Plots.jl [gh-ci-url]: https://github.com/JuliaPlots/Plots.jl/actions?query=workflow%3Aci
[appveyor-img]: https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true
[appveyor-url]: https://ci.appveyor.com/project/mkborregaard/plots-jl
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg [pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg
[pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html [pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html
@ -15,13 +12,16 @@
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg [docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
[docs-url]: http://docs.juliaplots.org/latest/ [docs-url]: http://docs.juliaplots.org/latest/
[![][travis-img]][travis-url] [![][gh-ci-img]][gh-ci-url]
[![][appveyor-img]][appveyor-url]
[![][pkgeval-img]][pkgeval-url] [![][pkgeval-img]][pkgeval-url]
[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://julialang.zulipchat.com/#narrow/stream/236493-plots) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://julialang.zulipchat.com/#narrow/stream/236493-plots)
[![][docs-img]][docs-url] [![][docs-img]][docs-url]
[![Codecov](https://codecov.io/gh/JuliaPlots/Plots.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaPlots/Plots.jl) [![Codecov](https://codecov.io/gh/JuliaPlots/Plots.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaPlots/Plots.jl)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4725317.svg)](https://doi.org/10.5281/zenodo.4725317)
This is the DOI for all Versions, please follow the link to get the DOI for a specific version.
#### Created by Tom Breloff (@tbreloff) #### Created by Tom Breloff (@tbreloff)
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people) #### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)

View File

@ -1,46 +0,0 @@
environment:
matrix:
- julia_version: 1.0
- julia_version: 1
- julia_version: nightly
platform:
- x86 # 32-bit
- x64 # 64-bit
# # Uncomment the following lines to allow failures on nightly julia
# # (tests will run but not make your overall status red)
matrix:
allow_failures:
- julia_version: nightly
branches:
only:
- master
- /release-.*/
cache:
- '%USERPROFILE%\.julia\artifacts'
notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false
install:
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))
build_script:
- echo "%JL_TEST_SCRIPT%"
- C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"
test_script:
- echo "%JL_TEST_SCRIPT%"
- C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"
# # Uncomment to support code coverage upload. Should only be enabled for packages
# # which would have coverage gaps without running on Windows
# on_success:
# - echo "%JL_CODECOV_SCRIPT%"
# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"

5
benchmark/Project.toml Normal file
View File

@ -0,0 +1,5 @@
[deps]
BenchmarkCI = "20533458-34a3-403d-a444-e18f38190b5b"
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
PkgBenchmark = "32113eaa-f34f-5b0d-bd6c-c81e245fc73d"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

10
benchmark/benchmarks.jl Normal file
View File

@ -0,0 +1,10 @@
using BenchmarkTools
using Plots
const SUITE = BenchmarkGroup()
julia_cmd = split(get(ENV, "TESTCMD", Base.JLOptions().julia_bin))
SUITE["load_plot_display"] = @benchmarkable run(`$julia_cmd --startup-file=no --project -e 'using Plots; display(plot(1:0.1:10, sin.(1:0.1:10)))'`)
SUITE["load"] = @benchmarkable run(`$julia_cmd --startup-file=no --project -e 'using Plots'`)
SUITE["plot"] = @benchmarkable p = plot(1:0.1:10, sin.(1:0.1:10)) samples=1 evals=1
SUITE["display"] = @benchmarkable display(p) setup=(p = plot(1:0.1:10, sin.(1:0.1:10))) samples=1 evals=1

View File

@ -0,0 +1,431 @@
# Use
# @warnpcfail precompile(args...)
# if you want to be warned when a precompile directive fails
macro warnpcfail(ex::Expr)
modl = __module__
file = __source__.file === nothing ? "?" : String(__source__.file)
line = __source__.line
quote
$(esc(ex)) || @warn """precompile directive
$($(Expr(:quote, ex)))
failed. Please report an issue in $($modl) (after checking for duplicates) or remove this directive.""" _file=$file _line=$line
end
end
const __bodyfunction__ = Dict{Method,Any}()
# Find keyword "body functions" (the function that contains the body
# as written by the developer, called after all missing keyword-arguments
# have been assigned values), in a manner that doesn't depend on
# gensymmed names.
# `mnokw` is the method that gets called when you invoke it without
# supplying any keywords.
function __lookup_kwbody__(mnokw::Method)
function getsym(arg)
isa(arg, Symbol) && return arg
@assert isa(arg, GlobalRef)
return arg.name
end
f = get(__bodyfunction__, mnokw, nothing)
if f === nothing
fmod = mnokw.module
# The lowered code for `mnokw` should look like
# %1 = mkw(kwvalues..., #self#, args...)
# return %1
# where `mkw` is the name of the "active" keyword body-function.
ast = Base.uncompressed_ast(mnokw)
if isa(ast, Core.CodeInfo) && length(ast.code) >= 2
callexpr = ast.code[end-1]
if isa(callexpr, Expr) && callexpr.head == :call
fsym = callexpr.args[1]
if isa(fsym, Symbol)
f = getfield(fmod, fsym)
elseif isa(fsym, GlobalRef)
if fsym.mod === Core && fsym.name === :_apply
f = getfield(mnokw.module, getsym(callexpr.args[2]))
elseif fsym.mod === Core && fsym.name === :_apply_iterate
f = getfield(mnokw.module, getsym(callexpr.args[3]))
else
f = getfield(fsym.mod, fsym.name)
end
else
f = missing
end
else
f = missing
end
else
f = missing
end
__bodyfunction__[mnokw] = f
end
return f
end
function _precompile_()
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:label, :blank), Tuple{Symbol, Bool}},Type{EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:label, :width, :height), Tuple{Symbol, Symbol, Length{:pct, Float64}}},Type{EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{GridLayout}},Type{Subplot},GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{GridLayout}},Type{Subplot},PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{Subplot{GRBackend}}},Type{Subplot},GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{Subplot{PlotlyBackend}}},Type{Subplot},PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Int64})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Tuple{Int64, Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Vector{Int64}}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:flip,), Tuple{Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{Symbol}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{typeof(datetimeformatter)}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :flip, :minorgrid, :guide), Tuple{Bool, Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims), Tuple{Bool, Tuple{Float64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims, :flip), Tuple{Bool, Tuple{Float64, Float64}, Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :minorgrid, :guide), Tuple{Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :minorgrid, :mirror, :guide), Tuple{Bool, Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid,), Tuple{Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:gridlinewidth, :grid, :gridalpha, :gridstyle, :foreground_color_grid), Tuple{Int64, Bool, Float64, Symbol, RGBA{Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guide,), Tuple{String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guide_position, :guidefontvalign, :mirror, :guide), Tuple{Symbol, Symbol, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guidefonthalign, :guide_position, :mirror, :guide), Tuple{Symbol, Symbol, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims, :flip, :ticks, :guide), Tuple{Tuple{Int64, Int64}, Bool, StepRange{Int64, Int64}, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Float64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:rotation,), Tuple{Int64}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:scale, :guide), Tuple{Symbol, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,), Tuple{Nothing}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,), Tuple{UnitRange{Int64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(default)),NamedTuple{(:shape,), Tuple{Symbol}},typeof(default)})
Base.precompile(Tuple{Core.kwftype(typeof(default)),NamedTuple{(:titlefont, :legendfontsize, :guidefont, :tickfont, :guide, :framestyle, :yminorgrid), Tuple{Tuple{Int64, String}, Int64, Tuple{Int64, Symbol}, Tuple{Int64, Symbol}, String, Symbol, Bool}},typeof(default)})
Base.precompile(Tuple{Core.kwftype(typeof(font)),NamedTuple{(:family, :pointsize, :halign, :valign, :rotation, :color), Tuple{String, Int64, Symbol, Symbol, Float64, RGBA{Float64}}},typeof(font)})
Base.precompile(Tuple{Core.kwftype(typeof(font)),NamedTuple{(:family, :pointsize, :valign, :halign, :rotation, :color), Tuple{String, Int64, Symbol, Symbol, Float64, RGBA{Float64}}},typeof(font)})
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),StepRange{Int64, Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),UnitRange{Int64},UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),UnitRange{Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),Vector{Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_set_font)),NamedTuple{(:halign, :valign, :rotation, :color), Tuple{Symbol, Symbol, Int64, RGBA{Float64}}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(heatmap)),Any,typeof(heatmap),Any,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(hline!)),Any,typeof(hline!),Any})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{GRBackend},Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,), Tuple{Vector{Tuple{Int64, Float64, PlotText}}}},typeof(plot!),Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,), Tuple{Vector{Tuple{Int64, Float64, PlotText}}}},typeof(plot!),Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,), Tuple{Vector{Tuple{Int64, Float64, PlotText}}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :xlims), Tuple{GridLayout, Tuple{Int64, Float64}}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Plot{GRBackend},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:line, :seriestype), Tuple{Tuple{Int64, Symbol, Float64, Matrix{Symbol}}, Symbol}},typeof(plot!),Plot{PlotlyBackend},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Function,Float64,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Plot{GRBackend},Function,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),Plot{GRBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),Plot{PlotlyBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:marker, :series_annotations, :seriestype), Tuple{Tuple{Int64, Float64, Symbol}, Vector{Any}, Symbol}},typeof(plot!),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Vector{Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot!),Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:title,), Tuple{String}},typeof(plot!),Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:title,), Tuple{String}},typeof(plot!),Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:title,), Tuple{String}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:w,), Tuple{Int64}},typeof(plot!),Plot{GRBackend},Vector{Float64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:xgrid,), Tuple{Tuple{Symbol, Symbol, Int64, Symbol, Float64}}},typeof(plot!),Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:xgrid,), Tuple{Tuple{Symbol, Symbol, Int64, Symbol, Float64}}},typeof(plot!),Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis,), Tuple{Tuple{String, Symbol}}},typeof(plot!),Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis,), Tuple{Tuple{String, Symbol}}},typeof(plot!),Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis,), Tuple{Tuple{String, Symbol}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype), Tuple{Vector{Float64}, Tuple{Symbol, Float64, Stroke}, Vector{Float64}, String, Symbol}},typeof(plot!),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:annotations, :leg), Tuple{Tuple{Int64, Float64, PlotText}, Bool}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:arrow,), Tuple{Int64}},typeof(plot),Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:aspect_ratio, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{String},Vector{String},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bins, :weights, :seriestype), Tuple{Symbol, Vector{Int64}, Symbol}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:color, :line, :marker), Tuple{Matrix{Symbol}, Tuple{Symbol, Int64}, Tuple{Matrix{Symbol}, Int64, Float64, Stroke}}},typeof(plot),Vector{Vector{T} where T}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:connections, :seriestype), Tuple{Tuple{Vector{Int64}, Vector{Int64}, Vector{Int64}}, Symbol}},typeof(plot),Vector{Int64},Vector{Int64},Vararg{Vector{Int64}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill, :seriestype), Tuple{Bool, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks, :seriestype), Tuple{Matrix{Symbol}, Matrix{String}, Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}}, Int64, String, Int64, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Vector{Float64}},Vector{Vector{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:grid, :title), Tuple{Tuple{Symbol, Symbol, Symbol, Int64, Float64}, String}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:lab, :w, :palette, :fill, :α), Tuple{String, Int64, PlotUtils.ContinuousColorGradient, Int64, Float64}},typeof(plot),StepRange{Int64, Int64},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend), Tuple{Matrix{String}, String, String, Int64, Symbol}},typeof(plot),Vector{Function},Float64,Vararg{Float64, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label,), Tuple{Matrix{String}}},typeof(plot),Vector{AbstractVector{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:labels,), Tuple{Matrix{String}}},typeof(plot),PortfolioComposition})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :group, :linetype, :linecolor), Tuple{GridLayout, Vector{String}, Matrix{Symbol}, Symbol}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :link), Tuple{Int64, Symbol}},typeof(plot),Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :link), Tuple{Int64, Symbol}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :margin), Tuple{GridLayout, AbsoluteLength}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :palette, :bg_inside), Tuple{Int64, Matrix{PlotUtils.ContinuousColorGradient}, Matrix{Symbol}}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :t, :leg, :ticks, :border), Tuple{GridLayout, Matrix{Symbol}, Bool, Nothing, Symbol}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :title, :titlelocation, :left_margin, :bottom_margin, :xrotation), Tuple{GridLayout, Matrix{String}, Symbol, Matrix{AbsoluteLength}, AbsoluteLength, Int64}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xguide, :yguide, :xguidefonthalign, :yguidefontvalign, :xguideposition, :yguideposition, :ymirror, :xmirror, :legend, :seriestype), Tuple{Int64, String, String, Matrix{Symbol}, Matrix{Symbol}, Symbol, Matrix{Symbol}, Matrix{Bool}, Matrix{Bool}, Bool, Matrix{Symbol}}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xlims), Tuple{GridLayout, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Vector{Tuple{Int64, Real}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :lab, :ms), Tuple{Tuple{Matrix{Symbol}, Int64}, Matrix{String}, Int64}},typeof(plot),Vector{Vector{T} where T},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :label, :legendtitle), Tuple{Tuple{Int64, Matrix{Symbol}}, Matrix{String}, String}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :leg, :fill), Tuple{Int64, Bool, Tuple{Int64, Symbol}}},typeof(plot),Function,Function,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line, :marker, :bg, :fg, :xlim, :ylim, :leg), Tuple{Tuple{Int64, Symbol, Symbol}, Tuple{Shape{Float64, Float64}, Int64, RGBA{Float64}}, Symbol, Symbol, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Bool}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line_z, :linewidth, :legend), Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int64, Bool}},typeof(plot),Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:m, :markersize, :lab, :bg, :xlim, :ylim, :seriestype), Tuple{Matrix{Symbol}, Int64, Matrix{String}, Symbol, Tuple{Int64, Int64}, Tuple{Int64, Int64}, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker,), Tuple{Bool}},typeof(plot),Vector{Union{Missing, Int64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:marker_z, :color, :legend, :seriestype), Tuple{typeof(+), Symbol, Bool, Symbol}},typeof(plot),Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:markershape, :markersize, :marker_z, :line_z, :linewidth), Tuple{Matrix{Symbol}, Matrix{Int64}, Matrix{Int64}, Matrix{Int64}, Matrix{Int64}}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:markershape, :seriestype, :label), Tuple{Symbol, Symbol, String}},typeof(plot),UnitRange{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:nbins, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:nbins, :show_empty_bins, :normed, :aspect_ratio, :seriestype), Tuple{Tuple{Int64, Int64}, Bool, Bool, Int64, Symbol}},typeof(plot),Vector{ComplexF64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:proj, :m), Tuple{Symbol, Int64}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:projection, :seriestype), Tuple{Symbol, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},UnitRange{Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:quiver, :seriestype), Tuple{Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Vararg{Vector{Float64}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:reg, :fill), Tuple{Bool, Tuple{Int64, Symbol}}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,), Tuple{Int64}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,), Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,), Tuple{Tuple{LinRange{Float64}, LinRange{Float64}}}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,), Tuple{typeof(sqrt)}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype, :markershape, :markersize, :color), Tuple{Matrix{Symbol}, Vector{Symbol}, Int64, Vector{Symbol}}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{DateTime},UnitRange{Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{OHLC}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:st, :xlabel, :ylabel, :zlabel), Tuple{Symbol, String, String, String}},typeof(plot),Vector{Float64},Vector{Float64},Vararg{Vector{Float64}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :l, :seriestype), Tuple{String, Float64, Symbol}},typeof(plot),Vector{String},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xflip, :yflip, :zflip, :zlabel, :dpi, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Int64, Bool, String, Bool, String, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xmirror, :ymirror, :zmirror, :zlabel, :dpi, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Int64, Bool, String, Bool, String, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :zlabel, :dpi, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, String, Int64, Bool, String, Bool, String, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,), Tuple{Matrix{String}}},typeof(plot),Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title,), Tuple{Matrix{String}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:w,), Tuple{Int64}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:xaxis, :background_color, :leg), Tuple{Tuple{String, Tuple{Int64, Int64}, StepRange{Int64, Int64}, Symbol}, RGB{Float64}, Bool}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:yflip, :aspect_ratio), Tuple{Bool, Symbol}},typeof(plot),Vector{Float64},Vector{Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:zcolor, :m, :leg, :cbar, :w), Tuple{StepRange{Int64, Int64}, Tuple{Int64, Float64, Symbol, Stroke}, Bool, Bool, Int64}},typeof(plot),Vector{Float64},Vector{Float64},Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(portfoliocomposition)),Any,typeof(portfoliocomposition),Any,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(scatter!)),Any,typeof(scatter!),Any})
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip, :disp), Tuple{Vector{Int64}, Bool}},typeof(test_examples),Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(test_examples)),NamedTuple{(:skip,), Tuple{Vector{Int64}}},typeof(test_examples),Symbol})
Base.precompile(Tuple{Type{GridLayout},Int64,Vararg{Int64, N} where N})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},AbstractVector{OHLC}})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},PortfolioComposition})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:barbins}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:barhist}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:bar}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:bins2d}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:histogram2d}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:histogram}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:hline}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:lens}},AbstractPlot})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:pie}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:quiver}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:steppost}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:steppre}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:sticks}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:vline}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:xerror}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Vector{ComplexF64}})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{GRBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{PlotlyBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{GRBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},DefaultsDict,Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},Dict{Symbol, Any},Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},DefaultsDict,Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},Dict{Symbol, Any},Symbol,Any})
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Int64},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Nothing},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Symbol},String})
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),StepRange{Int64, Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},StepRange{Int64, Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},UnitRange{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},Vector{Int64}})
Base.precompile(Tuple{typeof(_do_plot_show),Plot{GRBackend},Bool})
Base.precompile(Tuple{typeof(_do_plot_show),Plot{PlotlyBackend},Bool})
Base.precompile(Tuple{typeof(_heatmap_edges),Vector{Float64},Bool,Bool})
Base.precompile(Tuple{typeof(_plot!),Plot,Any,Any})
Base.precompile(Tuple{typeof(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Vector{Float64}})
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{typeof(_update_min_padding!),GridLayout})
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{GRBackend},Subplot{GRBackend},Dict{Symbol, Any},Int64,Bool})
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{PlotlyBackend},Subplot{PlotlyBackend},Dict{Symbol, Any},Int64,Bool})
Base.precompile(Tuple{typeof(_update_subplot_periphery),Subplot{GRBackend},Vector{Any}})
Base.precompile(Tuple{typeof(_update_subplot_periphery),Subplot{PlotlyBackend},Vector{Any}})
Base.precompile(Tuple{typeof(axis_limits),Subplot{GRBackend},Symbol,Bool,Bool})
Base.precompile(Tuple{typeof(axis_limits),Subplot{PlotlyBackend},Symbol,Bool,Bool})
Base.precompile(Tuple{typeof(backend),PlotlyBackend})
Base.precompile(Tuple{typeof(bbox),AbsoluteLength,AbsoluteLength,AbsoluteLength,AbsoluteLength})
Base.precompile(Tuple{typeof(bbox),Float64,Float64,Float64,Float64})
Base.precompile(Tuple{typeof(build_layout),GridLayout,Int64})
Base.precompile(Tuple{typeof(contour),Any,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64},Tuple{Int64, Float64}})
Base.precompile(Tuple{typeof(create_grid),Expr})
Base.precompile(Tuple{typeof(discrete_value!),Axis,Vector{String}})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64},Vararg{Vector{Float64}, N} where N})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(error_style!),DefaultsDict})
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(get_minor_ticks),Subplot{GRBackend},Axis,Tuple{Vector{Int64}, Vector{String}}})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_ticks),StepRange{Int64, Int64},Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Float64},Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(get_ticks),UnitRange{Int64},Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(get_xy),Vector{OHLC}})
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}},Vector{Float64}})
Base.precompile(Tuple{typeof(gr_add_legend),Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, Float64, Float64, Float64, Int64, Float64, Float64, Float64, Float64}},Vector{Float64}})
Base.precompile(Tuple{typeof(gr_display),Subplot{GRBackend},AbsoluteLength,AbsoluteLength,Vector{Float64}})
Base.precompile(Tuple{typeof(gr_draw_colorbar),GRColorbar,Subplot{GRBackend},Tuple{Float64, Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(gr_draw_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Float64,Float64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Shape{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Float64,Tuple{Float64, Float64},Int64,Float64,Int64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Int64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},UnitRange{Int64},Tuple{Vector{Float64}, Vector{Float64}},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRange{Int64, Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Vector{Float64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_shapes),Series,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_surface),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_fill_viewport),Vector{Float64},RGBA{Float64}})
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Float64}, Vector{String}},Int64})
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Int64}, Vector{String}},Int64})
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(gr_label_ticks_3d),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(gr_polaraxes),Int64,Float64,Subplot{GRBackend}})
Base.precompile(Tuple{typeof(gr_polyline),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{typeof(gr_set_gradient),PlotUtils.ContinuousColorGradient})
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}}})
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, Float64, Float64, Float64, Int64, Float64, Float64, Float64, Float64}}})
Base.precompile(Tuple{typeof(gr_viewport_from_bbox),Subplot{GRBackend},BoundingBox{Tuple{AbsoluteLength, AbsoluteLength}, Tuple{AbsoluteLength, AbsoluteLength}},AbsoluteLength,AbsoluteLength,Vector{Float64}})
Base.precompile(Tuple{typeof(heatmap_edges),Base.OneTo{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),UnitRange{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol,UnitRange{Int64},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol,Vector{Float64},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol})
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
Base.precompile(Tuple{typeof(layout_args),Int64})
Base.precompile(Tuple{typeof(make_fillrange_side),UnitRange{Int64},LinRange{Float64}})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Float64, Float64},Symbol,Function})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Float64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Int64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),StepRange{Int64, Int64},Tuple{Int64, Int64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),UnitRange{Int64},Tuple{Float64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(partialcircle),Int64,Float64,Int64})
Base.precompile(Tuple{typeof(plot),Any,Any,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(plot),Any})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend}})
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
Base.precompile(Tuple{typeof(processGridArg!),DefaultsDict,Bool,Symbol})
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol, Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Matrix{Symbol}})
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Matrix{Symbol}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},RGBA{Float64}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Shape{Float64, Float64}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Stroke})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol, Any},StepRange{Int64, Int64},Symbol})
Base.precompile(Tuple{typeof(process_axis_arg!),Dict{Symbol, Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(push!),Plot{GRBackend},Float64,Vector{Float64}})
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
Base.precompile(Tuple{typeof(scalefontsizes)})
Base.precompile(Tuple{typeof(series_annotations),Vector{Any}})
Base.precompile(Tuple{typeof(slice_arg),Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{Bool},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{Int64},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{PlotUtils.ContinuousColorGradient},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{RGBA{Float64}},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{String},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{Symbol},Int64})
Base.precompile(Tuple{typeof(spy),Any})
Base.precompile(Tuple{typeof(straightline_data),Tuple{Float64, Float64},Tuple{Float64, Float64},Vector{Float64},Vector{Float64},Int64})
Base.precompile(Tuple{typeof(stroke),Int64,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(text),String,Int64,Symbol,Vararg{Symbol, N} where N})
Base.precompile(Tuple{typeof(text),String,Symbol,Int64,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(text),String,Symbol})
Base.precompile(Tuple{typeof(title!),AbstractString})
Base.precompile(Tuple{typeof(unzip),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{typeof(vline!),Any})
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(xgrid!),Plot{PlotlyBackend},Symbol,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
Base.precompile(Tuple{typeof(yaxis!),Any,Any})
isdefined(Plots, Symbol("#add_major_or_minor_segments#125")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#125")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#126")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#126")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
let fbody = try __lookup_kwbody__(which(plot!, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Any,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Any,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Any,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Any,))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Any,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(text, (String,Int64,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(text),String,Int64,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(text, (String,Symbol,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(text),String,Symbol,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(title!, (AbstractString,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(title!),AbstractString,))
end
end
end

View File

@ -0,0 +1,4 @@
using Plots
Plots.test_examples(:gr, skip = Plots._backend_skips[:gr])
Plots.test_examples(:plotly, skip = Plots._backend_skips[:plotly], disp = false)

8
deps/SnoopCompile/snoop_bench.jl vendored Normal file
View File

@ -0,0 +1,8 @@
using CompileBot
snoop_bench(
BotConfig(
"Plots",
),
joinpath(@__DIR__, "precompile_script.jl"),
)

8
deps/SnoopCompile/snoop_bot.jl vendored Normal file
View File

@ -0,0 +1,8 @@
using CompileBot
snoop_bot(
BotConfig(
"Plots",
),
joinpath(@__DIR__, "precompile_script.jl"),
)

18
deps/build.jl vendored
View File

@ -1,18 +0,0 @@
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
file_path = ""
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global file_path
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
isfile(local_fn) && (file_path = local_fn)
else
file_path = local_fn
end
end
open("deps.jl", "w") do io
println(io, "const plotly_local_file_path = $(repr(file_path))")
end

View File

@ -1,55 +0,0 @@
# 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
project_flag = string("--project=", joinpath(homedir(), ".julia", "dev", "Plots"))
log_path = joinpath(tempdir(), "compiles.log")
precompiles_path = joinpath(tempdir(), "precompile")
# run examples with GR backend, logging what needs to be compiled
SnoopCompile.@snoopc project_flag log_path begin
using Plots
Plots.test_examples(:gr)
Plots.test_examples(:plotly, skip = Plots._backend_skips[:plotly])
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",
"OffsetArrays",
"SparseArrays",
"StaticArrays",
r"#{1,2}[^\"#]+#{1,2}\d+",
]
data = SnoopCompile.read(log_path)
pc = SnoopCompile.parcel(reverse!(data[2]), blacklist=blacklist)
SnoopCompile.write(precompiles_path, pc)

View File

@ -8,9 +8,9 @@ const _current_plots_version = VersionNumber(split(first(filter(line -> occursin
using Reexport using Reexport
import GeometryTypes import GeometryBasics
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
import SparseArrays: findnz using SparseArrays
using FFMPEG using FFMPEG
@ -25,17 +25,6 @@ import JSON
using Requires using Requires
if isfile(joinpath(@__DIR__, "..", "deps", "deps.jl"))
include(joinpath(@__DIR__, "..", "deps", "deps.jl"))
else
# This is a bit dirty, but I don't really see why anyone should be forced
# to build Plots, while it will just include exactly the below line
# as long as `ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] = "true"` is not set.
# If the above env is set + `plotly_local_file_path == ""``,
# it will warn in the __init__ function to run build
const plotly_local_file_path = ""
end
export export
grid, grid,
bbox, bbox,
@ -124,7 +113,11 @@ export
center, center,
BezierCurve, BezierCurve,
plotattr plotattr,
scalefontsize,
scalefontsizes,
resetfontsizes
# --------------------------------------------------------- # ---------------------------------------------------------
@ -161,6 +154,12 @@ const BBox = Measures.Absolute2DBox
# allow pixels and percentages # allow pixels and percentages
const px = AbsoluteLength(0.254) const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0) const pct = Length{:pct, Float64}(1.0)
Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
end end
@ -188,11 +187,16 @@ import RecipesPipeline: SliceIt,
datetimeformatter, datetimeformatter,
timeformatter timeformatter
# Use fixed version of Plotly instead of the latest one for stable dependency
# Ref: https://github.com/JuliaPlots/Plots.jl/pull/2779
const _plotly_min_js_filename = "plotly-1.57.1.min.js"
include("types.jl") include("types.jl")
include("utils.jl") include("utils.jl")
include("components.jl") include("colorbars.jl")
include("axes.jl") include("axes.jl")
include("args.jl") include("args.jl")
include("components.jl")
include("themes.jl") include("themes.jl")
include("plot.jl") include("plot.jl")
include("pipeline.jl") include("pipeline.jl")
@ -208,6 +212,7 @@ include("output.jl")
include("ijulia.jl") include("ijulia.jl")
include("fileio.jl") include("fileio.jl")
include("init.jl") include("init.jl")
include("legend.jl")
include("backends/plotly.jl") include("backends/plotly.jl")
include("backends/gr.jl") include("backends/gr.jl")
@ -225,8 +230,8 @@ let PlotOrSubplot = Union{Plot, Subplot}
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...) global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...) global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...) global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...) global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...) global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot, global xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
global yticks!(plt::PlotOrSubplot, global yticks!(plt::PlotOrSubplot,
@ -246,7 +251,6 @@ end
const CURRENT_BACKEND = CurrentBackend(:none) const CURRENT_BACKEND = CurrentBackend(:none)
include("precompile.jl") include("precompile_includer.jl")
_precompile_()
end # module end # module

View File

@ -90,15 +90,15 @@ function buildanimation(anim::Animation, fn::AbstractString,
if variable_palette if variable_palette
# generate a colorpalette for each frame for highest quality, but larger filesize # generate a colorpalette for each frame for highest quality, but larger filesize
palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1" palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
ffmpeg_exe(`-v $verbose_level -framerate $framerate -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`) ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`)
else else
# generate a colorpalette first so ffmpeg does not have to guess it # generate a colorpalette first so ffmpeg does not have to guess it
ffmpeg_exe(`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`) ffmpeg_exe(`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
# then apply the palette to get better results # then apply the palette to get better results
ffmpeg_exe(`-v $verbose_level -framerate $framerate -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`) ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`)
end end
else else
ffmpeg_exe(`-v $verbose_level -framerate $framerate -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`) ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`)
end end
show_msg && @info("Saved animation to ", fn) show_msg && @info("Saved animation to ", fn)
@ -137,8 +137,8 @@ end
# ----------------------------------------------- # -----------------------------------------------
function _animate(forloop::Expr, args...; callgif = false) function _animate(forloop::Expr, args...; callgif = false)
if forloop.head != :for if forloop.head (:for, :while)
error("@animate macro expects a for-block. got: $(forloop.head)") error("@animate macro expects a for- or while-block. got: $(forloop.head)")
end end
# add the call to frame to the end of each iteration # add the call to frame to the end of each iteration

View File

@ -59,7 +59,7 @@ const _arg_desc = KW(
:foreground_color => "Color Type. Base color for all foregrounds.", :foreground_color => "Color Type. Base color for all foregrounds.",
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot", :size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)", :pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
:window_title => "String. Title of the window.", :window_title => "String. Title of the standalone gui-window.",
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`", :show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.", :layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).", :link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
@ -90,13 +90,14 @@ const _arg_desc = KW(
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", :foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.", :color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position). Bottom left corner of legend is placed at (x,y). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` , `:inline` (note: only some may be supported in each backend)", :legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.",
:legendfontfamily => "String or Symbol. Font family of legend entries.", :legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.", :legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center", :legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center", :legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries", :legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries", :legendfontcolor => "Color Type. Font color of legend entries",
:legendtitle => "String. Legend title.",
:legendtitlefontfamily => "String or Symbol. Font family of the legend title.", :legendtitlefontfamily => "String or Symbol. Font family of the legend title.",
:legendtitlefontsize => "Integer. Font pointsize the legend title.", :legendtitlefontsize => "Integer. Font pointsize the legend title.",
:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center", :legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center",
@ -105,11 +106,24 @@ const _arg_desc = KW(
:legendtitlefontcolor => "Color Type. Font color 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)", :colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.", :clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.",
:colorbar_fontfamily => "String or Symbol. Font family of colobar entries.",
:colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.",
:colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.",
:colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries",
:colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`",
:colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:legendfont => "Font. Font of legend items.", :legendfont => "Font. Font of legend items.",
:legendtitlefont => "Font. Font of the legend title.", :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.", :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.",
:annotationfontfamily => "String or Symbol. Font family of annotations.",
:annotationfontsize => "Integer. Font pointsize of annotations.",
:annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.",
:annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.",
:annotationrotation => "Float. Rotation of annotations in degrees.",
:annotationcolor => "Colorant or :match. Color of annotations.",
:projection => "Symbol or String. '3d' or 'polar'", :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.", :aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.", :margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.", :left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.", :top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
@ -123,7 +137,12 @@ const _arg_desc = KW(
# axis args # axis args
:guide => "String. Axis guide (label).", :guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right", :guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]", :lims => """
NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).
`:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]
`:symmetric` sets the limits to be symmetric around zero.
Set widen=true to widen the specified limits (as occurs when lims are not specified).
""",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", :ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`", :scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.", :rotation => "Number. Degrees rotation of tick labels.",
@ -157,8 +176,11 @@ const _arg_desc = KW(
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.", :minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)", :minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)", :minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`", :tick_direction => "Symbol. Direction of the ticks. `:in`, `:out` or `:none`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`", :showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.", :widen => """
Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders.
Defaults to `:auto`, which widens unless limits were manually set.
""",
:draw_arrow => "Bool. Draw arrow at the end of the axis.", :draw_arrow => "Bool. Draw arrow at the end of the axis.",
) )

View File

@ -1,26 +1,46 @@
function makeplural(s::Symbol)
str = string(s)
if last(str) != 's'
return Symbol(string(s,"s"))
end
return s
end
function make_non_underscore(s::Symbol)
str = string(s)
str = replace(str, "_" => "")
return Symbol(str)
end
const _keyAliases = Dict{Symbol,Symbol}() const _keyAliases = Dict{Symbol,Symbol}()
function add_aliases(sym::Symbol, aliases::Symbol...) function add_aliases(sym::Symbol, aliases::Symbol...)
for alias in aliases for alias in aliases
if haskey(_keyAliases, alias) if haskey(_keyAliases, alias) || alias === sym
error("Already an alias $alias => $(_keyAliases[alias])... can't also alias $sym") return nothing
end end
_keyAliases[alias] = sym _keyAliases[alias] = sym
end end
return nothing
end end
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol}) function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
for (k,v) in aliases for (k,v) in aliases
s = string(k) s = string(k)
if '_' in s if '_' in s
aliases[Symbol(replace(s, "_" => ""))] = v aliases[make_non_underscore(k)] = v
end end
end end
end end
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol}, args::Vector{Symbol})
for arg in args
s = string(arg)
if '_' in s
aliases[make_non_underscore(arg)] = arg
end
end
end
# ------------------------------------------------------------ # ------------------------------------------------------------
const _allAxes = [:auto, :left, :right] const _allAxes = [:auto, :left, :right]
@ -31,10 +51,10 @@ const _axesAliases = Dict{Symbol,Symbol}(
) )
const _3dTypes = [ const _3dTypes = [
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d
] ]
const _allTypes = vcat([ const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :none, :line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins, :heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins,
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d,
:density, :bar, :hline, :vline, :density, :bar, :hline, :vline,
@ -81,7 +101,7 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases) add_non_underscore_aliases!(_typeAliases)
const _histogram_like = [:histogram, :barhist, :barbins] const _histogram_like = [:histogram, :barhist, :barbins]
const _line_like = [:line, :path, :steppre, :steppost] const _line_like = [:line, :path, :steppre, :stepmid, :steppost]
const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image] const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
like_histogram(seriestype::Symbol) = seriestype in _histogram_like like_histogram(seriestype::Symbol) = seriestype in _histogram_like
@ -104,6 +124,31 @@ const _styleAliases = Dict{Symbol,Symbol}(
:ddd => :dashdotdot, :ddd => :dashdotdot,
) )
const _shape_keys = Symbol[
:circle,
:rect,
:star5,
:diamond,
:hexagon,
:cross,
:xcross,
:utriangle,
:dtriangle,
:rtriangle,
:ltriangle,
:pentagon,
:heptagon,
:octagon,
:star4,
:star6,
:star7,
:star8,
:vline,
:hline,
:+,
:x,
]
const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes)))) const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes))))
const _markerAliases = Dict{Symbol,Symbol}( const _markerAliases = Dict{Symbol,Symbol}(
:n => :none, :n => :none,
@ -228,7 +273,7 @@ const _bar_width = 0.8
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
const _series_defaults = KW( const _series_defaults = KW(
:label => "AUTO", :label => :auto,
:colorbar_entry => true, :colorbar_entry => true,
:seriescolor => :auto, :seriescolor => :auto,
:seriesalpha => nothing, :seriesalpha => nothing,
@ -273,20 +318,26 @@ const _series_defaults = KW(
:show_empty_bins => false, # should empty bins in 2D histogram be colored as zero (otherwise they are transparent) :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 :contours => false, # add contours to 3d surface and wireframe plots
:contour_labels => false, :contour_labels => false,
:match_dimensions => false, # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
:subplot => :auto, # which subplot(s) does this series belong to? :subplot => :auto, # which subplot(s) does this series belong to?
:series_annotations => nothing, # a list of annotations which apply to the coordinates of this series :series_annotations => nothing, # a list of annotations which apply to the coordinates of this series
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow :primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
# one logical series to be broken up (path and markers, for example) # one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points :hover => nothing, # text to display when hovering over the data points
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. :stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
:connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh
:extra_kwargs => Dict() :extra_kwargs => Dict()
) )
const _plot_defaults = KW( const _plot_defaults = KW(
:plot_title => "", :plot_title => "",
:plot_titlefontsize => 16,
:plot_title_location => :center, # also :left or :right
:plot_titlefontfamily => :match,
:plot_titlefonthalign => :hcenter,
:plot_titlefontvalign => :vcenter,
:plot_titlefontrotation => 0.0,
:plot_titlefontcolor => :match,
:background_color => colorant"white", # default for all backgrounds, :background_color => colorant"white", # default for all backgrounds,
:background_color_outside => :match, # background outside grid, :background_color_outside => :match, # background outside grid,
:foreground_color => :auto, # default for all foregrounds, and title color, :foreground_color => :auto, # default for all foregrounds, and title color,
@ -332,6 +383,18 @@ const _subplot_defaults = KW(
:legendtitle => nothing, :legendtitle => nothing,
:colorbar => :legend, :colorbar => :legend,
:clims => :auto, :clims => :auto,
:colorbar_fontfamily => :match,
:colorbar_ticks => :auto,
:colorbar_tickfontfamily => :match,
:colorbar_tickfontsize => 8,
:colorbar_tickfonthalign => :hcenter,
:colorbar_tickfontvalign => :vcenter,
:colorbar_tickfontrotation => 0.0,
:colorbar_tickfontcolor => :match,
:colorbar_scale => :identity,
:colorbar_formatter => :auto,
:colorbar_discrete_values => [],
:colorbar_continuous_values => zeros(0),
:legendfontfamily => :match, :legendfontfamily => :match,
:legendfontsize => 8, :legendfontsize => 8,
:legendfonthalign => :hcenter, :legendfonthalign => :hcenter,
@ -345,6 +408,12 @@ const _subplot_defaults = KW(
:legendtitlefontrotation => 0.0, :legendtitlefontrotation => 0.0,
:legendtitlefontcolor => :match, :legendtitlefontcolor => :match,
:annotations => [], # annotation tuples... list of (x,y,annotation) :annotations => [], # annotation tuples... list of (x,y,annotation)
:annotationfontfamily => :match,
:annotationfontsize => 14,
:annotationhalign => :hcenter,
:annotationvalign => :vcenter,
:annotationrotation => 0.0,
:annotationcolor => :match,
:projection => :none, # can also be :polar or :3d :projection => :none, # can also be :polar or :3d
:aspect_ratio => :auto, # choose from :none or :equal :aspect_ratio => :auto, # choose from :none or :equal
:margin => 1mm, :margin => 1mm,
@ -354,6 +423,13 @@ const _subplot_defaults = KW(
:bottom_margin => :match, :bottom_margin => :match,
:subplot_index => -1, :subplot_index => -1,
:colorbar_title => "", :colorbar_title => "",
:colorbar_titlefontsize => 10,
:colorbar_title_location => :center, # also :left or :right
:colorbar_titlefontfamily => :match,
:colorbar_titlefonthalign => :hcenter,
:colorbar_titlefontvalign => :vcenter,
:colorbar_titlefontrotation => 0.0,
:colorbar_titlefontcolor => :match,
:framestyle => :axes, :framestyle => :axes,
:camera => (30,30), :camera => (30,30),
:extra_kwargs => Dict() :extra_kwargs => Dict()
@ -400,7 +476,7 @@ const _axis_defaults = KW(
:minorticks => false, :minorticks => false,
:minorgrid => false, :minorgrid => false,
:showaxis => true, :showaxis => true,
:widen => true, :widen => :auto,
:draw_arrow => false, :draw_arrow => false,
) )
@ -449,6 +525,7 @@ const _initial_axis_defaults = deepcopy(_axis_defaults)
const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize], const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize],
:legendfontsize => _subplot_defaults[:legendfontsize], :legendfontsize => _subplot_defaults[:legendfontsize],
:legendtitlefontsize => _subplot_defaults[:legendtitlefontsize], :legendtitlefontsize => _subplot_defaults[:legendtitlefontsize],
:annotationfontsize => _subplot_defaults[:annotationfontsize],
:tickfontsize => _axis_defaults[:tickfontsize], :tickfontsize => _axis_defaults[:tickfontsize],
:guidefontsize => _axis_defaults[:guidefontsize]) :guidefontsize => _axis_defaults[:guidefontsize])
@ -461,7 +538,7 @@ const _subplot_args = sort(union(collect(keys(_subplot_defaults))))
const _plot_args = sort(union(collect(keys(_plot_defaults)))) const _plot_args = sort(union(collect(keys(_plot_defaults))))
const _magic_axis_args = [:axis, :tickfont, :guidefont, :grid, :minorgrid] const _magic_axis_args = [:axis, :tickfont, :guidefont, :grid, :minorgrid]
const _magic_subplot_args = [:titlefont, :legendfont, :legendtitlefont, ] const _magic_subplot_args = [:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont]
const _magic_series_args = [:line, :marker, :fill] const _magic_series_args = [:line, :marker, :fill]
const _all_axis_args = sort(union([_axis_args; _magic_axis_args])) const _all_axis_args = sort(union([_axis_args; _magic_axis_args]))
@ -470,7 +547,7 @@ const _all_series_args = sort(union([_series_args; _magic_series_args]))
const _all_plot_args = _plot_args const _all_plot_args = _plot_args
const _all_args = const _all_args =
sort([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args]) sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args]))
is_subplot_attr(k) = k in _all_subplot_args is_subplot_attr(k) = k in _all_subplot_args
is_series_attr(k) = k in _all_series_args is_series_attr(k) = k in _all_series_args
@ -481,9 +558,6 @@ RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
is_default_attribute(k) = k in _internal_args || k in _all_args || is_axis_attr_noletter(k) is_default_attribute(k) = k in _internal_args || k in _all_args || is_axis_attr_noletter(k)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
makeplural(s::Symbol) = Symbol(string(s,"s"))
autopick_ignore_none_auto(arr::AVec, idx::Integer) = _cycle(setdiff(arr, [:none, :auto]), idx) autopick_ignore_none_auto(arr::AVec, idx::Integer) = _cycle(setdiff(arr, [:none, :auto]), idx)
autopick_ignore_none_auto(notarr, idx::Integer) = notarr autopick_ignore_none_auto(notarr, idx::Integer) = notarr
@ -502,6 +576,13 @@ end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# margin
add_aliases(:left_margin , :leftmargin )
add_aliases(:top_margin , :topmargin)
add_aliases(:bottom_margin , :bottommargin)
add_aliases(:right_margin ,:rightmargin)
# colors # colors
add_aliases(:seriescolor, :c, :color, :colour) add_aliases(:seriescolor, :c, :color, :colour)
add_aliases(:linecolor, :lc, :lcolor, :lcolour, :linecolour) add_aliases(:linecolor, :lc, :lcolor, :lcolour, :linecolour)
@ -583,6 +664,7 @@ add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor
add_aliases(:legend, :leg, :key) add_aliases(:legend, :leg, :key)
add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title) add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title)
add_aliases(:colorbar, :cb, :cbar, :colorkey) add_aliases(:colorbar, :cb, :cbar, :colorkey)
add_aliases(:colorbar_title, :colorbartitle, :cb_title, :cbtitle, :cbartitle, :cbar_title, :colorkeytitle, :colorkey_title)
add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits) add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits)
add_aliases(:smooth, :regression, :reg) add_aliases(:smooth, :regression, :reg)
add_aliases(:levels, :nlevels, :nlev, :levs) add_aliases(:levels, :nlevels, :nlev, :levs)
@ -598,7 +680,6 @@ add_aliases(:quiver, :velocity, :quiver2d, :gradient, :vectorfield)
add_aliases(:normalize, :norm, :normed, :normalized) add_aliases(:normalize, :norm, :normed, :normalized)
add_aliases(:show_empty_bins, :showemptybins, :showempty, :show_empty) add_aliases(:show_empty_bins, :showemptybins, :showempty, :show_empty)
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio) add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
add_aliases(:match_dimensions, :transpose, :transpose_z)
add_aliases(:subplot, :sp, :subplt, :splt) add_aliases(:subplot, :sp, :subplt, :splt)
add_aliases(:projection, :proj) add_aliases(:projection, :proj)
add_aliases(:titlelocation, :title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment) add_aliases(:titlelocation, :title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
@ -618,11 +699,11 @@ add_aliases(:contour_labels, :contourlabels, :clabels, :clabs)
add_aliases(:warn_on_unsupported, :warn) add_aliases(:warn_on_unsupported, :warn)
# add all pluralized forms to the _keyAliases dict # add all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults) for arg in _all_args
_keyAliases[makeplural(arg)] = arg add_aliases(arg, makeplural(arg))
end end
# add all non_underscored forms to the _keyAliases
add_non_underscore_aliases!(_keyAliases)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -944,8 +1025,9 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
replaceAliases!(plotattributes, _keyAliases) replaceAliases!(plotattributes, _keyAliases)
# handle axis args common to all axis # handle axis args common to all axis
args = RecipesPipeline.pop_kw!(plotattributes, :axis, ()) args = wraptuple(RecipesPipeline.pop_kw!(plotattributes, :axis, ()))
for arg in wraptuple(args) showarg = wraptuple(RecipesPipeline.pop_kw!(plotattributes, :showaxis, ()))
for arg in wraptuple((args..., showarg...))
for letter in (:x, :y, :z) for letter in (:x, :y, :z)
process_axis_arg!(plotattributes, arg, letter) process_axis_arg!(plotattributes, arg, letter)
end end
@ -961,9 +1043,9 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
end end
end end
# vline accesses the y argument but actually maps it to the x axis. # vline and others accesses the y argument but actually maps it to the x axis.
# Hence, we have to swap formatters # Hence, we have to swap formatters
if get(plotattributes, :seriestype, :path) == :vline if treats_y_as_x(get(plotattributes, :seriestype, :path))
xformatter = get(plotattributes, :xformatter, :auto) xformatter = get(plotattributes, :xformatter, :auto)
yformatter = get(plotattributes, :yformatter, :auto) yformatter = get(plotattributes, :yformatter, :auto)
plotattributes[:xformatter] = yformatter plotattributes[:xformatter] = yformatter
@ -1032,7 +1114,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
end end
# fonts # fonts
for fontname in (:titlefont, :legendfont, :legendtitlefont) for fontname in (:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont)
args = RecipesPipeline.pop_kw!(plotattributes, fontname, ()) args = RecipesPipeline.pop_kw!(plotattributes, fontname, ())
for arg in wraptuple(args) for arg in wraptuple(args)
processFontArg!(plotattributes, fontname, arg) processFontArg!(plotattributes, fontname, arg)
@ -1057,7 +1139,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
RecipesPipeline.reset_kw!(plotattributes, :marker) RecipesPipeline.reset_kw!(plotattributes, :marker)
if haskey(plotattributes, :markershape) if haskey(plotattributes, :markershape)
plotattributes[:markershape] = _replace_markershape(plotattributes[:markershape]) plotattributes[:markershape] = _replace_markershape(plotattributes[:markershape])
if plotattributes[:markershape] == :none && plotattributes[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected if plotattributes[:markershape] == :none && get(plotattributes, :seriestype, :path) in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
plotattributes[:markershape] = :circle plotattributes[:markershape] = :circle
end end
elseif anymarker elseif anymarker
@ -1113,7 +1195,6 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots) if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
@warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`") @warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`")
end end
return return
end end
@ -1199,6 +1280,8 @@ end
convertLegendValue(val::Bool) = val ? :best : :none convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Nothing) = :none convertLegendValue(val::Nothing) = :none
convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::Tuple{<:Real,Symbol}) = v
convertLegendValue(v::Real) = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v) convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -1269,13 +1352,22 @@ const _match_map = KW(
:right_margin => :margin, :right_margin => :margin,
:bottom_margin => :margin, :bottom_margin => :margin,
:titlefontfamily => :fontfamily_subplot, :titlefontfamily => :fontfamily_subplot,
:legendfontfamily => :fontfamily_subplot,
:legendtitlefontfamily => :fontfamily_subplot,
:titlefontcolor => :foreground_color_subplot, :titlefontcolor => :foreground_color_subplot,
:legendfontfamily => :fontfamily_subplot,
:legendfontcolor => :foreground_color_subplot, :legendfontcolor => :foreground_color_subplot,
:legendtitlefontfamily => :fontfamily_subplot,
:legendtitlefontcolor => :foreground_color_subplot, :legendtitlefontcolor => :foreground_color_subplot,
:colorbar_fontfamily => :fontfamily_subplot,
:colorbar_titlefontfamily => :fontfamily_subplot,
:colorbar_titlefontcolor => :foreground_color_subplot,
:colorbar_tickfontfamily => :fontfamily_subplot,
:colorbar_tickfontcolor => :foreground_color_subplot,
:plot_titlefontfamily => :fontfamily,
:plot_titlefontcolor => :foreground_color,
:tickfontcolor => :foreground_color_text, :tickfontcolor => :foreground_color_text,
:guidefontcolor => :foreground_color_guide, :guidefontcolor => :foreground_color_guide,
:annotationfontfamily => :fontfamily_subplot,
:annotationcolor => :foreground_color_subplot,
) )
# these can match values from the parent container (axis --> subplot --> plot) # these can match values from the parent container (axis --> subplot --> plot)
@ -1499,9 +1591,18 @@ function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in, subplot
_update_subplot_periphery(sp, anns) _update_subplot_periphery(sp, anns)
_update_subplot_colors(sp) _update_subplot_colors(sp)
lims_warned = false
for letter in (:x, :y, :z) for letter in (:x, :y, :z)
_update_axis(plt, sp, plotattributes_in, letter, subplot_index) _update_axis(plt, sp, plotattributes_in, letter, subplot_index)
lk = Symbol(letter, :lims)
# warn against using `Range` in x,y,z lims
if !lims_warned && haskey(plotattributes_in, lk) && plotattributes_in[lk] isa AbstractRange
@warn("lims should be a Tuple, not $(typeof(plotattributes_in[lk])).")
lims_warned = true
end end
end
_update_subplot_colorbars(sp)
end end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -1553,6 +1654,20 @@ function _slice_series_args!(plotattributes::AKW, plt::Plot, sp::Subplot, comman
return plotattributes return plotattributes
end end
label_to_string(label::Bool, series_plotindex) = label ? label_to_string(:auto, series_plotindex) : ""
label_to_string(label::Nothing, series_plotindex) = ""
label_to_string(label::Missing, series_plotindex) = ""
function label_to_string(label::Symbol, series_plotindex)
if label==:auto
return string("y", series_plotindex)
elseif label==:none
return ""
else
throw(ArgumentError("unsupported symbol $(label) passed to `label`"))
end
end
label_to_string(label, series_plotindex) = string(label) # Fallback to string promotion
function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot) function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot)
pkg = plt.backend pkg = plt.backend
globalIndex = plotattributes[:series_plotindex] globalIndex = plotattributes[:series_plotindex]
@ -1621,10 +1736,7 @@ function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot)
end end
# set label # set label
label = plotattributes[:label] plotattributes[:label] = label_to_string.(plotattributes[:label], globalIndex)
label = (label == "AUTO" ? "y$globalIndex" : label)
label = label in (:none, nothing, false) ? "" : label
plotattributes[:label] = label
_replace_linewidth(plotattributes) _replace_linewidth(plotattributes)
plotattributes plotattributes
@ -1645,3 +1757,80 @@ function _series_index(plotattributes, sp)
end end
return idx return idx
end end
#--------------------------------------------------
## inspired by Base.@kwdef
macro add_attributes( level, expr )
expr = macroexpand(__module__, expr) # to expand @static
expr isa Expr && expr.head === :struct || error("Invalid usage of @add_attributes")
T = expr.args[2]
if T isa Expr && T.head === :<:
T = T.args[1]
end
key_args = Any[]
value_args = Any[]
_splitdef!(expr.args[3], value_args, key_args)
insert_block = Expr(:block)
for (key, value) in zip(key_args, value_args)
# e.g. _series_defualts[key] = value
exp_key = Symbol(lowercase(string(T)), "_", key)
pl_key = makeplural(exp_key)
push!(insert_block.args, Expr(
:(=), Expr(:ref, Symbol("_", level, "_defaults"), QuoteNode(exp_key)), value
))
push!(insert_block.args, :(
add_aliases($(QuoteNode(exp_key)), $(QuoteNode(pl_key)))
))
push!(insert_block.args, :(
add_aliases($(QuoteNode(exp_key)), $(QuoteNode(make_non_underscore(exp_key))))
))
push!(insert_block.args, :(
add_aliases($(QuoteNode(exp_key)), $(QuoteNode(make_non_underscore(pl_key))))
))
end
return quote
$expr
$insert_block
end |> esc
end
function _splitdef!(blk, value_args, key_args)
for i in eachindex(blk.args)
ei = blk.args[i]
if ei isa Symbol
# var
continue
elseif ei isa Expr
if ei.head === :(=)
lhs = ei.args[1]
if lhs isa Symbol
# var = defexpr
var = lhs
elseif lhs isa Expr && lhs.head === :(::) && lhs.args[1] isa Symbol
# var::T = defexpr
var = lhs.args[1]
else
# something else, e.g. inline inner constructor
# F(...) = ...
continue
end
defexpr = ei.args[2] # defexpr
push!(value_args, defexpr)
push!(key_args, var)
blk.args[i] = lhs
elseif ei.head === :(::) && ei.args[1] isa Symbol
# var::Typ
var = ei.args[1]
push!(value_args, var)
push!(key_args, var)
elseif ei.head === :block
# can arise with use of @static inside type decl
_kwdef!(ei, value_args, key_args)
end
end
end
blk
end

View File

@ -35,7 +35,6 @@ end
function process_axis_arg!(plotattributes::AKW, arg, letter = "") function process_axis_arg!(plotattributes::AKW, arg, letter = "")
T = typeof(arg) T = typeof(arg)
arg = get(_scaleAliases, arg, arg) arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font if typeof(arg) <: Font
plotattributes[Symbol(letter,:tickfont)] = arg plotattributes[Symbol(letter,:tickfont)] = arg
plotattributes[Symbol(letter,:guidefont)] = arg plotattributes[Symbol(letter,:guidefont)] = arg
@ -95,6 +94,12 @@ function attr!(axis::Axis, args...; kw...)
for vi in v for vi in v
discrete_value!(axis, vi) discrete_value!(axis, vi)
end end
#could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType
# or could perhaps check if dateformatter or datetimeformatter is in use
elseif k == :lims && isa(v, Tuple{Date,Date})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
elseif k == :lims && isa(v, Tuple{DateTime,DateTime})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
else else
plotattributes[k] = v plotattributes[k] = v
end end
@ -124,11 +129,18 @@ const _label_func = Dict{Symbol,Function}(
) )
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string) labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing) const _label_func_tex = Dict{Symbol,Function}(
amin, amax = axis_limits(sp, axis[:letter]) :log10 => x -> "10^{$x}",
:log2 => x -> "2^{$x}",
:ln => x -> "e^{$x}",
)
labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode)
function optimal_ticks_and_labels(ticks, alims, scale, formatter)
amin, amax = alims
# scale the limits # scale the limits
scale = axis[:scale]
sf = RecipesPipeline.scale_func(scale) sf = RecipesPipeline.scale_func(scale)
# If the axis input was a Date or DateTime use a special logic to find # If the axis input was a Date or DateTime use a special logic to find
@ -139,7 +151,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
# rather than on the input format # rather than on the input format
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime # TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
if ticks === nothing && scale == :identity if ticks === nothing && scale == :identity
if axis[:formatter] == RecipesPipeline.dateformatter if formatter == RecipesPipeline.dateformatter
# optimize_datetime_ticks returns ticks and labels(!) based on # optimize_datetime_ticks returns ticks and labels(!) based on
# integers/floats corresponding to the DateTime type. Thus, the axes # integers/floats corresponding to the DateTime type. Thus, the axes
# limits, which resulted from converting the Date type to integers, # limits, which resulted from converting the Date type to integers,
@ -150,7 +162,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
k_min = 2, k_max = 4) k_min = 2, k_max = 4)
# Now the ticks are converted back to floats corresponding to Dates. # Now the ticks are converted back to floats corresponding to Dates.
return ticks / 864e5, labels return ticks / 864e5, labels
elseif axis[:formatter] == RecipesPipeline.datetimeformatter elseif formatter == RecipesPipeline.datetimeformatter
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4) return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
end end
end end
@ -174,22 +186,15 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
# chosen ticks is not too much bigger than amin - amax: # chosen ticks is not too much bigger than amin - amax:
strict_span = false, strict_span = false,
) )
axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax)) # axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax))
else else
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks))) scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end end
unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks) unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks)
labels = if any(isfinite, unscaled_ticks) labels = if any(isfinite, unscaled_ticks)
formatter = axis[:formatter] if formatter in (:auto, :plain, :scientific, :engineering)
if formatter == :auto map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter))
# the default behavior is to make strings of the scaled values and then apply the labelfunc
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :auto))
elseif formatter == :plain
# Leave the numbers in plain format
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, :plain))
elseif formatter == :scientific
Showoff.showoff(unscaled_ticks, :scientific)
elseif formatter == :latex elseif formatter == :latex
map(x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), Showoff.showoff(unscaled_ticks, :auto)) map(x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), Showoff.showoff(unscaled_ticks, :auto))
else else
@ -212,50 +217,115 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
end end
# return (continuous_values, discrete_values) for the ticks on this axis # return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(sp::Subplot, axis::Axis) function get_ticks(sp::Subplot, axis::Axis; update = true)
ticks = _transform_ticks(axis[:ticks]) if update || !haskey(axis.plotattributes, :optimized_ticks)
ticks in (:none, nothing, false) && return nothing
# treat :native ticks as :auto
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values] dvals = axis[:discrete_values]
cv, dv = if typeof(ticks) <: Symbol ticks = _transform_ticks(axis[:ticks])
if !isempty(dvals) axis.plotattributes[:optimized_ticks] = if ticks isa Symbol && ticks !== :none &&
# discrete ticks... ispolar(sp) && axis[:letter] === :x && !isempty(dvals)
n = length(dvals) collect(0:pi/4:7pi/4), string.(0:45:315)
rng = if ticks == :auto
Int[round(Int,i) for i in range(1, stop=n, length=min(n,15))]
else # if ticks == :all
1:n
end
axis[:continuous_values][rng], dvals[rng]
elseif ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else else
# compute optimal ticks and labels cvals = axis[:continuous_values]
optimal_ticks_and_labels(sp, axis) alims = axis_limits(sp, axis[:letter])
scale = axis[:scale]
formatter = axis[:formatter]
get_ticks(ticks, cvals, dvals, alims, scale, formatter)
end end
elseif typeof(ticks) <: Union{AVec, Int}
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(sp, axis, ticks)
end end
elseif typeof(ticks) <: NTuple{2, Any} return axis.plotattributes[:optimized_ticks]
# assuming we're passed (ticks, labels)
ticks
else
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
end
# @show ticks dvals cv dv
return cv, dv
end end
# Ticks getter functions
for l in (:x, :y, :z)
axis = string(l, "-axis") # "x-axis"
ticks = string(l, "ticks") # "xticks"
f = Symbol(ticks) # :xticks
@eval begin
"""
$($f)(p::Plot)
returns a vector of the $($axis) ticks of the subplots of `p`.
Example use:
```jldoctest
julia> p = plot(1:5, $($ticks)=[1,2])
julia> $($f)(p)
1-element Vector{Tuple{Vector{Float64}, Vector{String}}}:
([1.0, 2.0], ["1", "2"])
```
If `p` consists of a single subplot, you might want to grab
only the first element, via
```jldoctest
julia> $($f)(p)[1]
([1.0, 2.0], ["1", "2"])
```
or you can call $($f) on the first (only) subplot of `p` via
```jldoctest
julia> $($f)(p[1])
([1.0, 2.0], ["1", "2"])
```
"""
$f(p::Plot) = get_ticks(p, $(Meta.quot(l)))
"""
$($f)(sp::Subplot)
returns the $($axis) ticks of the subplot `sp`.
Note that the ticks are returned as tuples of values and labels:
```jldoctest
julia> sp = plot(1:5, $($ticks)=[1,2]).subplots[1]
Subplot{1}
julia> $($f)(sp)
([1.0, 2.0], ["1", "2"])
```
"""
$f(sp::Subplot) = get_ticks(sp, $(Meta.quot(l)))
export $f
end
end
# get_ticks from axis symbol :x, :y, or :z
get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[Symbol(s, :axis)])
get_ticks(p::Plot, s::Symbol) = [get_ticks(sp, s) for sp in p.subplots]
function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where T
if ticks === :none
return T[], String[]
elseif !isempty(dvals)
n = length(dvals)
if ticks === :all || n < 16
return cvals, string.(dvals)
else
Δ = ceil(Int, n / 10)
rng = Δ:Δ:n
return cvals[rng], string.(dvals[rng])
end
else
return optimal_ticks_and_labels(nothing, args...)
end
end
get_ticks(ticks::AVec, cvals, dvals, args...) = optimal_ticks_and_labels(ticks, args...)
function get_ticks(ticks::Int, dvals, cvals, args...)
if !isempty(dvals)
rng = round.(Int, range(1, stop=length(dvals), length=ticks))
cvals[rng], string.(dvals[rng])
else
optimal_ticks_and_labels(ticks, args...)
end
end
get_ticks(ticks::NTuple{2, Any}, args...) = ticks
get_ticks(::Nothing, cvals::T, args...) where T = T[], String[]
get_ticks(ticks::Bool, args...) =
ticks ? get_ticks(:auto, args...) : get_ticks(nothing, args...)
get_ticks(::T, args...) where T = error("Unknown ticks type in get_ticks: $T")
_transform_ticks(ticks) = ticks _transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks) _transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2]) _transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
@ -431,20 +501,22 @@ function widen(lmin, lmax, scale = :identity)
end end
# figure out if widening is a good idea. # figure out if widening is a good idea.
const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d) const _widen_seriestypes = (:line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
function default_should_widen(axis::Axis) function default_should_widen(axis::Axis)
should_widen = false if axis[:widen] isa Bool
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round) return axis[:widen]
end
# automatic behavior: widen if limits aren't specified and series type is appropriate
(is_2tuple(axis[:lims]) || axis[:lims] == :round) && return false
for sp in axis.sps for sp in axis.sps
for series in series_list(sp) for series in series_list(sp)
if series.plotattributes[:seriestype] in _widen_seriestypes if series.plotattributes[:seriestype] in _widen_seriestypes
should_widen = true return true
end end
end end
end end
end false
should_widen
end end
function round_limits(amin,amax) function round_limits(amin,amax)
@ -463,13 +535,20 @@ function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(l
has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2 has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
if has_user_lims if has_user_lims
lmin, lmax = lims lmin, lmax = lims
if lmin != :auto && isfinite(lmin) if lmin == :auto
elseif isfinite(lmin)
amin = lmin amin = lmin
end end
if lmax != :auto && isfinite(lmax) if lmax == :auto
elseif isfinite(lmax)
amax = lmax amax = lmax
end end
end end
if lims == :symmetric
aval = max(abs(amin), abs(amax))
amin = -aval
amax = aval
end
if amax <= amin && isfinite(amin) if amax <= amin && isfinite(amin)
amax = amin + 1.0 amax = amin + 1.0
end end
@ -485,7 +564,7 @@ function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(l
else else
amin, amax amin, amax
end end
elseif should_widen && axis[:widen] elseif should_widen
widen(amin, amax, axis[:scale]) widen(amin, amax, axis[:scale])
elseif lims == :round elseif lims == :round
round_limits(amin,amax) round_limits(amin,amax)
@ -577,391 +656,240 @@ end
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# compute the line segments which should be drawn for this axis # compute the line segments which should be drawn for this axis
function axis_drawing_info(sp::Subplot) function axis_drawing_info(sp, letter)
xaxis, yaxis = sp[:xaxis], sp[:yaxis] # find out which axis we are dealing with
xmin, xmax = axis_limits(sp, :x) asym = Symbol(letter, :axis)
ymin, ymax = axis_limits(sp, :y) isy = letter === :y
xticks = get_ticks(sp, xaxis) oletter = isy ? :x : :y
yticks = get_ticks(sp, yaxis) oasym = Symbol(oletter, :axis)
xminorticks = get_minor_ticks(sp, xaxis, xticks)
yminorticks = get_minor_ticks(sp, yaxis, yticks) # get axis objects, ticks and minor ticks
xaxis_segs = Segments(2) ax, oax = sp[asym], sp[oasym]
yaxis_segs = Segments(2) amin, amax = axis_limits(sp, letter)
xtick_segs = Segments(2) oamin, oamax = axis_limits(sp, oletter)
ytick_segs = Segments(2) ticks = get_ticks(sp, ax, update = false)
xgrid_segs = Segments(2) minor_ticks = get_minor_ticks(sp, ax, ticks)
ygrid_segs = Segments(2)
xminorgrid_segs = Segments(2) # initialize the segments
yminorgrid_segs = Segments(2) segments = Segments(2)
xborder_segs = Segments(2) tick_segments = Segments(2)
yborder_segs = Segments(2) grid_segments = Segments(2)
minorgrid_segments = Segments(2)
border_segments = Segments(2)
if sp[:framestyle] != :none if sp[:framestyle] != :none
# xaxis oa1, oa2 = if sp[:framestyle] in (:origin, :zerolines)
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0 0.0, 0.0
else else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) xor(ax[:mirror], oax[:flip]) ? (oamax, oamin) : (oamin, oamax)
end end
if xaxis[:showaxis] if ax[:showaxis]
if sp[:framestyle] != :grid if sp[:framestyle] != :grid
push!(xaxis_segs, (xmin, y1), (xmax, y1)) push!(segments, reverse_if((amin, oa1), isy), reverse_if((amax, oa1), isy))
# don't show the 0 tick label for the origin framestyle # don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1 if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
showticks = xticks[1] .!= 0 i = findfirst(==(0), ticks[1])
xticks = (xticks[1][showticks], xticks[2][showticks]) if i !== nothing
deleteat!(ticks[1], i)
deleteat!(ticks[2], i)
end end
end end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2), (xmax, y2)) # top spine
end end
if !(xaxis[:ticks] in (:none, nothing, false)) if sp[:framestyle] in (:semi, :box) # top spine
f = RecipesPipeline.scale_func(yaxis[:scale]) push!(
invf = RecipesPipeline.inverse_scale_func(yaxis[:scale]) border_segments,
reverse_if((amin, oa2), isy),
reverse_if((amax, oa2), isy),
)
end
end
if ax[:ticks] (:none, nothing, false)
f = RecipesPipeline.scale_func(oax[:scale])
invf = RecipesPipeline.inverse_scale_func(oax[:scale])
add_major_or_minor_segments(ticks, grid, segments, factor, cond) = begin
if cond
tick_start, tick_stop = if sp[:framestyle] == :origin tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(ymax) - f(ymin))) t = invf(f(0) + factor * (f(oamax) - f(oamin)))
(-t, t) (-t, t)
else else
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1 ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in) t = invf(f(oa1) + factor * (f(oa2) - f(oa1)) * ticks_in)
(y1, t) (oa1, t)
end
end end
for xtick in xticks[1] for tick in ticks
if xaxis[:showaxis] if ax[:showaxis] && cond
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick push!(
tick_segments,
reverse_if((tick, tick_start), isy),
reverse_if((tick, tick_stop), isy),
)
end end
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid if grid
end push!(
segments,
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid] reverse_if((tick, oamin), isy),
tick_start, tick_stop = if sp[:framestyle] == :origin reverse_if((tick, oamax), isy),
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 end
end end
end end
# add major grid segments
add_major_or_minor_segments(ticks[1], ax[:grid], grid_segments, 0.012, ax[:tick_direction] !== :none)
# yaxis # add minor grid segments
x1, x2 = if sp[:framestyle] in (:origin, :zerolines) if ax[:minorticks] (:none, nothing, false) || ax[:minorgrid]
0.0, 0.0 add_major_or_minor_segments(minor_ticks, ax[:minorgrid], minorgrid_segments, 0.006, true)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
if yaxis[:showaxis]
if sp[:framestyle] != :grid
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
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
end
if !(yaxis[:ticks] in (:none, nothing, false))
f = RecipesPipeline.scale_func(xaxis[:scale])
invf = RecipesPipeline.inverse_scale_func(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), (tick_stop, ytick)) # left tick
end
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
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), (tick_stop, ytick)) # left tick
end
yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end end
end 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 return (
ticks = ticks,
segments = segments,
tick_segments = tick_segments,
grid_segments = grid_segments,
minorgrid_segments = minorgrid_segments,
border_segments = border_segments
)
end end
function sort_3d_axes(a, b, c, letter)
function axis_drawing_info_3d(sp::Subplot) if letter === :x
xaxis, yaxis, zaxis = sp[:xaxis], sp[:yaxis], sp[:zaxis] a, b, c
xmin, xmax = axis_limits(sp, :x) elseif letter === :y
ymin, ymax = axis_limits(sp, :y) b, a, c
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 else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax) c, b, a
end 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 = RecipesPipeline.scale_func(yaxis[:scale])
invf = RecipesPipeline.inverse_scale_func(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 = RecipesPipeline.scale_func(xaxis[:scale])
invf = RecipesPipeline.inverse_scale_func(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 = RecipesPipeline.scale_func(xaxis[:scale])
invf = RecipesPipeline.inverse_scale_func(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 end
function axis_drawing_info_3d(sp, letter)
near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x
ax = sp[Symbol(letter, :axis)]
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
famin, famax = axis_limits(sp, far_letter)
ticks = get_ticks(sp, ax, update = false)
minor_ticks = get_minor_ticks(sp, ax, ticks)
# initialize the segments
segments = Segments(3)
tick_segments = Segments(3)
grid_segments = Segments(3)
minorgrid_segments = Segments(3)
border_segments = Segments(3)
if sp[:framestyle] != :none# && letter === :x
na0, na1 = if sp[:framestyle] in (:origin, :zerolines)
0, 0
else
# reverse_if((namin, namax), xor(ax[:mirror], nax[:flip]))
reverse_if(reverse_if((namin, namax), letter === :y), xor(ax[:mirror], nax[:flip]))
end
fa0, fa1 = if sp[:framestyle] in (:origin, :zerolines)
0, 0
else
reverse_if((famin, famax), xor(ax[:mirror], fax[:flip]))
end
if ax[:showaxis]
if sp[:framestyle] != :grid
push!(
segments,
sort_3d_axes(amin, na0, fa0, letter),
sort_3d_axes(amax, na0, fa0, letter),
)
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
i0 = findfirst(==(0), ticks[1])
if i0 !== nothing
deleteat!(ticks[1], i0)
deleteat!(ticks[2], i0)
end
end
end
if sp[:framestyle] in (:semi, :box)
push!(
border_segments,
sort_3d_axes(amin, na1, fa1, letter),
sort_3d_axes(amax, na1, fa1, letter),
)
end
end
if ax[:ticks] (:none, nothing, false)
f = RecipesPipeline.scale_func(nax[:scale])
invf = RecipesPipeline.inverse_scale_func(nax[:scale])
ga0, ga1 = sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1)
add_major_or_minor_segments(ticks, grid, segments, factor, cond) = begin
if cond
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + factor * (f(namax) - f(namin)))
(-t, t)
else
ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(na0) + factor * (f(na1) - f(na0)) * ticks_in)
(na0, t)
end
end
for tick in ticks
if ax[:showaxis] && cond
push!(
tick_segments,
sort_3d_axes(tick, tick_start, fa0, letter),
sort_3d_axes(tick, tick_stop, fa0, letter),
)
end
if grid
fa0_, fa1_ = reverse_if((fa0, fa1), ax[:mirror])
ga0_, ga1_ = reverse_if((ga0, ga1), ax[:mirror])
push!(
segments,
sort_3d_axes(tick, ga0_, fa0_, letter),
sort_3d_axes(tick, ga1_, fa0_, letter),
)
push!(
segments,
sort_3d_axes(tick, ga1_, fa0_, letter),
sort_3d_axes(tick, ga1_, fa1_, letter),
)
end
end
end
# add major grid segments
add_major_or_minor_segments(ticks[1], ax[:grid], grid_segments, 0.012, ax[:tick_direction] !== :none)
# add minor grid segments
if ax[:minorticks] (:none, nothing, false) || ax[:minorgrid]
add_major_or_minor_segments(minor_ticks, ax[:minorgrid], minorgrid_segments, 0.006, true)
end
end
end
return (
ticks = ticks,
segments = segments,
tick_segments = tick_segments,
grid_segments = grid_segments,
minorgrid_segments = minorgrid_segments,
border_segments = border_segments
)
end
reverse_if(x, cond) = cond ? reverse(x) : x
axis_tuple(x, y, letter) = reverse_if((x, y), letter === :y)
axes_shift(t, i) = i % 3 == 0 ? t : i % 3 == 1 ? (t[3], t[1], t[2]) : (t[2], t[3], t[1])

View File

@ -1,5 +1,3 @@
using Pkg
struct NoBackend <: AbstractBackend end struct NoBackend <: AbstractBackend end
const _backendType = Dict{Symbol, DataType}(:none => NoBackend) const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
@ -190,12 +188,16 @@ function backend(sym::Symbol)
end end
end end
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize] const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize, :pgfplots]
function warn_on_deprecated_backend(bsym::Symbol) function warn_on_deprecated_backend(bsym::Symbol)
if bsym in _deprecated_backends if bsym in _deprecated_backends
if bsym == :pgfplots
@warn("Backend $bsym has been deprecated. Use pgfplotsx instead.")
else
@warn("Backend $bsym has been deprecated.") @warn("Backend $bsym has been deprecated.")
end end
end
end end
@ -314,7 +316,6 @@ const _gr_attr = merge_with_base_supported([
:layout, :layout,
:title, :window_title, :title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :guide, :lims, :ticks, :scale, :flip,
:match_dimensions,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign, :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor, :titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign, :legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
@ -365,10 +366,10 @@ is_marker_supported(::GRBackend, shape::Shape) = true
function _initialize_backend(pkg::PlotlyBackend) function _initialize_backend(pkg::PlotlyBackend)
try try
@eval Main begin @eval Main begin
import ORCA import PlotlyBase
end end
catch catch
@info "For saving to png with the Plotly backend ORCA has to be installed." @info "For saving to png with the Plotly backend PlotlyBase has to be installed."
end end
end end
@ -427,6 +428,7 @@ const _plotly_seriestype = [
:shape, :shape,
:scattergl, :scattergl,
:straightline, :straightline,
:mesh3d
] ]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot] const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [ const _plotly_marker = [
@ -469,7 +471,6 @@ const _pgfplots_attr = merge_with_base_supported([
:polar, :polar,
# :normalize, :weights, :contours, # :normalize, :weights, :contours,
:aspect_ratio, :aspect_ratio,
# :match_dimensions,
:tick_direction, :tick_direction,
:framestyle, :framestyle,
:camera, :camera,
@ -485,7 +486,7 @@ const _pgfplots_scale = [:identity, :ln, :log2, :log10]
function _initialize_backend(pkg::PlotlyJSBackend) function _initialize_backend(pkg::PlotlyJSBackend)
@eval Main begin @eval Main begin
import PlotlyJS, ORCA import PlotlyJS
export PlotlyJS export PlotlyJS
end end
end end
@ -530,6 +531,10 @@ const _pyplot_attr = merge_with_base_supported([
:guidefontfamily, :guidefontsize, :guidefontcolor, :guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
:colorbar_ticks, :colorbar_tickfontfamily, :colorbar_tickfontsize,
:colorbar_tickfonthalign, :colorbar_tickfontvalign,
:colorbar_tickfontrotation, :colorbar_tickfontcolor,
:colorbar_scale,
:marker_z, :line_z, :fill_z, :marker_z, :line_z, :fill_z,
:levels, :levels,
:ribbon, :quiver, :arrow, :ribbon, :quiver, :arrow,
@ -538,7 +543,6 @@ const _pyplot_attr = merge_with_base_supported([
:polar, :polar,
:normalize, :weights, :normalize, :weights,
:contours, :aspect_ratio, :contours, :aspect_ratio,
:match_dimensions,
:clims, :clims,
:inset_subplots, :inset_subplots,
:dpi, :dpi,
@ -551,6 +555,7 @@ const _pyplot_attr = merge_with_base_supported([
const _pyplot_seriestype = [ const _pyplot_seriestype = [
:path, :path,
:steppre, :steppre,
:stepmid,
:steppost, :steppost,
:shape, :shape,
:straightline, :straightline,
@ -624,7 +629,6 @@ const _hdf5_attr = merge_with_base_supported([
:polar, :polar,
:normalize, :weights, :normalize, :weights,
:contours, :aspect_ratio, :contours, :aspect_ratio,
:match_dimensions,
:clims, :clims,
:inset_subplots, :inset_subplots,
:dpi, :dpi,
@ -633,6 +637,7 @@ const _hdf5_attr = merge_with_base_supported([
const _hdf5_seriestype = [ const _hdf5_seriestype = [
:path, :path,
:steppre, :steppre,
:stepmid,
:steppost, :steppost,
:shape, :shape,
:straightline, :straightline,
@ -662,11 +667,6 @@ mutable struct HDF5Plot_PlotRef
end end
const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing) const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText,
Shape,
}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# inspectdr # inspectdr
@ -702,7 +702,6 @@ const _inspectdr_attr = merge_with_base_supported([
:polar, :polar,
# :normalize, :weights, # :normalize, :weights,
# :contours, :aspect_ratio, # :contours, :aspect_ratio,
:match_dimensions,
# :clims, # :clims,
# :inset_subplots, # :inset_subplots,
:dpi, :dpi,
@ -710,7 +709,7 @@ const _inspectdr_attr = merge_with_base_supported([
]) ])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot] const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [ const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost :path, :scatter, :shape, :straightline, #, :steppre, :stepmid, :steppost
] ]
#see: _allMarkers, _shape_keys #see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[ const _inspectdr_marker = Symbol[
@ -763,7 +762,6 @@ const _pgfplotsx_attr = merge_with_base_supported([
:ticks, :ticks,
:scale, :scale,
:flip, :flip,
:match_dimensions,
:titlefontfamily, :titlefontfamily,
:titlefontsize, :titlefontsize,
:titlefonthalign, :titlefonthalign,
@ -826,6 +824,7 @@ const _pgfplotsx_seriestype = [
:surface, :surface,
:wireframe, :wireframe,
:heatmap, :heatmap,
:mesh3d,
:contour, :contour,
:contour3d, :contour3d,
:quiver, :quiver,
@ -849,6 +848,7 @@ const _pgfplotsx_marker = [
:rtriangle, :rtriangle,
:cross, :cross,
:xcross, :xcross,
:x,
:star5, :star5,
:pentagon, :pentagon,
:hline, :hline,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,6 @@ Add in functionality to Plots.jl:
is_marker_supported(::InspectDRBackend, shape::Shape) = true is_marker_supported(::InspectDRBackend, shape::Shape) = true
_inspectdr_to_pixels(bb::BoundingBox) =
InspectDR.BoundingBox(to_pixels(left(bb)), to_pixels(right(bb)), to_pixels(top(bb)), to_pixels(bottom(bb)))
#Do we avoid Map to avoid possible pre-comile issues? #Do we avoid Map to avoid possible pre-comile issues?
function _inspectdr_mapglyph(s::Symbol) function _inspectdr_mapglyph(s::Symbol)
s == :rect && return :square s == :rect && return :square
@ -79,6 +76,58 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
function _inspectdr_getaxisticks(ticks, gridlines, xfrm)
TickCustom = InspectDR.TickCustom
_xfrm(coord) = InspectDR.axis2aloc(Float64(coord), xfrm.spec) #Ensure Float64 - in case
ttype = ticksType(ticks)
if ticks == :native
#keep current
elseif ttype == :ticks_and_labels
pos = ticks[1]; labels = ticks[2]; nticks = length(ticks[1])
newticks = TickCustom[TickCustom(_xfrm(pos[i]), labels[i]) for i in 1:nticks]
gridlines = InspectDR.GridLinesCustom(gridlines)
gridlines.major = newticks
gridlines.minor = []
gridlines.displayminor = false
elseif ttype == :ticks
nticks = length(ticks)
gridlines.major = Float64[_xfrm(t) for t in ticks]
gridlines.minor = []
gridlines.displayminor = false
elseif isnothing(ticks)
gridlines.major = []
gridlines.minor = []
else #Assume ticks == :native
#keep current
end
return gridlines #keep current
end
function _inspectdr_setticks(sp::Subplot, plot, strip, xaxis, yaxis)
InputXfrm1D = InspectDR.InputXfrm1D
_get_ticks(axis) = :native == axis[:ticks] ? (:native) : get_ticks(sp, axis)
wantnative(ticks) = (:native == ticks)
xticks = _get_ticks(xaxis)
yticks = _get_ticks(yaxis)
if wantnative(xticks) && wantnative(yticks)
#Don't "eval" tick values
return
end
#TODO: Allow InspectDR to independently "eval" x or y ticks
ext = InspectDR.getextents_aloc(plot, 1)
grid = InspectDR._eval(strip.grid, plot.xscale, strip.yscale, ext)
grid.xlines = _inspectdr_getaxisticks(xticks, grid.xlines, InputXfrm1D(plot.xscale))
grid.ylines = _inspectdr_getaxisticks(yticks, grid.ylines, InputXfrm1D(strip.yscale))
strip.grid = grid
end
# ---------------------------------------------------------------------------
function _inspectdr_getscale(s::Symbol, yaxis::Bool) function _inspectdr_getscale(s::Symbol, yaxis::Bool)
#TODO: Support :asinh, :sqrt #TODO: Support :asinh, :sqrt
kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis
@ -167,6 +216,7 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
st = series[:seriestype] st = series[:seriestype]
sp = series[:subplot] sp = series[:subplot]
plot = sp.o plot = sp.o
clims = get_clims(sp, series)
#Don't do anything without a "subplot" object: Will process later. #Don't do anything without a "subplot" object: Will process later.
if nothing == plot; return; end if nothing == plot; return; end
@ -237,7 +287,7 @@ For st in :shape:
color = linecolor, fillcolor = fillcolor color = linecolor, fillcolor = fillcolor
) )
end end
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost) elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost)
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think). #NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth] linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth: #More efficient & allows some support for markerstrokewidth:
@ -256,8 +306,8 @@ For st in :shape:
wfrm.glyph = InspectDR.glyph( wfrm.glyph = InspectDR.glyph(
shape = _inspectdr_mapglyph(series[:markershape]), shape = _inspectdr_mapglyph(series[:markershape]),
size = _inspectdr_mapglyphsize(series[:markersize]), size = _inspectdr_mapglyphsize(series[:markersize]),
color = _inspectdr_mapcolor(plot_color(series[:markerstrokecolor], series[:markerstrokealpha])), color = _inspectdr_mapcolor(plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series))),
fillcolor = _inspectdr_mapcolor(plot_color(series[:markercolor], series[:markeralpha])), fillcolor = _inspectdr_mapcolor(plot_color(get_markercolor(series, clims), get_markeralpha(series))),
) )
end end
@ -302,38 +352,48 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
xmin, xmax = -rmax, rmax xmin, xmax = -rmax, rmax
ymin, ymax = -rmax, rmax ymin, ymax = -rmax, rmax
end end
plot.xext = InspectDR.PExtents1D() #reset
strip.yext = InspectDR.PExtents1D() #reset
plot.xext_full = InspectDR.PExtents1D(xmin, xmax) plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
strip.yext_full = InspectDR.PExtents1D(ymin, ymax) strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
#Set current extents = full extents (needed for _eval(strip.grid,...))
plot.xext = plot.xext_full
strip.yext = strip.yext_full
_inspectdr_setticks(sp, plot, strip, xaxis, yaxis)
a = plot.annotation a = plot.annotation
a.title = sp[:title] a.title = sp[:title]
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]] a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
l = plot.layout #Modify base layout of new object:
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot]) l = plot.layout.defaults = deepcopy(InspectDR.defaults.plotlayout)
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside]) #IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots.
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis]) #Works because plot uses defaults (not user-overwritten `layout.values`)
l[:font_title] = InspectDR.Font(sp[:titlefontfamily], l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l.font_title = InspectDR.Font(sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]), _inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor]) color = _inspectdr_mapcolor(sp[:titlefontcolor])
) )
#Cannot independently control fonts of axes with InspectDR: #Cannot independently control fonts of axes with InspectDR:
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefontfamily], l.font_axislabel = InspectDR.Font(xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]), _inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor]) color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
) )
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily], l.font_ticklabel = InspectDR.Font(xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]), _inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor]) color = _inspectdr_mapcolor(xaxis[:tickfontcolor])
) )
l[:enable_legend] = (sp[:legend] != :none) l.enable_legend = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute??? #l.halloc_legend = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfontfamily], l.font_legend = InspectDR.Font(sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfontsize]), _inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:legendfontcolor]) color = _inspectdr_mapcolor(sp[:legendfontcolor])
) )
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend]) l.frame_legend.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
#_round!() ensures values use integer spacings (looks better on screen):
InspectDR._round!(InspectDR.autofit2font!(l, legend_width=10.0)) #10 "em"s wide
return
end end
# called just before updating layout bounding boxes... in case you need to prep # called just before updating layout bounding boxes... in case you need to prep
@ -347,8 +407,9 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
#Don't use window_title... probably not what you want. #Don't use window_title... probably not what you want.
#mplot.title = plt[:window_title] #mplot.title = plt[:window_title]
end end
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
mplot.layout[:frame] = mplot.layout[:frame] #register changes
resize!(mplot.subplots, length(plt.subplots)) resize!(mplot.subplots, length(plt.subplots))
nsubplots = length(plt.subplots) nsubplots = length(plt.subplots)
for (i, sp) in enumerate(plt.subplots) for (i, sp) in enumerate(plt.subplots)
@ -412,11 +473,16 @@ end
function _update_plot_object(plt::Plot{InspectDRBackend}) function _update_plot_object(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o) mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot; return; end if nothing == mplot; return; end
mplot.bblist = InspectDR.BoundingBox[]
for (i, sp) in enumerate(plt.subplots) for (i, sp) in enumerate(plt.subplots)
graphbb = _inspectdr_to_pixels(plotarea(sp)) figw, figh = sp.plt[:size]
plot = mplot.subplots[i] pcts = bbox_to_pcts(sp.bbox, figw*px, figh*px)
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb) _left, _bottom, _width, _height = pcts
ymax = 1.0-_bottom
ymin = ymax - _height
bb = InspectDR.BoundingBox(_left, _left+_width, ymin, ymax)
push!(mplot.bblist, bb)
end end
gplot = _inspectdr_getgui(plt.o) gplot = _inspectdr_getgui(plt.o)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
# https://plot.ly/javascript/getting-started # https://plot.ly/javascript/getting-started
is_subplot_supported(::PlotlyBackend) = true is_subplot_supported(::PlotlyBackend) = true
@ -8,7 +7,7 @@ function _plotly_framestyle(style::Symbol)
return style return style
else else
default_style = get((semi = :box, origin = :zerolines), style, :axes) default_style = get((semi = :box, origin = :zerolines), style, :axes)
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.") @warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was chosen instead.")
default_style default_style
end end
end end
@ -20,21 +19,15 @@ using UUIDs
# ---------------------------------------------------------------- # ----------------------------------------------------------------
plotly_legend_pos(pos::Symbol) = get( function labelfunc(scale::Symbol, backend::PlotlyBackend)
( texfunc = labelfunc_tex(scale)
right = [1.0, 0.5], function (x)
left = [0.0, 0.5], tex_x = texfunc(x)
top = [0.5, 1.0], sup_x = replace( tex_x, r"\^{(.*)}"=>s"<sup>\1</sup>" )
bottom = [0.5, 0.0], # replace dash with \minus (U+2212)
bottomleft = [0.0, 0.0], replace(sup_x, "-" => "")
bottomright = [1.0, 0.0], end
topright = [1.0, 1.0], end
topleft = [0.0, 1.0],
),
pos,
[1.0, 1.0],
)
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
function plotly_font(font::Font, color = font.color) function plotly_font(font::Font, color = font.color)
KW( KW(
@ -127,16 +120,17 @@ end
# this method gets the start/end in percentage of the canvas for this axis direction # this method gets the start/end in percentage of the canvas for this axis direction
function plotly_domain(sp::Subplot, letter) function plotly_domain(sp::Subplot)
figw, figh = sp.plt[:size] figw, figh = sp.plt[:size]
pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px) pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px)
pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts) pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts)
i1,i2 = (letter == :x ? (1,3) : (2,4)) x_domain = [pcts[1], pcts[1] + pcts[3]]
[pcts[i1], pcts[i1]+pcts[i2]] y_domain = [pcts[2], pcts[2] + pcts[4]]
return x_domain, y_domain
end end
function plotly_axis(plt::Plot, axis::Axis, sp::Subplot) function plotly_axis(axis, sp, anchor = nothing, domain = nothing)
letter = axis[:letter] letter = axis[:letter]
framestyle = sp[:framestyle] framestyle = sp[:framestyle]
ax = KW( ax = KW(
@ -149,20 +143,16 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
:zerolinecolor => rgba_string(axis[:foreground_color_axis]), :zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes) && axis[:showaxis], :showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])), :linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside", :ticks => axis[:tick_direction] === :out ? "outside" :
axis[:tick_direction] === :in ? "inside" : "",
:mirror => framestyle == :box, :mirror => framestyle == :box,
:showticklabels => axis[:showaxis], :showticklabels => axis[:showaxis],
) )
if anchor !== nothing
if letter in (:x,:y) ax[:anchor] = anchor
ax[:domain] = plotly_domain(sp, letter)
if RecipesPipeline.is3d(sp)
# don't link 3d axes for synchronized interactivity
x_idx = y_idx = sp[:subplot_index]
else
x_idx, y_idx = plotly_link_indicies(plt, sp)
end end
ax[:anchor] = "$(letter==:x ? "y$(y_idx)" : "x$(x_idx)")" if domain !== nothing
ax[:domain] = domain
end end
ax[:tickangle] = -axis[:rotation] ax[:tickangle] = -axis[:rotation]
@ -257,14 +247,19 @@ function plotly_layout(plt::Plot)
# set to supported framestyle # set to supported framestyle
sp[:framestyle] = _plotly_framestyle(sp[:framestyle]) sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
# if any(RecipesPipeline.is3d, seriesargs) if ispolar(sp)
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
else
x_domain, y_domain = plotly_domain(sp)
if RecipesPipeline.is3d(sp) if RecipesPipeline.is3d(sp)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
plotattributes_out[:scene] = KW( plotattributes_out[Symbol(:scene, spidx)] = KW(
Symbol("xaxis$(spidx)") => plotly_axis(plt, sp[:xaxis], sp), :domain => KW(:x => x_domain, :y => y_domain),
Symbol("yaxis$(spidx)") => plotly_axis(plt, sp[:yaxis], sp), Symbol("xaxis$(spidx)") => plotly_axis(sp[:xaxis], sp),
Symbol("zaxis$(spidx)") => plotly_axis(plt, sp[:zaxis], sp), Symbol("yaxis$(spidx)") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$(spidx)") => plotly_axis(sp[:zaxis], sp),
#2.6 multiplier set camera eye such that whole plot can be seen #2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW( :camera => KW(
@ -275,28 +270,19 @@ function plotly_layout(plt::Plot)
), ),
), ),
) )
elseif ispolar(sp)
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
else else
plotattributes_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp) plotattributes_out[Symbol("xaxis$(x_idx)")] =
plotly_axis(sp[:xaxis], sp, string("y", y_idx) , x_domain)
# don't allow yaxis to be reupdated/reanchored in a linked subplot # don't allow yaxis to be reupdated/reanchored in a linked subplot
spidx == y_idx ? plotattributes_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing if spidx == y_idx
plotattributes_out[Symbol("yaxis$(y_idx)")] =
plotly_axis(sp[:yaxis], sp, string("x", x_idx), y_domain)
end
end
end end
# legend # legend
plotattributes_out[:showlegend] = sp[:legend] != :none plotly_add_legend!(plotattributes_out, sp)
xpos,ypos = plotly_legend_pos(sp[:legend])
if sp[:legend] != :none
plotattributes_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => xpos,
:y => ypos
)
end
# annotations # annotations
for ann in sp[:annotations] for ann in sp[:annotations]
@ -336,9 +322,89 @@ function plotly_layout(plt::Plot)
plotattributes_out[:hovermode] = "none" plotattributes_out[:hovermode] = "none"
end end
plotattributes_out plotattributes_out = recursive_merge(plotattributes_out, plt.attr[:extra_plot_kwargs])
end end
function plotly_add_legend!(plotattributes_out::KW, sp::Subplot)
plotattributes_out[:showlegend] = sp[:legend] != :none
legend_position = plotly_legend_pos(sp[:legend])
if sp[:legend] != :none
plotattributes_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:borderwidth => 1,
:traceorder => "normal",
:xanchor => legend_position.xanchor,
:yanchor => legend_position.yanchor,
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => legend_position.coords[1],
:y => legend_position.coords[2],
:title => KW(
:text => sp[:legendtitle] === nothing ? "" : string(sp[:legendtitle]),
:font => plotly_font(legendtitlefont(sp)),
),
)
end
end
function plotly_legend_pos(pos::Symbol)
xleft = 0.07
ybot = 0.07
ytop = 1.0
xcenter = 0.55
ycenter = 0.52
center = 0.5
youtertop = 1.1
youterbot = -0.15
xouterright = 1.05
xouterleft = -0.15
plotly_legend_position_mapping = (
right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"),
left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"),
top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"),
bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"),
bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"),
bottomright = (coords = [1.0, ybot], xanchor = "right", yanchor = "bottom"),
topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"),
topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"),
outertop =(coords = [center, youtertop ], xanchor = "upper", yanchor = "middle"),
outerbottom =(coords = [center, youterbot], xanchor = "lower", yanchor = "middle"),
outerleft =(coords = [xouterleft, center], xanchor = "left", yanchor = "top"),
outerright =(coords = [xouterright, center], xanchor = "right", yanchor = "top"),
outertopleft =(coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"),
outertopright = (coords = [xouterright, ytop], xanchor = "upper", yanchor = "right"),
outerbottomleft =(coords = [xouterleft, ybot], xanchor = "lower", yanchor = "left"),
outerbottomright =(coords = [xouterright, ybot], xanchor = "lower", yanchor = "right"),
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto")
)
legend_position = get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default)
end
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = (coords=v, xanchor="left", yanchor="top")
plotly_legend_pos(theta::Real) = plotly_legend_pos((theta, :inner))
function plotly_legend_pos(v::Tuple{S,Symbol}) where S<:Real
(s,c) = sincosd(v[1])
xanchors = ["left", "center", "right"]
yanchors = ["bottom", "middle", "top"]
if v[2] === :inner
rect = (0.07,0.5,1.0,0.07,0.52,1.0)
xanchor = xanchors[legend_anchor_index(c)]
yanchor = yanchors[legend_anchor_index(s)]
else
rect = (-0.15,0.5,1.05,-0.15,0.52,1.1)
xanchor = xanchors[4-legend_anchor_index(c)]
yanchor = yanchors[4-legend_anchor_index(s)]
end
return (coords=legend_pos_from_angle(v[1],rect...), xanchor=xanchor, yanchor=yanchor)
end
function plotly_layout_json(plt::Plot) function plotly_layout_json(plt::Plot)
JSON.json(plotly_layout(plt), 4) JSON.json(plotly_layout(plt), 4)
end end
@ -416,8 +482,8 @@ function plotly_data(series::Series, letter::Symbol, data)
data data
end end
if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe) if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d)
plotly_surface_data(series, data) handle_surface(data)
else else
plotly_data(data) plotly_data(data)
end end
@ -427,10 +493,6 @@ plotly_data(v::AbstractArray) = v
plotly_data(surf::Surface) = surf.surf plotly_data(surf::Surface) = surf.surf
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v) plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
plotly_surface_data(series::Series, a::AbstractVector) = a
plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false)
plotly_surface_data(series::Series, a::Surface) = plotly_surface_data(series, a.surf)
function plotly_native_data(axis::Axis, data::AbstractArray) function plotly_native_data(axis::Axis, data::AbstractArray)
if !isempty(axis[:discrete_values]) if !isempty(axis[:discrete_values])
construct_categorical_data(data, axis) construct_categorical_data(data, axis)
@ -471,9 +533,17 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out = KW() plotattributes_out = KW()
# these are the axes that the series should be mapped to # these are the axes that the series should be mapped to
x_idx, y_idx = plotly_link_indicies(plt, sp) if RecipesPipeline.is3d(sp)
spidx = length(plt.subplots) > 1 ? sp[:subplot_index] : ""
plotattributes_out[:xaxis] = "x$spidx"
plotattributes_out[:yaxis] = "y$spidx"
plotattributes_out[:zaxis] = "z$spidx"
plotattributes_out[:scene] = "scene$spidx"
else
x_idx, y_idx = length(plt.subplots) > 1 ? plotly_link_indicies(plt, sp) : ("", "")
plotattributes_out[:xaxis] = "x$(x_idx)" plotattributes_out[:xaxis] = "x$(x_idx)"
plotattributes_out[:yaxis] = "y$(y_idx)" plotattributes_out[:yaxis] = "y$(y_idx)"
end
plotattributes_out[:showlegend] = should_add_to_legend(series) plotattributes_out[:showlegend] = should_add_to_legend(series)
if st == :straightline if st == :straightline
@ -538,11 +608,34 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:opacity] = 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]) plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
end end
plotattributes_out[:showscale] = hascolorbar(sp) plotattributes_out[:showscale] = hascolorbar(sp)
end end
elseif st == :mesh3d
plotattributes_out[:type] = "mesh3d"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if series[:connections] !== nothing
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
i,j,k = series[:connections]
if !(length(i) == length(j) == length(k))
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
end
plotattributes_out[:i] = i
plotattributes_out[:j] = j
plotattributes_out[:k] = k
else
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
end
end
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:color] = rgba_string(plot_color(series[:fillcolor], series[:fillalpha]))
plotattributes_out[:opacity] = series[:fillalpha]
if series[:fill_z] !== nothing
plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
end
plotattributes_out[:showscale] = hascolorbar(sp)
else else
@warn("Plotly: seriestype $st isn't supported.") @warn("Plotly: seriestype $st isn't supported.")
return KW() return KW()
@ -570,7 +663,7 @@ function plotly_series(plt::Plot, series::Series)
end end
function plotly_series_shapes(plt::Plot, series::Series, clims) function plotly_series_shapes(plt::Plot, series::Series, clims)
segments = iter_segments(series) segments = series_segments(series)
plotattributes_outs = Vector{KW}(undef, length(segments)) plotattributes_outs = Vector{KW}(undef, length(segments))
# TODO: create a plotattributes_out for each polygon # TODO: create a plotattributes_out for each polygon
@ -589,7 +682,8 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
for (letter, data) in zip((:x, :y), shape_data(series, 100)) for (letter, data) in zip((:x, :y), shape_data(series, 100))
) )
for (i,rng) in enumerate(segments) for (k, segment) in enumerate(segments)
i, rng = segment.attr_index, segment.range
length(rng) < 2 && continue length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill # to draw polygons, we actually draw lines with fill
@ -608,10 +702,10 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
:dash => string(get_linestyle(series, i)), :dash => string(get_linestyle(series, i)),
) )
end end
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false plotattributes_out[:showlegend] = k==1 ? should_add_to_legend(series) : false
plotly_polar!(plotattributes_out, series) plotly_polar!(plotattributes_out, series)
plotly_hover!(plotattributes_out, _cycle(series[:hover], i)) plotly_hover!(plotattributes_out, _cycle(series[:hover], i))
plotattributes_outs[i] = plotattributes_out plotattributes_outs[k] = plotattributes_out
end end
if series[:fill_z] !== nothing if series[:fill_z] !== nothing
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill)) push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
@ -632,12 +726,16 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) && hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple)) (isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
segments = iter_segments(series) segments = collect(series_segments(series, st))
plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments)) plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments))
for (i,rng) in enumerate(segments) needs_scatter_fix = !isscatter && hasmarker && !any(isnan,y) && length(segments) > 1
for (k, segment) in enumerate(segments)
i, rng = segment.attr_index, segment.range
plotattributes_out = deepcopy(plotattributes_base) plotattributes_out = deepcopy(plotattributes_base)
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false plotattributes_out[:showlegend] = k==1 ? should_add_to_legend(series) : false
plotattributes_out[:legendgroup] = series[:label] plotattributes_out[:legendgroup] = series[:label]
# set the type # set the type
@ -671,13 +769,15 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
# add "marker" # add "marker"
if hasmarker if hasmarker
mcolor = rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i)))
lcolor = rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i)))
plotattributes_out[:marker] = KW( plotattributes_out[:marker] = KW(
:symbol => get_plotly_marker(_cycle(series[:markershape], i), string(_cycle(series[:markershape], i))), :symbol => get_plotly_marker(_cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => series[:markeralpha], # :opacity => needs_scatter_fix ? [1, 0] : 1,
:size => 2 * _cycle(series[:markersize], i), :size => 2 * _cycle(series[:markersize], i),
:color => rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))), :color => needs_scatter_fix ? [mcolor, "rgba(0, 0, 0, 0.000)"] : mcolor,
:line => KW( :line => KW(
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))), :color => needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor,
:width => _cycle(series[:markerstrokewidth], i), :width => _cycle(series[:markerstrokewidth], i),
), ),
) )
@ -690,6 +790,8 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
:width => get_linewidth(series, i), :width => get_linewidth(series, i),
:shape => if st == :steppre :shape => if st == :steppre
"vh" "vh"
elseif st == :stepmid
"hvh"
elseif st == :steppost elseif st == :steppost
"hv" "hv"
else else
@ -722,16 +824,15 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
else else
# if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange # if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange
# is the series that will do the filling # is the series that will do the filling
fillrng = Tuple(series[:fillrange][i][rng] for i in 1:2) plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], series[:fillrange])
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
plotattributes_out_fillrange[:line][:width] = 0 plotattributes_out_fillrange[:line][:width] = 0
delete!(plotattributes_out, :fill) delete!(plotattributes_out, :fill)
delete!(plotattributes_out, :fillcolor) delete!(plotattributes_out, :fillcolor)
end end
plotattributes_outs[(2 * i - 1):(2 * i)] = [plotattributes_out_fillrange, plotattributes_out] plotattributes_outs[(2k-1):(2k)] = [plotattributes_out_fillrange, plotattributes_out]
else else
plotattributes_outs[i] = plotattributes_out plotattributes_outs[k] = plotattributes_out
end end
end end
@ -759,8 +860,8 @@ function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symb
end end
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line) # zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
plotattributes_out[:marker] = KW( plotattributes_out[:marker] = KW(
:size => 0, :size => 1e-10,
:opacity => 0, :opacity => 1e-10,
:color => [0.5], :color => [0.5],
:cmin => cmin, :cmin => cmin,
:cmax => cmax, :cmax => cmax,
@ -807,26 +908,19 @@ plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt), 4)
html_head(plt::Plot{PlotlyBackend}) = plotly_html_head(plt) html_head(plt::Plot{PlotlyBackend}) = plotly_html_head(plt)
html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt) html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt)
const ijulia_initialized = Ref(false)
function plotly_html_head(plt::Plot) function plotly_html_head(plt::Plot)
local_file = ("file://" * plotly_local_file_path)
plotly = plotly =
use_local_dependencies[] ? local_file : "https://cdn.plot.ly/plotly-latest.min.js" use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)"
if isijulia() && !ijulia_initialized[]
# using requirejs seems to be key to load a js depency in IJulia! include_mathjax = get(plt[:extra_plot_kwargs], :include_mathjax, "")
# https://requirejs.org/docs/start.html mathjax_file = include_mathjax != "cdn" ? ("file://" * include_mathjax) : "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"
# https://github.com/JuliaLang/IJulia.jl/issues/345 mathjax_head = include_mathjax == "" ? "" : "<script src=\"$mathjax_file\"></script>\n\t\t"
display("text/html", """
<script type="text/javascript"> if isijulia()
requirejs([$(repr(plotly))], function(p) { mathjax_head
window.Plotly = p else
}); "$mathjax_head<script src=$(repr(plotly))></script>"
</script>
""")
ijulia_initialized[] = true
end end
return "<script src=$(repr(plotly))></script>"
end end
function plotly_html_body(plt, style = nothing) function plotly_html_body(plt, style = nothing)
@ -834,12 +928,33 @@ function plotly_html_body(plt, style = nothing)
w, h = plt[:size] w, h = plt[:size]
style = "width:$(w)px;height:$(h)px;" style = "width:$(w)px;height:$(h)px;"
end end
requirejs_prefix = ""
requirejs_suffix = ""
if isijulia()
# require.js adds .js automatically
plotly_no_ext =
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/$(_plotly_min_js_filename)"
plotly_no_ext = plotly_no_ext[1:end-3]
requirejs_prefix = """
requirejs.config({
paths: {
Plotly: '$(plotly_no_ext)'
}
});
require(['Plotly'], function (Plotly) {
"""
requirejs_suffix = "});"
end
uuid = UUIDs.uuid4() uuid = UUIDs.uuid4()
html = """ html = """
<div id=\"$(uuid)\" style=\"$(style)\"></div> <div id=\"$(uuid)\" style=\"$(style)\"></div>
<script> <script>
PLOT = document.getElementById('$(uuid)'); $(requirejs_prefix)
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt))); $(js_body(plt, uuid))
$(requirejs_suffix)
</script> </script>
""" """
html html
@ -847,7 +962,7 @@ end
function js_body(plt::Plot, uuid) function js_body(plt::Plot, uuid)
js = """ js = """
PLOT = document.getElementById('$(uuid)'); var PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt))); Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
""" """
end end
@ -871,7 +986,7 @@ end
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend}) function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, standalone_html(plt)) write(io, embeddable_html(plt))
end end

View File

@ -1,14 +1,14 @@
function plotlybase_syncplot(plt::Plot) function plotlybase_syncplot(plt::Plot)
plt.o = ORCA.PlotlyBase.Plot() plt.o = PlotlyBase.Plot()
traces = ORCA.PlotlyBase.GenericTrace[] traces = PlotlyBase.GenericTrace[]
for series_dict in plotly_series(plt) for series_dict in plotly_series(plt)
plotly_type = pop!(series_dict, :type) plotly_type = pop!(series_dict, :type)
push!(traces, ORCA.PlotlyBase.GenericTrace(plotly_type; series_dict...)) push!(traces, PlotlyBase.GenericTrace(plotly_type; series_dict...))
end end
ORCA.PlotlyBase.addtraces!(plt.o, traces...) PlotlyBase.addtraces!(plt.o, traces...)
layout = plotly_layout(plt) layout = plotly_layout(plt)
w, h = plt[:size] w, h = plt[:size]
ORCA.PlotlyBase.relayout!(plt.o, layout, width = w, height = h) PlotlyBase.relayout!(plt.o, layout, width = w, height = h)
return plt.o return plt.o
end end
@ -19,5 +19,5 @@ for (mime, fmt) in (
"image/eps" => "eps", "image/eps" => "eps",
) )
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyBackend}) = @eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyBackend}) =
ORCA.PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = $fmt) PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = $fmt)
end end

View File

@ -34,13 +34,12 @@ _show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBack
html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt) html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt)
html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt) html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt)
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, standalone_html(plt)) _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, embeddable_html(plt))
_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt)) _display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt))
function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend}) function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend})
plt_html = sprint(show, MIME("text/html"), plt) return PlotlyJS.WebIO.render(plotlyjs_syncplot(plt))
return PlotlyJS.WebIO.render(PlotlyJS.WebIO.dom"div"(innerHTML=plt_html))
end end
function closeall(::PlotlyJSBackend) function closeall(::PlotlyJSBackend)

View File

@ -13,6 +13,7 @@ append!(Base.Multimedia.displays, otherdisplays)
pycolors = PyPlot.pyimport("matplotlib.colors") pycolors = PyPlot.pyimport("matplotlib.colors")
pypath = PyPlot.pyimport("matplotlib.path") pypath = PyPlot.pyimport("matplotlib.path")
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d") mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
axes_grid1 = PyPlot.pyimport("mpl_toolkits.axes_grid1")
pypatches = PyPlot.pyimport("matplotlib.patches") pypatches = PyPlot.pyimport("matplotlib.patches")
pyfont = PyPlot.pyimport("matplotlib.font_manager") pyfont = PyPlot.pyimport("matplotlib.font_manager")
pyticker = PyPlot.pyimport("matplotlib.ticker") pyticker = PyPlot.pyimport("matplotlib.ticker")
@ -22,6 +23,8 @@ pynp."seterr"(invalid="ignore")
pytransforms = PyPlot.pyimport("matplotlib.transforms") pytransforms = PyPlot.pyimport("matplotlib.transforms")
pycollections = PyPlot.pyimport("matplotlib.collections") pycollections = PyPlot.pyimport("matplotlib.collections")
pyart3d = PyPlot.art3D pyart3d = PyPlot.art3D
pyrcparams = PyPlot.PyDict(PyPlot.matplotlib."rcParams")
# "support" matplotlib v1.5 # "support" matplotlib v1.5
set_facecolor_sym = if PyPlot.version < v"2" set_facecolor_sym = if PyPlot.version < v"2"
@ -58,6 +61,9 @@ end
# # anything else just gets a bluesred gradient # # anything else just gets a bluesred gradient
# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α) # py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
py_handle_surface(v) = v
py_handle_surface(z::Surface) = z.surf
py_color(s) = py_color(parse(Colorant, string(s))) py_color(s) = py_color(parse(Colorant, string(s)))
py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c)) py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c))
py_color(cs::AVec) = map(py_color, cs) py_color(cs::AVec) = map(py_color, cs)
@ -146,12 +152,14 @@ end
function py_stepstyle(seriestype::Symbol) function py_stepstyle(seriestype::Symbol)
seriestype == :steppost && return "steps-post" seriestype == :steppost && return "steps-post"
seriestype == :stepmid && return "steps-mid"
seriestype == :steppre && return "steps-pre" seriestype == :steppre && return "steps-pre"
return "default" return "default"
end end
function py_fillstepstyle(seriestype::Symbol) function py_fillstepstyle(seriestype::Symbol)
seriestype == :steppost && return "post" seriestype == :steppost && return "post"
seriestype == :stepmid && return "mid"
seriestype == :steppre && return "pre" seriestype == :steppre && return "pre"
return nothing return nothing
end end
@ -174,15 +182,7 @@ function add_pyfixedformatter(cbar, vals::AVec)
end end
function labelfunc(scale::Symbol, backend::PyPlotBackend) function labelfunc(scale::Symbol, backend::PyPlotBackend)
if scale == :log10 PyPlot.LaTeXStrings.latexstring labelfunc_tex(scale)
x -> PyPlot.LaTeXStrings.latexstring("10^{$x}")
elseif scale == :log2
x -> PyPlot.LaTeXStrings.latexstring("2^{$x}")
elseif scale == :ln
x -> PyPlot.LaTeXStrings.latexstring("e^{$x}")
else
string
end
end end
function py_mask_nans(z) function py_mask_nans(z)
@ -207,9 +207,15 @@ function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
end end
end end
py_linecolormap(series::Series) = py_colormap(series[:linecolor]) function py_linecolormap(series::Series)
py_markercolormap(series::Series) = py_colormap(series[:markercolor]) py_colormap(cgrad(series[:linecolor], alpha=get_linealpha(series)))
py_fillcolormap(series::Series) = py_colormap(series[:fillcolor]) end
function py_markercolormap(series::Series)
py_colormap(cgrad(series[:markercolor], alpha=get_markeralpha(series)))
end
function py_fillcolormap(series::Series)
py_colormap(cgrad(series[:fillcolor], alpha=get_fillalpha(series)))
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -275,7 +281,6 @@ end
function py_bbox_axis(ax, letter) function py_bbox_axis(ax, letter)
ticks = py_bbox_ticks(ax, letter) ticks = py_bbox_ticks(ax, letter)
labels = py_bbox_axislabel(ax, letter) labels = py_bbox_axislabel(ax, letter)
# letter == "x" && @show ticks labels ticks+labels
ticks + labels ticks + labels
end end
@ -350,7 +355,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
fix_xy_lengths!(plt, series) fix_xy_lengths!(plt, series)
# ax = getAxis(plt, series) # ax = getAxis(plt, series)
x, y, z = series[:x], series[:y], series[:z] x, y, z = (py_handle_surface(series[letter]) for letter in (:x, :y, :z))
if st == :straightline if st == :straightline
x, y = straightline_data(series) x, y = straightline_data(series)
elseif st == :shape elseif st == :shape
@ -375,8 +380,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
vmin, vmax = clims = get_clims(sp, series) vmin, vmax = clims = get_clims(sp, series)
# Dict to store extra kwargs # Dict to store extra kwargs
if st == :wireframe if st == :wireframe || st == :hexbin
extrakw = KW() # vmin, vmax cause an error for wireframe plot # vmin, vmax cause an error for wireframe plot
# We are not supporting clims for hexbin as calculation of bins is not trivial
extrakw = KW()
else else
extrakw = KW(:vmin => vmin, :vmax => vmax) extrakw = KW(:vmin => vmin, :vmax => vmax)
end end
@ -403,9 +410,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# for each plotting command, optionally build and add a series handle to the list # for each plotting command, optionally build and add a series handle to the list
# line plot # line plot
if st in (:path, :path3d, :steppre, :steppost, :straightline) if st in (:path, :path3d, :steppre, :stepmid, :steppost, :straightline)
if maximum(series[:linewidth]) > 0 if maximum(series[:linewidth]) > 0
segments = iter_segments(series)
# TODO: check LineCollection alternative for speed # 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 # # multicolored line segments
@ -436,14 +442,16 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# end # end
# push!(handles, handle) # push!(handles, handle)
# else # else
for (i, rng) in enumerate(iter_segments(series)) for (k, segment) in enumerate(series_segments(series, st))
i, rng = segment.attr_index, segment.range
handle = ax."plot"((arg[rng] for arg in xyargs)...; handle = ax."plot"((arg[rng] for arg in xyargs)...;
label = i == 1 ? series[:label] : "", label = k == 1 ? series[:label] : "",
zorder = series[:series_plotindex], zorder = series[:series_plotindex],
color = py_color(single_color(get_linecolor(series, clims, i)), get_linealpha(series, i)), color = py_color(single_color(get_linecolor(series, clims, i)), get_linealpha(series, i)),
linewidth = py_thickness_scale(plt, get_linewidth(series, i)), linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
linestyle = py_linestyle(st, get_linestyle(series, i)), linestyle = py_linestyle(st, get_linestyle(series, i)),
solid_capstyle = "round", solid_capstyle = "butt",
dash_capstyle = "butt",
drawstyle = py_stepstyle(st) drawstyle = py_stepstyle(st)
)[1] )[1]
push!(handles, handle) push!(handles, handle)
@ -478,124 +486,33 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
# add markers? # add markers?
if series[:markershape] != :none && st in (:path, :scatter, :path3d, if series[:markershape] != :none && st in (
:scatter3d, :steppre, :steppost, :path, :scatter, :path3d, :scatter3d, :steppre, :stepmid, :steppost, :bar
:bar) )
markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] !== nothing for segment in series_segments(series, :scatter)
# py_color(plot_color.(get_markercolor.(series, clims, eachindex(x)), get_markeralpha.(series, eachindex(x)))) i, rng = segment.attr_index, segment.range
[py_color(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))) for i in eachindex(x)]
else
py_color(plot_color(series[:markercolor], series[:markeralpha]))
end
extrakw[:c] = if markercolor isa Array
permutedims(hcat([[m...] for m in markercolor]...),[2,1])
elseif markercolor isa Tuple
reshape([markercolor...], 1, length(markercolor))
else
error("This case is not handled. Please file an issue.")
end
xyargs = if st == :bar && !isvertical(series) xyargs = if st == :bar && !isvertical(series)
(y, x) if RecipesPipeline.is3d(sp)
y[rng], x[rng], z[rng]
else else
xyargs y[rng], x[rng]
end end
if isa(series[:markershape], AbstractVector{Shape})
# this section will create one scatter per data point to accommodate the
# vector of shapes
handle = []
x,y = xyargs
shapes = series[:markershape]
msc = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series))
lw = py_thickness_scale(plt, series[:markerstrokewidth])
for i=eachindex(y)
if series[:marker_z] !== nothing
extrakw[:c] = [py_color(get_markercolor(series, i), get_markercoloralpha(series, i))]
end
push!(handle, ax."scatter"(_cycle(x,i), _cycle(y,i);
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = py_marker(_cycle(shapes,i)),
s = py_thickness_scale(plt, _cycle(series[:markersize],i)).^ 2,
facecolors = py_color(get_markercolor(series, i), get_markercoloralpha(series, i)),
edgecolors = msc,
linewidths = lw,
extrakw...
))
end
push!(handles, handle)
elseif isa(series[:markershape], AbstractVector{Symbol})
handle = []
x,y = xyargs
shapes = series[:markershape]
prev_marker = py_marker(_cycle(shapes,1))
cur_x_list = []
cur_y_list = []
cur_color_list = []
cur_scale_list = []
delete!(extrakw, :c)
for i=eachindex(y)
cur_marker = py_marker(_cycle(shapes,i))
if ( cur_marker == prev_marker )
push!(cur_x_list, _cycle(x,i))
push!(cur_y_list, _cycle(y,i))
push!(cur_color_list, _cycle(markercolor, i))
push!(cur_scale_list, py_thickness_scale(plt, _cycle(series[:markersize],i)).^ 2)
continue
end
push!(handle, ax."scatter"(cur_x_list, cur_y_list;
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = prev_marker,
s = cur_scale_list,
edgecolors = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
facecolors = cur_color_list,
extrakw...
))
cur_x_list = [_cycle(x,i)]
cur_y_list = [_cycle(y,i)]
cur_color_list = [_cycle(markercolor, i)]
cur_scale_list = [py_thickness_scale(plt, _cycle(series[:markersize],i)) .^ 2]
prev_marker = cur_marker
end
if !isempty(cur_color_list)
push!(handle, ax."scatter"(cur_x_list, cur_y_list;
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = prev_marker,
s = cur_scale_list,
edgecolors = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
facecolors = cur_color_list,
extrakw...
))
end
push!(handles, handle)
else else
# do a normal scatter plot if RecipesPipeline.is3d(sp)
x[rng], y[rng], z[rng]
else
x[rng], y[rng]
end
end
handle = ax."scatter"(xyargs...; handle = ax."scatter"(xyargs...;
label = series[:label], label = series[:label],
zorder = series[:series_plotindex] + 0.5, zorder = series[:series_plotindex] + 0.5,
marker = py_marker(series[:markershape]), marker = py_marker(_cycle(series[:markershape], i)),
s = py_thickness_scale(plt, series[:markersize]) .^2, s = py_thickness_scale(plt, _cycle(series[:markersize], i)).^ 2,
edgecolors = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)), facecolors = py_color(get_markercolor(series, i), get_markeralpha(series, i)),
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]), edgecolors = py_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i)),
linewidths = py_thickness_scale(plt, get_markerstrokewidth(series, i)),
extrakw... extrakw...
) )
push!(handles, handle) push!(handles, handle)
@ -603,31 +520,27 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
if st == :hexbin if st == :hexbin
handle = ax."hexbin"(x, y, extrakw[:mincnt] = get(series[:extra_kwargs], :mincnt, nothing)
extrakw[:edgecolors] = get(series[:extra_kwargs], :edgecolors, py_color(get_linecolor(series)))
handle = ax."hexbin"(x, y;
label = series[:label], label = series[:label],
C = series[:weights], C = series[:weights],
gridsize = series[:bins]==:auto ? 100 : series[:bins], # 100 is the default value gridsize = series[:bins]==:auto ? 100 : series[:bins], # 100 is the default value
linewidths = py_thickness_scale(plt, series[:linewidth]), linewidths = py_thickness_scale(plt, series[:linewidth]),
edgecolors = py_color(get_linecolor(series)),
alpha = series[:fillalpha], alpha = series[:fillalpha],
cmap = py_fillcolormap(series), # applies to the pcolorfast object cmap = py_fillcolormap(series), # applies to the pcolorfast object
zorder = series[:series_plotindex], zorder = series[:series_plotindex],
# extrakw... # for some reason vmin and vmax are NaN??? extrakw...
) )
push!(handles, handle) push!(handles, handle)
end end
if st in (:contour, :contour3d) if st in (:contour, :contour3d)
z = transpose_z(series, z.surf)
if typeof(x)<:Plots.Surface
x = Plots.transpose_z(series, x.surf)
end
if typeof(y)<:Plots.Surface
y = Plots.transpose_z(series, y.surf)
end
if st == :contour3d if st == :contour3d
extrakw[:extend3d] = true extrakw[:extend3d] = true
if !ismatrix(x) || !ismatrix(y)
x, y = repeat(x', length(y), 1), repeat(y, 1, length(x))
end
end end
if typeof(series[:linecolor]) <: AbstractArray if typeof(series[:linecolor]) <: AbstractArray
@ -654,6 +567,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
handle = ax."contourf"(x, y, z, levelargs...; handle = ax."contourf"(x, y, z, levelargs...;
label = series[:label], label = series[:label],
zorder = series[:series_plotindex] + 0.5, zorder = series[:series_plotindex] + 0.5,
alpha = series[:fillalpha],
extrakw... extrakw...
) )
push!(handles, handle) push!(handles, handle)
@ -661,17 +575,17 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
if st in (:surface, :wireframe) if st in (:surface, :wireframe)
if typeof(z) <: AbstractMatrix || typeof(z) <: Surface if z isa AbstractMatrix
x, y, z = map(Array, (x,y,z))
if !ismatrix(x) || !ismatrix(y) if !ismatrix(x) || !ismatrix(y)
x = repeat(x', length(y), 1) x, y = repeat(x', length(y), 1), repeat(y, 1, length(x))
y = repeat(y, 1, length(series[:x]))
end end
z = transpose_z(series, z)
if st == :surface if st == :surface
if series[:fill_z] !== nothing if series[:fill_z] !== nothing
# the surface colors are different than z-value # the surface colors are different than z-value
extrakw[:facecolors] = py_shading(series[:fillcolor], transpose_z(series, series[:fill_z].surf)) extrakw[:facecolors] = py_shading(
series[:fillcolor],
py_handle_surface(series[:fill_z]),
)
extrakw[:shade] = false extrakw[:shade] = false
else else
extrakw[:cmap] = py_fillcolormap(series) extrakw[:cmap] = py_fillcolormap(series)
@ -719,22 +633,24 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
if st == :image if st == :image
# @show typeof(z) xmin, xmax = ignorenan_extrema(series[:x])
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y]) ymin, ymax = ignorenan_extrema(series[:y])
img = Array(transpose_z(series, z.surf)) dx = (xmax - xmin) / (length(series[:x]) - 1) / 2
z = if eltype(img) <: Colors.AbstractGray dy = (ymax - ymin) / (length(series[:y]) - 1) / 2
float(img) z = if eltype(z) <: Colors.AbstractGray
elseif eltype(img) <: Colorant float(z)
map(c -> Float64[red(c),green(c),blue(c),alpha(c)], img) elseif eltype(z) <: Colorant
map(c -> Float64[red(c),green(c),blue(c),alpha(c)], z)
else else
z # hopefully it's in a data format that will "just work" with imshow z # hopefully it's in a data format that will "just work" with imshow
end end
handle = ax."imshow"(z; handle = ax."imshow"(
z;
zorder = series[:series_plotindex], zorder = series[:series_plotindex],
cmap = py_colormap(cgrad(plot_color([:black, :white]))), cmap = py_colormap(cgrad(plot_color([:black, :white]))),
vmin = 0.0, vmin = 0.0,
vmax = 1.0, vmax = 1.0,
extent = (xmin-0.5, xmax+0.5, ymax+0.5, ymin-0.5) extent = (xmin - dx, xmax + dx, ymax + dy, ymin - dy)
) )
push!(handles, handle) push!(handles, handle)
@ -745,7 +661,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end end
if st == :heatmap if st == :heatmap
x, y, z = heatmap_edges(x, sp[:xaxis][:scale]), heatmap_edges(y, sp[:yaxis][:scale]), transpose_z(series, z.surf) x, y = heatmap_edges(x, sp[:xaxis][:scale], y, sp[:yaxis][:scale], size(z))
expand_extrema!(sp[:xaxis], x) expand_extrema!(sp[:xaxis], x)
expand_extrema!(sp[:yaxis], y) expand_extrema!(sp[:yaxis], y)
@ -767,7 +683,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if st == :shape if st == :shape
handle = [] handle = []
for (i, rng) in enumerate(iter_segments(series)) for segment in series_segments(series)
i, rng = segment.attr_index, segment.range
if length(rng) > 1 if length(rng) > 1
path = pypath."Path"(hcat(x[rng], y[rng])) path = pypath."Path"(hcat(x[rng], y[rng]))
patches = pypatches."PathPatch"( patches = pypatches."PathPatch"(
@ -794,7 +711,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# handle area filling # handle area filling
fillrange = series[:fillrange] fillrange = series[:fillrange]
if fillrange !== nothing && st != :contour if fillrange !== nothing && st != :contour
for (i, rng) in enumerate(iter_segments(series)) for segment in series_segments(series)
i, rng = segment.attr_index, segment.range
f, dim1, dim2 = if isvertical(series) f, dim1, dim2 = if isvertical(series)
:fill_between, x[rng], y[rng] :fill_between, x[rng], y[rng]
else else
@ -831,7 +749,17 @@ function py_set_lims(ax, sp::Subplot, axis::Axis)
getproperty(ax, Symbol("set_", letter, "lim"))(lfrom, lto) getproperty(ax, Symbol("set_", letter, "lim"))(lfrom, lto)
end end
function py_set_ticks(ax, ticks, letter) function py_surround_latextext(latexstring, env)
if !isempty(latexstring) && latexstring[1] == '$' && latexstring[end] == '$'
unenclosed = latexstring[2:end-1]
else
unenclosed = latexstring
end
PyPlot.LaTeXStrings.latexstring(env, "{", unenclosed, "}")
end
function py_set_ticks(sp, ax, ticks, letter, env)
ticks == :auto && return ticks == :auto && return
axis = getproperty(ax, Symbol(letter,"axis")) axis = getproperty(ax, Symbol(letter,"axis"))
if ticks == :none || ticks === nothing || ticks == false if ticks == :none || ticks === nothing || ticks == false
@ -848,7 +776,14 @@ function py_set_ticks(ax, ticks, letter)
axis."set_ticks"(ticks) axis."set_ticks"(ticks)
elseif ttype == :ticks_and_labels elseif ttype == :ticks_and_labels
axis."set_ticks"(ticks[1]) axis."set_ticks"(ticks[1])
axis."set_ticklabels"(ticks[2])
if get(sp[:extra_kwargs], :rawticklabels, false)
tick_labels = ticks[2]
else
tick_labels = [py_surround_latextext(ticklabel, env) for ticklabel in ticks[2]]
end
axis."set_ticklabels"(tick_labels)
else else
error("Invalid input for $(letter)ticks: $ticks") error("Invalid input for $(letter)ticks: $ticks")
end end
@ -874,33 +809,52 @@ function py_compute_axis_minval(sp::Subplot, axis::Axis)
minval minval
end end
function py_set_scale(ax, sp::Subplot, axis::Axis) function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol)
scale = axis[:scale]
letter = axis[:letter]
scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale") scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale")
func = getproperty(ax, Symbol("set_", letter, "scale")) func = getproperty(ax, Symbol("set_", letter, "scale"))
if PyPlot.version v"3.3" # https://matplotlib.org/3.3.0/api/api_changes.html
pyletter = Symbol("")
else
pyletter = letter
end
kw = KW() kw = KW()
arg = if scale == :identity arg = if scale == :identity
"linear" "linear"
else else
kw[Symbol(:base,letter)] = if scale == :ln kw[Symbol(:base, pyletter)] = if scale == :ln
elseif scale == :log2 elseif scale == :log2
2 2
elseif scale == :log10 elseif scale == :log10
10 10
end end
kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) axis = sp[Symbol(letter, :axis)]
kw[Symbol(:linthresh, pyletter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis))
"symlog" "symlog"
end end
func(arg; kw...) func(arg; kw...)
end end
function py_set_scale(ax, sp::Subplot, axis::Axis)
scale = axis[:scale]
letter = axis[:letter]
py_set_scale(ax, sp, scale, letter)
end
function py_set_spine_color(spines, color)
for loc in spines
spines[loc]."set_color"(color)
end
end
function py_set_spine_color(spines::Dict, color)
for (loc, spine) in spines
spine."set_color"(color)
end
end
function py_set_axis_colors(sp, ax, a::Axis) function py_set_axis_colors(sp, ax, a::Axis)
for (loc, spine) in ax.spines py_set_spine_color(ax.spines, py_color(a[:foreground_color_border]))
spine."set_color"(py_color(a[:foreground_color_border]))
end
axissym = Symbol(a[:letter], :axis) axissym = Symbol(a[:letter], :axis)
if PyPlot.PyCall.hasproperty(ax, axissym) if PyPlot.PyCall.hasproperty(ax, axissym)
tickcolor = sp[:framestyle] in (:zerolines, :grid) ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis]) tickcolor = sp[:framestyle] in (:zerolines, :grid) ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis])
@ -997,47 +951,142 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end end
kw[:spacing] = "proportional" kw[:spacing] = "proportional"
# create and store the colorbar object (handle) and the axis that it is drawn on. if RecipesPipeline.is3d(sp) || ispolar(sp)
# note: the colorbar axis is positioned independently from the subplot axis cbax = fig."add_axes"([0.9, 0.1, 0.03, 0.8], label=string("cbar", sp[:subplot_index]))
fig = plt.o cb = fig."colorbar"(handle; cax=cbax, kw...)
cbax = fig."add_axes"([0.8,0.1,0.03,0.8], label = string(gensym())) else
cb = fig."colorbar"(handle; cax = cbax, kw...) # divider approach works only with 2d plots
cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor])) divider = axes_grid1.make_axes_locatable(ax)
for lab in cb."ax"."yaxis"."get_ticklabels"() # width = axes_grid1.axes_size.AxesY(ax, aspect=1.0 / 3.5)
lab."set_fontsize"(py_thickness_scale(plt, sp[:yaxis][:tickfontsize])) # pad = axes_grid1.axes_size.Fraction(0.5, width) # Colorbar is spaced 0.5 of its size away from the ax
lab."set_family"(sp[:yaxis][:tickfontfamily]) # cbax = divider.append_axes("right", size=width, pad=pad) # This approach does not work well in subplots
lab."set_color"(py_color(sp[:yaxis][:tickfontcolor])) colorbar_position = "right"
colorbar_pad = "2.5%"
colorbar_orientation="vertical"
if sp[:colorbar] == :left
colorbar_position = string(sp[:colorbar])
colorbar_pad = "5%"
elseif sp[:colorbar] == :top
colorbar_position = string(sp[:colorbar])
colorbar_pad = "2.5%"
colorbar_orientation="horizontal"
elseif sp[:colorbar] == :bottom
colorbar_position = string(sp[:colorbar])
colorbar_pad = "5%"
colorbar_orientation="horizontal"
end end
cbax = divider.append_axes(colorbar_position, size="5%", pad=colorbar_pad, label=string("cbar", sp[:subplot_index])) # Reasonable value works most of the usecases
cb = fig."colorbar"(handle; cax=cbax, orientation = colorbar_orientation, kw...)
if sp[:colorbar] == :left
cbax.yaxis.set_ticks_position("left")
elseif sp[:colorbar] == :top
cbax.xaxis.set_ticks_position("top")
elseif sp[:colorbar] == :bottom
cbax.xaxis.set_ticks_position("bottom")
end
end
cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:colorbar_titlefontsize]),family=sp[:colorbar_titlefontfamily], color = py_color(sp[:colorbar_titlefontcolor]))
# cb."formatter".set_useOffset(false) # This for some reason does not work, must be a pyplot bug, instead this is a workaround:
cb."formatter".set_powerlimits((-Inf, Inf))
cb."update_ticks"()
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
ticks = get_colorbar_ticks(sp)
if sp[:colorbar] in (:top, :bottom)
axis = sp[:xaxis] # colorbar inherits from x axis
cbar_axis = cb."ax"."xaxis"
ticks_letter=:x
else
axis = sp[:yaxis] # colorbar inherits from y axis
cbar_axis = cb."ax"."yaxis"
ticks_letter=:y
end
py_set_scale(cb.ax, sp, sp[:colorbar_scale], ticks_letter)
sp[:colorbar_ticks] == :native ? nothing : py_set_ticks(sp, cb.ax, ticks, ticks_letter, env)
for lab in cbar_axis."get_ticklabels"()
lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize]))
lab."set_family"(sp[:colorbar_tickfontfamily])
lab."set_color"(py_color(sp[:colorbar_tickfontcolor]))
end
# Adjust thickness of the cbar ticks
intensity = 0.5
cbar_axis."set_tick_params"(
direction = axis[:tick_direction] == :out ? "out" : "in",
width=py_thickness_scale(plt, intensity),
length = axis[:tick_direction] == :none ? 0 : 5 * py_thickness_scale(plt, intensity)
)
cb.outline."set_linewidth"(py_thickness_scale(plt, 1))
sp.attr[:cbar_handle] = cb sp.attr[:cbar_handle] = cb
sp.attr[:cbar_ax] = cbax sp.attr[:cbar_ax] = cbax
end end
# framestyle # framestyle
if !ispolar(sp) && !RecipesPipeline.is3d(sp) if !ispolar(sp) && !RecipesPipeline.is3d(sp)
ax.spines["left"]."set_linewidth"(py_thickness_scale(plt, 1)) for pos in ("left", "right", "top", "bottom")
ax.spines["bottom"]."set_linewidth"(py_thickness_scale(plt, 1)) # Scale all axes by default first
ax.spines[pos]."set_linewidth"(py_thickness_scale(plt, 1))
end
# Then set visible some of them
if sp[:framestyle] == :semi if sp[:framestyle] == :semi
intensity = 0.5 intensity = 0.5
ax.spines["right"]."set_alpha"(intensity)
ax.spines["top"]."set_alpha"(intensity) spine = sp[:yaxis][:mirror] ? "left" : "right"
ax.spines["right"]."set_linewidth"(py_thickness_scale(plt, intensity)) ax.spines[spine]."set_alpha"(intensity)
ax.spines["top"]."set_linewidth"(py_thickness_scale(plt, intensity)) ax.spines[spine]."set_linewidth"(py_thickness_scale(plt, intensity))
spine = sp[:xaxis][:mirror] ? "bottom" : "top"
ax.spines[spine]."set_linewidth"(py_thickness_scale(plt, intensity))
ax.spines[spine]."set_alpha"(intensity)
elseif sp[:framestyle] == :box
ax.tick_params(top=true) # Add ticks too
ax.tick_params(right=true) # Add ticks too
elseif sp[:framestyle] in (:axes, :origin) elseif sp[:framestyle] in (:axes, :origin)
ax.spines["right"]."set_visible"(false) sp[:xaxis][:mirror] ? ax.spines["bottom"]."set_visible"(false) : ax.spines["top"]."set_visible"(false)
ax.spines["top"]."set_visible"(false) sp[:yaxis][:mirror] ? ax.spines["left"]."set_visible"(false) : ax.spines["right"]."set_visible"(false)
if sp[:framestyle] == :origin if sp[:framestyle] == :origin
ax.spines["bottom"]."set_position"("zero") ax.spines["bottom"]."set_position"("zero")
ax.spines["left"]."set_position"("zero") ax.spines["left"]."set_position"("zero")
end end
elseif sp[:framestyle] in (:grid, :none, :zerolines) elseif sp[:framestyle] in (:grid, :none, :zerolines)
if PyPlot.version >= v"3.4.1" # that is one where it worked, the API change may have some other value
for spine in ax.spines
ax.spines[string(spine)]."set_visible"(false)
end
else
for (loc, spine) in ax.spines for (loc, spine) in ax.spines
spine."set_visible"(false) spine."set_visible"(false)
end end
end
if sp[:framestyle] == :zerolines if sp[:framestyle] == :zerolines
ax."axhline"(y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75)) ax."axhline"(y = 0, color = py_color(sp[:xaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
ax."axvline"(x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75)) ax."axvline"(x = 0, color = py_color(sp[:yaxis][:foreground_color_axis]), lw = py_thickness_scale(plt, 0.75))
end end
end end
if sp[:xaxis][:mirror]
ax.xaxis."set_label_position"("top") # the guides
sp[:framestyle] == :box ? nothing : ax.xaxis."tick_top"()
end
if sp[:yaxis][:mirror]
ax.yaxis."set_label_position"("right") # the guides
sp[:framestyle] == :box ? nothing : ax.yaxis."tick_right"()
end
end end
# axis attributes # axis attributes
@ -1046,17 +1095,13 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
PyPlot.PyCall.hasproperty(ax, axissym) || continue PyPlot.PyCall.hasproperty(ax, axissym) || continue
axis = sp[axissym] axis = sp[axissym]
pyaxis = getproperty(ax, axissym) pyaxis = getproperty(ax, axissym)
if axis[:mirror] && letter != :z
pos = letter == :x ? "top" : "right"
pyaxis."set_label_position"(pos) # the guides
pyaxis."set_ticks_position"("both") # the hash marks
getproperty(pyaxis, Symbol(:tick_, pos))() # the tick labels
end
if axis[:guide_position] != :auto && letter != :z if axis[:guide_position] != :auto && letter != :z
pyaxis."set_label_position"(axis[:guide_position]) pyaxis."set_label_position"(axis[:guide_position])
end end
py_set_scale(ax, sp, axis) py_set_scale(ax, sp, axis)
axis[:ticks] != :native ? py_set_lims(ax, sp, axis) : nothing axis[:ticks] == :native ? nothing : py_set_lims(ax, sp, axis)
if ispolar(sp) && letter == :y if ispolar(sp) && letter == :y
ax."set_rlabel_position"(90) ax."set_rlabel_position"(90)
end end
@ -1065,10 +1110,41 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if sp[:framestyle] == :origin && length(ticks) > 1 if sp[:framestyle] == :origin && length(ticks) > 1
ticks[2][ticks[1] .== 0] .= "" ticks[2][ticks[1] .== 0] .= ""
end end
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
# Set ticks
fontProperties = PyPlot.PyCall.PyDict(
Dict(
"family" => axis[:tickfontfamily],
"size" => py_thickness_scale(plt, axis[:tickfontsize]),
"rotation" => axis[:tickfontrotation],
)
)
positions = getproperty(ax, Symbol("get_",letter,"ticks"))()
pyaxis.set_major_locator(pyticker.FixedLocator(positions))
if RecipesPipeline.is3d(sp)
getproperty(ax, Symbol("set_",letter,"ticklabels"))(
positions;
(Symbol(k) => v for (k, v) in fontProperties)...
)
else
getproperty(ax, Symbol("set_",letter,"ticklabels"))(
positions,
fontdict=fontProperties,
)
end
# workaround to set mathtext.fontspec per Text element
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
axis[:ticks] == :native ? nothing : py_set_ticks(sp, ax, ticks, letter, env)
# Tick marks
intensity = 0.5 # This value corresponds to scaling of other grid elements intensity = 0.5 # This value corresponds to scaling of other grid elements
pyaxis."set_tick_params"(direction = axis[:tick_direction] == :out ? "out" : "in", width=py_thickness_scale(plt, intensity)) pyaxis."set_tick_params"(
direction = axis[:tick_direction] == :out ? "out" : "in",
width=py_thickness_scale(plt, intensity),
length = axis[:tick_direction] == :none ? 0 : 5 * py_thickness_scale(plt, intensity)
)
getproperty(ax, Symbol("set_", letter, "label"))(axis[:guide]) getproperty(ax, Symbol("set_", letter, "label"))(axis[:guide])
if get(axis.plotattributes, :flip, false) if get(axis.plotattributes, :flip, false)
@ -1087,11 +1163,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
pyaxis."label"."set_rotation"(axis[:guidefontrotation]) pyaxis."label"."set_rotation"(axis[:guidefontrotation])
end end
for lab in getproperty(ax, Symbol("get_", letter, "ticklabels"))()
lab."set_fontsize"(py_thickness_scale(plt, axis[:tickfontsize]))
lab."set_family"(axis[:tickfontfamily])
lab."set_rotation"(axis[:rotation])
end
if axis[:grid] && !(ticks in (:none, nothing, false)) if axis[:grid] && !(ticks in (:none, nothing, false))
fgcolor = py_color(axis[:foreground_color_grid]) fgcolor = py_color(axis[:foreground_color_grid])
pyaxis."grid"(true, pyaxis."grid"(true,
@ -1110,7 +1182,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
pyaxis."set_tick_params"( pyaxis."set_tick_params"(
which = "minor", which = "minor",
direction = axis[:tick_direction] == :out ? "out" : "in", direction = axis[:tick_direction] == :out ? "out" : "in",
width=py_thickness_scale(plt, intensity)) length = axis[:tick_direction] == :none ? 0 : py_thickness_scale(plt, intensity),
)
end end
if axis[:minorgrid] if axis[:minorgrid]
@ -1120,7 +1193,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
pyaxis."set_tick_params"( pyaxis."set_tick_params"(
which = "minor", which = "minor",
direction = axis[:tick_direction] == :out ? "out" : "in", direction = axis[:tick_direction] == :out ? "out" : "in",
width=py_thickness_scale(plt, intensity)) length = axis[:tick_direction] == :none ? 0 : py_thickness_scale(plt, intensity)
)
pyaxis."grid"(true, pyaxis."grid"(true,
which = "minor", which = "minor",
@ -1202,6 +1276,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
toppad = 0mm toppad = 0mm
rightpad = 0mm rightpad = 0mm
bottompad = 0mm bottompad = 0mm
for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), py_bbox_legend(ax)) for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), py_bbox_legend(ax))
if ispositive(width(bb)) && ispositive(height(bb)) if ispositive(width(bb)) && ispositive(height(bb))
leftpad = max(leftpad, left(plotbb) - left(bb)) leftpad = max(leftpad, left(plotbb) - left(bb))
@ -1211,11 +1286,23 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
end end
end end
if haskey(sp.attr, :cbar_ax) # Treat colorbar the same way
ax = sp.attr[:cbar_handle]."ax"
for bb in (py_bbox_axis(ax, "x"), py_bbox_axis(ax, "y"), py_bbox_title(ax), )
if ispositive(width(bb)) && ispositive(height(bb))
leftpad = max(leftpad, left(plotbb) - left(bb))
toppad = max(toppad, top(plotbb) - top(bb))
rightpad = max(rightpad, right(bb) - right(plotbb))
bottompad = max(bottompad, bottom(bb) - bottom(plotbb))
end
end
end
# optionally add the width of colorbar labels and colorbar to rightpad # optionally add the width of colorbar labels and colorbar to rightpad
if haskey(sp.attr, :cbar_ax) if RecipesPipeline.is3d(sp) && haskey(sp.attr, :cbar_ax)
bb = py_bbox(sp.attr[:cbar_handle]."ax"."get_yticklabels"()) bb = py_bbox(sp.attr[:cbar_handle]."ax"."get_yticklabels"())
sp.attr[:cbar_width] = _cbar_width + width(bb) + 2.3mm + (sp[:colorbar_title] == "" ? 0px : 30px) sp.attr[:cbar_width] = width(bb) + (sp[:colorbar_title] == "" ? 0px : 30px)
rightpad = rightpad + sp.attr[:cbar_width]
end end
# add in the user-specified margin # add in the user-specified margin
@ -1255,44 +1342,26 @@ end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
py_legend_pos(pos::Symbol) = get( py_legend_pos(pos::Tuple{S,T}) where {S<:Real,T<:Real} = "lower left"
(
right = "right", function py_legend_pos(pos::Tuple{<:Real,Symbol})
left = "center left", (s,c) = sincosd(pos[1])
top = "upper center", if pos[2] === :outer
bottom = "lower center", s = -s
bottomleft = "lower left", c = -c
bottomright = "lower right", end
topright = "upper right", yanchors = ["lower","center","upper"]
topleft = "upper left", xanchors = ["left","center","right"]
outerright = "center left", return join([yanchors[legend_anchor_index(s)], xanchors[legend_anchor_index(c)]], ' ')
outerleft = "right", end
outertop = "lower center",
outerbottom = "upper center", function py_legend_bbox(pos::Tuple{T,Symbol}) where T<:Real
outerbottomleft = "lower right", if pos[2] === :outer
outerbottomright = "lower left", return legend_pos_from_angle(pos[1],-0.15,0.5,1.0,-0.15,0.5,1.0)
outertopright = "upper left", end
outertopleft = "upper right", legend_pos_from_angle(pos[1],0.0,0.5,1.0,0.0,0.5,1.0)
), end
pos,
"best",
)
py_legend_pos(pos) = "lower left"
py_legend_bbox(pos::Symbol) = get(
(
outerright = (1.0, 0.5, 0.0, 0.0),
outerleft = (-0.15, 0.5, 0.0, 0.0),
outertop = (0.5, 1.0, 0.0, 0.0),
outerbottom = (0.5, -0.15, 0.0, 0.0),
outerbottomleft = (-0.15, 0.0, 0.0, 0.0),
outerbottomright = (1.0, 0.0, 0.0, 0.0),
outertopright = (1.0, 1.0, 0.0, 0.0),
outertopleft = (-0.15, 1.0, 0.0, 0.0),
),
pos,
(0.0, 0.0, 1.0, 1.0),
)
py_legend_bbox(pos) = pos py_legend_bbox(pos) = pos
function py_add_legend(plt::Plot, sp::Subplot, ax) function py_add_legend(plt::Plot, sp::Subplot, ax)
@ -1311,14 +1380,17 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
edgecolor = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), edgecolor = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)),
facecolor = py_color(single_color(get_fillcolor(series, clims)), get_fillalpha(series)), facecolor = py_color(single_color(get_fillcolor(series, clims)), get_fillalpha(series)),
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)), linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
linestyle = py_linestyle(series[:seriestype], get_linestyle(series)) linestyle = py_linestyle(series[:seriestype], get_linestyle(series)),
capstyle = "butt"
) )
elseif series[:seriestype] in (:path, :straightline, :scatter, :steppre, :steppost) elseif series[:seriestype] in (:path, :straightline, :scatter, :steppre, :stepmid, :steppost)
hasline = get_linewidth(series) > 0 hasline = get_linewidth(series) > 0
PyPlot.plt."Line2D"((0,1),(0,0), PyPlot.plt."Line2D"((0, 1),(0,0),
color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)),
linewidth = py_thickness_scale(plt, hasline * sp[:legendfontsize] / 8), linewidth = py_thickness_scale(plt, hasline * sp[:legendfontsize] / 8),
linestyle = py_linestyle(:path, get_linestyle(series)), linestyle = py_linestyle(:path, get_linestyle(series)),
solid_capstyle = "butt", solid_joinstyle = "miter",
dash_capstyle = "butt", dash_joinstyle = "miter",
marker = py_marker(_cycle(series[:markershape], 1)), marker = py_marker(_cycle(series[:markershape], 1)),
markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]), markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]),
markeredgecolor = py_color(single_color(get_markerstrokecolor(series)), get_markerstrokealpha(series)), markeredgecolor = py_color(single_color(get_markerstrokecolor(series)), get_markerstrokealpha(series)),
@ -1335,6 +1407,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
# if anything was added, call ax.legend and set the colors # if anything was added, call ax.legend and set the colors
if !isempty(handles) if !isempty(handles)
leg = legend_angle(leg)
leg = ax."legend"(handles, leg = ax."legend"(handles,
labels, labels,
loc = py_legend_pos(leg), loc = py_legend_pos(leg),
@ -1344,7 +1417,8 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
facecolor = py_color(sp[:background_color_legend]), facecolor = py_color(sp[:background_color_legend]),
edgecolor = py_color(sp[:foreground_color_legend]), edgecolor = py_color(sp[:foreground_color_legend]),
framealpha = alpha(plot_color(sp[:background_color_legend])), framealpha = alpha(plot_color(sp[:background_color_legend])),
fancybox = false # makes the legend box square fancybox = false, # makes the legend box square
borderpad = 0.8 # to match GR legendbox
) )
frame = leg."get_frame"() frame = leg."get_frame"()
frame."set_linewidth"(py_thickness_scale(plt, 1)) frame."set_linewidth"(py_thickness_scale(plt, 1))
@ -1375,13 +1449,10 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
pcts = bbox_to_pcts(sp.plotarea, figw, figh) pcts = bbox_to_pcts(sp.plotarea, figw, figh)
ax."set_position"(pcts) ax."set_position"(pcts)
# set the cbar position if there is one if haskey(sp.attr, :cbar_ax) && RecipesPipeline.is3d(sp) # 2D plots are completely handled by axis dividers
if haskey(sp.attr, :cbar_ax)
cbw = sp.attr[:cbar_width] cbw = sp.attr[:cbar_width]
# this is the bounding box of just the colors of the colorbar (not labels) # this is the bounding box of just the colors of the colorbar (not labels)
ex = sp[:zaxis][:extrema] cb_bbox = BoundingBox(right(sp.bbox)-cbw - 2mm, top(sp.bbox) + 2mm, _cbar_width-1mm, height(sp.bbox) - 4mm)
has_toplabel = !(1e-7 < max(abs(ex.emax), abs(ex.emin)) < 1e7)
cb_bbox = BoundingBox(right(sp.bbox)-cbw+1mm, top(sp.bbox) + (has_toplabel ? 4mm : 2mm), _cbar_width-1mm, height(sp.bbox) - (has_toplabel ? 6mm : 4mm))
pcts = bbox_to_pcts(cb_bbox, figw, figh) pcts = bbox_to_pcts(cb_bbox, figw, figh)
sp.attr[:cbar_ax]."set_position"(pcts) sp.attr[:cbar_ax]."set_position"(pcts)
end end

View File

@ -19,6 +19,10 @@ function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr
""" """
end end
function embeddable_html(plt::AbstractPlot)
html_head(plt) * html_body(plt)
end
function open_browser_window(filename::AbstractString) function open_browser_window(filename::AbstractString)
@static if Sys.isapple() @static if Sys.isapple()
return run(`open $(filename)`) return run(`open $(filename)`)
@ -45,7 +49,7 @@ function standalone_html_window(plt::AbstractPlot)
old = use_local_dependencies[] # save state to restore afterwards old = use_local_dependencies[] # save state to restore afterwards
# if we open a browser ourself, we can host local files, so # if we open a browser ourself, we can host local files, so
# when we have a local plotly downloaded this is the way to go! # when we have a local plotly downloaded this is the way to go!
use_local_dependencies[] = isfile(plotly_local_file_path) use_local_dependencies[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
filename = write_temp_html(plt) filename = write_temp_html(plt)
open_browser_window(filename) open_browser_window(filename)
# restore for other backends # restore for other backends

90
src/colorbars.jl Normal file
View File

@ -0,0 +1,90 @@
# These functions return an operator for use in `get_clims(::Seres, op)`
process_clims(lims::Tuple{<:Number,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ignorenan_extrema
process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
# don't specialize on ::Function otherwise python functions won't work
process_clims(f) = f
function get_clims(sp::Subplot, op=process_clims(sp[:clims]))
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims]))
zmin, zmax = if series[:colorbar_entry]
get_clims(sp, op)
else
get_clims(series, op)
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
"""
function get_clims(series::Series, op=ignorenan_extrema)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...)
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(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
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap,:surface) ||
any(series[z] !== nothing for z [:marker_z,:line_z,:fill_z])
cbar_gradient
else
nothing
end
end
hascolorbar(series::Series) = colorbar_style(series) !== nothing
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
function get_colorbar_ticks(sp::Subplot; update = true)
if update || !haskey(sp.attr, :colorbar_optimized_ticks)
ticks = _transform_ticks(sp[:colorbar_ticks])
cvals = sp[:colorbar_continuous_values]
dvals = sp[:colorbar_discrete_values]
clims = get_clims(sp)
scale = sp[:colorbar_scale]
formatter = sp[:colorbar_formatter]
sp.attr[:colorbar_optimized_ticks] =
get_ticks(ticks, cvals, dvals, clims, scale, formatter)
end
return sp.attr[:colorbar_optimized_ticks]
end
function _update_subplot_colorbars(sp::Subplot)
# Dynamic callback from the pipeline if needed
end

View File

@ -1,7 +1,5 @@
const P2 = GeometryBasics.Point2{Float64}
const P3 = GeometryBasics.Point3{Float64}
const P2 = GeometryTypes.Point2{Float64}
const P3 = GeometryTypes.Point3{Float64}
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b)) nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b)) nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
@ -11,9 +9,9 @@ compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angl
# ------------------------------------------------------------- # -------------------------------------------------------------
struct Shape struct Shape{X<:Number, Y<:Number}
x::Vector{Float64} x::Vector{X}
y::Vector{Float64} y::Vector{Y}
# function Shape(x::AVec, y::AVec) # function Shape(x::AVec, y::AVec)
# # if x[1] != x[end] || y[1] != y[end] # # if x[1] != x[end] || y[1] != y[end]
# # new(vcat(x, x[1]), vcat(y, y[1])) # # new(vcat(x, x[1]), vcat(y, y[1]))
@ -44,21 +42,17 @@ function coords(shape::Shape)
shape.x, shape.y shape.x, shape.y
end end
function coords(shapes::AVec{Shape}) #coords(shapes::AVec{Shape}) = unzip(map(coords, shapes))
length(shapes) == 0 && return zeros(0), zeros(0) function coords(shapes::AVec{<:Shape})
xs = map(get_xs, shapes) c = map(coords, shapes)
ys = map(get_ys, shapes) x = [q[1] for q in c]
x, y = map(copy, coords(shapes[1])) y = [q[2] for q in c]
for shape in shapes[2:end]
nanappend!(x, shape.x)
nanappend!(y, shape.y)
end
x, y x, y
end end
"get an array of tuples of points on a circle with radius `r`" "get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1) function partialcircle(start_θ, end_θ, n = 20, r=1)
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)] [(r*cos(u), r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
end end
"interleave 2 vectors into each other (like a zipper's teeth)" "interleave 2 vectors into each other (like a zipper's teeth)"
@ -77,7 +71,6 @@ function weave(x,y; ordering = Vector[x,y])
ret ret
end end
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms" "create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
function makestar(n; offset = -0.5, radius = 1.0) function makestar(n; offset = -0.5, radius = 1.0)
z1 = offset * π z1 = offset * π
@ -93,7 +86,6 @@ function makeshape(n; offset = -0.5, radius = 1.0)
Shape(partialcircle(z, z + 2π, n+1, radius)) Shape(partialcircle(z, z + 2π, n+1, radius))
end end
function makecross(; offset = -0.5, radius = 1.0) function makecross(; offset = -0.5, radius = 1.0)
z2 = offset * π z2 = offset * π
z1 = z2 - π/8 z1 = z2 - π/8
@ -103,7 +95,6 @@ function makecross(; offset = -0.5, radius = 1.0)
ordering=Vector[outercircle,innercircle,outercircle])) ordering=Vector[outercircle,innercircle,outercircle]))
end end
from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle)) from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
function makearrowhead(angle; h = 2.0, w = 0.4) function makearrowhead(angle; h = 2.0, w = 0.4)
@ -112,31 +103,6 @@ function makearrowhead(angle; h = 2.0, w = 0.4)
from_polar(angle + 0.5π, w) - tip, (0,0)]) from_polar(angle + 0.5π, w) - tip, (0,0)])
end end
const _shape_keys = Symbol[
:circle,
:rect,
:star5,
:diamond,
:hexagon,
:cross,
:xcross,
:utriangle,
:dtriangle,
:rtriangle,
:ltriangle,
:pentagon,
:heptagon,
:octagon,
:star4,
:star6,
:star7,
:star8,
:vline,
:hline,
:+,
:x,
]
const _shapes = KW( const _shapes = KW(
:circle => makeshape(20), :circle => makeshape(20),
:rect => makeshape(4, offset=-0.25), :rect => makeshape(4, offset=-0.25),
@ -239,9 +205,12 @@ function rotate!(shape::Shape, Θ::Real, c = center(shape))
end end
"rotate an object in space" "rotate an object in space"
function rotate(shape::Shape, Θ::Real, c = center(shape)) function rotate(shape::Shape, θ::Real, c = center(shape))
shapecopy = deepcopy(shape) x, y = coords(shape)
rotate!(shapecopy, Θ, c) cx, cy = c
x_new = rotate_x.(x, y, θ, cx, cy)
y_new = rotate_y.(x, y, θ, cx, cy)
Shape(x_new, y_new)
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -319,7 +288,7 @@ function font(args...;kw...)
for symbol in keys(kw) for symbol in keys(kw)
if symbol == :family if symbol == :family
family = kw[:family] family = string(kw[:family])
elseif symbol == :pointsize elseif symbol == :pointsize
pointsize = kw[:pointsize] pointsize = kw[:pointsize]
elseif symbol == :halign elseif symbol == :halign
@ -358,9 +327,15 @@ end
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()` Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
""" """
function scalefontsizes(factor::Number) function scalefontsizes(factor::Number)
for k in (:titlefontsize, :guidefontsize, :tickfontsize, :legendfontsize) for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
scalefontsize(k, factor) scalefontsize(k, factor)
end end
for letter in (:x,:y,:z)
for k in (:guidefontsize, :tickfontsize)
scalefontsize(Symbol(letter, k), factor)
end
end
end end
""" """
@ -369,15 +344,27 @@ end
Resets font sizes to initial default values. Resets font sizes to initial default values.
""" """
function scalefontsizes() function scalefontsizes()
for k in (:titlefontsize, :guidefontsize, :tickfontsize, :legendfontsize) for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
f = default(k) f = default(k)
if k in keys(_initial_fontsizes) if k in keys(_initial_fontsizes)
factor = f / _initial_fontsizes[k] factor = f / _initial_fontsizes[k]
scalefontsize(k, 1.0/factor) scalefontsize(k, 1.0/factor)
end end
end end
for letter in (:x,:y,:z)
for k in (:guidefontsize, :tickfontsize)
if k in keys(_initial_fontsizes)
f = default(Symbol(letter, k))
factor = f / _initial_fontsizes[k]
scalefontsize(Symbol(letter, k), 1.0/factor)
end
end
end
end end
resetfontsizes() = scalefontsizes()
"Wrap a string with font info" "Wrap a string with font info"
struct PlotText struct PlotText
str::AbstractString str::AbstractString
@ -487,6 +474,11 @@ mutable struct SeriesAnnotations
baseshape::Union{Shape, AbstractVector{Shape}, Nothing} baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
scalefactor::Tuple scalefactor::Tuple
end end
series_annotations(scalar) = series_annotations([scalar])
function series_annotations(anns::AMat)
map(series_annotations, anns)
end
function series_annotations(strs::AbstractVector, args...) function series_annotations(strs::AbstractVector, args...)
fnt = font() fnt = font()
shp = nothing shp = nothing
@ -583,16 +575,27 @@ end
annotations(::Nothing) = [] annotations(::Nothing) = []
annotations(anns::AVec) = anns annotations(anns::AVec) = anns
annotations(anns::AMat) = map(annotations, anns)
annotations(anns) = Any[anns] annotations(anns) = Any[anns]
annotations(sa::SeriesAnnotations) = sa annotations(sa::SeriesAnnotations) = sa
# Expand arrays of coordinates, positions and labels into induvidual annotations # Expand arrays of coordinates, positions and labels into induvidual annotations
# and make sure labels are of type PlotText # and make sure labels are of type PlotText
function process_annotation(sp::Subplot, xs, ys, labs, font = font()) function process_annotation(sp::Subplot, xs, ys, labs, font = nothing)
anns = [] anns = []
labs = makevec(labs) labs = makevec(labs)
xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs) xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs)
ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys) ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys)
if isnothing(font)
font = Plots.font(;
family=sp[:annotationfontfamily],
pointsize=sp[:annotationfontsize],
halign=sp[:annotationhalign],
valign=sp[:annotationvalign],
rotation=sp[:annotationrotation],
color=sp[:annotationcolor],
)
end
for i in 1:max(xlength, ylength, length(labs)) for i in 1:max(xlength, ylength, length(labs))
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i) x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
x = typeof(x) <: TimeType ? Dates.value(x) : x x = typeof(x) <: TimeType ? Dates.value(x) : x
@ -601,14 +604,24 @@ function process_annotation(sp::Subplot, xs, ys, labs, font = font())
alphabet = "abcdefghijklmnopqrstuvwxyz" alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font))) push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else else
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font))) push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab[1], font, lab[2:end]...) : text(lab, font)))
end end
end end
anns anns
end end
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font()) function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = nothing)
anns = [] anns = []
positions, labs = makevec(positions), makevec(labs) positions, labs = makevec(positions), makevec(labs)
if isnothing(font)
font = Plots.font(;
family=sp[:annotationfontfamily],
pointsize=sp[:annotationfontsize],
halign=sp[:annotationhalign],
valign=sp[:annotationvalign],
rotation=sp[:annotationrotation],
color=sp[:annotationcolor],
)
end
for i in 1:max(length(positions), length(labs)) for i in 1:max(length(positions), length(labs))
pos, lab = _cycle(positions, i), _cycle(labs, i) pos, lab = _cycle(positions, i), _cycle(labs, i)
pos = get(_positionAliases, pos, pos) pos = get(_positionAliases, pos, pos)
@ -616,12 +629,15 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol},
alphabet = "abcdefghijklmnopqrstuvwxyz" alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font))) push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else else
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font))) push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab[1], font, lab[2:end]...) : text(lab, font)))
end end
end end
anns anns
end end
function process_any_label(lab, font=Font())
lab isa Tuple ? text(lab...) : text( lab, font )
end
# Give each annotation coordinates based on specified position # Give each annotation coordinates based on specified position
function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText) function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}( position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}(
@ -638,6 +654,7 @@ function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
(x, y, lab) (x, y, lab)
end end
locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label) locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label)
locate_annotation(sp::Subplot, x, y, z, label::PlotText) = (x, y, z, label)
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)" "type which represents z-values for colors and sizes (and anything else that might come up)"
@ -737,7 +754,7 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"create a BezierCurve for plotting" "create a BezierCurve for plotting"
mutable struct BezierCurve{T <: GeometryTypes.Point} mutable struct BezierCurve{T <: GeometryBasics.Point}
control_points::Vector{T} control_points::Vector{T}
end end

View File

@ -7,9 +7,9 @@ mutable struct PlotExample
exprs::Vector{Expr} exprs::Vector{Expr}
end end
# the _examples we'll run for each # the _examples we'll run for each backend
const _examples = PlotExample[ const _examples = PlotExample[
PlotExample( PlotExample( # 1
"Lines", "Lines",
"A simple line plot of the columns.", "A simple line plot of the columns.",
[:( [:(
@ -18,7 +18,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 2
"Functions, adding data, and animations", "Functions, adding data, and animations",
""" """
Plot multiple functions. You can also put the function first, or use the form `plot(f, Plot multiple functions. You can also put the function first, or use the form `plot(f,
@ -30,16 +30,16 @@ const _examples = PlotExample[
""", """,
[:( [:(
begin begin
p = plot([sin, cos], zeros(0), leg = false) p = plot([sin, cos], zeros(0), leg = false, xlims = (0, 2π), ylims = (-1, 1))
anim = Animation() anim = Animation()
for x in range(0, stop = 10π, length = 100) for x in range(0, stop = 2π, length = 20)
push!(p, x, Float64[sin(x), cos(x)]) push!(p, x, Float64[sin(x), cos(x)])
frame(anim) frame(anim)
end end
end end
)], )],
), ),
PlotExample( PlotExample( # 3
"Parametric plots", "Parametric plots",
"Plot function pair (x(u), y(u)).", "Plot function pair (x(u), y(u)).",
[ [
@ -58,7 +58,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 4
"Colors", "Colors",
""" """
Access predefined palettes (or build your own with the `colorscheme` method). Access predefined palettes (or build your own with the `colorscheme` method).
@ -89,7 +89,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 5
"Global", "Global",
""" """
Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow
@ -121,13 +121,7 @@ const _examples = PlotExample[
], ],
), ),
# PlotExample("Two-axis", PlotExample( # 6
# "Use the `axis` arguments.",
# [
# :(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
# ]),
PlotExample(
"Images", "Images",
"Plot an image. y-axis is set to flipped", "Plot an image. y-axis is set to flipped",
[ [
@ -142,7 +136,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 7
"Arguments", "Arguments",
""" """
Plot multiple series with different numbers of points. Mix arguments that apply to all Plot multiple series with different numbers of points. Mix arguments that apply to all
@ -166,7 +160,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 8
"Build plot in pieces", "Build plot in pieces",
"Start with a base plot...", "Start with a base plot...",
[:( [:(
@ -175,7 +169,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 9
"", "",
"and add to it later.", "and add to it later.",
[:( [:(
@ -184,7 +178,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 10
"Histogram2D", "Histogram2D",
"", "",
[:( [:(
@ -193,7 +187,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 11
"Line types", "Line types",
"", "",
[ [
@ -214,7 +208,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 12
"Line styles", "Line styles",
"", "",
[ [
@ -237,7 +231,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 13
"Marker types", "Marker types",
"", "",
[ [
@ -247,14 +241,15 @@ const _examples = PlotExample[
m -> m in Plots.supported_markers(), m -> m in Plots.supported_markers(),
Plots._shape_keys, Plots._shape_keys,
) )
markers = reshape(markers, 1, length(markers)) markers = permutedims(markers)
n = length(markers) n = length(markers)
x = range(0, stop = 10, length = n + 2)[2:(end - 1)] x = range(0, stop = 10, length = n + 2)[2:(end - 1)]
y = repeat(reshape(reverse(x), 1, :), n, 1) y = repeat(reshape(reverse(x), 1, :), n, 1)
scatter( scatter(
x, x,
y, y,
m = (8, :auto), m = markers,
markersize = 8,
lab = map(string, markers), lab = map(string, markers),
bg = :linen, bg = :linen,
xlim = (0, 10), xlim = (0, 10),
@ -264,7 +259,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 14
"Bar", "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)",
[:( [:(
@ -273,7 +268,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 15
"Histogram", "Histogram",
"", "",
[ [
@ -288,7 +283,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 16
"Subplots", "Subplots",
""" """
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate Use the `layout` keyword, and optionally the convenient `@layout` macro to generate
@ -310,7 +305,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 17
"Adding to subplots", "Adding to subplots",
""" """
Note here the automatic grid layout, as well as the order in which new series are added Note here the automatic grid layout, as well as the order in which new series are added
@ -329,14 +324,20 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample("", "", [:( PlotExample( # 18
"",
"",
[
:(
begin begin
using Random using Random
Random.seed!(111) Random.seed!(111)
plot!(Plots.fakedata(100, 10)) plot!(Plots.fakedata(100, 10))
end end
)]), )
PlotExample( ]
),
PlotExample( # 19
"Open/High/Low/Close", "Open/High/Low/Close",
""" """
Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y` Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y`
@ -365,7 +366,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 20
"Annotations", "Annotations",
""" """
The `annotations` keyword is used for text annotations in data-coordinates. Pass in a The `annotations` keyword is used for text annotations in data-coordinates. Pass in a
@ -408,7 +409,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 21
"Custom Markers", "Custom Markers",
"""A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported """A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported
backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and
@ -454,7 +455,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 22
"Contours", "Contours",
""" """
Any value for fill works here. We first build a filled contour from a function, then an Any value for fill works here. We first build a filled contour from a function, then an
@ -474,7 +475,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 23
"Pie", "Pie",
"", "",
[:( [:(
@ -485,7 +486,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 24
"3D", "3D",
"", "",
[ [
@ -511,7 +512,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 25
"DataFrames", "DataFrames",
"Plot using DataFrame column symbols.", "Plot using DataFrame column symbols.",
[ [
@ -534,7 +535,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 26
"Groups and Subplots", "Groups and Subplots",
"", "",
[ [
@ -552,7 +553,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 27
"Polar Plots", "Polar Plots",
"", "",
[:( [:(
@ -563,7 +564,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 28
"Heatmap, categorical axes, and aspect_ratio", "Heatmap, categorical axes, and aspect_ratio",
"", "",
[:( [:(
@ -575,7 +576,7 @@ const _examples = PlotExample[
end end
)], )],
), ),
PlotExample( PlotExample( # 29
"Layouts, margins, label rotation, title location", "Layouts, margins, label rotation, title location",
"", "",
[ [
@ -595,7 +596,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 30
"Boxplot and Violin series recipes", "Boxplot and Violin series recipes",
"", "",
[ [
@ -620,7 +621,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 31
"Animation with subplots", "Animation with subplots",
"The `layout` macro can be used to create an animation with subplots.", "The `layout` macro can be used to create an animation with subplots.",
[ [
@ -628,14 +629,15 @@ const _examples = PlotExample[
begin begin
l = @layout([[a; b] c]) l = @layout([[a; b] c])
p = plot( p = plot(
plot([sin, cos], 1, leg = false), plot([sin, cos], 1, ylims = (-1, 1), leg = false),
scatter([atan, cos], 1, leg = false), scatter([atan, cos], 1, ylims = (-1, 1.5), leg = false),
plot(log, 1, xlims = (1, 10π), ylims = (0, 5), leg = false), plot(log, 1, ylims = (0, 2), leg = false),
layout = l, layout = l,
xlims = (1, 2π),
) )
anim = Animation() anim = Animation()
for x in range(1, stop = 10π, length = 100) for x in range(1, stop = 2π, length = 20)
plot(push!( plot(push!(
p, p,
x, x,
@ -647,7 +649,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 32
"Spy", "Spy",
""" """
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
@ -681,7 +683,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 33
"Magic grid argument", "Magic grid argument",
""" """
The grid lines can be modified individually for each axis with the magic `grid` argument. The grid lines can be modified individually for each axis with the magic `grid` argument.
@ -711,7 +713,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 34
"Framestyle", "Framestyle",
""" """
The style of the frame/axes of a (sub)plot can be changed with the `framestyle` The style of the frame/axes of a (sub)plot can be changed with the `framestyle`
@ -735,7 +737,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 35
"Lines and markers with varying colors", "Lines and markers with varying colors",
""" """
You can use the `line_z` and `marker_z` properties to associate a color with You can use the `line_z` and `marker_z` properties to associate a color with
@ -761,7 +763,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 36
"Portfolio Composition maps", "Portfolio Composition maps",
""" """
see: http://stackoverflow.com/a/37732384/5075246 see: http://stackoverflow.com/a/37732384/5075246
@ -787,7 +789,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 37
"Ribbons", "Ribbons",
""" """
Ribbons can be added to lines via the `ribbon` keyword; Ribbons can be added to lines via the `ribbon` keyword;
@ -810,7 +812,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 38
"Histogram2D (complex values)", "Histogram2D (complex values)",
"", "",
[ [
@ -829,7 +831,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 39
"Unconnected lines using `missing` or `NaN`", "Unconnected lines using `missing` or `NaN`",
""" """
Missing values and non-finite values, including `NaN`, are not plotted. Missing values and non-finite values, including `NaN`, are not plotted.
@ -853,7 +855,7 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( PlotExample( # 40
"Lens", "Lens",
"A lens lets you easily magnify a region of a plot. x and y coordinates refer to the to be magnified region and the via the `inset` keyword the subplot index and the bounding box (in relative coordinates) of the inset plot with the magnified plot can be specified. Additional attributes count for the inset plot.", "A lens lets you easily magnify a region of a plot. x and y coordinates refer to the to be magnified region and the via the `inset` keyword the subplot index and the bounding box (in relative coordinates) of the inset plot with the magnified plot can be specified. Additional attributes count for the inset plot.",
[ [
@ -875,7 +877,7 @@ const _examples = PlotExample[
end, end,
], ],
), ),
PlotExample( PlotExample( # 41
"Array Types", "Array Types",
"Plots supports different `Array` types that follow the `AbstractArray` interface, like `StaticArrays` and `OffsetArrays.`", "Plots supports different `Array` types that follow the `AbstractArray` interface, like `StaticArrays` and `OffsetArrays.`",
[ [
@ -885,11 +887,12 @@ const _examples = PlotExample[
sv = SVector{10}(rand(10)) sv = SVector{10}(rand(10))
ov = OffsetVector(rand(10), -2) ov = OffsetVector(rand(10), -2)
plot([sv, ov], label = ["StaticArray" "OffsetArray"]) plot([sv, ov], label = ["StaticArray" "OffsetArray"])
plot!(3ov, ribbon=ov, label="OffsetArray ribbon")
end end
end, end,
], ],
), ),
PlotExample( PlotExample( # 42
"Setting defaults and font arguments", "Setting defaults and font arguments",
"", "",
[ [
@ -919,7 +922,7 @@ const _examples = PlotExample[
end, end,
], ],
), ),
PlotExample( PlotExample( # 43
"Heatmap with DateTime axis", "Heatmap with DateTime axis",
"", "",
[ [
@ -934,7 +937,7 @@ const _examples = PlotExample[
end, end,
], ],
), ),
PlotExample( PlotExample( # 44
"Linked axes", "Linked axes",
"", "",
[ [
@ -946,7 +949,7 @@ const _examples = PlotExample[
end, end,
], ],
), ),
PlotExample( PlotExample( # 45
"Error bars and array type recipes", "Error bars and array type recipes",
"", "",
[ [
@ -973,8 +976,8 @@ const _examples = PlotExample[
surf = Measurement.((1:10) .* (1:10)', rand(10,10)) surf = Measurement.((1:10) .* (1:10)', rand(10,10))
plot( plot(
scatter(x, [x y], msw = 0), scatter(x, [x y]),
scatter(x, y, z, msw = 0), scatter(x, y, z),
heatmap(x, y, surf), heatmap(x, y, surf),
wireframe(x, y, surf), wireframe(x, y, surf),
legend = :topleft legend = :topleft
@ -983,28 +986,247 @@ const _examples = PlotExample[
end, end,
], ],
), ),
PlotExample( # 46
"Tuples and `Point`s as data",
"",
[quote
using GeometryBasics
using Distributions
d = MvNormal([1.0 0.75; 0.75 2.0])
plot([(1,2),(3,2),(2,1),(2,3)])
scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25)
end]
),
PlotExample( # 47
"Mesh3d",
"""
Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically.
You can also specify the connections using the connections keyword.
The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle,
such that elements at the same position of these vectors form a triangle.
""",
[
:(
begin
# specify the vertices
x=[0, 1, 2, 0]
y=[0, 0, 1, 2]
z=[0, 2, 0, 1]
# specify the triangles
# every column is one triangle,
# where the values denote the indices of the vertices of the triangle
i=[0, 0, 0, 1]
j=[1, 2, 3, 2]
k=[2, 3, 1, 3]
# the four triangles gives above give a tetrahedron
mesh3d(x,y,z;connections=(i,j,k))
end
),
],
),
PlotExample( # 48
"Vectors of markershapes and segments",
"",
[quote
using Base.Iterators: cycle, take
yv = ones(9)
ys = [1; 1; NaN; ones(6)]
y = 5 .- [yv 2ys 3yv 4ys]
plt_color_rows = plot(
y,
seriestype = [:path :path :scatter :scatter],
markershape = collect(take(cycle((:utriangle, :rect)), 9)),
markersize = 8,
color = collect(take(cycle((:red, :black)), 9))
)
plt_z_cols = plot(
y,
markershape = [:utriangle :x :circle :square],
markersize = [5 10 10 5],
marker_z = [5 4 3 2],
line_z = [1 3 3 1],
linewidth = [1 10 5 1]
)
plot(plt_color_rows, plt_z_cols)
end]
),
PlotExample( # 49
"Polar heatmaps",
"",
[quote
x = range(0, 2π, length=9)
y = 0:4
z = (1:4) .+ (1:8)'
heatmap(x, y, z, projection = :polar)
end]
),
PlotExample( # 50
"3D surface with axis guides",
"",
[quote
f(x,a) = 1/x + a*x^2
xs = collect(0.1:0.05:2.0);
as = collect(0.2:0.1:2.0);
x_grid = [x for x in xs for y in as];
a_grid = [y for x in xs for y in as];
plot(x_grid, a_grid, f.(x_grid,a_grid),
st = :surface,
xlabel = "longer xlabel",
ylabel = "longer ylabel",
zlabel = "longer zlabel",
)
end]
),
PlotExample( # 51
"Images with custom axes",
"",
[quote
using Plots
using TestImages
img = testimage("lighthouse")
# plot the image reversing the first dimension and setting yflip = false
plot([-π, π], [-1, 1], reverse(img, dims=1), yflip=false, aspect_ratio=:none)
# plot other data
plot!(sin, -π, π, lw=3, color=:red)
end]
),
PlotExample(
"3d quiver",
"",
[quote
using Plots
ϕs = range(-π, π, length=50)
θs = range(0, π, length=25)
θqs = range(1, π-1, length=25)
x = vec([sin(θ) * cos(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)])
y = vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)])
z = vec([cos(θ) for (ϕ, θ) in Iterators.product(ϕs, θs)])
u = 0.1 * vec([sin(θ) * cos(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θqs)])
v = 0.1 * vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θqs)])
w = 0.1 * vec([cos(θ) for (ϕ, θ) in Iterators.product(ϕs, θqs)])
quiver(x,y,z, quiver=(u,v,w))
end]
),
PlotExample( # 53
"Step Types",
"A comparison of the various step-like `seriestype`s",
[
:(
begin
x = 1:5
y = [1, 2, 3, 2, 1]
default(shape=:circle)
plot(
plot(x, y, markershape=:circle, seriestype=:steppre, label="steppre"),
plot(x, y, markershape=:circle, seriestype=:stepmid, label="stepmid"),
plot(x, y, markershape=:circle, seriestype=:steppost, label="steppost"),
layout=(3,1)
)
end
),
],
),
PlotExample( # 54
"Guide positions and alignment",
"",
[
:(
begin
plot(
rand(10, 4),
layout=4,
xguide="x guide",
yguide="y guide",
xguidefonthalign=[:left :right :right :left],
yguidefontvalign=[:top :bottom :bottom :top],
xguideposition=:top,
yguideposition=[:right :left :right :left],
ymirror=[false true true false],
xmirror=[false false true true],
legend=false,
seriestype=[:bar :scatter :path :stepmid]
)
end
),
],
),
PlotExample( # 55
"3D axis flip / mirror",
"",
[
:(
begin
using LinearAlgebra
scalefontsizes(.4)
x, y = collect(-6:0.5:10), collect(-8:0.5:8)
args = x, y, (x, y) -> sinc(norm([x, y]) / π)
kwargs = Dict(:xlabel=>"x", :ylabel=>"y", :zlabel=>"z", :grid=>true, :minorgrid=>true)
plots = [wireframe(args..., title = "wire"; kwargs...)]
for ax (:x, :y, :z)
push!(plots, wireframe(
args...,
title = "wire-flip-$ax",
xflip = ax == :x,
yflip = ax == :y,
zflip = ax == :z;
kwargs...,
))
end
for ax (:x, :y, :z)
push!(plots, wireframe(
args...,
title = "wire-mirror-$ax",
xmirror = ax == :x,
ymirror = ax == :y,
zmirror = ax == :z;
kwargs...,
))
end
plt = plot(plots..., layout=(@layout [_ ° _; ° ° °; ° ° °]), margin=0Plots.px)
resetfontsizes()
plt
end
),
],
),
] ]
# Some constants for PlotDocs and PlotReferenceImages # Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 31] _animation_examples = [2, 31]
_backend_skips = Dict( _backend_skips = Dict(
:gr => [25, 30], :gr => [25, 30, 47],
:pyplot => [2, 25, 30, 31], :pyplot => [2, 25, 30, 31, 47, 49, 55],
:plotlyjs => [2, 21, 24, 25, 30, 31], :plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51, 55],
:plotly => [2, 21, 24, 25, 30, 31], :plotly => [2, 21, 24, 25, 30, 31, 49, 50, 51, 55],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39],
:pgfplotsx => [ :pgfplotsx => [
2, # animation 2, # animation
6, # images 6, # images
10, # histogram2d
16, # pgfplots thinks the upper panel is too small 16, # pgfplots thinks the upper panel is too small
22, # contourf
25, # @df
30, # @df 30, # @df
31, # animation 31, # animation
32, # spy 32, # spy
38, # histogram2d 49, # polar heatmap
45, # wireframe 51, # image with custom axes
], ],
) )

View File

@ -4,7 +4,7 @@ const use_local_plotlyjs = Ref(false)
function _init_ijulia_plotting() function _init_ijulia_plotting()
# IJulia is more stable with local file # IJulia is more stable with local file
use_local_plotlyjs[] = isfile(plotly_local_file_path) use_local_plotlyjs[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
ENV["MPLBACKEND"] = "Agg" ENV["MPLBACKEND"] = "Agg"
end end
@ -54,9 +54,9 @@ function _ijulia_display_dict(plt::Plot)
elseif output_type == :html elseif output_type == :html
mime = "text/html" mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt) out[mime] = sprint(show, MIME(mime), plt)
_ijulia__extra_mime_info!(plt, out)
else else
error("Unsupported output type $output_type") error("Unsupported output type $output_type")
end end
_ijulia__extra_mime_info!(plt, out)
out out
end end

View File

@ -1,4 +1,7 @@
using REPL using REPL
using Scratch
const plotly_local_file_path = Ref{Union{Nothing, String}}(nothing)
function _plots_defaults() function _plots_defaults()
@ -13,9 +16,10 @@ end
function __init__() function __init__()
user_defaults = _plots_defaults() user_defaults = _plots_defaults()
if haskey(user_defaults, :theme) if haskey(user_defaults, :theme)
theme(pop!(user_defaults, :theme)) theme(pop!(user_defaults, :theme); user_defaults...)
end else
default(; user_defaults...) default(; user_defaults...)
end
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay()) insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
@ -29,49 +33,41 @@ function __init__()
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin @require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin
fn = joinpath(@__DIR__, "backends", "hdf5.jl") fn = joinpath(@__DIR__, "backends", "hdf5.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" begin @require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" begin
fn = joinpath(@__DIR__, "backends", "inspectdr.jl") fn = joinpath(@__DIR__, "backends", "inspectdr.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" begin @require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" begin
fn = joinpath(@__DIR__, "backends", "pgfplots.jl") fn = joinpath(@__DIR__, "backends", "deprecated", "pgfplots.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require ORCA = "47be7bcc-f1a6-5447-8b36-7eeeff7534fd" begin @require PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" begin
fn = joinpath(@__DIR__, "backends", "orca.jl") fn = joinpath(@__DIR__, "backends", "plotlybase.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin @require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin
fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl") fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin @require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin
fn = joinpath(@__DIR__, "backends", "plotlyjs.jl") fn = joinpath(@__DIR__, "backends", "plotlyjs.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin @require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin
fn = joinpath(@__DIR__, "backends", "pyplot.jl") fn = joinpath(@__DIR__, "backends", "pyplot.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" begin @require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" begin
fn = joinpath(@__DIR__, "backends", "unicodeplots.jl") fn = joinpath(@__DIR__, "backends", "unicodeplots.jl")
include(fn) include(fn)
@require Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise.track(Plots, fn)
end end
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin @require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
@ -82,15 +78,16 @@ function __init__()
end end
end end
if haskey(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL") if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
use_local_plotlyjs[] = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true" global plotly_local_file_path[] = joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
use_local_dependencies[] = isfile(plotly_local_file_path) && use_local_plotlyjs[] if !isfile(plotly_local_file_path[])
if use_local_plotlyjs[] && !isfile(plotly_local_file_path) download("https://cdn.plot.ly/$(_plotly_min_js_filename)", plotly_local_file_path[])
@warn("PLOTS_HOST_DEPENDENCY_LOCAL is set to true, but no local plotly file found. run Pkg.build(\"Plots\") and make sure PLOTS_HOST_DEPENDENCY_LOCAL is set to true")
end end
else
use_local_plotlyjs[] = true
end
use_local_dependencies[] = use_local_plotlyjs[] use_local_dependencies[] = use_local_plotlyjs[]
end
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin @require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin

View File

@ -4,34 +4,6 @@
to_pixels(m::AbsoluteLength) = m.value / 0.254 to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm const _cbar_width = 5mm
#Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
#Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
Base.zero(::Type{typeof(mm)}) = 0mm
Base.one(::Type{typeof(mm)}) = 1mm
Base.typemin(::typeof(mm)) = -Inf*mm
Base.typemax(::typeof(mm)) = Inf*mm
Base.convert(::Type{F}, l::AbsoluteLength) where {F<:AbstractFloat} = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
# Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
# Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
# Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
Base.zero(::Type{typeof(pct)}) = 0pct
Base.one(::Type{typeof(pct)}) = 1pct
Base.typemin(::typeof(pct)) = 0pct
Base.typemax(::typeof(pct)) = 1pct
const defaultbox = BoundingBox(0mm, 0mm, 0mm, 0mm) const defaultbox = BoundingBox(0mm, 0mm, 0mm, 0mm)
left(bbox::BoundingBox) = bbox.x0[1] left(bbox::BoundingBox) = bbox.x0[1]
@ -258,7 +230,7 @@ end
grid(args...; kw...) grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g. Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,04))` creates a grid with three rows and two `grid(3,2, widths = (0.6,0.4))` creates a grid with three rows and two
columns of different width. columns of different width.
""" """
grid(args...; kw...) = GridLayout(args...; kw...) grid(args...; kw...) = GridLayout(args...; kw...)
@ -345,10 +317,8 @@ end
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!) # recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
nr, nc = size(layout) nr, nc = size(layout)
# # create a matrix for each minimum padding direction # # create a matrix for each minimum padding direction
# _update_min_padding!(layout) # _update_min_padding!(layout)
minpad_left = map(leftpad, layout.grid) minpad_left = map(leftpad, layout.grid)
minpad_top = map(toppad, layout.grid) minpad_top = map(toppad, layout.grid)
minpad_right = map(rightpad, layout.grid) minpad_right = map(rightpad, layout.grid)
@ -407,10 +377,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
# this is the minimum perimeter as decided by this child's parent, so that # this is the minimum perimeter as decided by this child's parent, so that
# all children on this border have the same value # all children on this border have the same value
min_child_perimeter = [ min_child_perimeter = [
c == 1 ? layout.minpad[1] : 0mm, c == 1 ? layout.minpad[1] : pad_left[c],
r == 1 ? layout.minpad[2] : 0mm, r == 1 ? layout.minpad[2] : pad_top[r],
c == nc ? layout.minpad[3] : 0mm, c == nc ? layout.minpad[3] : pad_right[c],
r == nr ? layout.minpad[4] : 0mm r == nr ? layout.minpad[4] : pad_bottom[r]
] ]
# recursively update the child's children # recursively update the child's children
@ -436,7 +406,7 @@ end
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
calc_num_subplots(layout::AbstractLayout) = 1 calc_num_subplots(layout::AbstractLayout) = get(layout.attr, :blank, false) ? 0 : 1
function calc_num_subplots(layout::GridLayout) function calc_num_subplots(layout::GridLayout)
tot = 0 tot = 0
for l in layout.grid for l in layout.grid
@ -805,9 +775,17 @@ end
"Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis." "Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis."
function twinx(sp::Subplot) function twinx(sp::Subplot)
sp[:right_margin] = max(sp[:right_margin], 30px) plot!(sp.plt,
plot!(sp.plt, inset = (sp[:subplot_index], bbox(0,0,1,1))) inset = (sp[:subplot_index], bbox(0,0,1,1)),
right_margin = sp[:right_margin],
left_margin = sp[:left_margin],
top_margin = sp[:top_margin],
bottom_margin = sp[:bottom_margin],
)
twinsp = sp.plt.subplots[end] twinsp = sp.plt.subplots[end]
twinsp[:xaxis][:grid] = false
twinsp[:yaxis][:grid] = false
twinsp[:xaxis][:showaxis] = false
twinsp[:yaxis][:mirror] = true twinsp[:yaxis][:mirror] = true
twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0) twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0)
link_axes!(sp[:xaxis], twinsp[:xaxis]) link_axes!(sp[:xaxis], twinsp[:xaxis])

59
src/legend.jl Normal file
View File

@ -0,0 +1,59 @@
"""
```julia
legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax, inout)
```
Return `(x,y)` at an angle `theta` degrees from
`(xcenter,ycenter)` on a rectangle defined by (`xmin`,
`xmax`, `ymin`, `ymax`).
"""
function legend_pos_from_angle(theta, xmin, xcenter, xmax, ymin, ycenter, ymax)
(s,c) = sincosd(theta)
x = c < 0 ? (xmin-xcenter)/c : (xmax-xcenter)/c
y = s < 0 ? (ymin-ycenter)/s : (ymax-ycenter)/s
A = min(x,y)
return (xcenter + A*c, ycenter + A*s)
end
"""
Split continuous range `[-1,1]` evenly into an integer `[1,2,3]`
"""
function legend_anchor_index(x)
x<-1//3 && return 1
x<1//3 && return 2
return 3
end
"""
Turn legend argument into a (theta, :inner) or (theta, :outer) tuple.
For backends where legend position is given in normal coordinates (0,0) -- (1,1),
so :topleft exactly corresponds to (45, :inner) etc.
If `leg` is a (::Real,::Real) tuple, keep it as is.
"""
legend_angle(leg::Real) = (leg,:inner)
legend_angle(leg::Tuple{S,T}) where {S<:Real,T<:Real} = leg
legend_angle(leg::Tuple{S,Symbol}) where S<:Real = leg
legend_angle(leg::Symbol) = get(
(
topleft = (135,:inner),
top = (90, :inner),
topright = (45, :inner),
left = (180,:inner),
right = (0, :inner),
bottomleft = (225,:inner),
bottom = (270,:inner),
bottomright = (315,:inner),
outertopleft = (135,:outer),
outertop = (90, :outer),
outertopright = (45, :outer),
outerleft = (180,:outer),
outerright = (0, :outer),
outerbottomleft = (225,:outer),
outerbottom = (270,:outer),
outerbottomright = (315,:outer),
),
leg,
(45, :inner)
)

View File

@ -112,7 +112,7 @@ function savefig(plt::Plot, fn::AbstractString)
fn = abspath(expanduser(fn)) fn = abspath(expanduser(fn))
# get the extension # get the extension
fn, ext = splitext(fn) _, ext = splitext(fn)
ext = chop(ext, head = 1, tail = 0) ext = chop(ext, head = 1, tail = 0)
if isempty(ext) if isempty(ext)
ext = defaultOutputFormat(plt) ext = defaultOutputFormat(plt)
@ -194,9 +194,9 @@ function _display(plt::Plot)
@warn("_display is not defined for this backend.") @warn("_display is not defined for this backend.")
end end
Base.show(io::IO, m::MIME"text/plain", plt::Plot) = show(io, plt)
# for writing to io streams... first prepare, then callback # for writing to io streams... first prepare, then callback
for mime in ( for mime in (
"text/plain",
"text/html", "text/html",
"image/png", "image/png",
"image/eps", "image/eps",
@ -221,9 +221,6 @@ end
Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) = Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) =
showjuno(io, MIME("text/html"), plt) showjuno(io, MIME("text/html"), plt)
# default text/plain for all backends
_show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
"Close all open gui windows of the current backend" "Close all open gui windows of the current backend"
closeall() = closeall(backend()) closeall() = closeall(backend())
@ -249,25 +246,17 @@ closeall() = closeall(backend())
# Atom PlotPane # Atom PlotPane
# --------------------------------------------------------- # ---------------------------------------------------------
function showjuno(io::IO, m, plt) function showjuno(io::IO, m, plt)
sz = collect(plt[:size])
dpi = plt[:dpi] dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
jsize = get(io, :juno_plotsize, [400, 500])
jratio = get(io, :juno_dpi_ratio, 1) 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] = jratio * Plots.DPI plt[:dpi] = jratio * Plots.DPI
plt[:thickness_scaling] *= scale
prepare_output(plt) prepare_output(plt)
try try
_showjuno(io, m, plt) _showjuno(io, m, plt)
finally finally
plt[:size] = sz
plt[:dpi] = dpi plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end end
end end

View File

@ -4,43 +4,31 @@
function RecipesPipeline.warn_on_recipe_aliases!( function RecipesPipeline.warn_on_recipe_aliases!(
plt::Plot, plt::Plot,
plotattributes, plotattributes::AKW,
recipe_type, recipe_type::Symbol,
args..., @nospecialize(args)
) )
for k in keys(plotattributes) for k in keys(plotattributes)
if !is_default_attribute(k) if !is_default_attribute(k)
dk = get(_keyAliases, k, k) dk = get(_keyAliases, k, k)
if k !== dk if k !== dk
@warn "Attribute alias `$k` detected in the $recipe_type recipe defined for the signature $(_signature_string(Val{recipe_type}, args...)). To ensure expected behavior it is recommended to use the default attribute `$dk`." if recipe_type == :user
signature_string = RecipesPipeline.userrecipe_signature_string(args)
elseif recipe_type == :type
signature_string = RecipesPipeline.typerecipe_signature_string(args)
elseif recipe_type == :plot
signature_string = RecipesPipeline.plotrecipe_signature_string(args)
elseif recipe_type == :series
signature_string = RecipesPipeline.seriesrecipe_signature_string(args)
else
throw(ArgumentError("Invalid recipe type `$recipe_type`"))
end
@warn "Attribute alias `$k` detected in the $recipe_type recipe defined for the signature $signature_string. To ensure expected behavior it is recommended to use the default attribute `$dk`."
end end
plotattributes[dk] = RecipesPipeline.pop_kw!(plotattributes, k) plotattributes[dk] = RecipesPipeline.pop_kw!(plotattributes, k)
end end
end end
end end
function RecipesPipeline.warn_on_recipe_aliases!(
plt::Plot,
v::AbstractVector,
recipe_type,
args...,
)
foreach(x -> RecipesPipeline.warn_on_recipe_aliases!(plt, x, recipe_type, args...), v)
end
function RecipesPipeline.warn_on_recipe_aliases!(
plt::Plot,
rd::RecipeData,
recipe_type,
args...,
)
RecipesPipeline.warn_on_recipe_aliases!(plt, rd.plotattributes, recipe_type, args...)
end
function _signature_string(::Type{Val{:user}}, args...)
return string("(::", join(string.(typeof.(args)), ", ::"), ")")
end
_signature_string(::Type{Val{:type}}, T) = "(::Type{$T}, ::$T)"
_signature_string(::Type{Val{:plot}}, st) = "(::Type{Val{:$st}}, ::AbstractPlot)"
_signature_string(::Type{Val{:series}}, st) = "(::Type{Val{:$st}}, x, y, z)"
## Grouping ## Grouping
@ -49,12 +37,23 @@ RecipesPipeline.splittable_attribute(plt::Plot, key, val::SeriesAnnotations, len
RecipesPipeline.splittable_attribute(plt, key, val.strs, len) RecipesPipeline.splittable_attribute(plt, key, val.strs, len)
function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations, indices) function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations, indices)
split_strs = _RecipesPipeline.split_attribute(key, val.strs, indices) split_strs = RecipesPipeline.split_attribute(plt, key, val.strs, indices)
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor) return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
end end
## Preprocessing attributes ## Preprocessing attributes
function RecipesPipeline.preprocess_axis_args!(plt::Plot, plotattributes, letter)
# Fix letter for seriestypes that are x only but data gets passed as y
if treats_y_as_x(get(plotattributes, :seriestype, :path))
if get(plotattributes, :orientation, :vertical) == :vertical
letter = :x
end
end
plotattributes[:letter] = letter
RecipesPipeline.preprocess_axis_args!(plt, plotattributes)
end
RecipesPipeline.preprocess_attributes!(plt::Plot, plotattributes) = RecipesPipeline.preprocess_attributes!(plt::Plot, plotattributes) =
RecipesPipeline.preprocess_attributes!(plotattributes) # in src/args.jl RecipesPipeline.preprocess_attributes!(plotattributes) # in src/args.jl
@ -142,7 +141,7 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW)
end end
RecipesPipeline.get_axis_limits(plt::Plot, f, letter) = axis_limits(plt[1], letter) RecipesPipeline.get_axis_limits(plt::Plot, letter) = axis_limits(plt[1], letter)
## Plot recipes ## Plot recipes
@ -155,8 +154,23 @@ RecipesPipeline.type_alias(plt::Plot) = get(_typeAliases, st, st)
function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list) function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list)
_plot_setup(plt, plotattributes, kw_list) _plot_setup(plt, plotattributes, kw_list)
_subplot_setup(plt, plotattributes, kw_list) _subplot_setup(plt, plotattributes, kw_list)
return nothing
end end
function RecipesPipeline.process_sliced_series_attributes!(plt::Plots.Plot, kw_list)
# swap errors
err_inds = findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list)
for ind in err_inds
if get(kw_list[ind-1],:seriestype,:path) == :scatter
tmp = copy(kw_list[ind])
kw_list[ind] = copy(kw_list[ind-1])
kw_list[ind-1] = tmp
end
end
return nothing
end
# TODO: Should some of this logic be moved to RecipesPipeline? # TODO: Should some of this logic be moved to RecipesPipeline?
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# merge in anything meant for the Plot # merge in anything meant for the Plot
@ -292,6 +306,7 @@ function RecipesPipeline.slice_series_attributes!(plt::Plot, kw_list, kw)
# in series attributes given as vector with one element per series, # in series attributes given as vector with one element per series,
# select the value for current series # select the value for current series
_slice_series_args!(kw, plt, sp, series_idx(kw_list, kw)) _slice_series_args!(kw, plt, sp, series_idx(kw_list, kw))
return nothing
end end
RecipesPipeline.series_defaults(plt::Plot) = _series_defaults # in args.jl RecipesPipeline.series_defaults(plt::Plot) = _series_defaults # in args.jl
@ -316,7 +331,7 @@ function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T}
st = _override_seriestype_check(plotattributes, st) st = _override_seriestype_check(plotattributes, st)
# change to a 3d projection for this subplot? # change to a 3d projection for this subplot?
if RecipesPipeline.needs_3d_axes(st) if RecipesPipeline.needs_3d_axes(st) || (st == :quiver && plotattributes[:z] !== nothing)
sp.attr[:projection] = "3d" sp.attr[:projection] = "3d"
end end
@ -330,9 +345,9 @@ end
function _override_seriestype_check(plotattributes::AKW, st::Symbol) function _override_seriestype_check(plotattributes::AKW, st::Symbol)
# do we want to override the series type? # do we want to override the series type?
if !RecipesPipeline.is3d(st) && !(st in (:contour, :contour3d)) if !RecipesPipeline.is3d(st) && !(st in (:contour, :contour3d, :quiver))
z = plotattributes[:z] z = plotattributes[:z]
if !isa(z, Nothing) && if z !== nothing &&
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z)) (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d) st = (st == :scatter ? :scatter3d : :path3d)
plotattributes[:seriestype] = st plotattributes[:seriestype] = st
@ -341,6 +356,14 @@ function _override_seriestype_check(plotattributes::AKW, st::Symbol)
st st
end end
function needs_any_3d_axes(sp::Subplot)
any(
RecipesPipeline.needs_3d_axes(
_override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype])
) for s in series_list(sp)
)
end
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol) function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
# adjust extrema and discrete info # adjust extrema and discrete info
if st == :image if st == :image

View File

@ -23,7 +23,38 @@ current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}" Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
Base.print(io::IO, plt::Plot) = print(io, string(plt)) Base.print(io::IO, plt::Plot) = print(io, string(plt))
Base.show(io::IO, plt::Plot) = print(io, string(plt)) function Base.show(io::IO, plt::Plot)
print(io, string(plt))
sp_ekwargs = getindex.(plt.subplots, :extra_kwargs)
s_ekwargs = getindex.(plt.series_list, :extra_kwargs)
if isempty(plt[:extra_plot_kwargs]) && all(isempty, sp_ekwargs) && all(isempty, s_ekwargs)
return
end
print(io,"\nCaptured extra kwargs:\n")
do_show = true
for (key, value) in plt[:extra_plot_kwargs]
do_show && println(io, " Plot:")
println(io, " "^4, key, ": ", value)
do_show = false
end
do_show = true
for (i, ekwargs) in enumerate(sp_ekwargs)
for (key, value) in ekwargs
do_show && println(io, " SubplotPlot{$i}:")
println(io, " "^4, key, ": ", value)
do_show = false
end
do_show = true
end
for (i, ekwargs) in enumerate(s_ekwargs)
for (key, value) in ekwargs
do_show && println(io, " Series{$i}:")
println(io, " "^4, key, ": ", value)
do_show = false
end
do_show = true
end
end
getplot(plt::Plot) = plt getplot(plt::Plot) = plt
getattr(plt::Plot, idx::Int = 1) = plt.attr getattr(plt::Plot, idx::Int = 1) = plt.attr
@ -43,10 +74,11 @@ The main plot command. Use `plot` to create a new plot object, and `plot!` to ad
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected. There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])` When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])`
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr` function, where `attr` is the symbol `:Series`, `:Subplot`, `:Plot`, or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring; e.g. `plotattr("seriestype")`. as a String to look up its docstring, e.g., `plotattr("seriestype")`.
""" """
function plot(args...; kw...) function plot(args...; kw...)
@nospecialize
# this creates a new plot with args/kw and sets it to be the current plot # this creates a new plot with args/kw and sets it to be the current plot
plotattributes = KW(kw) plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes) RecipesPipeline.preprocess_attributes!(plotattributes)
@ -59,7 +91,9 @@ end
# build a new plot from existing plots # build a new plot from existing plots
# note: we split into plt1 and plts_tail so we can dispatch correctly # note: we split into plt1 and plts_tail so we can dispatch correctly
function plot(plt1::Plot, plts_tail::Plot...; kw...) plot(plt1::Plot, plts_tail::Plot...; kw...) = plot!(deepcopy(plt1), deepcopy.(plts_tail)...; kw...)
function plot!(plt1::Plot, plts_tail::Plot...; kw...)
@nospecialize
plotattributes = KW(kw) plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes) RecipesPipeline.preprocess_attributes!(plotattributes)
@ -141,6 +175,7 @@ end
# this adds to the current plot, or creates a new plot if none are current # this adds to the current plot, or creates a new plot if none are current
function plot!(args...; kw...) function plot!(args...; kw...)
@nospecialize
local plt local plt
try try
plt = current() plt = current()
@ -152,6 +187,7 @@ end
# this adds to a specific plot... most plot commands will flow through here # this adds to a specific plot... most plot commands will flow through here
function plot!(plt::Plot, args...; kw...) function plot!(plt::Plot, args...; kw...)
@nospecialize
plotattributes = KW(kw) plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes) RecipesPipeline.preprocess_attributes!(plotattributes)
# merge!(plt.user_attr, plotattributes) # merge!(plt.user_attr, plotattributes)
@ -164,6 +200,7 @@ end
# a list of series KW dicts. # a list of series KW dicts.
# note: at entry, we only have those preprocessed args which were passed in... no default values yet # note: at entry, we only have those preprocessed args which were passed in... no default values yet
function _plot!(plt::Plot, plotattributes, args) function _plot!(plt::Plot, plotattributes, args)
@nospecialize
RecipesPipeline.recipe_pipeline!(plt, plotattributes, args) RecipesPipeline.recipe_pipeline!(plt, plotattributes, args)
current(plt) current(plt)
_do_plot_show(plt, plt[:show]) _do_plot_show(plt, plt[:show])
@ -205,10 +242,12 @@ end
# plot to a Subplot # plot to a Subplot
function plot(sp::Subplot, args...; kw...) function plot(sp::Subplot, args...; kw...)
@nospecialize
plt = sp.plt plt = sp.plt
plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots)) plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end end
function plot!(sp::Subplot, args...; kw...) function plot!(sp::Subplot, args...; kw...)
@nospecialize
plt = sp.plt plt = sp.plt
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots)) plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end end

View File

@ -1,740 +0,0 @@
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("#_make_hist##kw")) && precompile(Tuple{getfield(Plots, Symbol("#_make_hist##kw")), NamedTuple{(:normed, :weights), Tuple{Bool, Array{Int64, 1}}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}}, Symbol})
isdefined(Plots, Symbol("#_make_hist##kw")) && precompile(Tuple{getfield(Plots, Symbol("#_make_hist##kw")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64})
isdefined(Plots, Symbol("#_make_hist##kw")) && precompile(Tuple{getfield(Plots, Symbol("#_make_hist##kw")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}, Array{Float64, 1}}, Tuple{Int64, Int64}})
isdefined(Plots, Symbol("#_make_hist##kw")) && precompile(Tuple{getfield(Plots, Symbol("#_make_hist##kw")), NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}}, typeof(Plots._make_hist), Tuple{Array{Float64, 1}}, Symbol})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:formatter,), Tuple{Symbol}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:formatter,), Tuple{typeof(RecipesPipeline.datetimeformatter)}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:grid, :lims), Tuple{Bool, Tuple{Int64, Int64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:grid, :lims, :flip), Tuple{Bool, Tuple{Int64, Int64}, Bool}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:grid,), Tuple{Bool}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:gridlinewidth, :grid, :gridalpha, :gridstyle, :foreground_color_grid), Tuple{Int64, Bool, Float64, Symbol, ColorTypes.RGBA{Float64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:guide,), Tuple{String}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:lims, :flip, :ticks, :guide), Tuple{Tuple{Int64, Int64}, Bool, Base.StepRange{Int64, Int64}, String}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:lims,), Tuple{Tuple{Float64, Float64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:lims,), Tuple{Tuple{Int64, Float64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:rotation,), Tuple{Int64}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:scale, :guide), Tuple{Symbol, String}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:ticks,), Tuple{Base.UnitRange{Int64}}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#attr!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#attr!##kw")), NamedTuple{(:ticks,), Tuple{Nothing}}, typeof(Plots.attr!), Plots.Axis})
isdefined(Plots, Symbol("#contour##kw")) && precompile(Tuple{getfield(Plots, Symbol("#contour##kw")), NamedTuple{(:fill,), Tuple{Bool}}, typeof(Plots.contour), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Int})
isdefined(Plots, Symbol("#default##kw")) && precompile(Tuple{getfield(Plots, Symbol("#default##kw")), NamedTuple{(:titlefont, :legendfontsize, :guidefont, :tickfont, :guide, :framestyle, :yminorgrid), Tuple{Tuple{Int64, String}, Int64, Tuple{Int64, Symbol}, Tuple{Int64, Symbol}, String, Symbol, Bool}}, typeof(Plots.default)})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Array{Float64, 1}, Array{Float64, 1}})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Array{Int64, 1}, Array{Float64, 1}})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Base.StepRange{Int64, Int64}, Array{Float64, 1}})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Base.UnitRange{Int64}, Array{Float64, 1}})
isdefined(Plots, Symbol("#gr_polyline##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_polyline##kw")), NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}}, typeof(Plots.gr_polyline), Base.UnitRange{Int64}, Base.UnitRange{Int64}})
isdefined(Plots, Symbol("#gr_set_font##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_set_font##kw")), NamedTuple{(:halign, :valign, :rotation), Tuple{Symbol, Symbol, Int64}}, typeof(Plots.gr_set_font), Plots.Font})
isdefined(Plots, Symbol("#gr_set_font##kw")) && precompile(Tuple{getfield(Plots, Symbol("#gr_set_font##kw")), NamedTuple{(:halign, :valign, :rotation, :color), Tuple{Symbol, Symbol, Int64, ColorTypes.RGBA{Float64}}}, typeof(Plots.gr_set_font), Plots.Font})
isdefined(Plots, Symbol("#heatmap##kw")) && precompile(Tuple{getfield(Plots, Symbol("#heatmap##kw")), NamedTuple{(:aspect_ratio,), Tuple{Int64}}, typeof(Plots.heatmap), Array{String, 1}, Int})
isdefined(Plots, Symbol("#histogram##kw")) && precompile(Tuple{getfield(Plots, Symbol("#histogram##kw")), NamedTuple{(:bins, :weights), Tuple{Symbol, Array{Int64, 1}}}, typeof(Plots.histogram), Array{Float64, 1}})
isdefined(Plots, Symbol("#histogram2d##kw")) && precompile(Tuple{getfield(Plots, Symbol("#histogram2d##kw")), 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("#histogram2d##kw")) && precompile(Tuple{getfield(Plots, Symbol("#histogram2d##kw")), NamedTuple{(:nbins,), Tuple{Int64}}, typeof(Plots.histogram2d), Array{Float64, 1}, Array{Float64, 1}})
isdefined(Plots, Symbol("#hline!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#hline!##kw")), NamedTuple{(:line,), Tuple{Tuple{Int64, Symbol, Float64, Array{Symbol, 2}}}}, typeof(Plots.hline!), Array{Float64, 2}})
isdefined(Plots, Symbol("#lens!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#lens!##kw")), NamedTuple{(:inset,), Tuple{Tuple{Int64, Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}}}}, typeof(Plots.lens!), Array{Int64, 1}, Int})
isdefined(Plots, Symbol("#pie##kw")) && precompile(Tuple{getfield(Plots, Symbol("#pie##kw")), NamedTuple{(:title, :l), Tuple{String, Float64}}, typeof(Plots.pie), Array{String, 1}, Int})
isdefined(Plots, Symbol("#plotly_annotation_dict##kw")) && precompile(Tuple{getfield(Plots, Symbol("#plotly_annotation_dict##kw")), NamedTuple{(:xref, :yref), Tuple{String, String}}, typeof(Plots.plotly_annotation_dict), Float64, Float64, Plots.PlotText})
isdefined(Plots, Symbol("#plotly_annotation_dict##kw")) && precompile(Tuple{getfield(Plots, Symbol("#plotly_annotation_dict##kw")), NamedTuple{(:xref, :yref), Tuple{String, String}}, typeof(Plots.plotly_annotation_dict), Float64, Float64, String})
isdefined(Plots, Symbol("#plotly_annotation_dict##kw")) && precompile(Tuple{getfield(Plots, Symbol("#plotly_annotation_dict##kw")), NamedTuple{(:xref, :yref), Tuple{String, String}}, typeof(Plots.plotly_annotation_dict), Int64, Float64, Plots.PlotText})
isdefined(Plots, Symbol("#plotly_annotation_dict##kw")) && precompile(Tuple{getfield(Plots, Symbol("#plotly_annotation_dict##kw")), NamedTuple{(:xref, :yref), Tuple{String, String}}, typeof(Plots.plotly_annotation_dict), Int64, Float64, String})
isdefined(Plots, Symbol("#portfoliocomposition##kw")) && precompile(Tuple{getfield(Plots, Symbol("#portfoliocomposition##kw")), NamedTuple{(:labels,), Tuple{Array{String, 2}}}, typeof(Plots.portfoliocomposition), Array{Float64, 2}, Int})
isdefined(Plots, Symbol("#scatter!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter!##kw")), 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("#scatter!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter!##kw")), NamedTuple{(:markersize, :c), Tuple{Int64, Symbol}}, typeof(Plots.scatter!), Array{Float64, 1}})
isdefined(Plots, Symbol("#scatter!##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter!##kw")), 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("#scatter##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter##kw")), 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("#scatter##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter##kw")), 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("#scatter##kw")) && precompile(Tuple{getfield(Plots, Symbol("#scatter##kw")), NamedTuple{(:marker_z, :color, :legend), Tuple{typeof(Base.:+), Symbol, Bool}}, typeof(Plots.scatter), Array{Float64, 1}, Array{Float64, 1}})
isdefined(Plots, Symbol("#standalone_html##kw")) && precompile(Tuple{getfield(Plots, Symbol("#standalone_html##kw")), NamedTuple{(:title,), Tuple{String}}, typeof(Plots.standalone_html), Plots.Plot{Plots.PlotlyBackend}})
isdefined(Plots, Symbol("#test_examples##kw")) && precompile(Tuple{getfield(Plots, Symbol("#test_examples##kw")), NamedTuple{(:skip,), Tuple{Array{Int64, 1}}}, typeof(Plots.test_examples), Symbol})
precompile(Tuple{typeof(Plots.__init__)})
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_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}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._add_the_series), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._as_gradient), PlotUtils.ContinuousColorGradient})
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.ContinuousColorGradient, 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._create_backend_figure), Plots.Plot{Plots.PlotlyBackend}})
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}, Array{Int64, 1}})
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, Array{Int64, 1}})
precompile(Tuple{typeof(Plots._cycle), Nothing, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Plots._cycle), Nothing, Int64})
precompile(Tuple{typeof(Plots._cycle), PlotUtils.ColorPalette, Int64})
precompile(Tuple{typeof(Plots._cycle), PlotUtils.ContinuousColorGradient, Int64})
precompile(Tuple{typeof(Plots._cycle), Plots.Shape, Int64})
precompile(Tuple{typeof(Plots._cycle), Plots.Subplot{Plots.GRBackend}, Int64})
precompile(Tuple{typeof(Plots._cycle), Plots.Subplot{Plots.PlotlyBackend}, Int64})
precompile(Tuple{typeof(Plots._cycle), Symbol, Int64})
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}, Symbol})
precompile(Tuple{typeof(Plots._do_plot_show), Plots.Plot{Plots.PlotlyBackend}, Bool})
precompile(Tuple{typeof(Plots._expand_subplot_extrema), Plots.Subplot{Plots.GRBackend}, RecipesPipeline.DefaultsDict, Symbol})
precompile(Tuple{typeof(Plots._expand_subplot_extrema), Plots.Subplot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict, Symbol})
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._initialize_backend), Plots.PlotlyBackend})
precompile(Tuple{typeof(Plots._override_seriestype_check), RecipesPipeline.DefaultsDict, Symbol})
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{Dates.DateTime, 1}, Base.UnitRange{Int64}, Array{Float64, 2}}})
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}}})
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}, Float64, Float64}})
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}, Array{Float64, 1}}})
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{Tuple{Int64, Real}, 1}}})
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, 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.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{Float64, 1}, 1}, Array{Array{Float64, 1}, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}, Array{Float64, 2}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Array{T, 1} where T, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Base.Complex{Float64}, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Dates.DateTime, 1}, Base.UnitRange{Int64}, Array{Float64, 2}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}, Array{Float64, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Float64, 2}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Function, 1}, Float64, Float64}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}, Array{Float64, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Int64, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Plots.OHLC{T} where T<:Real, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{Float64, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{String, 1}, Array{String, 1}, Array{Float64, 2}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Tuple{Int64, Real}, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Array{Union{Base.Missing, Int64}, 1}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, 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.PlotlyBackend}, 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.PlotlyBackend}, 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.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Base.StepRange{Int64, Int64}, Array{Float64, 2}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Base.UnitRange{Int64}}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.PortfolioComposition}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Tuple{Plots.Spy}})
precompile(Tuple{typeof(Plots._plot!), Plots.Plot{Plots.PlotlyBackend}, 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.PlotlyBackend}, Base.Dict{Symbol, Any}, Array{Base.Dict{Symbol, Any}, 1}})
precompile(Tuple{typeof(Plots._plotly_framestyle), Symbol})
precompile(Tuple{typeof(Plots._plots_defaults)})
precompile(Tuple{typeof(Plots._prepare_subplot), Plots.Plot{Plots.GRBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._prepare_subplot), Plots.Plot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._preprocess_barlike), RecipesPipeline.DefaultsDict, Array{Float64, 1}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots._preprocess_barlike), RecipesPipeline.DefaultsDict, Array{Int64, 1}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots._preprocess_barlike), RecipesPipeline.DefaultsDict, Base.OneTo{Int64}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots._preprocess_binlike), RecipesPipeline.DefaultsDict, 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._replace_linewidth), RecipesPipeline.DefaultsDict})
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), RecipesPipeline.DefaultsDict, Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots._series_index), RecipesPipeline.DefaultsDict, Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots._show), Base.IOStream, Base.Multimedia.MIME{Symbol("image/png")}, Plots.Plot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots._slice_series_args!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Int64})
precompile(Tuple{typeof(Plots._slice_series_args!), Base.Dict{Symbol, Any}, Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, Int64})
precompile(Tuple{typeof(Plots._slice_series_args!), RecipesPipeline.DefaultsDict, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}, Int64})
precompile(Tuple{typeof(Plots._slice_series_args!), RecipesPipeline.DefaultsDict, Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, Int64})
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.PlotlyBackend}, 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, RecipesPipeline.DefaultsDict, 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}, RecipesPipeline.DefaultsDict, Symbol, Int64})
precompile(Tuple{typeof(Plots._update_axis), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Symbol, Int64})
precompile(Tuple{typeof(Plots._update_axis), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict, Symbol, Int64})
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.PlotlyBackend}, 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.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots._update_min_padding!), Plots.Subplot{Plots.PlotlyBackend}})
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}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._update_plot_args), Plots.Plot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots._update_plot_args), Plots.Plot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots._update_series_attributes!), RecipesPipeline.DefaultsDict, Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots._update_series_attributes!), RecipesPipeline.DefaultsDict, Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}})
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}, RecipesPipeline.DefaultsDict, Int64, Bool})
precompile(Tuple{typeof(Plots._update_subplot_args), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, Base.Dict{Symbol, Any}, Int64, Bool})
precompile(Tuple{typeof(Plots._update_subplot_args), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict, Int64, Bool})
precompile(Tuple{typeof(Plots._update_subplot_colors), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots._update_subplot_colors), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots._update_subplot_periphery), Plots.Subplot{Plots.GRBackend}, Array{Any, 1}})
precompile(Tuple{typeof(Plots._update_subplot_periphery), Plots.Subplot{Plots.PlotlyBackend}, 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.aliasesAndAutopick), RecipesPipeline.DefaultsDict, Symbol, Base.Dict{Symbol, Symbol}, Array{Symbol, 1}, Int64})
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.arrow), Int64})
precompile(Tuple{typeof(Plots.attr), Plots.EmptyLayout, Symbol, Symbol})
precompile(Tuple{typeof(Plots.attr), Plots.EmptyLayout, Symbol})
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_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})
precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.PlotlyBackend}, Symbol, Bool, Bool})
precompile(Tuple{typeof(Plots.axis_limits), Plots.Subplot{Plots.PlotlyBackend}, Symbol})
precompile(Tuple{typeof(Plots.backend), Plots.GRBackend})
precompile(Tuple{typeof(Plots.backend), Plots.PlotlyBackend})
precompile(Tuple{typeof(Plots.backend), Symbol})
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.bbox!), Plots.Subplot{Plots.PlotlyBackend}, 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), Float64, Float64, Float64, Float64})
precompile(Tuple{typeof(Plots.bbox), Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}})
precompile(Tuple{typeof(Plots.bbox_to_pcts), 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}, Bool})
precompile(Tuple{typeof(Plots.bbox_to_pcts), 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}})
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.bottom), Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}})
precompile(Tuple{typeof(Plots.bottompad), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.bottompad), Plots.Subplot{Plots.PlotlyBackend}})
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), RecipesPipeline.DefaultsDict})
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!), RecipesPipeline.DefaultsDict, Symbol})
precompile(Tuple{typeof(Plots.colorbar_style), Plots.Series})
precompile(Tuple{typeof(Plots.compute_gridsize), Int64, Int64, Int64})
precompile(Tuple{typeof(Plots.concatenate_fillrange), Base.UnitRange{Int64}, Tuple{Array{Float64, 1}, Array{Float64, 1}}})
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.convert_sci_unicode), String})
precompile(Tuple{typeof(Plots.convert_to_polar), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}, Tuple{Int64, Float64}})
precompile(Tuple{typeof(Plots.copy_series!), Plots.Series, Symbol})
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_vcat), Expr})
precompile(Tuple{typeof(Plots.default), Symbol, Bool})
precompile(Tuple{typeof(Plots.default), Symbol, Int64})
precompile(Tuple{typeof(Plots.default), Symbol, String})
precompile(Tuple{typeof(Plots.default), Symbol, Symbol})
precompile(Tuple{typeof(Plots.default), Symbol})
precompile(Tuple{typeof(Plots.default_should_widen), Plots.Axis})
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!), RecipesPipeline.DefaultsDict, Symbol, Symbol})
precompile(Tuple{typeof(Plots.error_coords), Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.error_coords), Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.error_style!), RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.error_zipit), 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, 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.StepRange{Int64, Int64}})
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, Int64})
precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, RecipesPipeline.Surface{Array{Float64, 2}}})
precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Axis, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Subplot{Plots.GRBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.expand_extrema!), Plots.Subplot{Plots.PlotlyBackend}, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.extend_by_data!), Array{Float64, 1}, Float64})
precompile(Tuple{typeof(Plots.extend_series_data!), Plots.Series, Float64, Symbol})
precompile(Tuple{typeof(Plots.fakedata), Int64, Int64})
precompile(Tuple{typeof(Plots.fg_color), RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.font), Int64, 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_aspect_ratio), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.get_aspect_ratio), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.get_axis), Plots.Subplot{Plots.GRBackend}, Symbol})
precompile(Tuple{typeof(Plots.get_axis), Plots.Subplot{Plots.PlotlyBackend}, Symbol})
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}})
precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.PlotlyBackend}, Plots.Series})
precompile(Tuple{typeof(Plots.get_clims), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.get_colorgradient), Plots.Series})
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_gradient), PlotUtils.ContinuousColorGradient})
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, 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_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{Int64, 1}, Array{String, 1}}})
precompile(Tuple{typeof(Plots.get_plotly_marker), Symbol, String})
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.PlotlyBackend}, Int64, Symbol})
precompile(Tuple{typeof(Plots.get_series_color), Int64, Plots.Subplot{Plots.GRBackend}, Int64, Symbol})
precompile(Tuple{typeof(Plots.get_series_color), Int64, Plots.Subplot{Plots.PlotlyBackend}, Int64, Symbol})
precompile(Tuple{typeof(Plots.get_series_color), PlotUtils.ContinuousColorGradient, Plots.Subplot{Plots.GRBackend}, Int64, Symbol})
precompile(Tuple{typeof(Plots.get_series_color), PlotUtils.ContinuousColorGradient, Plots.Subplot{Plots.PlotlyBackend}, 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.PlotlyBackend}, Int64, Symbol})
precompile(Tuple{typeof(Plots.get_subplot), Plots.Plot{Plots.GRBackend}, Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.get_subplot), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.get_ticks), Plots.Subplot{Plots.GRBackend}, Plots.Axis})
precompile(Tuple{typeof(Plots.get_ticks), Plots.Subplot{Plots.PlotlyBackend}, 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.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.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), Plots.Series, Float64, Float64, Tuple{Float64, Float64}, Int64, Float64, Float64, Plots.Shape})
precompile(Tuple{typeof(Plots.gr_draw_marker), Plots.Series, Float64, Float64, Tuple{Float64, Float64}, Int64, Float64, Float64, Symbol})
precompile(Tuple{typeof(Plots.gr_draw_marker), Plots.Series, Int64, Float64, Tuple{Float64, Float64}, Int64, Float64, Float64, Plots.Shape})
precompile(Tuple{typeof(Plots.gr_draw_marker), Plots.Series, Int64, Float64, Tuple{Float64, Float64}, Int64, Float64, Float64, Symbol})
precompile(Tuple{typeof(Plots.gr_draw_marker), Plots.Series, Int64, Int64, Tuple{Float64, Float64}, Int64, Float64, Float64, Plots.Shape})
precompile(Tuple{typeof(Plots.gr_draw_marker), Plots.Series, Int64, Int64, Tuple{Float64, Float64}, Int64, Float64, Float64, Symbol})
precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64, 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{Int64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64, 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, 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}, Int64})
precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Base.OneTo{Int64}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64, 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, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}, Tuple{Float64, Float64}, Int64, Int64})
precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.gr_draw_markers), Plots.Series, Float64, Float64, Tuple{Float64, Float64}, Float64, Float64})
precompile(Tuple{typeof(Plots.gr_fill_viewport), Array{Float64, 1}, ColorTypes.RGBA{Float64}})
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{Int64, 1}, Array{String, 1}}, Int64})
precompile(Tuple{typeof(Plots.gr_getcolorind), ColorTypes.RGBA{Float64}})
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_linetype), Symbol})
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_bordercolor), ColorTypes.RGBA{Float64}})
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_gradient), PlotUtils.ContinuousColorGradient})
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.ContinuousColorGradient})
precompile(Tuple{typeof(Plots.gr_set_linecolor), PlotUtils.ContinuousColorGradient})
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}, Int64})
precompile(Tuple{typeof(Plots.gr_set_transparency), ColorTypes.RGBA{Float64}, Nothing})
precompile(Tuple{typeof(Plots.gr_set_transparency), Float64})
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_yticks_font), Plots.Subplot{Plots.GRBackend}})
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})
precompile(Tuple{typeof(Plots.gr_tick_label), Plots.Axis, String})
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_w3tondc), Float64, Float64, Float64})
precompile(Tuple{typeof(Plots.gui), Plots.Plot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.gui), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.guide_padding), 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}, 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.has_attribute_segments), Plots.Series})
precompile(Tuple{typeof(Plots.has_black_border_for_default), Symbol})
precompile(Tuple{typeof(Plots.hascolorbar), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.hascolorbar), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.hasgrid), Symbol, Symbol})
precompile(Tuple{typeof(Plots.heatmap), Array{Dates.DateTime, 1}, Int})
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, Base.UnitRange{Int64}, 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})
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})
precompile(Tuple{typeof(Plots.heatmap_edges), Base.UnitRange{Int64}, Symbol, Bool})
precompile(Tuple{typeof(Plots.heatmap_edges), Base.UnitRange{Int64}, 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_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.inline), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.intersection_point), Float64, Float64, Float64, Float64, Float64, Float64})
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{Float64, Float64}})
precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Int64, Float64}})
precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Int64, Int64}})
precompile(Tuple{typeof(Plots.is_2tuple), Tuple{Int64, Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}}})
precompile(Tuple{typeof(Plots.is_axis_attr), Symbol})
precompile(Tuple{typeof(Plots.is_default_attribute), Symbol})
precompile(Tuple{typeof(Plots.is_marker_supported), Plots.GRBackend, Symbol})
precompile(Tuple{typeof(Plots.is_marker_supported), Plots.PlotlyBackend, 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_seriestype_supported), Plots.GRBackend, Symbol})
precompile(Tuple{typeof(Plots.is_seriestype_supported), Plots.PlotlyBackend, Symbol})
precompile(Tuple{typeof(Plots.is_seriestype_supported), Symbol})
precompile(Tuple{typeof(Plots.is_uniformly_spaced), Array{Float64, 1}})
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.ispolar), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.isvertical), Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots.isvertical), RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.iter_segments), Array{Float64, 1}, Array{Float64, 1}, Int})
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.OneTo{Int64}, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Plots.iter_segments), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.iter_segments), Base.StepRange{Int64, 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.labelfunc), Symbol, Plots.GRBackend})
precompile(Tuple{typeof(Plots.labelfunc), Symbol, Plots.PlotlyBackend})
precompile(Tuple{typeof(Plots.layout_args), Base.Dict{Symbol, Any}, Int64})
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.layout_args), RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.left), Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}})
precompile(Tuple{typeof(Plots.left), Measures.BoundingBox{Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}, Tuple{Measures.Length{:w, Float64}, Measures.Length{:h, Float64}}}})
precompile(Tuple{typeof(Plots.leftpad), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.leftpad), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.legendfont), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.legendfont), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.legendtitlefont), Plots.Subplot{Plots.GRBackend}})
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})
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_axes!), Plots.Subplot{Plots.PlotlyBackend}, 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.locate_annotation), Plots.Subplot{Plots.PlotlyBackend}, Int64, Float64, Plots.PlotText})
precompile(Tuple{typeof(Plots.make_fillrange_from_ribbon), Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots.make_fillrange_side), Base.UnitRange{Int64}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.make_fillrange_side), Base.UnitRange{Int64}, Base.LinRange{Float64}})
precompile(Tuple{typeof(Plots.make_fillrange_side), Base.UnitRange{Int64}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
precompile(Tuple{typeof(Plots.make_fillrange_side), Base.UnitRange{Int64}, 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.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.PlotlyBackend}, Plots.Axis, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Plots.optimal_ticks_and_labels), Plots.Subplot{Plots.PlotlyBackend}, Plots.Axis, Nothing})
precompile(Tuple{typeof(Plots.parse_axis_kw), Symbol})
precompile(Tuple{typeof(Plots.partialcircle), Float64, Float64, Int64, Int64})
precompile(Tuple{typeof(Plots.partialcircle), Int64, Float64, Int64, Int64})
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.plotarea!), Plots.Subplot{Plots.PlotlyBackend}, 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}})
precompile(Tuple{typeof(Plots.plotarea), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_annotation_dict), Float64, Float64, Plots.PlotText})
precompile(Tuple{typeof(Plots.plotly_apply_aspect_ratio), Plots.Subplot{Plots.PlotlyBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.plotly_axis), Plots.Plot{Plots.PlotlyBackend}, Plots.Axis, Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_colorbar_hack), Plots.Series, Base.Dict{Symbol, Any}, Symbol})
precompile(Tuple{typeof(Plots.plotly_colorscale), PlotUtils.CategoricalColorGradient, Int64})
precompile(Tuple{typeof(Plots.plotly_colorscale), PlotUtils.ContinuousColorGradient, Int64})
precompile(Tuple{typeof(Plots.plotly_colorscale), PlotUtils.ContinuousColorGradient, Nothing})
precompile(Tuple{typeof(Plots.plotly_data), Array{Float64, 1}})
precompile(Tuple{typeof(Plots.plotly_data), Array{Int64, 1}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Array{Int64, 1}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Base.OneTo{Int64}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Base.StepRange{Int64, Int64}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, Nothing})
precompile(Tuple{typeof(Plots.plotly_data), Plots.Series, Symbol, RecipesPipeline.Surface{Array{Float64, 2}}})
precompile(Tuple{typeof(Plots.plotly_domain), Plots.Subplot{Plots.PlotlyBackend}, Symbol})
precompile(Tuple{typeof(Plots.plotly_font), Plots.Font, ColorTypes.RGBA{Float64}})
precompile(Tuple{typeof(Plots.plotly_font), Plots.Font})
precompile(Tuple{typeof(Plots.plotly_hover!), Base.Dict{Symbol, Any}, Array{Nothing, 1}})
precompile(Tuple{typeof(Plots.plotly_hover!), Base.Dict{Symbol, Any}, Nothing})
precompile(Tuple{typeof(Plots.plotly_html_body), Plots.Plot{Plots.PlotlyBackend}, Nothing})
precompile(Tuple{typeof(Plots.plotly_html_head), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_layout), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_legend_pos), Symbol})
precompile(Tuple{typeof(Plots.plotly_link_indicies), Plots.Plot{Plots.PlotlyBackend}, Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Array{Float64, 1}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Array{Float64, 2}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Array{Int64, 1}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Base.OneTo{Int64}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Base.StepRange{Int64, Int64}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, Base.UnitRange{Int64}})
precompile(Tuple{typeof(Plots.plotly_native_data), Plots.Axis, RecipesPipeline.Surface{Array{Float64, 2}}})
precompile(Tuple{typeof(Plots.plotly_polar!), Base.Dict{Symbol, Any}, Plots.Series})
precompile(Tuple{typeof(Plots.plotly_polaraxis), Plots.Subplot{Plots.PlotlyBackend}, Plots.Axis})
precompile(Tuple{typeof(Plots.plotly_series), Plots.Plot{Plots.PlotlyBackend}, Plots.Series})
precompile(Tuple{typeof(Plots.plotly_series), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 1}, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Array{Float64, 1}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Array{Int64, 1}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Array{Int64, 1}, Array{Int64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Base.OneTo{Int64}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Base.OneTo{Int64}, Base.UnitRange{Int64}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Base.UnitRange{Int64}, Array{Float64, 1}, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_segments), Plots.Series, Base.Dict{Symbol, Any}, Nothing, Nothing, Nothing, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_series_shapes), Plots.Plot{Plots.PlotlyBackend}, Plots.Series, Tuple{Float64, Float64}})
precompile(Tuple{typeof(Plots.plotly_surface_data), Plots.Series, RecipesPipeline.Surface{Array{Float64, 2}}})
precompile(Tuple{typeof(Plots.png), Plots.Plot{Plots.GRBackend}, String})
precompile(Tuple{typeof(Plots.prepare_output), Plots.Plot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.prepare_output), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Bool})
precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Int64})
precompile(Tuple{typeof(Plots.processFillArg), Base.Dict{Symbol, Any}, Symbol})
precompile(Tuple{typeof(Plots.processFontArg!), Base.Dict{Symbol, Any}, Symbol, Int64})
precompile(Tuple{typeof(Plots.processFontArg!), Base.Dict{Symbol, Any}, Symbol, String})
precompile(Tuple{typeof(Plots.processFontArg!), Base.Dict{Symbol, Any}, Symbol, 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.processGridArg!), RecipesPipeline.DefaultsDict, Bool, Symbol})
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.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}, 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.processMinorGridArg!), Base.Dict{Symbol, Any}, Bool, 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_annotation), Plots.Subplot{Plots.PlotlyBackend}, Int64, Float64, Plots.PlotText, Plots.Font})
precompile(Tuple{typeof(Plots.process_annotation), Plots.Subplot{Plots.PlotlyBackend}, 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.recompute_lengths), Array{Measures.Measure, 1}})
precompile(Tuple{typeof(Plots.replaceAlias!), Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Symbol}})
precompile(Tuple{typeof(Plots.replaceAlias!), RecipesPipeline.DefaultsDict, Symbol, Base.Dict{Symbol, Symbol}})
precompile(Tuple{typeof(Plots.replaceAliases!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Symbol}})
precompile(Tuple{typeof(Plots.replaceAliases!), RecipesPipeline.DefaultsDict, Base.Dict{Symbol, Symbol}})
precompile(Tuple{typeof(Plots.reset_axis_defaults_byletter!)})
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.rightpad), Plots.Subplot{Plots.PlotlyBackend}})
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), Plots.SeriesAnnotations})
precompile(Tuple{typeof(Plots.series_annotations_shapes!), Plots.Series, Symbol})
precompile(Tuple{typeof(Plots.series_idx), Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots.shape_data), Plots.Series, Int64})
precompile(Tuple{typeof(Plots.should_add_to_legend), Plots.Series})
precompile(Tuple{typeof(Plots.showaxis), Symbol, Symbol})
precompile(Tuple{typeof(Plots.shrink_by), Float64, Float64, Float64})
precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Bool})
precompile(Tuple{typeof(Plots.slice_arg!), Base.Dict{Symbol, Any}, RecipesPipeline.DefaultsDict, Symbol, Int64, Bool})
precompile(Tuple{typeof(Plots.slice_arg!), RecipesPipeline.DefaultsDict, RecipesPipeline.DefaultsDict, Symbol, Int64, Bool})
precompile(Tuple{typeof(Plots.slice_arg), Array{ColorTypes.RGBA{Float64}, 2}, Int64})
precompile(Tuple{typeof(Plots.slice_arg), Array{Float64, 2}, Int64})
precompile(Tuple{typeof(Plots.slice_arg), Array{Measures.Length{:mm, Float64}, 2}, Int64})
precompile(Tuple{typeof(Plots.slice_arg), Array{PlotUtils.ContinuousColorGradient, 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{Float64, Float64}, 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.slice_arg), typeof(identity), 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), Plots.PlotlyBackend})
precompile(Tuple{typeof(Plots.supported_markers)})
precompile(Tuple{typeof(Plots.supported_styles), Plots.GRBackend})
precompile(Tuple{typeof(Plots.supported_styles), Plots.PlotlyBackend})
precompile(Tuple{typeof(Plots.supported_styles)})
precompile(Tuple{typeof(Plots.test_examples), Symbol})
precompile(Tuple{typeof(Plots.text), String, Int64, Symbol, Symbol})
precompile(Tuple{typeof(Plots.text), String, Plots.Font})
precompile(Tuple{typeof(Plots.text), String, Symbol, Int64, Int})
precompile(Tuple{typeof(Plots.text), String, Symbol})
precompile(Tuple{typeof(Plots.text_size), Int64, Int64, Int64})
precompile(Tuple{typeof(Plots.tick_padding), Plots.Subplot{Plots.PlotlyBackend}, Plots.Axis})
precompile(Tuple{typeof(Plots.tickfont), Plots.Axis})
precompile(Tuple{typeof(Plots.ticksType), Tuple{Array{Float64, 1}, Array{Any, 1}}})
precompile(Tuple{typeof(Plots.ticksType), Tuple{Array{Float64, 1}, Array{String, 1}}})
precompile(Tuple{typeof(Plots.ticksType), Tuple{Array{Int64, 1}, Array{String, 1}}})
precompile(Tuple{typeof(Plots.title!), String})
precompile(Tuple{typeof(Plots.title_padding), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.titlefont), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.titlefont), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.top), Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}})
precompile(Tuple{typeof(Plots.toppad), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.toppad), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.transpose_z), Plots.Series, Array{Float64, 2}, Bool})
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.Subplot{Plots.GRBackend}, Array{Measures.Length{:mm, Float64}, 1}})
precompile(Tuple{typeof(Plots.update_child_bboxes!), Plots.Subplot{Plots.PlotlyBackend}, 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.PlotlyBackend}})
precompile(Tuple{typeof(Plots.vline!), Array{Int64, 1}})
precompile(Tuple{typeof(Plots.wand_edges), Array{Float64, 1}})
precompile(Tuple{typeof(Plots.warn_on_unsupported), Plots.GRBackend, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.warn_on_unsupported), Plots.PlotlyBackend, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.warn_on_unsupported_args), Plots.GRBackend, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.warn_on_unsupported_args), Plots.PlotlyBackend, RecipesPipeline.DefaultsDict})
precompile(Tuple{typeof(Plots.warn_on_unsupported_scales), Plots.GRBackend, Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots.warn_on_unsupported_scales), Plots.PlotlyBackend, Base.Dict{Symbol, Any}})
precompile(Tuple{typeof(Plots.widen), Float64, Float64, Symbol})
precompile(Tuple{typeof(Plots.wraptuple), Array{Any, 1}})
precompile(Tuple{typeof(Plots.wraptuple), Array{Float64, 1}})
precompile(Tuple{typeof(Plots.wraptuple), Base.StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
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{Symbol, 2}, Int64, Float64, Plots.Stroke}})
precompile(Tuple{typeof(Plots.wraptuple), Tuple{Array{Symbol, 2}, Int64}})
precompile(Tuple{typeof(Plots.wraptuple), Tuple{Base.LinRange{Float64}, Base.LinRange{Float64}}})
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, String}})
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.write_temp_html), Plots.Plot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.xgrid!), Plots.Plot{Plots.GRBackend}, Symbol, Int})
precompile(Tuple{typeof(Plots.xgrid!), Plots.Plot{Plots.PlotlyBackend}, Symbol, Int})
precompile(Tuple{typeof(Plots.xlims), Int64})
precompile(Tuple{typeof(Plots.xlims), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.xlims), Plots.Subplot{Plots.PlotlyBackend}})
precompile(Tuple{typeof(Plots.xy_mm_to_pcts), Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}})
precompile(Tuple{typeof(Plots.yaxis!), String, Symbol})
precompile(Tuple{typeof(Plots.ylims), Int64})
precompile(Tuple{typeof(Plots.ylims), Plots.Subplot{Plots.GRBackend}})
precompile(Tuple{typeof(Plots.ylims), Plots.Subplot{Plots.PlotlyBackend}})
end

View File

@ -0,0 +1,20 @@
should_precompile = true
# Don't edit the following! Instead change the script for `snoop_bot`.
ismultios = false
ismultiversion = false
# precompile_enclosure
@static if !should_precompile
# nothing
elseif !ismultios && !ismultiversion
@static if isfile(joinpath(
@__DIR__,
"../deps/SnoopCompile/precompile/precompile_Plots.jl",
))
include("../deps/SnoopCompile/precompile/precompile_Plots.jl")
_precompile_()
end
else
end # precompile_enclosure

View File

@ -78,6 +78,8 @@ const POTENTIAL_VECTOR_ARGUMENTS = [
:fillrange, :fillrange,
] ]
@nospecialize
@recipe function f(::Type{Val{:line}}, x, y, z) @recipe function f(::Type{Val{:line}}, x, y, z)
indices = sortperm(x) indices = sortperm(x)
x := x[indices] x := x[indices]
@ -112,7 +114,7 @@ end
@recipe function f(::Type{Val{:hline}}, x, y, z) @recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y) n = length(y)
newx = repeat(Float64[-1, 1, NaN], n) newx = repeat(Float64[1, 2, NaN], n)
newy = vec(Float64[yi for i = 1:3, yi in y]) newy = vec(Float64[yi for i = 1:3, yi in y])
x := newx x := newx
y := newy y := newy
@ -124,9 +126,8 @@ end
@recipe function f(::Type{Val{:vline}}, x, y, z) @recipe function f(::Type{Val{:vline}}, x, y, z)
n = length(y) n = length(y)
newx = vec(Float64[yi for i = 1:3, yi in y]) newx = vec(Float64[yi for i = 1:3, yi in y])
newy = repeat(Float64[-1, 1, NaN], n)
x := newx x := newx
y := newy y := repeat(Float64[1, 2, NaN], n)
seriestype := :straightline seriestype := :straightline
() ()
end end
@ -164,45 +165,81 @@ end
x := x x := x
y := y y := y
seriestype := :scatter seriestype := :scatter
@series begin
()
end
@series begin @series begin
seriestype := :path seriestype := :path
label := "" label := ""
primary := false primary := false
() ()
end end
primary := false
() ()
end end
@deps scatterpath path scatter @deps scatterpath path scatter
# ---------------------------------------------------------------------------
# regression line and scatter
# plots line corresponding to linear regression of y on a constant and x
@recipe function f(::Type{Val{:linearfit}}, x, y, z)
x := x
y := y
seriestype := :scatter
@series begin
()
end
@series begin
y := mean(y) .+ cov(x, y) / var(x) .* (x .- mean(x))
seriestype := :path
label := ""
primary := false
()
end
primary := false
()
end
@specialize
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# steps # steps
make_steps(x, st) = x make_steps(x, st, even) = x
function make_steps(x::AbstractArray, st) function make_steps(x::AbstractArray, st, even)
n = length(x) n = length(x)
n == 0 && return zeros(0) n == 0 && return zeros(0)
newx = zeros(2n - 1) newx = zeros(2n - (even ? 0 : 1))
for i = 1:n newx[1] = x[1]
for i = 2:n
idx = 2i - 1 idx = 2i - 1
if st == :mid
newx[idx] = newx[idx-1] = (x[i] + x[i-1]) / 2
else
newx[idx] = x[i] newx[idx] = x[i]
if i > 1
newx[idx - 1] = x[st == :pre ? i : i - 1] newx[idx - 1] = x[st == :pre ? i : i - 1]
end end
end end
even && (newx[end] = x[end])
return newx return newx
end end
make_steps(t::Tuple, st) = Tuple(make_steps(ti, st) for ti in t) make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t)
@nospecialize
# create a path from steps # create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z) @recipe function f(::Type{Val{:steppre}}, x, y, z)
plotattributes[:x] = make_steps(x, :post) plotattributes[:x] = make_steps(x, :post, false)
plotattributes[:y] = make_steps(y, :pre) plotattributes[:y] = make_steps(y, :pre, false)
seriestype := :path seriestype := :path
# handle fillrange # handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre) plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre, false)
# create a secondary series for the markers # create a secondary series for the markers
if plotattributes[:markershape] != :none if plotattributes[:markershape] != :none
@ -221,13 +258,38 @@ end
@deps steppre path scatter @deps steppre path scatter
# create a path from steps # create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z) @recipe function f(::Type{Val{:stepmid}}, x, y, z)
plotattributes[:x] = make_steps(x, :pre) plotattributes[:x] = make_steps(x, :mid, true)
plotattributes[:y] = make_steps(y, :post) plotattributes[:y] = make_steps(y, :post, true)
seriestype := :path seriestype := :path
# handle fillrange # handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post) plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, true)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
y := y
label := ""
primary := false
()
end
markershape := :none
end
()
end
@deps stepmid path scatter
# create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z)
plotattributes[:x] = make_steps(x, :pre, false)
plotattributes[:y] = make_steps(y, :post, false)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, false)
# create a secondary series for the markers # create a secondary series for the markers
if plotattributes[:markershape] != :none if plotattributes[:markershape] != :none
@ -263,24 +325,39 @@ end
end end
end end
newx, newy = zeros(3n), zeros(3n) newx, newy = zeros(3n), zeros(3n)
for i = 1:n newz = z !== nothing ? zeros(3n) : nothing
for (i, (xi, yi, zi)) = enumerate(zip(x, y, z !== nothing ? z : 1:n))
rng = (3i - 2):(3i) rng = (3i - 2):(3i)
newx[rng] = [x[i], x[i], NaN] newx[rng] = [xi, xi, NaN]
newy[rng] = [_cycle(fr, i), y[i], NaN] if z !== nothing
newy[rng] = [yi, yi, NaN]
newz[rng] = [_cycle(fr, i), zi, NaN]
else
newy[rng] = [_cycle(fr, i), yi, NaN]
end
end end
x := newx x := newx
y := newy y := newy
if z !== nothing
z := newz
end
fillrange := nothing fillrange := nothing
seriestype := :path seriestype := :path
if plotattributes[:linecolor] == :auto && plotattributes[:marker_z] !== nothing && plotattributes[:line_z] === nothing
line_z := plotattributes[:marker_z]
end
# create a secondary series for the markers # create a primary series for the markers
if plotattributes[:markershape] != :none if plotattributes[:markershape] != :none
primary := false
@series begin @series begin
seriestype := :scatter seriestype := :scatter
x := x x := x
y := y y := y
label := "" if z !== nothing
primary := false z := z
end
primary := true
() ()
end end
markershape := :none markershape := :none
@ -289,6 +366,8 @@ end
end end
@deps sticks path scatter @deps sticks path scatter
@specialize
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# bezier curves # bezier curves
@ -303,6 +382,8 @@ function bezier_value(pts::AVec, t::Real)
val val
end end
@nospecialize
# create segmented bezier curves in place of line segments # create segmented bezier curves in place of line segments
@recipe function f(::Type{Val{:curves}}, x, y, z; npoints = 30) @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)
@ -374,7 +455,7 @@ end
bw = plotattributes[:bar_width] bw = plotattributes[:bar_width]
hw = if bw === nothing hw = if bw === nothing
if nx > 1 if nx > 1
0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(procx))) 0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(procx))))
else else
0.5 * _bar_width 0.5 * _bar_width
end end
@ -391,6 +472,15 @@ end
fillto = map(x -> _is_positive(x) ? typeof(baseline)(x) : baseline, fillto) fillto = map(x -> _is_positive(x) ? typeof(baseline)(x) : baseline, fillto)
end end
if !isnothing(plotattributes[:series_annotations])
if isvertical(plotattributes)
annotations := (x,y,plotattributes[:series_annotations].strs,:bottom)
else
annotations := (y,x,plotattributes[:series_annotations].strs,:left)
end
series_annotations := nothing
end
# create the bar shapes by adding x/y segments # create the bar shapes by adding x/y segments
xseg, yseg = Segments(), Segments() xseg, yseg = Segments(), Segments()
for i = 1:ny for i = 1:ny
@ -458,9 +548,12 @@ end
() ()
end end
@deps plots_heatmap shape @deps plots_heatmap shape
@specialize
is_3d(::Type{Val{:plots_heatmap}}) = true is_3d(::Type{Val{:plots_heatmap}}) = true
RecipesPipeline.is_surface(::Type{Val{:plots_heatmap}}) = true RecipesPipeline.is_surface(::Type{Val{:plots_heatmap}}) = true
RecipesPipeline.is_surface(::Type{Val{:hexbin}}) = true
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Histograms # Histograms
@ -521,6 +614,8 @@ function _preprocess_binlike(plotattributes, x, y)
end end
@nospecialize
@recipe function f(::Type{Val{:barbins}}, x, y, z) @recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y) _preprocess_binlike(plotattributes, x, y)
@ -552,6 +647,8 @@ end
end end
@deps scatterbins xerror scatter @deps scatterbins xerror scatter
@specialize
function _stepbins_path( function _stepbins_path(
edge, edge,
weights, weights,
@ -618,8 +715,8 @@ function _stepbins_path(
(x, y) (x, y)
end end
@recipe function f(::Type{Val{:stepbins}}, x, y, z) @recipe function f(::Type{Val{:stepbins}}, x, y, z)
@nospecialize
axis = axis =
plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis] plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
@ -756,6 +853,7 @@ function _make_hist(
normalize!(h, mode = _hist_norm_mode(normed)) normalize!(h, mode = _hist_norm_mode(normed))
end end
@nospecialize
@recipe function f(::Type{Val{:histogram}}, x, y, z) @recipe function f(::Type{Val{:histogram}}, x, y, z)
seriestype := length(y) > 1e6 ? :stephist : :barhist seriestype := length(y) > 1e6 ? :stephist : :barhist
@ -765,7 +863,7 @@ end
@recipe function f(::Type{Val{:barhist}}, x, y, z) @recipe function f(::Type{Val{:barhist}}, x, y, z)
h = _make_hist( h = _make_hist(
(y,), tuple(y),
plotattributes[:bins], plotattributes[:bins],
normed = plotattributes[:normalize], normed = plotattributes[:normalize],
weights = plotattributes[:weights], weights = plotattributes[:weights],
@ -779,7 +877,7 @@ end
@recipe function f(::Type{Val{:stephist}}, x, y, z) @recipe function f(::Type{Val{:stephist}}, x, y, z)
h = _make_hist( h = _make_hist(
(y,), tuple(y),
plotattributes[:bins], plotattributes[:bins],
normed = plotattributes[:normalize], normed = plotattributes[:normalize],
weights = plotattributes[:weights], weights = plotattributes[:weights],
@ -793,7 +891,7 @@ end
@recipe function f(::Type{Val{:scatterhist}}, x, y, z) @recipe function f(::Type{Val{:scatterhist}}, x, y, z)
h = _make_hist( h = _make_hist(
(y,), tuple(y),
plotattributes[:bins], plotattributes[:bins],
normed = plotattributes[:normalize], normed = plotattributes[:normalize],
weights = plotattributes[:weights], weights = plotattributes[:weights],
@ -860,9 +958,7 @@ end
x := Plots._bin_centers(edge_x) x := Plots._bin_centers(edge_x)
y := Plots._bin_centers(edge_y) y := Plots._bin_centers(edge_y)
z := Surface(float_weights) z := Surface(permutedims(float_weights))
match_dimensions := true
seriestype := :heatmap seriestype := :heatmap
() ()
end end
@ -913,6 +1009,19 @@ end
@deps pie shape @deps pie shape
# ---------------------------------------------------------------------------
# mesh 3d replacement for non-plotly backends
@recipe function f(::Type{Val{:mesh3d}}, x, y, z)
# As long as no i,j,k are supplied this should work with PyPlot and GR
seriestype := :surface
if plotattributes[:connections] !== nothing
throw(ArgumentError("Giving triangles using the connections argument is only supported on Plotly backend."))
end
()
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# scatter 3d # scatter 3d
@ -928,7 +1037,6 @@ end
# note: don't add dependencies because this really isn't a drop-in replacement # note: don't add dependencies because this really isn't a drop-in replacement
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# lens! - magnify a region of a plot # lens! - magnify a region of a plot
lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...) lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...)
@ -950,8 +1058,12 @@ export lens!
lens_index = last(plt.subplots)[:subplot_index] + 1 lens_index = last(plt.subplots)[:subplot_index] + 1
x1, x2 = plotattributes[:x] x1, x2 = plotattributes[:x]
y1, y2 = plotattributes[:y] y1, y2 = plotattributes[:y]
backup = copy(plotattributes)
empty!(plotattributes)
series_plotindex := backup[:series_plotindex]
seriestype := :path seriestype := :path
label := "" primary := false
linecolor := :lightgray linecolor := :lightgray
bbx_mag = (x1 + x2) / 2 bbx_mag = (x1 + x2) / 2
bby_mag = (y1 + y2) / 2 bby_mag = (y1 + y2) / 2
@ -961,6 +1073,7 @@ export lens!
if xl1 < xi_lens < xl2 && if xl1 < xi_lens < xl2 &&
yl1 < yi_lens < yl2 yl1 < yi_lens < yl2
@series begin @series begin
primary := false
subplot := sp_index subplot := sp_index
x := [xi_mag, xi_lens] x := [xi_mag, xi_lens]
y := [yi_mag, yi_lens] y := [yi_mag, yi_lens]
@ -969,6 +1082,7 @@ export lens!
end end
# add magnification shape # add magnification shape
@series begin @series begin
primary := false
subplot := sp_index subplot := sp_index
x := [x1, x1, x2, x2, x1] x := [x1, x1, x2, x2, x1]
y := [y1, y2, y2, y1, y1] y := [y1, y2, y2, y1, y1]
@ -977,20 +1091,19 @@ export lens!
# add subplot # add subplot
for series in sp.series_list for series in sp.series_list
@series begin @series begin
plotattributes = merge(plotattributes, copy(series.plotattributes)) plotattributes = merge(backup, copy(series.plotattributes))
subplot := lens_index subplot := lens_index
label := "" primary := false
xlims := (x1, x2) xlims := (x1, x2)
ylims := (y1, y2) ylims := (y1, y2)
() ()
end end
end end
backup = copy(plotattributes) nothing
empty!(plotattributes)
seriestype := :path
series_plotindex := backup[:series_plotindex]
end end
@specialize
function intersection_point(xA, yA, xB, yB, h, w) function intersection_point(xA, yA, xB, yB, h, w)
s = (yA - yB) / (xA - xB) s = (yA - yB) / (xA - xB)
hh = h / 2 hh = h / 2
@ -1018,6 +1131,7 @@ end
# contourf - filled contours # contourf - filled contours
@recipe function f(::Type{Val{:contourf}}, x, y, z) @recipe function f(::Type{Val{:contourf}}, x, y, z)
@nospecialize
fillrange := true fillrange := true
seriestype := :contour seriestype := :contour
() ()
@ -1027,8 +1141,24 @@ end
# Error Bars # Error Bars
function error_style!(plotattributes::AKW) function error_style!(plotattributes::AKW)
msc = plotattributes[:markerstrokecolor]
msc = if msc === :match
plotattributes[:subplot][:foreground_color_subplot]
elseif msc === :auto
get_series_color(
plotattributes[:linecolor],
plotattributes[:subplot],
plotattributes[:series_plotindex],
plotattributes[:seriestype],
)
else
msc
end
plotattributes[:seriestype] = :path plotattributes[:seriestype] = :path
plotattributes[:markercolor] = plotattributes[:markerstrokecolor] plotattributes[:markerstrokecolor] = msc
plotattributes[:markercolor] = msc
plotattributes[:linecolor] = msc
plotattributes[:linewidth] = plotattributes[:markerstrokewidth] plotattributes[:linewidth] = plotattributes[:markerstrokewidth]
plotattributes[:label] = "" plotattributes[:label] = ""
end end
@ -1059,9 +1189,17 @@ function error_coords(errorbar, errordata, otherdata...)
return (ed, od...) return (ed, od...)
end end
# clamp non-NaN values in an array to Base.eps(Float64) for log-scale plots
function clamp_to_eps!(ary)
replace!(x -> x <= 0.0 ? Base.eps(Float64) : x, ary)
nothing
end
# we will create a series of path segments, where each point represents one # we will create a series of path segments, where each point represents one
# side of an errorbar # side of an errorbar
@nospecialize
@recipe function f(::Type{Val{:xerror}}, x, y, z) @recipe function f(::Type{Val{:xerror}}, x, y, z)
error_style!(plotattributes) error_style!(plotattributes)
markershape := :vline markershape := :vline
@ -1072,6 +1210,9 @@ end
plotattributes[:x], plotattributes[:y], plotattributes[:z] = plotattributes[:x], plotattributes[:y], plotattributes[:z] =
error_coords(xerr, x, y, z) error_coords(xerr, x, y, z)
end end
if :xscale keys(plotattributes) && plotattributes[:xscale] == :log10
clamp_to_eps!(plotattributes[:x])
end
() ()
end end
@deps xerror path @deps xerror path
@ -1086,6 +1227,9 @@ end
plotattributes[:y], plotattributes[:x], plotattributes[:z] = plotattributes[:y], plotattributes[:x], plotattributes[:z] =
error_coords(yerr, y, x, z) error_coords(yerr, y, x, z)
end end
if :yscale keys(plotattributes) && plotattributes[:yscale] == :log10
clamp_to_eps!(plotattributes[:y])
end
() ()
end end
@deps yerror path @deps yerror path
@ -1098,10 +1242,14 @@ end
plotattributes[:z], plotattributes[:x], plotattributes[:y] = plotattributes[:z], plotattributes[:x], plotattributes[:y] =
error_coords(zerr, z, x, y) error_coords(zerr, z, x, y)
end end
if :zscale keys(plotattributes) && plotattributes[:zscale] == :log10
clamp_to_eps!(plotattributes[:z])
end
() ()
end end
@deps zerror path @deps zerror path
@specialize
# TODO: move quiver to PlotRecipes # TODO: move quiver to PlotRecipes
@ -1115,19 +1263,32 @@ function quiver_using_arrows(plotattributes::AKW)
if !isa(plotattributes[:arrow], Arrow) if !isa(plotattributes[:arrow], Arrow)
plotattributes[:arrow] = arrow() plotattributes[:arrow] = arrow()
end end
is_3d = haskey(plotattributes,:z) && !isnothing(plotattributes[:z])
velocity = error_zipit(plotattributes[:quiver]) velocity = error_zipit(plotattributes[:quiver])
xorig, yorig = plotattributes[:x], plotattributes[:y] xorig, yorig = plotattributes[:x], plotattributes[:y]
zorig = is_3d ? plotattributes[:z] : []
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates # for each point, we create an arrow of velocity vi, translated to the x/y coordinates
x, y = zeros(0), zeros(0) x, y = zeros(0), zeros(0)
for i = 1:max(length(xorig), length(yorig)) is_3d && ( z = zeros(0))
for i = 1:max(length(xorig), length(yorig), is_3d ? 0 : length(zorig))
# get the starting position # get the starting position
xi = _cycle(xorig, i) xi = _cycle(xorig, i)
yi = _cycle(yorig, i) yi = _cycle(yorig, i)
zi = is_3d ? _cycle(zorig, i) : 0
# get the velocity # get the velocity
vi = _cycle(velocity, i) vi = _cycle(velocity, i)
if is_3d
vx, vy, vz = if istuple(vi)
vi[1], vi[2], vi[3]
elseif isscalar(vi)
vi, vi, vi
elseif isa(vi, Function)
vi(xi, yi, zi)
else
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
end
else # 2D quiver
vx, vy = if istuple(vi) vx, vy = if istuple(vi)
first(vi), last(vi) first(vi), last(vi)
elseif isscalar(vi) elseif isscalar(vi)
@ -1137,13 +1298,16 @@ function quiver_using_arrows(plotattributes::AKW)
else else
error("unexpected vi type $(typeof(vi)) for quiver: $vi") error("unexpected vi type $(typeof(vi)) for quiver: $vi")
end end
end
# add the points # add the points
nanappend!(x, [xi, xi + vx, NaN]) nanappend!(x, [xi, xi + vx, NaN])
nanappend!(y, [yi, yi + vy, NaN]) nanappend!(y, [yi, yi + vy, NaN])
is_3d && nanappend!(z, [zi, zi + vz, NaN])
end end
plotattributes[:x], plotattributes[:y] = x, y plotattributes[:x], plotattributes[:y] = x, y
if is_3d
plotattributes[:z] = z
end
# KW[plotattributes] # KW[plotattributes]
end end
@ -1198,6 +1362,7 @@ end
# function apply_series_recipe(plotattributes::AKW, ::Type{Val{:quiver}}) # function apply_series_recipe(plotattributes::AKW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z) @recipe function f(::Type{Val{:quiver}}, x, y, z)
@nospecialize
if :arrow in supported_attrs() if :arrow in supported_attrs()
quiver_using_arrows(plotattributes) quiver_using_arrows(plotattributes)
else else
@ -1230,12 +1395,14 @@ end
else else
seriestype := :heatmap seriestype := :heatmap
yflip --> true yflip --> true
cbar --> false colorbar --> false
fillcolor --> ColorGradient([:black, :white]) fillcolor --> cgrad([:black, :white])
SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0.0, 1.0)) SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0.0, 1.0))
end end
end end
@nospecialize
# images - colors # images - colors
@recipe function f(mat::AMat{T}) where {T <: Colorant} @recipe function f(mat::AMat{T}) where {T <: Colorant}
n, m = axes(mat) n, m = axes(mat)
@ -1247,7 +1414,7 @@ end
else else
seriestype := :heatmap seriestype := :heatmap
yflip --> true yflip --> true
cbar --> false colorbar --> false
aspect_ratio --> :equal aspect_ratio --> :equal
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat) z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, m, n, Surface(z) SliceIt, m, n, Surface(z)
@ -1261,12 +1428,22 @@ end
coords(shape) coords(shape)
end end
@recipe function f(shapes::AVec{Shape}) @recipe function f(shapes::AVec{<:Shape})
seriestype --> :shape seriestype --> :shape
# For backwards compatibility, column vectors of segmenting attributes are
# interpreted as having one element per shape
for attr in union(_segmenting_array_attributes, _segmenting_vector_attributes)
v = get(plotattributes, attr, nothing)
if v isa AVec || v isa AMat && size(v,2) == 1
@warn "Column vector attribute `$attr` reinterpreted as row vector (one value per shape).\n" *
"Pass a row vector instead (e.g. using `permutedims`) to suppress this warning."
plotattributes[attr] = permutedims(v)
end
end
coords(shapes) coords(shapes)
end end
@recipe function f(shapes::AMat{Shape}) @recipe function f(shapes::AMat{<:Shape})
seriestype --> :shape seriestype --> :shape
for j in axes(shapes, 2) for j in axes(shapes, 2)
@series coords(vec(shapes[:, j])) @series coords(vec(shapes[:, j]))
@ -1287,8 +1464,8 @@ end
else else
seriestype := :heatmap seriestype := :heatmap
yflip --> true yflip --> true
cbar --> false colorbar --> false
fillcolor --> ColorGradient([:black, :white]) fillcolor --> cgrad([:black, :white])
SliceIt, x, y, Surface(convert(Matrix{Float64}, mat)) SliceIt, x, y, Surface(convert(Matrix{Float64}, mat))
end end
end end
@ -1302,23 +1479,24 @@ end
else else
seriestype := :heatmap seriestype := :heatmap
yflip --> true yflip --> true
cbar --> false colorbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat) z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, x, y, Surface(z) SliceIt, x, y, Surface(z)
end end
end end
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Lists of tuples and GeometryTypes.Points # Lists of tuples and GeometryBasics.Points
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@recipe f(v::AVec{<:GeometryTypes.Point}) = RecipesPipeline.unzip(v) @recipe f(v::AVec{<:GeometryBasics.Point}) = RecipesPipeline.unzip(v)
@recipe f(p::GeometryTypes.Point) = [p] @recipe f(p::GeometryBasics.Point) = [p]
# Special case for 4-tuples in :ohlc series # Special case for 4-tuples in :ohlc series
@recipe f(xyuv::AVec{<:Tuple{R1, R2, R3, R4}}) where {R1, R2, R3, R4} = @recipe f(xyuv::AVec{<:Tuple{R1, R2, R3, R4}}) where {R1, R2, R3, R4} =
get(plotattributes, :seriestype, :path) == :ohlc ? OHLC[OHLC(t...) for t in xyuv] : get(plotattributes, :seriestype, :path) == :ohlc ? OHLC[OHLC(t...) for t in xyuv] :
RecipesPipeline.unzip(xyuv) RecipesPipeline.unzip(xyuv)
@specialize
# ------------------------------------------------- # -------------------------------------------------
@ -1358,6 +1536,8 @@ end
# TODO: when I allow `@recipe f(::Type{T}, v::T) = ...` definitions to replace convertToAnyVector, # TODO: when I allow `@recipe f(::Type{T}, v::T) = ...` definitions to replace convertToAnyVector,
# then I should replace these with one definition to convert to a vector of 4-tuples # then I should replace these with one definition to convert to a vector of 4-tuples
@nospecialize
# to squash ambiguity warnings... # to squash ambiguity warnings...
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error() @recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
@recipe f( @recipe f(
@ -1415,17 +1595,17 @@ end
@recipe function f(::Type{Val{:spy}}, x, y, z) @recipe function f(::Type{Val{:spy}}, x, y, z)
yflip := true yflip := true
aspect_ratio := 1 aspect_ratio := 1
rs, cs, zs = findnz(z.surf) rs, cs, zs = Plots.findnz(z.surf)
xlims := ignorenan_extrema(cs) xlims := widen(ignorenan_extrema(cs)..., get(plotattributes, :xscale, :identity))
ylims := ignorenan_extrema(rs) ylims := widen(ignorenan_extrema(rs)..., get(plotattributes, :yscale, :identity))
if plotattributes[:markershape] == :none markershape --> :circle
markershape := :circle markersize --> 1
end
if plotattributes[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0 markerstrokewidth := 0
if length(unique(zs)) == 1
seriescolor --> :black
else
marker_z := zs marker_z := zs
end
label := "" label := ""
x := cs x := cs
y := rs y := rs
@ -1435,8 +1615,24 @@ end
() ()
end end
@specialize
Plots.findnz(A::AbstractSparseMatrix) = SparseArrays.findnz(A)
# fallback function for finding non-zero elements of non-sparse matrices
function Plots.findnz(A::AbstractMatrix)
keysnz = findall(!iszero, A)
rs = [k[1] for k in keysnz]
cs = [k[2] for k in keysnz]
zs = A[keysnz]
rs, cs, zs
end
# ------------------------------------------------- # -------------------------------------------------
@nospecialize
"Adds ax+b... straight line over the current plot, without changing the axis limits" "Adds ax+b... straight line over the current plot, without changing the axis limits"
abline!(plt::Plot, a, b; kw...) = abline!(plt::Plot, a, b; kw...) =
plot!(plt, [0, 1], [b, b + a]; seriestype = :straightline, kw...) plot!(plt, [0, 1], [b, b + a]; seriestype = :straightline, kw...)
@ -1462,50 +1658,6 @@ end
end end
# --------------------------------------------------
# Color Gradients
@userplot ShowLibrary
@recipe function f(cl::ShowLibrary)
if !(length(cl.args) == 1 && isa(cl.args[1], Symbol))
error("showlibrary takes the name of a color library as a Symbol")
end
library = PlotUtils.color_libraries[cl.args[1]]
z = sqrt.((1:15) * reshape(1:20, 1, :))
seriestype := :heatmap
ticks := nothing
legend := false
layout --> length(library.lib)
i = 0
for grad in sort(collect(keys(library.lib)))
@series begin
seriescolor := cgrad(grad, cl.args[1])
title := string(grad)
subplot := i += 1
z
end
end
end
@userplot ShowGradient
@recipe function f(grad::ShowGradient)
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
error("showgradient takes the name of a color gradient as a Symbol")
end
z = sqrt.((1:15) * reshape(1:20, 1, :))
seriestype := :heatmap
ticks := nothing
legend := false
seriescolor := grad.args[1]
title := string(grad.args[1])
z
end
# Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246 # Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246
@userplot PortfolioComposition @userplot PortfolioComposition
@ -1550,3 +1702,5 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
end end
end end
end end
@specialize

View File

@ -1,3 +1,5 @@
@nospecialize
""" """
scatter(x,y) scatter(x,y)
scatter!(x,y) scatter!(x,y)
@ -55,6 +57,7 @@ Plot a histogram.
# Example # Example
```julia-repl ```julia-repl
julia> histogram([1,2,1,1,4,3,8],bins=0:8) julia> histogram([1,2,1,1,4,3,8],bins=0:8)
julia> histogram([1,2,1,1,4,3,8],bins=0:8,weights=weights([4,7,3,9,12,2,6]))
``` ```
""" """
@shorthands histogram @shorthands histogram
@ -69,7 +72,7 @@ Make a histogram bar plot. See `histogram`.
""" """
stephist(x) stephist(x)
stephist(x) stephist!(x)
Make a histogram step plot (bin counts are represented using horizontal lines Make a histogram step plot (bin counts are represented using horizontal lines
instead of bars). See `histogram`. instead of bars). See `histogram`.
@ -318,6 +321,27 @@ julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
""" """
@shorthands scatter3d @shorthands scatter3d
"""
mesh3d(x,y,z)
mesh3d(x,y,z; connections)
Plot a 3d mesh. On Plotly the triangles can be specified using the connections argument.
# Example
```Julia
x=[0, 1, 2, 0]
y=[0, 0, 1, 2]
z=[0, 2, 0, 1]
i=[0, 0, 0, 1]
j=[1, 2, 3, 2]
k=[2, 3, 1, 3]
plot(x,y,z,seriestype=:mesh3d;connections=(i,j,k))
```
"""
@shorthands mesh3d
""" """
boxplot(x, y) boxplot(x, y)
boxplot!(x, y) boxplot!(x, y)
@ -397,13 +421,13 @@ xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...) ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot" "Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...) xlims!(lims::Tuple; kw...) = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot" "Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...) ylims!(lims::Tuple; kw...) = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot" "Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...) zlims!(lims::Tuple; kw...) = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...) xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...) ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
@ -411,10 +435,10 @@ zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmi
"Set xticks for an existing plot" "Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...) xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...)
"Set yticks for an existing plot" "Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...) yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...)
xticks!( xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
@ -454,3 +478,5 @@ xaxis!(args...; kw...) = plot!(; xaxis = args
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...) yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...) xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...) ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
@specialize

View File

@ -1,4 +1,6 @@
function treats_y_as_x(seriestype)
return seriestype in (:vline, :vspan, :histogram, :barhist, :stephist, :scatterhist)
end
function replace_image_with_heatmap(z::Array{T}) where T<:Colorant function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
n, m = size(z) n, m = size(z)
colors = palette(vec(z)) colors = palette(vec(z))
@ -51,10 +53,16 @@ function Base.push!(segments::Segments{T}, vs::AVec) where T
end end
struct SeriesSegment
# indexes of this segement in series data vectors
range::UnitRange
# index into vector-valued attributes corresponding to this segment
attr_index::Int
end
# ----------------------------------------------------- # -----------------------------------------------------
# helper to manage NaN-separated segments # helper to manage NaN-separated segments
struct NaNSegmentsIterator
mutable struct SegmentsIterator
args::Tuple args::Tuple
n1::Int n1::Int
n2::Int n2::Int
@ -64,30 +72,50 @@ function iter_segments(args...)
tup = Plots.wraptuple(args) tup = Plots.wraptuple(args)
n1 = minimum(map(firstindex, tup)) n1 = minimum(map(firstindex, tup))
n2 = maximum(map(lastindex, tup)) n2 = maximum(map(lastindex, tup))
SegmentsIterator(tup, n1, n2) NaNSegmentsIterator(tup, n1, n2)
end end
function iter_segments(series::Series) function series_segments(series::Series, seriestype::Symbol = :path)
x, y, z = series[:x], series[:y], series[:z] x, y, z = series[:x], series[:y], series[:z]
if x === nothing (x === nothing || isempty(x)) && return UnitRange{Int}[]
return UnitRange{Int}[]
elseif has_attribute_segments(series)
if series[:seriestype] in (:scatter, :scatter3d)
return [[i] for i in eachindex(y)]
else
if any(isnan,y)
return [iter_segments(y)...]
else
return [i:(i + 1) for i in firstindex(y):lastindex(y)-1]
end
end
else
segs = UnitRange{Int}[]
args = RecipesPipeline.is3d(series) ? (x, y, z) : (x, y) args = RecipesPipeline.is3d(series) ? (x, y, z) : (x, y)
for seg in iter_segments(args...) nan_segments = collect(iter_segments(args...))
push!(segs, seg)
segments = if has_attribute_segments(series)
Iterators.flatten(map(nan_segments) do r
if seriestype in (:scatter, :scatter3d)
(SeriesSegment(i:i, i) for i in r)
else
(SeriesSegment(i:i+1, i) for i in first(r):last(r)-1)
end
end)
else
(SeriesSegment(r, 1) for r in nan_segments)
end
warn_on_attr_dim_mismatch(series, x, y, z, segments)
return segments
end
function warn_on_attr_dim_mismatch(series, x, y, z, segments)
isempty(segments) && return
seg_range = UnitRange(minimum(first(seg.range) for seg in segments),
maximum(last(seg.range) for seg in segments))
for attr in _segmenting_vector_attributes
v = get(series, attr, nothing)
if v isa AVec && eachindex(v) != seg_range
@warn "Indices $(eachindex(v)) of attribute `$attr` does not match data indices $seg_range."
if any(v -> !isnothing(v) && any(isnan, v), (x,y,z))
@info """Data contains NaNs or missing values, and indices of `$attr` vector do not match data indices.
If you intend elements of `$attr` to apply to individual NaN-separated segements in the data,
pass each segment in a separate vector instead, and use a row vector for `$attr`. Legend entries
may be suppressed by passing an empty label.
For example,
plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], $attr=[1 2])
"""
end
end end
return segs
end end
end end
@ -97,7 +125,7 @@ anynan(args::Tuple) = i -> anynan(i,args)
anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend) anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend) allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = itr.n1) function Base.iterate(itr::NaNSegmentsIterator, nextidx::Int = itr.n1)
i = findfirst(!anynan(itr.args), nextidx:itr.n2) i = findfirst(!anynan(itr.args), nextidx:itr.n2)
i === nothing && return nothing i === nothing && return nothing
nextval = nextidx + i - 1 nextval = nextidx + i - 1
@ -107,6 +135,7 @@ function Base.iterate(itr::SegmentsIterator, nextidx::Int = itr.n1)
nextval:nextnan-1, nextnan nextval:nextnan-1, nextnan
end end
Base.IteratorSize(::NaNSegmentsIterator) = Base.SizeUnknown()
# Find minimal type that can contain NaN and x # Find minimal type that can contain NaN and x
# To allow use of NaN separated segments with categorical x axis # To allow use of NaN separated segments with categorical x axis
@ -126,8 +155,8 @@ isnothing(x) = false
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj _cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
_cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj _cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
_cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))] _cycle(v::AVec, idx::Int) = v[mod(idx, axes(v,1))]
_cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))] _cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[end, mod(idx, axes(v,2))] : v[:, mod(idx, axes(v,2))]
_cycle(v, idx::Int) = v _cycle(v, idx::Int) = v
_cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices) _cycle(v::AVec, indices::AVec{Int}) = map(i -> _cycle(v,i), indices)
@ -151,15 +180,18 @@ maketuple(x::Tuple{T,S}) where {T,S} = x
for i in 2:4 for i in 2:4
@eval begin @eval begin
RecipesPipeline.unzip(v::Union{AVec{<:Tuple{Vararg{T,$i} where T}}, RecipesPipeline.unzip(
AVec{<:GeometryTypes.Point{$i}}}) = $(Expr(:tuple, (:([t[$j] for t in v]) for j=1:i)...)) v::Union{AVec{<:Tuple{Vararg{T,$i} where T}}, AVec{<:GeometryBasics.Point{$i}}},
) = $(Expr(:tuple, (:([t[$j] for t in v]) for j=1:i)...))
end end
end end
RecipesPipeline.unzip(v::Union{AVec{<:GeometryTypes.Point{N}}, RecipesPipeline.unzip(
AVec{<:Tuple{Vararg{T,N} where T}}}) where N = error("$N-dimensional unzip not implemented.") ::Union{AVec{<:GeometryBasics.Point{N}}, AVec{<:Tuple{Vararg{T,N} where T}}}
RecipesPipeline.unzip(v::Union{AVec{<:GeometryTypes.Point}, ) where N = error("$N-dimensional unzip not implemented.")
AVec{<:Tuple}}) = error("Can't unzip points of different dimensions.") RecipesPipeline.unzip(::Union{AVec{<:GeometryBasics.Point}, AVec{<:Tuple}}) = error(
"Can't unzip points of different dimensions."
)
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x # given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x) function _expand_limits(lims, x)
@ -206,30 +238,27 @@ end
createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end] createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end]
Base.first(c::Colorant) = c
Base.first(x::Symbol) = x
sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes))) sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes)))
function _heatmap_edges(v::AVec, isedges::Bool = false) function _heatmap_edges(v::AVec, isedges::Bool = false, ispolar::Bool = false)
length(v) == 1 && return v[1] .+ [-0.5, 0.5] length(v) == 1 && return v[1] .+ [ispolar ? max(-v[1], -0.5) : -0.5, 0.5]
if isedges return v end if isedges return v end
# `isedges = true` means that v is a vector which already describes edges # `isedges = true` means that v is a vector which already describes edges
# and does not need to be extended. # and does not need to be extended.
vmin, vmax = ignorenan_extrema(v) vmin, vmax = ignorenan_extrema(v)
extra_min = (v[2] - v[1]) / 2 extra_min = ispolar ? min(v[1], (v[2] - v[1]) / 2) : (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2 extra_max = (v[end] - v[end - 1]) / 2
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max) vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
end end
"create an (n+1) list of the outsides of heatmap rectangles" "create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false) function heatmap_edges(v::AVec, scale::Symbol = :identity, isedges::Bool = false, ispolar::Bool = false)
f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale) f, invf = RecipesPipeline.scale_func(scale), RecipesPipeline.inverse_scale_func(scale)
map(invf, _heatmap_edges(map(f,v), isedges)) map(invf, _heatmap_edges(map(f,v), isedges, ispolar))
end end
function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int}) function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int}, ispolar::Bool = false)
nx, ny = length(x), length(y) nx, ny = length(x), length(y)
# ismidpoints = z_size == (ny, nx) # This fails some tests, but would actually be # 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. # the correct check, since (4, 3) != (3, 4) and a missleading plot is produced.
@ -241,7 +270,7 @@ function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size:
or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""") or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""")
end end
x, y = heatmap_edges(x, xscale, isedges), x, y = heatmap_edges(x, xscale, isedges),
heatmap_edges(y, yscale, isedges) heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots
return x, y return x, y
end end
@ -294,13 +323,11 @@ limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert(::Type{Vector{T}}, rng::AbstractRange{T}) where {T<:Real} = T[x for x in rng] # recursively merge kw-dicts, e.g. for merging extra_kwargs / extra_plot_kwargs in plotly)
Base.convert(::Type{Vector{T}}, rng::AbstractRange{S}) where {T<:Real,S<:Real} = T[x for x in rng] recursive_merge(x::AbstractDict...) = merge(recursive_merge, x...)
# if values are not AbstractDicts, take the last definition (as does merge)
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b))) recursive_merge(x...) = x[end]
nanpush!(a::AbstractVector, b) = (push!(a, NaN); push!(a, b)) nanpush!(a::AbstractVector, b) = (push!(a, NaN); push!(a, b))
nanappend!(a::AbstractVector, b) = (push!(a, NaN); append!(a, b)) nanappend!(a::AbstractVector, b) = (push!(a, NaN); append!(a, b))
@ -338,17 +365,8 @@ function indices_and_unique_values(z::AbstractArray)
newz, vals newz, vals
end end
# this is a helper function to determine whether we need to transpose a surface matrix. handle_surface(z) = z
# it depends on whether the backend matches rows to x (transpose_on_match == true) or vice versa handle_surface(z::Surface) = permutedims(z.surf)
# for example: PyPlot sends rows to y, so transpose_on_match should be true
function transpose_z(plotattributes, z, transpose_on_match::Bool = true)
if plotattributes[:match_dimensions] == transpose_on_match
# z'
permutedims(z, [2,1])
else
z
end
end
function ok(x::Number, y::Number, z::Number = 0) function ok(x::Number, y::Number, z::Number = 0)
isfinite(x) && isfinite(y) && isfinite(z) isfinite(x) && isfinite(y) && isfinite(z)
@ -356,10 +374,10 @@ end
ok(tup::Tuple) = ok(tup...) ok(tup::Tuple) = ok(tup...)
# compute one side of a fill range from a ribbon # compute one side of a fill range from a ribbon
function make_fillrange_side(y, rib) function make_fillrange_side(y::AVec, rib)
frs = zeros(length(y)) frs = zeros(axes(y))
for (i, (yi, ri)) in enumerate(zip(y, Base.Iterators.cycle(rib))) for (i, yi) in pairs(y)
frs[i] = yi + ri frs[i] = yi + _cycle(rib,i)
end end
frs frs
end end
@ -414,80 +432,7 @@ xlims(sp_idx::Int = 1) = xlims(current(), sp_idx)
ylims(sp_idx::Int = 1) = ylims(current(), sp_idx) ylims(sp_idx::Int = 1) = ylims(current(), sp_idx)
zlims(sp_idx::Int = 1) = zlims(current(), sp_idx) zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
# These functions return an operator for use in `get_clims(::Seres, op)` iscontour(series::Series) = series[:seriestype] in (:contour, :contour3d)
process_clims(lims::NTuple{2,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ignorenan_extrema
process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
# don't specialize on ::Function otherwise python functions won't work
process_clims(f) = f
function get_clims(sp::Subplot, op=process_clims(sp[:clims]))
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims]))
zmin, zmax = if series[:colorbar_entry]
get_clims(sp, op)
else
get_clims(series, op)
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
"""
function get_clims(series::Series, op=ignorenan_extrema)
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, op(vals.surf)...)
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(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
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap,:surface) ||
any(series[z] !== nothing for z [:marker_z,:line_z,:fill_z])
cbar_gradient
else
nothing
end
end
hascolorbar(series::Series) = colorbar_style(series) !== nothing
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
iscontour(series::Series) = series[:seriestype] == :contour
isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing
function contour_levels(series::Series, clims) function contour_levels(series::Series, clims)
@ -583,20 +528,7 @@ function get_markerstrokewidth(series, i::Int = 1)
_cycle(series[:markerstrokewidth], i) _cycle(series[:markerstrokewidth], i)
end end
function has_attribute_segments(series::Series) const _segmenting_vector_attributes = (
# we want to check if a series needs to be split into segments just because
# of its attributes
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
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, :seriescolor,
:seriesalpha, :seriesalpha,
:linecolor, :linecolor,
@ -611,10 +543,19 @@ function has_attribute_segments(series::Series)
:markerstrokecolor, :markerstrokecolor,
:markerstrokealpha, :markerstrokealpha,
:markerstrokewidth, :markerstrokewidth,
] :markershape,
) || any( )
typeof(series[attr]) <: AbstractArray for attr in (:line_z, :fill_z, :marker_z)
) const _segmenting_array_attributes = (:line_z, :fill_z, :marker_z)
function has_attribute_segments(series::Series)
# we want to check if a series needs to be split into segments just because
# of its attributes
series[:seriestype] == :shape && return false
# check relevant attributes if they have multiple inputs
return any(series[attr] isa AbstractVector && length(series[attr]) > 1
for attr in _segmenting_vector_attributes
) || any(series[attr] isa AbstractArray for attr in _segmenting_array_attributes)
end end
function get_aspect_ratio(sp) function get_aspect_ratio(sp)
@ -983,7 +924,7 @@ px2inch(px::Real) = float(px / PX_PER_INCH)
inch2mm(inches::Real) = float(inches * MM_PER_INCH) inch2mm(inches::Real) = float(inches * MM_PER_INCH)
mm2inch(mm::Real) = float(mm / MM_PER_INCH) mm2inch(mm::Real) = float(mm / MM_PER_INCH)
px2mm(px::Real) = float(px * MM_PER_PX) px2mm(px::Real) = float(px * MM_PER_PX)
mm2px(mm::Real) = float(px / MM_PER_PX) mm2px(mm::Real) = float(mm / MM_PER_PX)
"Smallest x in plot" "Smallest x in plot"
@ -998,54 +939,72 @@ ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
# --------------------------------------------------------------- # ---------------------------------------------------------------
# get fonts from objects: # get fonts from objects:
titlefont(sp::Subplot) = font( plottitlefont(p::Plot) = font(;
sp[:titlefontfamily], family = p[:plot_titlefontfamily],
sp[:titlefontsize], pointsize = p[:plot_titlefontsize],
sp[:titlefontvalign], valign = p[:plot_titlefontvalign],
sp[:titlefonthalign], halign = p[:plot_titlefonthalign],
sp[:titlefontrotation], rotation = p[:plot_titlefontrotation],
sp[:titlefontcolor], color = p[:plot_titlefontcolor],
) )
legendfont(sp::Subplot) = font( colorbartitlefont(sp::Subplot) = font(;
sp[:legendfontfamily], family = sp[:colorbar_titlefontfamily],
sp[:legendfontsize], pointsize = sp[:colorbar_titlefontsize],
sp[:legendfontvalign], valign = sp[:colorbar_titlefontvalign],
sp[:legendfonthalign], halign = sp[:colorbar_titlefonthalign],
sp[:legendfontrotation], rotation = sp[:colorbar_titlefontrotation],
sp[:legendfontcolor], color = sp[:colorbar_titlefontcolor],
) )
legendtitlefont(sp::Subplot) = font( titlefont(sp::Subplot) = font(;
sp[:legendtitlefontfamily], family = sp[:titlefontfamily],
sp[:legendtitlefontsize], pointsize = sp[:titlefontsize],
sp[:legendtitlefontvalign], valign = sp[:titlefontvalign],
sp[:legendtitlefonthalign], halign = sp[:titlefonthalign],
sp[:legendtitlefontrotation], rotation = sp[:titlefontrotation],
sp[:legendtitlefontcolor], color = sp[:titlefontcolor],
) )
tickfont(ax::Axis) = font( legendfont(sp::Subplot) = font(;
ax[:tickfontfamily], family = sp[:legendfontfamily],
ax[:tickfontsize], pointsize = sp[:legendfontsize],
ax[:tickfontvalign], valign = sp[:legendfontvalign],
ax[:tickfonthalign], halign = sp[:legendfonthalign],
ax[:tickfontrotation], rotation = sp[:legendfontrotation],
ax[:tickfontcolor], color = sp[:legendfontcolor],
) )
guidefont(ax::Axis) = font( legendtitlefont(sp::Subplot) = font(;
ax[:guidefontfamily], family = sp[:legendtitlefontfamily],
ax[:guidefontsize], pointsize = sp[:legendtitlefontsize],
ax[:guidefontvalign], valign = sp[:legendtitlefontvalign],
ax[:guidefonthalign], halign = sp[:legendtitlefonthalign],
ax[:guidefontrotation], rotation = sp[:legendtitlefontrotation],
ax[:guidefontcolor], color = sp[:legendtitlefontcolor],
)
tickfont(ax::Axis) = font(;
family = ax[:tickfontfamily],
pointsize = ax[:tickfontsize],
valign = ax[:tickfontvalign],
halign = ax[:tickfonthalign],
rotation = ax[:tickfontrotation],
color = ax[:tickfontcolor],
)
guidefont(ax::Axis) = font(;
family = ax[:guidefontfamily],
pointsize = ax[:guidefontsize],
valign = ax[:guidefontvalign],
halign = ax[:guidefonthalign],
rotation = ax[:guidefontrotation],
color = ax[:guidefontcolor],
) )
# --------------------------------------------------------------- # ---------------------------------------------------------------
# converts unicode scientific notation unsupported by pgfplots and gr # converts unicode scientific notation, as returned by Showoff,
# into a format that works # to a tex-like format (supported by gr, pyplot, and pgfplots).
function convert_sci_unicode(label::AbstractString) function convert_sci_unicode(label::AbstractString)
unicode_dict = Dict( unicode_dict = Dict(
@ -1074,10 +1033,21 @@ end
function straightline_data(series, expansion_factor = 1) function straightline_data(series, expansion_factor = 1)
sp = series[:subplot] sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp)) xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
x, y = series[:x], series[:y]
# handle axes scales
xscale = sp[:xaxis][:scale]
xf = RecipesPipeline.scale_func(xscale)
xinvf = RecipesPipeline.inverse_scale_func(xscale)
yscale = sp[:yaxis][:scale]
yf = RecipesPipeline.scale_func(yscale)
yinvf = RecipesPipeline.inverse_scale_func(yscale)
xl, yl = xf.(xl), yf.(yl)
x, y = xf.(series[:x]), yf.(series[:y])
n = length(x) n = length(x)
if n == 2
return straightline_data(xl, yl, x, y, expansion_factor) xdata, ydata = if n == 2
straightline_data(xl, yl, x, y, expansion_factor)
else else
k, r = divrem(n, 3) k, r = divrem(n, 3)
if r == 0 if r == 0
@ -1086,11 +1056,13 @@ function straightline_data(series, expansion_factor = 1)
inds = (3 * i - 2):(3 * i - 1) inds = (3 * i - 2):(3 * i - 1)
xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds], expansion_factor) xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds], expansion_factor)
end end
return xdata, ydata xdata, ydata
else else
error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n") error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n")
end end
end end
return xinvf.(xdata), yinvf.(ydata)
end end
function straightline_data(xl, yl, x, y, expansion_factor = 1) function straightline_data(xl, yl, x, y, expansion_factor = 1)
@ -1122,20 +1094,28 @@ end
function shape_data(series, expansion_factor = 1) function shape_data(series, expansion_factor = 1)
sp = series[:subplot] sp = series[:subplot]
xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp)) xl, yl = isvertical(series) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp))
# handle axes scales
xscale = sp[:xaxis][:scale]
xf = RecipesPipeline.scale_func(xscale)
xinvf = RecipesPipeline.inverse_scale_func(xscale)
yscale = sp[:yaxis][:scale]
yf = RecipesPipeline.scale_func(yscale)
yinvf = RecipesPipeline.inverse_scale_func(yscale)
x, y = copy(series[:x]), copy(series[:y]) x, y = copy(series[:x]), copy(series[:y])
factor = 100
for i in eachindex(x) for i in eachindex(x)
if x[i] == -Inf if x[i] == -Inf
x[i] = xl[1] - expansion_factor * (xl[2] - xl[1]) x[i] = xinvf(xf(xl[1]) - expansion_factor * (xf(xl[2]) - xf(xl[1])))
elseif x[i] == Inf elseif x[i] == Inf
x[i] = xl[2] + expansion_factor * (xl[2] - xl[1]) x[i] = xinvf(xf(xl[2]) + expansion_factor * (xf(xl[2]) - xf(xl[1])))
end end
end end
for i in eachindex(y) for i in eachindex(y)
if y[i] == -Inf if y[i] == -Inf
y[i] = yl[1] - expansion_factor * (yl[2] - yl[1]) y[i] = yinvf(yf(yl[1]) - expansion_factor * (yf(yl[2]) - yf(yl[1])))
elseif y[i] == Inf elseif y[i] == Inf
y[i] = yl[2] + expansion_factor * (yl[2] - yl[1]) y[i] = yinvf(yf(yl[2]) + expansion_factor * (yf(yl[2]) - yf(yl[1])))
end end
end end
return x, y return x, y

View File

@ -1,15 +1,36 @@
import Plots._current_plots_version import Plots._current_plots_version
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = !is_ci(), sigma = [1,1], tol = 1e-2) # replace `f(args...)` with `f(rng, args...)` for `f ∈ (rand, randn)`
function replace_rand!(ex) end
function replace_rand!(ex::Expr)
for arg in ex.args
replace_rand!(arg)
end
if ex.head === :call && ex.args[1] (:rand, :randn)
pushfirst!(ex.args, ex.args[1])
ex.args[2] = :rng
end
end
function fix_rand!(ex)
replace_rand!(ex)
pushfirst!(ex.args[1].args, :(rng = StableRNG(1234)))
end
function image_comparison_tests(
pkg::Symbol,
idx::Int;
debug = false,
popup = !is_ci(),
sigma = [1, 1],
tol = 1e-2,
)
Plots._debugMode.on = debug Plots._debugMode.on = debug
example = Plots._examples[idx] example = Plots._examples[idx]
Plots.theme(:default) Plots.theme(:default)
@info("Testing plot: $pkg:$idx:$(example.header)") @info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg) backend(pkg)
backend() backend()
default(size=(500,300)) default(size = (500, 300))
# ensure consistent results
Random.seed!(1234)
fn = "ref$idx.png" fn = "ref$idx.png"
reffn = reference_file(pkg, idx, _current_plots_version) reffn = reference_file(pkg, idx, _current_plots_version)
@ -19,25 +40,29 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = !i
func = (fn, idx) -> begin func = (fn, idx) -> begin
expr = Expr(:block) expr = Expr(:block)
append!(expr.args, example.exprs) append!(expr.args, example.exprs)
fix_rand!(expr)
eval(expr) eval(expr)
png(fn) png(fn)
end end
# the test # the test
vtest = VisualTest(func, reffn, idx) vtest = VisualTest(func, reffn, idx)
test_images(vtest, popup=popup, sigma=sigma, tol=tol, newfn = newfn) test_images(vtest, popup = popup, sigma = sigma, tol = tol, newfn = newfn)
end end
function image_comparison_facts(pkg::Symbol; function image_comparison_facts(
pkg::Symbol;
skip = [], # skip these examples (int index) skip = [], # skip these examples (int index)
only = nothing, # limit to these examples (int index) only = nothing, # limit to these examples (int index)
debug = false, # print debug information? debug = false, # print debug information?
sigma = [1,1], # number of pixels to "blur" sigma = [1, 1], # number of pixels to "blur"
tol = 1e-2) # acceptable error (percent) tol = 1e-2,
for i in 1:length(Plots._examples) ) # acceptable error (percent)
for i = 1:length(Plots._examples)
i in skip && continue 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 @test image_comparison_tests(pkg, i, debug = debug, sigma = sigma, tol = tol) |>
success == true
end end
end end
end end

60
test/integration_dates.jl Normal file
View File

@ -0,0 +1,60 @@
using Plots, Test, Dates
@testset "Limits" begin
y=[1.0*i*i for i in 1:10]
x=[Date(2019,11,i) for i in 1:10]
rx=[x[3],x[5]]
p = plot(x,y, widen = false)
vspan!(p, rx, label="", alpha=0.2)
ref_ylims = (y[1], y[end])
ref_xlims = (x[1].instant.periods.value, x[end].instant.periods.value)
@test Plots.ylims(p) == ref_ylims
@test Plots.xlims(p) == ref_xlims
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
@static if haskey(ENV, "APPVEYOR")
@info "Skipping display tests on AppVeyor"
else
@test isa(display(p), Nothing) == true
closeall()
end
end # testset
@testset "Date xlims" begin
y=[1.0*i*i for i in 1:10]
x=[Date(2019,11,i) for i in 1:10]
span = (Date(2019,10,31), Date(2019,11,11))
ref_xlims = map(date->date.instant.periods.value, span)
p = plot(x,y, xlims=span, widen = false)
@test Plots.xlims(p) == ref_xlims
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
@static if haskey(ENV, "APPVEYOR")
@info "Skipping display tests on AppVeyor"
else
@test isa(display(p), Nothing) == true
closeall()
end
end # testset
@testset "DateTime xlims" begin
y=[1.0*i*i for i in 1:10]
x=[DateTime(2019,11,i,11) for i in 1:10]
span = (DateTime(2019,10,31,11,59,59), DateTime(2019,11,11,12,01,15))
ref_xlims = map(date->date.instant.periods.value, span)
p = plot(x,y, xlims=span, widen = false)
@test Plots.xlims(p) == ref_xlims
#@static if (haskey(ENV, "APPVEYOR") || haskey(ENV, "CI"))
@static if haskey(ENV, "APPVEYOR")
@info "Skipping display tests on AppVeyor"
else
@test isa(display(p), Nothing) == true
closeall()
end
end # testset

View File

@ -1,14 +1,41 @@
using Plots: guidefont, series_annotations
import ImageMagick import ImageMagick
using VisualRegressionTests using VisualRegressionTests
using Plots using Plots
using Random using Random
using StableRNGs
using Test using Test
using TestImages
using FileIO using FileIO
using Gtk using Gtk
using LibGit2 using LibGit2
using GeometryTypes import GeometryBasics
using Dates using Dates
using RecipesBase
@testset "Plotly standalone" begin
@test_nowarn Plots._init_ijulia_plotting()
@test Plots.plotly_local_file_path[] === nothing
temp = Plots.use_local_dependencies[]
withenv("PLOTS_HOST_DEPENDENCY_LOCAL" => true) do
Plots.__init__()
@test Plots.plotly_local_file_path[] isa String
@test isfile(Plots.plotly_local_file_path[])
@test Plots.use_local_dependencies[] = true
@test_nowarn Plots._init_ijulia_plotting()
end
Plots.plotly_local_file_path[] = nothing
Plots.use_local_dependencies[] = temp
end # testset
include("test_defaults.jl")
include("test_axes.jl")
include("test_axis_letter.jl")
include("test_components.jl")
include("test_shorthands.jl")
include("integration_dates.jl")
include("test_recipes.jl")
include("test_hdf5plots.jl") include("test_hdf5plots.jl")
include("test_pgfplotsx.jl") include("test_pgfplotsx.jl")
@ -17,7 +44,7 @@ reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImag
function reference_file(backend, i, version) function reference_file(backend, i, version)
refdir = reference_dir("Plots", string(backend)) refdir = reference_dir("Plots", string(backend))
fn = "ref$i.png" fn = "ref$i.png"
versions = sort(VersionNumber.(readdir(refdir)), rev = true) versions = sort(VersionNumber.(readdir(refdir)), rev=true)
reffn = joinpath(refdir, string(version), fn) reffn = joinpath(refdir, string(version), fn)
for v in versions for v in versions
@ -43,27 +70,27 @@ include("imgcomp.jl")
Random.seed!(1234) Random.seed!(1234)
default(show=false, reuse=true) default(show=false, reuse=true)
is_ci() = get(ENV, "CI", "false") == "true" is_ci() = get(ENV, "CI", "false") == "true"
img_tol = is_ci() ? 1e-2 : Sys.islinux() ? 1e-3 : 0.1 const IMG_TOL = VERSION < v"1.4" && Sys.iswindows() ? 1e-1 : is_ci() ? 1e-2 : 1e-3
## Uncomment the following lines to update reference images for different backends ## Uncomment the following lines to update reference images for different backends
# @testset "GR" begin # @testset "GR" begin
# image_comparison_facts(:gr, tol=img_tol, skip = Plots._backend_skips[:gr]) # image_comparison_facts(:gr, tol=IMG_TOL, skip = Plots._backend_skips[:gr])
# end # end
# #
# plotly() # plotly()
# @testset "Plotly" begin # @testset "Plotly" begin
# image_comparison_facts(:plotly, tol=img_tol, skip = Plots._backend_skips[:plotlyjs]) # image_comparison_facts(:plotly, tol=IMG_TOL, skip = Plots._backend_skips[:plotlyjs])
# end # end
# #
# pyplot() # pyplot()
# @testset "PyPlot" begin # @testset "PyPlot" begin
# image_comparison_facts(:pyplot, tol=img_tol, skip = Plots._backend_skips[:pyplot]) # image_comparison_facts(:pyplot, tol=IMG_TOL, skip = Plots._backend_skips[:pyplot])
# end # end
# #
# pgfplotsx() # pgfplotsx()
# @testset "PGFPlotsX" begin # @testset "PGFPlotsX" begin
# image_comparison_facts(:pgfplotsx, tol=img_tol, skip = Plots._backend_skips[:pgfplotsx]) # image_comparison_facts(:pgfplotsx, tol=IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
# end # end
# 10 Histogram2D # 10 Histogram2D
@ -81,7 +108,7 @@ img_tol = is_ci() ? 1e-2 : Sys.islinux() ? 1e-3 : 0.1
@static if haskey(ENV, "APPVEYOR") @static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor" @info "Skipping GR image comparison tests on AppVeyor"
else else
image_comparison_facts(:gr, tol=img_tol, skip = Plots._backend_skips[:gr]) image_comparison_facts(:gr, tol=IMG_TOL, skip=Plots._backend_skips[:gr])
end end
end end
@ -107,12 +134,21 @@ img_tol = is_ci() ? 1e-2 : Sys.islinux() ? 1e-3 : 0.1
@test isa(p, Plots.Plot) == true @test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true @test isa(display(p), Nothing) == true
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4]) p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))]) annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
hline!(p, [3.1]) hline!(p, [3.1])
@test isa(p, Plots.Plot) == true @test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true @test isa(display(p), Nothing) == true
end end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test isa(p, Plots.Plot) == true
@test_broken isa(display(p), Nothing) == true
end
end end
@testset "Axes" begin @testset "Axes" begin
@ -121,27 +157,42 @@ end
@test typeof(axis) == Plots.Axis @test typeof(axis) == Plots.Axis
@test Plots.discrete_value!(axis, "HI") == (0.5, 1) @test Plots.discrete_value!(axis, "HI") == (0.5, 1)
@test Plots.discrete_value!(axis, :yo) == (1.5, 2) @test Plots.discrete_value!(axis, :yo) == (1.5, 2)
@test Plots.ignorenan_extrema(axis) == (0.5,1.5) @test Plots.ignorenan_extrema(axis) == (0.5, 1.5)
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1) @test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i=1:5]) Plots.discrete_value!(axis, ["x$i" for i = 1:5])
Plots.discrete_value!(axis, ["x$i" for i=0:2]) Plots.discrete_value!(axis, ["x$i" for i = 0:2])
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5) @test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
end end
@testset "NoFail" begin @testset "NoFail" begin
#ensure backend with tested display
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
@testset "Plot" begin
plots = [histogram([1, 0, 0, 0, 0, 0]), plots = [histogram([1, 0, 0, 0, 0, 0]),
plot([missing]), plot([missing]),
plot([missing, missing]),
plot(fill(missing, 10)),
plot([missing; 1:4]), plot([missing; 1:4]),
plot([fill(missing,10); 1:4]), plot([fill(missing, 10); 1:4]),
plot([1 1; 1 missing]), plot([1 1; 1 missing]),
plot(["a" "b"; missing "d"], [1 2; 3 4])] plot(["a" "b"; missing "d"], [1 2; 3 4])]
for plt in plots for plt in plots
display(plt) display(plt)
end end
@test_nowarn plot(x->x^2,0,2) @test_nowarn plot(x -> x^2, 0, 2)
end
@testset "Bar" begin
p = bar([3,2,1], [1,2,3]);
@test isa(p, Plots.Plot)
@test isa(display(p), Nothing) == true
end
end end
@testset "EmptyAnim" begin @testset "EmptyAnim" begin
anim = @animate for i in [] anim = @animate for i in []
end end
@ -149,16 +200,10 @@ end
@test_throws ArgumentError gif(anim) @test_throws ArgumentError gif(anim)
end end
@testset "Segments" begin @testset "NaN-separated Segments" begin
function segments(args...) segments(args...) = collect(iter_segments(args...))
segs = UnitRange{Int}[]
for seg in iter_segments(args...)
push!(segs,seg)
end
segs
end
nan10 = fill(NaN,10) nan10 = fill(NaN, 10)
@test segments(11:20) == [1:10] @test segments(11:20) == [1:10]
@test segments([NaN]) == [] @test segments([NaN]) == []
@test segments(nan10) == [] @test segments(nan10) == []
@ -170,12 +215,17 @@ end
end end
@testset "Utils" begin @testset "Utils" begin
zipped = ([(1,2)], [("a","b")], [(1,"a"),(2,"b")], zipped = ([(1, 2)], [("a", "b")], [(1, "a"),(2, "b")],
[(1,2),(3,4)], [(1,2,3),(3,4,5)], [(1,2,3,4),(3,4,5,6)], [(1, 2),(3, 4)], [(1, 2, 3),(3, 4, 5)], [(1, 2, 3, 4),(3, 4, 5, 6)],
[(1,2.0),(missing,missing)], [(1,missing),(missing,"a")], [(1, 2.0),(missing, missing)], [(1, missing),(missing, "a")],
[(missing,missing)], [(missing,missing,missing),("a","b","c")]) [(missing, missing)], [(missing, missing, missing),("a", "b", "c")])
for z in zipped for z in zipped
@test isequal(collect(zip(Plots.unzip(z)...)), z) @test isequal(collect(zip(Plots.unzip(z)...)), z)
@test isequal(collect(zip(Plots.unzip(GeometryTypes.Point.(z))...)), z) @test isequal(collect(zip(Plots.unzip(GeometryBasics.Point.(z))...)), z)
end end
op1 = Plots.process_clims((1.0, 2.0))
op2 = Plots.process_clims((1, 2.0))
data = randn(100, 100)
@test op1(data) == op2(data)
@test Plots.process_clims(nothing) == Plots.process_clims(missing) == Plots.process_clims(:auto)
end end

65
test/test_axes.jl Normal file
View File

@ -0,0 +1,65 @@
using Plots, Test
@testset "Showaxis" begin
for value in Plots._allShowaxisArgs
@test plot(1:5, showaxis = value)[1][:yaxis][:showaxis] isa Bool
end
@test plot(1:5, showaxis = :y)[1][:yaxis][:showaxis] == true
@test plot(1:5, showaxis = :y)[1][:xaxis][:showaxis] == false
end
@testset "Magic axis" begin
@test plot(1, axis=nothing)[1][:xaxis][:ticks] == []
@test plot(1, axis=nothing)[1][:yaxis][:ticks] == []
end # testset
@testset "Categorical ticks" begin
p1 = plot('A':'M', 1:13)
p2 = plot('A':'Z', 1:26)
p3 = plot('A':'Z', 1:26, ticks = :all)
@test Plots.get_ticks(p1[1], p1[1][:xaxis])[2] == string.('A':'M')
@test Plots.get_ticks(p2[1], p2[1][:xaxis])[2] == string.('C':3:'Z')
@test Plots.get_ticks(p3[1], p3[1][:xaxis])[2] == string.('A':'Z')
end
@testset "Ticks getter functions" begin
ticks1 = ([1,2,3], ("a","b","c"))
ticks2 = ([4,5], ("e","f"))
p1 = plot(1:5, 1:5, 1:5, xticks=ticks1, yticks=ticks1, zticks=ticks1)
p2 = plot(1:5, 1:5, 1:5, xticks=ticks2, yticks=ticks2, zticks=ticks2)
p = plot(p1, p2)
@test xticks(p) == yticks(p) == zticks(p) == [ticks1, ticks2]
@test xticks(p[1]) == yticks(p[1]) == zticks(p[1]) == ticks1
end
@testset "Axis limits" begin
pl = plot(1:5, xlims=:symmetric, widen = false)
@test Plots.xlims(pl) == (-5, 5)
pl = plot(1:3)
@test Plots.xlims(pl) == Plots.widen(1,3)
pl = plot([1.05,2.0,2.95], ylims=:round)
@test Plots.ylims(pl) == (1, 3)
pl = plot(1:3, xlims=(1,5))
@test Plots.xlims(pl) == (1, 5)
pl = plot(1:3, xlims=(1,5), widen=true)
@test Plots.xlims(pl) == Plots.widen(1, 5)
end
@testset "3D Axis" begin
ql = quiver([1, 2], [2, 1], [3, 4], quiver = ([1, -1], [0, 0], [1, -0.5]), arrow=true)
@test ql[1][:projection] == "3d"
end
@testset "twinx" begin
pl = plot(1:10, margin = 2Plots.cm)
twpl = twinx(pl)
pl! = plot!(twinx(), -(1:10))
@test twpl[:right_margin] == 2Plots.cm
@test twpl[:left_margin] == 2Plots.cm
@test twpl[:top_margin] == 2Plots.cm
@test twpl[:bottom_margin] == 2Plots.cm
end

25
test/test_axis_letter.jl Normal file
View File

@ -0,0 +1,25 @@
using Plots, Test
@testset "axis letter" begin
using Plots, RecipesBase
# a custom type for dispacthing the axis-letter-testing recipe
struct MyType <: Number
val::Float64
end
value(m::MyType) = m.val
data = MyType.(sort(randn(20)))
# A recipe that puts the axis letter in the title
@recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:MyType}
title --> string(plotattributes[:letter])
value.(m)
end
@testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist], o in [:vertical, :horizontal]
@test f(data, orientation=o).subplots[1].attr[:title] == (o == :vertical ? "x" : "y")
end
@testset "$f" for f in [hline, hspan]
@test f(data).subplots[1].attr[:title] == "y"
end
@testset "$f" for f in [vline, vspan]
@test f(data).subplots[1].attr[:title] == "x"
end
end

151
test/test_components.jl Normal file
View File

@ -0,0 +1,151 @@
using Plots, Test
@testset "Shapes" begin
@testset "Type" begin
square = Shape([(0, 0.0), (1, 0.0), (1, 1.0), (0, 1.0)])
@test isa(square, Shape{Int64,Float64})
@test coords(square) isa Tuple{Vector{S},Vector{T}} where {T,S}
end
@testset "Copy" begin
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
square2 = Shape(square)
@test square2.x == square.x
@test square2.y == square.y
end
@testset "Center" begin
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
@test Plots.center(square) == (0.5, 0.5)
end
@testset "Translate" begin
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
squareUp = Shape([(0, 1), (1, 1), (1, 2), (0, 2)])
squareUpRight = Shape([(1, 1), (2, 1), (2, 2), (1, 2)])
@test Plots.translate(square, 0, 1).x == squareUp.x
@test Plots.translate(square, 0, 1).y == squareUp.y
@test Plots.center(translate!(square, 1)) == (1.5, 1.5)
end
@testset "Rotate" begin
# 2 radians rotation matrix
R2 = [cos(2) sin(2); -sin(2) cos(2)]
coords = [0 0; 1 0; 1 1; 0 1]'
coordsRotated2 = R2 * (coords .- 0.5) .+ 0.5
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
# make a new, rotated square
square2 = Plots.rotate(square, -2)
@test square2.x coordsRotated2[1, :]
@test square2.y coordsRotated2[2, :]
# unrotate the new square in place
rotate!(square2, 2)
@test square2.x coords[1, :]
@test square2.y coords[2, :]
end
@testset "Plot" begin
ang = range(0, 2π, length = 60)
ellipse(x, y, w, h) = Shape(w * sin.(ang) .+ x, h * cos.(ang) .+ y)
myshapes = [ellipse(x, rand(), rand(), rand()) for x = 1:4]
@test coords(myshapes) isa Tuple{Vector{Vector{S}},Vector{Vector{T}}} where {T,S}
local p
@test_nowarn p = plot(myshapes)
@test p[1][1][:seriestype] == :shape
end
end
@testset "Brush" begin
@testset "Colors" begin
baseline = brush(1, RGB(0, 0, 0))
@test brush(:black) == baseline
@test brush("black") == baseline
end
@testset "Weight" begin
@test brush(10).size == 10
@test brush(0.1).size == 1
end
@testset "Alpha" begin
@test brush(0.4).alpha == 0.4
@test brush(20).alpha == nothing
end
@testset "Bad Argument" begin
# using test_logs because test_warn seems to not work anymore
@test_logs (:warn, "Unused brush arg: nothing (Nothing)") begin
brush(nothing)
end
end
end
@testset "Fonts" begin
@testset "Scaling" begin
sizesToCheck = [
:titlefontsize,
:legendfontsize,
:legendtitlefontsize,
:xtickfontsize,
:ytickfontsize,
:ztickfontsize,
:xguidefontsize,
:yguidefontsize,
:zguidefontsize,
]
# get inital font sizes
initialSizes = [Plots.default(s) for s in sizesToCheck]
#scale up font sizes
scalefontsizes(2)
# get inital font sizes
doubledSizes = [Plots.default(s) for s in sizesToCheck]
@test doubledSizes == initialSizes * 2
# reset font sizes
resetfontsizes()
finalSizes = [Plots.default(s) for s in sizesToCheck]
@test finalSizes == initialSizes
end
end
@testset "Series Annotations" begin
square = Shape([(0, 0), (1, 0), (1, 1), (0, 1)])
@test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin
p = plot(
[1, 2, 3],
series_annotations = (
["a"],
2, # pass a scale factor
(1, 4), # pass two scale factors (overwrites first one)
square, # pass a shape
font(:courier), # pass an annotation font
:triangle, # pass an incorrect argument
),
)
sa = p.series_list[1].plotattributes[:series_annotations]
@test sa.strs == ["a"]
@test sa.font.family == "courier"
@test sa.baseshape == square
@test sa.scalefactor == (1, 4)
end
spl = scatter(
4.53 .* [1/1 1/2 1/3 1/4 1/5],
[0 0 0 0 0],
layout = (5, 1),
ylims = (-1.1, 1.1),
xlims = (0, 5),
series_annotations = permutedims([["1/1"],["1/2"],["1/3"],["1/4"],["1/5"]]),
)
@test spl.series_list[1].plotattributes[:series_annotations].strs == ["1/1"]
@test spl.series_list[2].plotattributes[:series_annotations].strs == ["1/2"]
@test spl.series_list[3].plotattributes[:series_annotations].strs == ["1/3"]
@test spl.series_list[4].plotattributes[:series_annotations].strs == ["1/4"]
@test spl.series_list[5].plotattributes[:series_annotations].strs == ["1/5"]
end

13
test/test_defaults.jl Normal file
View File

@ -0,0 +1,13 @@
using Plots, Test
const PLOTS_DEFAULTS = Dict(:theme => :wong2, :fontfamily => :palantino)
Plots.__init__()
@testset "Loading theme" begin
pl = plot(1:5)
@test pl[1][1][:seriescolor] == RGBA(colorant"black")
@test guidefont(pl[1][:xaxis]).family == "palantino"
end
empty!(PLOTS_DEFAULTS)
Plots.__init__()

View File

@ -21,12 +21,12 @@ end
@test !haskey(axis.contents[1].options.dict, "fill") @test !haskey(axis.contents[1].options.dict, "fill")
@testset "Legends" begin @testset "Legends" begin
legends_plot = plot( rand(5,2), lab = ["1" ""] ) legends_plot = plot(rand(5, 2), lab = ["1" ""])
scatter!(legends_plot, rand(5) ) scatter!(legends_plot, rand(5))
Plots._update_plot_object(legends_plot) Plots._update_plot_object(legends_plot)
axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents
leg_entries = filter( x -> x isa PGFPlotsX.LegendEntry, axis_contents ) leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter( x -> x isa PGFPlotsX.Plot, axis_contents ) series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2 @test length(leg_entries) == 2
@test !haskey(series[1].options.dict, "forget plot") @test !haskey(series[1].options.dict, "forget plot")
@test haskey(series[2].options.dict, "forget plot") @test haskey(series[2].options.dict, "forget plot")
@ -91,8 +91,8 @@ end
scatter!(pic, rand(100), markersize = 6, c = :orange) scatter!(pic, rand(100), markersize = 6, c = :orange)
Plots._update_plot_object(pic) Plots._update_plot_object(pic)
axis_contents = Plots.pgfx_axes(pic.o)[1].contents axis_contents = Plots.pgfx_axes(pic.o)[1].contents
leg_entries = filter( x -> x isa PGFPlotsX.LegendEntry, axis_contents ) leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter( x -> x isa PGFPlotsX.Plot, axis_contents ) series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2 @test length(leg_entries) == 2
@test length(series) == 4 @test length(series) == 4
@test haskey(series[1].options.dict, "forget plot") @test haskey(series[1].options.dict, "forget plot")
@ -106,7 +106,7 @@ end
end), Plots._shape_keys) end), Plots._shape_keys)
markers = reshape(markers, 1, length(markers)) markers = reshape(markers, 1, length(markers))
n = length(markers) n = length(markers)
x = (range(0, stop = 10, length = n + 2))[2:(end - 1)] x = (range(0, stop = 10, length = n + 2))[2:(end-1)]
y = repeat(reshape(reverse(x), 1, :), n, 1) y = repeat(reshape(reverse(x), 1, :), n, 1)
scatter( scatter(
x, x,
@ -231,7 +231,7 @@ end
# TODO: support :semi # TODO: support :semi
end # testset end # testset
@testset "Quiver" begin @testset "Quiver" begin
x = (-2pi):0.2:(2 * pi) x = (-2pi):0.2:(2*pi)
y = sin.(x) y = sin.(x)
u = ones(length(x)) u = ones(length(x))
@ -255,7 +255,7 @@ end
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 1 @test length(nodes) == 1
mktempdir() do path mktempdir() do path
file_path =joinpath(path,"annotations.tex") file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path) @test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io open(file_path) do io
lines = readlines(io) lines = readlines(io)
@ -271,7 +271,7 @@ end
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 3 @test length(nodes) == 3
mktempdir() do path mktempdir() do path
file_path =joinpath(path,"annotations.tex") file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path) @test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io open(file_path) do io
lines = readlines(io) lines = readlines(io)
@ -296,12 +296,17 @@ end
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content) nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 9 @test length(nodes) == 9
mktempdir() do path mktempdir() do path
file_path =joinpath(path,"annotations.tex") file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(annotation_plot, file_path) @test_nowarn savefig(annotation_plot, file_path)
open(file_path) do io open(file_path) do io
lines = readlines(io) lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 9 @test count(s -> occursin("node", s), lines) == 9
end end
# test .tikz extension
file_path = joinpath(path, "annotations.tikz")
@test_nowarn savefig(annotation_plot, file_path)
@test_nowarn open(file_path) do io
end
end end
end # testset end # testset
@testset "Ribbon" begin @testset "Ribbon" begin
@ -314,17 +319,35 @@ end
Plots._update_plot_object(ribbon_plot) Plots._update_plot_object(ribbon_plot)
axis = Plots.pgfx_axes(ribbon_plot.o)[1] axis = Plots.pgfx_axes(ribbon_plot.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents) plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 4 @test length(plots) == 3
@test !haskey(plots[1].options.dict, "fill") @test haskey(plots[1].options.dict, "fill")
@test !haskey(plots[2].options.dict, "fill") @test haskey(plots[2].options.dict, "fill")
@test !haskey(plots[3].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 !== nothing
@test ribbon_plot.o.the_plot !== nothing @test ribbon_plot.o.the_plot !== nothing
# mktempdir() do path
# @test_nowarn savefig(ribbon_plot, path*"ribbon.svg")
# end
end # testset end # testset
@testset "Markers and Paths" begin
pl = plot(
5 .- ones(9),
markershape = [:utriangle, :rect],
markersize = 8,
color = [:red, :black],
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 9
end # testset
@testset "Groups and Subplots" begin
group = rand(map((i->begin
"group $(i)"
end), 1:4), 100)
pl = plot(rand(100), layout = @layout([a b; c]), group = group, linetype = [:bar :scatter :steppre], linecolor = :match)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
legend_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis.contents)
@test length(legend_entries) == 2
end
end # testset end # testset
@testset "Extra kwargs" begin @testset "Extra kwargs" begin
@ -334,15 +357,65 @@ end # testset
@test pl[1].attr[:extra_kwargs][:test] == "me" @test pl[1].attr[:extra_kwargs][:test] == "me"
pl = plot(1:5, test = "me", extra_kwargs = :plot) pl = plot(1:5, test = "me", extra_kwargs = :plot)
@test pl.attr[:extra_plot_kwargs][:test] == "me" @test pl.attr[:extra_plot_kwargs][:test] == "me"
pl = plot(1:5, extra_kwargs = Dict(:plot => Dict(:test => "me"), :series => Dict(:and => "me too"))) pl = plot(
1:5,
extra_kwargs = Dict(
:plot => Dict(:test => "me"),
:series => Dict(:and => "me too"),
),
)
@test pl.attr[:extra_plot_kwargs][:test] == "me" @test pl.attr[:extra_plot_kwargs][:test] == "me"
@test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too" @test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too"
pl = plot( pl = plot(
plot(1:5, title="Line"), plot(1:5, title = "Line"),
scatter(1:5, title="Scatter", extra_kwargs=Dict(:subplot=>Dict("axis line shift" => "10pt"))) scatter(
1:5,
title = "Scatter",
extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")),
),
) )
Plots._update_plot_object(pl) Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o) axes = Plots.pgfx_axes(pl.o)
@test !haskey(axes[1].options.dict, "axis line shift") @test !haskey(axes[1].options.dict, "axis line shift")
@test haskey(axes[2].options.dict, "axis line shift") @test haskey(axes[2].options.dict, "axis line shift")
pl = plot(
x -> x,
-1:1;
add = raw"\node at (0,0.5) {\huge hi};",
extra_kwargs = :subplot,
)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
plot!(pl)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
end # testset
@testset "Titlefonts" begin
pl = plot(1:5, title = "Test me", titlefont = (2, :left))
@test pl[1][:title] == "Test me"
@test pl[1][:titlefontsize] == 2
@test pl[1][:titlefonthalign] == :left
Plots._update_plot_object(pl)
ax_opt = Plots.pgfx_axes(pl.o)[1].options
@test ax_opt["title"] == "Test me"
@test(haskey(ax_opt.dict, "title style")) isa Test.Pass
pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left))
@test pl[:plot_title] == "Test me"
@test pl[:plot_titlefontsize] == 2
@test pl[:plot_titlefonthalign] == :left
pl = heatmap(
rand(3, 3),
colorbar_title = "Test me",
colorbar_titlefont = (12, :right),
)
@test pl[1][:colorbar_title] == "Test me"
@test pl[1][:colorbar_titlefontsize] == 12
@test pl[1][:colorbar_titlefonthalign] == :right
end # testset end # testset

49
test/test_recipes.jl Normal file
View File

@ -0,0 +1,49 @@
using Plots, Test
using OffsetArrays
@testset "lens!" begin
pl = plot(1:5)
lens!(pl, [1,2], [1,2], inset = (1, bbox(0.0,0.0,0.2,0.2)), colorbar = false)
@test length(pl.series_list) == 4
@test pl[2][:colorbar] == :none
end # testset
@testset "vline, vspan" begin
vl = vline([1], widen = false)
@test Plots.xlims(vl) == (1,2)
@test Plots.ylims(vl) == (1,2)
vl = vline([1], xlims=(0,2), widen = false)
@test Plots.xlims(vl) == (0,2)
vl = vline([1], ylims=(-3,5), widen = false)
@test Plots.ylims(vl) == (-3,5)
vsp = vspan([1,3], widen = false)
@test Plots.xlims(vsp) == (1,3)
@test Plots.ylims(vsp) == (0,1) # TODO: might be problematic on log-scales
vsp = vspan([1,3], xlims=(-2,5), widen = false)
@test Plots.xlims(vsp) == (-2,5)
vsp = vspan([1,3], ylims=(-2,5), widen = false)
@test Plots.ylims(vsp) == (-2,5)
end # testset
@testset "offset axes" begin
tri = OffsetVector(vcat(1:5, 4:-1:1), 11:19)
sticks = plot(tri, seriestype = :sticks)
@test length(sticks) == 1
end
@testset "framestyle axes" begin
pl = plot(-1:1, -1:1, -1:1)
sp = pl.subplots[1]
defaultret = Plots.axis_drawing_info_3d(sp, :x)
for letter in [:x, :y, :z]
for fr in [:box :semi :origin :zerolines :grid :none]
prevha = UInt64(0)
push!(sp.attr, :framestyle => fr)
ret = Plots.axis_drawing_info_3d(sp, letter)
ha = hash(string(ret))
@test ha != prevha
prevha = ha
end
end
end

48
test/test_shorthands.jl Normal file
View File

@ -0,0 +1,48 @@
using Plots, Test
@testset "Shorthands" begin
@testset "Set Lims" begin
p = plot(rand(10))
xlims!((1,20))
@test xlims(p) == (1,20)
ylims!((-1,1))
@test ylims(p) == (-1,1)
zlims!((-1,1))
@test zlims(p) == (-1,1)
xlims!(-1,11)
@test xlims(p) == (-1,11)
ylims!((-10,10))
@test ylims(p) == (-10,10)
zlims!((-10,10))
@test zlims(p) == (-10,10)
end
@testset "Set Ticks" begin
p = plot([0,2,3,4,5,6,7,8,9,10])
xticks = 2:6
xticks!(xticks)
@test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == xticks
yticks = 0.2:0.1:0.7
yticks!(yticks)
@test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == yticks
xticks = [5,6,7.5]
xlabels = ["a","b","c"]
xticks!(xticks, xlabels)
@test Plots.get_subplot(current(),1).attr[:xaxis][:ticks] == (xticks, xlabels)
yticks = [.5,.6,.75]
ylabels = ["z","y","x"]
yticks!(yticks, ylabels)
@test Plots.get_subplot(current(),1).attr[:yaxis][:ticks] == (yticks, ylabels)
end
end

Binary file not shown.