Compare commits

..

3 Commits

Author SHA1 Message Date
Thomas Breloff
01b9cc92fd remove mkdir call in tests; closes #397 2016-07-22 11:18:47 -04:00
Thomas Breloff
7a650d918b unicodeplots size fix 2016-07-22 09:45:44 -04:00
Thomas Breloff
b6fa4bcda4 plotly ticks fix 2016-07-21 11:01:04 -04:00
107 changed files with 11168 additions and 24350 deletions

View File

@ -1,12 +0,0 @@
always_for_in = true
import_to_using = false
align_pair_arrow = true
align_assignment = true
align_conditional = true
always_use_return = false
conditional_to_if = false
whitespace_in_kwargs = true
remove_extra_newlines = true
whitespace_ops_in_indices = true
short_to_long_function_def = false
annotate_untyped_fields_with_any = false

6
.gitattributes vendored
View File

@ -1,6 +0,0 @@
# 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

@ -1,33 +0,0 @@
---
name: Bug report
about: Create a bug report
title: "[BUG]"
labels: bug
assignees: ''
---
<!-- Please search existing issues to avoid duplicates. -->
## Details
### Backends
This bug occurs on ( insert `x` below )
Backend | yes | no | untested
-------------|-----|-----|---------
gr (default) | | |
pyplot | | |
plotlyjs | | |
pgfplotsx | | |
unicodeplots | | |
inspectdr | | |
gaston | | |
### Versions
Plots.jl version:
Backend version (`]st -m <backend(s)>`):
Output of `versioninfo()`:

View File

@ -1,10 +0,0 @@
---
name: Feature request
about: Suggest a feature or enhancement
title: "[FR]"
labels: feature request
assignees: ''
---
Please search existing issues to avoid duplicates.

View File

@ -1,17 +0,0 @@
name: CompatHelper
on:
schedule:
- cron: '00 00 * * *'
jobs:
CompatHelper:
runs-on: ubuntu-latest
steps:
- name: Pkg.add("CompatHelper")
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
- name: CompatHelper.main()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} # optional
run: julia -e 'using CompatHelper; CompatHelper.main()'

View File

@ -1,108 +0,0 @@
# NOTE: this file should be named 'SnoopCompile.yml', cf github.com/aminya/CompileBot.jl/blob/master/src/CompileBot.jl#L57
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: "nul"
PLOTS_TEST: "true"
runs-on: ${{matrix.os}}
continue-on-error: ${{ matrix.version == '~1.8.0-0' }}
strategy:
fail-fast: false
matrix:
version: # NOTE: the versions below should match those in your botconfig
- '1.6' # ⎤
- '1.7' # |
- '~1.8.0-0' # |
# - 'nightly' # ⎦ <<< keep these versions in sync with deps/SnoopCompile/snoop_bot_config.jl
# ^^^^^^^^^ for 'nightly', see github.com/JuliaPlots/Plots.jl/issues/4079
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: Set Swap Space
uses: pierotofy/set-swap-space@master
with:
swap-size-gb: 10 # required (not enough memory on github actions virtual machine)
- name: Install dependencies
run: |
cat /proc/cpuinfo
cat /proc/meminfo
cat /proc/swaps
free
df -h
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: |
if ! grep -m1 -q 'format: off' artifact/src/precompile_includer.jl; then sed -i '1 i\#! format: off' artifact/src/precompile_includer.jl; fi
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 [skip ci]
title: "[AUTO] Update precompiles [skip ci]"
labels: |
SnoopCompile
no changelog
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,15 +0,0 @@
name: TagBot
on:
issue_comment:
types:
- created
workflow_dispatch:
jobs:
TagBot:
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
runs-on: ubuntu-latest
steps:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ssh: ${{ secrets.TAGBOT_KEY }}

View File

@ -1,31 +0,0 @@
name: benchmarks
on:
pull_request:
jobs:
Benchmark:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: '1.7'
# 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 }}

View File

@ -1,93 +0,0 @@
name: ci
on:
push:
branches:
- master
pull_request:
defaults:
run:
shell: bash
jobs:
CI:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
GKS_ENCODING: "utf8"
GKSwstype: "nul"
name: Julia ${{ matrix.version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.version == 'nightly' }}
strategy:
fail-fast: false
matrix:
version:
- '1.6' # LTS
- '1.7' # latest stable
os:
- ubuntu-latest
- windows-latest
- macos-latest
arch:
- x64
# - x86
include:
- version: 'nightly'
os: ubuntu-latest
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 }}-
# 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
sudo apt-get -y update
sudo apt-get -y install gnuplot poppler-utils texlive-{latex-base,latex-extra,luatex}
sudo fc-cache -vr
# 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")'
# Codecov
- uses: julia-actions/julia-processcoverage@v1
if: startsWith(matrix.os,'ubuntu')
- uses: codecov/codecov-action@v2
if: startsWith(matrix.os,'ubuntu')
with:
file: lcov.info
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,34 +0,0 @@
name: docs
on:
workflow_dispatch:
push:
branches:
- master
tags: '*'
jobs:
Build_docs:
runs-on: ubuntu-latest
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: Build documentation
env:
PYTHON: ""
DOCUMENTER_KEY: ${{secrets.DOCUMENTER_KEY}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
run: bash docs/ci_build.sh

View File

@ -1,54 +0,0 @@
name: format
on:
pull_request:
push:
branches:
- 'master'
jobs:
code-style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
- name: Install dependencies
run: |
using Pkg
Pkg.add([
PackageSpec("JuliaFormatter"),
PackageSpec(url = "https://github.com/tkf/JuliaProjectFormatter.jl.git"),
])
shell: julia --color=yes {0}
- name: Format Julia files
run: |
using JuliaFormatter
format(["src", "test"])
shell: julia --color=yes --compile=min -O0 {0}
- name: suggester / JuliaFormatter
uses: reviewdog/action-suggester@v1
with:
tool_name: JuliaFormatter
fail_on_error: true
# reviewdog/action-suggester not using `cleanup` flag?
- name: Cleanup
if: success() || failure()
run: |
git checkout -- .
git clean --force
shell: bash
- name: Format Julia project files
if: success() || failure()
run: |
using JuliaProjectFormatter
format_projects()
shell: julia --color=yes --compile=min -O0 {0}
- name: suggester / JuliaProjectFormatter
if: success() || failure()
uses: reviewdog/action-suggester@v1
with:
tool_name: JuliaProjectFormatter
fail_on_error: true

View File

@ -1,35 +0,0 @@
name: format
on:
schedule:
- cron: '0 0 1 * *'
jobs:
pr:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install JuliaFormatter and format
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))'
julia -e 'using JuliaFormatter; [format(["src", "test"]) for _ in 1:2]'
git diff --exit-code
- name: Create Pull Request
if: ${{ failure() }}
id: cpr
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Format .jl files [skip ci]"
title: 'Automatic JuliaFormatter.jl run'
branch: auto-juliaformatter-pr
delete-branch: true
labels: formatting, automated pr, no changelog
- name: Check outputs
if: ${{ failure() }}
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

10
.gitignore vendored
View File

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

60
.travis.yml Normal file
View File

@ -0,0 +1,60 @@
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
- linux
- osx
julia:
- release
- nightly
matrix:
allow_failures:
- julia: nightly
# # before install:
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install wkhtmltopdf; fi
# ref: http://askubuntu.com/a/556672 for the wkhtmltopdf apt repository info
sudo: required
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:pov/wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltopdf -V ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltoimage -V ; fi
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@"' | sudo tee /usr/local/bin/wkhtmltopdf.sh >/dev/null
# sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
# # borrowed from Blink.jl's travis file
# matrix:
# include:
# - os: linux
# julia: 0.4
# env: TESTCMD="xvfb-run julia"
# - os: osx
# julia: 0.4
# env: TESTCMD="julia"
notifications:
email: true
# uncomment the following lines to override the default test script
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
- julia test/travis_commands.jl
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
# # - julia -e 'Pkg.clone("https://github.com/JunoLab/Blink.jl.git"); Pkg.build("Blink"); import Blink; Blink.AtomShell.install()'
# # - julia -e 'Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")'
# - julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
#
# # - $TESTCMD -e 'Pkg.test("Plots"; coverage=false)'
# - julia -e 'Pkg.test("Plots"; coverage=false)'
# # - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'

View File

@ -1,722 +0,0 @@
{
"title": "Plots.jl",
"license": "MIT",
"creators": [
{
"affiliation": "Headlands Technologies",
"name": "Tom Breloff"
}
],
"contributors":[
{
"affiliation": "TU Wien",
"name": "Daniel Schwabeneder",
"orcid": "0000-0002-0412-0777",
"type": "ProjectLeader"
},
{
"affiliation": "GLOBE Institute, University of Copenhagen",
"name": "Michael Krabbe Borregaard",
"orcid": "0000-0002-8146-8435",
"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",
"affiliation": "Columbia University",
"orcid": "0000-0001-6055-1291",
"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": "Mosè 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"
},
{
"name": "Jan Thorben Schneider",
"type": "Other"
},
{
"orcid": "0000-0003-4102-2460",
"affiliation": "Alogus Research Corporation",
"name": "Lee Phillips",
"type": "Other"
},
{
"name": "Tom Gillam",
"type": "Other"
},
{
"name": "Steve Leung",
"type": "Other"
},
{
"name": "Xu Zhi-Yuan",
"type": "Other"
}
],
"upload_type": "software"
}

555
NEWS.md
View File

@ -3,562 +3,17 @@
#### notes on release changes, ongoing development, and future planned work #### notes on release changes, ongoing development, and future planned work
## NOTE: this file is deprecated, see the [TagBot](https://github.com/marketplace/actions/julia-tagbot) auto-generated changelogs instead - All new development should target 0.7!
## 0.28.3
- support generalized array interface
- save to pdf, svg and eps in plotlyjs
- fix for clims in line_z
- optimize heatmap logic in gr
## 0.26.3
- fix `vline` with dates
- fix PyPlot logscale bug
- avoid annotation clipping for PyPlot
- allow plotting of Any vectors and 3D plotting again in convertToAnyVector
- specify legend title font in GR and PyPlot
- delete `pushtomaster.sh`
- use `=== nothing`
## 0.26.2
- improve empty animation build error
- fix GR axis flip for heatmaps and images
- fix ribbons specified as tuples
- add Char recipe
- fix Plotly plots with single-element series
- rewrite PlotlyJS backend
## 0.26.1
- handle `Char`s as input data
- fix html saving for Plotly
- expand ~ in paths on UNIX systems
- convertToAnyVector clean-up
- fix color_palette grouping issue
## 0.26.0
- use FFMPEG.jl
- add missing method for convertToAnyVector
## 0.25.3
- add areaplot
- allow missing in z_color arguments
- more general tuple recipe
- stephist logscale improvements
## 0.25.2
- improvements to handle missings
- pyplot: allow setting the color gradient for z values
- document :colorbar_entry
- limit number of automatic bins
- fix ENV['PLOTS_DEFAULT_BACKEND']
- don't let aspect_ratio impact subplot size
- implement arrowstyle for GR
- fix bug in plotly_convert_to_datetime
- improve missing support
- gr: polar heatmaps
- make sure show returns nothing
## 0.25.1
- fix gr_display
## 0.25.0
- Replace StaticArrays with GeometryTypes
- Contour fixes for GR
## 0.24.0
- Update to the new PyCall and PyPlot API
- fix drawing of ticks
- fix y label position with GR
## 0.23.2
- pyplot fixes
- Add option :tex_output_standalone to set the 'include_preamble' argument in the PGFPlots backend.
- fix ticks
- support plotly json mime
- fix image axis limits
- default to radius 0 at center for polar plots
## 0.23.1
- slightly faster load time
- fixed errant MethodError
- fix bar plots with unicodeplots
- better colorbars for contour
- add volume seriestype for GR
- fix passing a tuple to custom ticks
- add vline to pgfplots
- add tex output for pyplot
- better 3d axis labels for GR
## 0.23.0
- compatible with StatPlots -> StatsPlots name shift
- fix histograms for vectors with NaN and Inf
- change gif behaviour (remove cache-busting)
- improved docstrings for shorthands functions
- fix font rotation for pyplot
- fix greyscale images for pyplot
- clamp greyscale images with values outside 0,1
- support keyword argument for font options
- allow vector of markers for pyplot scatter
## 0.22.5
- improve behaviour of plotlyjs backend
## 0.22.4
- Add support for discrete contourf plots with GR
## 0.22.3
- Fix the `showtheme` function
## 0.22.2
- Allow annotations to accept a Tuple instead of the result of a text call (making it possible to specify font characteristics in recipes). E.g. `annotations = (2, 4, ("test", :right, 8, :red))` is the same as `annotations = (2, 4, text("test", :right, 8, :red))`
## 0.22.1
- push PlotsDisplay just after REPLDisplay
## 0.22.0
- deprecate GLVisualize
- allow 1-row and 1-column heatmaps
- add portfoliodecomposition recipe from PlotRecipes
- solve Shape bug
- simplify PyPlot backend installation
- fix wireframe bug in PyPlot
- fix color bug in PyPlot
- minor bug fixes in gr and pyplot
## 0.21.0
- Compatibility with StaticArrays 0.9.0
- Up GR min version to 0.35
- fix :mirror
## 0.20.6
- fixes for PlotDocs.jl
- fix gr axis color argument
- Shapes for inspectdr
- don't load plotly js file by default
## 0.20.5
- fix precompilation issue when depending on Plots
## 0.20.4
- honour `html_output_format` in Juno
## 0.20.3
- implement guide position in gr, pyplot and pgfplots
- inspectdr fixes
- default appveyor
- rudimentary missings support
- deprecation fixes for PGFPlots
## 0.20.0
Many updates, min julia 1.0
- change display type to use PlotsDisplay (fixes Juno integration)
- change all internal uses of `d` to `plotattributes` (no user change)
- change spy implementation to use `scatter` not `heatmap`
- sort x axes when passing a vector of strings as x
- improve performance of marker_z
- update CI to 1.0
- minor depwarn ifixes
- only draw one colorbar with GR
- add colorbar_title to GR and pgfplots
- fix savefig with latexstrings for PyPlot
- fix NamedTuple integration
- don't export `P2` and `P3`
- make it possible to use 2-argument function as argument to marker_z
- make `plotattr` work again
## 0.19.3
- fix some julia 0.7 deprecations
- fix 32-bit OS functionality
## 0.19.2
- several small fixes for 1.0 compatibility
## 0.19.1
- don't broadcast plot_color
## 0.19.0
- Refactor conditional loading to use Requires
- Many fixes for 1.0 compatibility
## 0.18.0
- update minor version to 0.7
## 0.17.4
- fix thickness_scaling for pyplot
## 0.17.3
- Log-scale heatmap edge computation
- Fix size and dpi for GR and PyPlot
- Fix fillrange with line segments on PyPlot and Plotly
- fix flip for heatmap and image on GR
- New attributes for PGFPlots
- Widen axes for most series types and log scales
- Plotly: fix log scale with no ticks
- Fix axis flip on Plotly
- Fix hover and zcolor interaction in Plotly
- WebIO integration for PlotlyJS backend
## 0.17.2
- fix single subplot in plotly
- implement `(xyz)lims = :round`
- PyPlot: fix bg_legend = invisible()
- set fallback tick specification for axes with discrete values
- restructure of show methods
## 0.17.1
- Fix contour for PGFPlots
- 32Bit fix: Int64 -> Int
- Make series of shapes and segments toggle together in Plotly(JS)
- Fix marker arguments
- Fix processing order of series recipes
- Fix Plotly(JS) ribbon
- Contour plots with x,y in grid form on PyPlot
## 0.17.0
- Add GR dependency to make it the default backend
- Improve histogram2d bin estimation
- Allow vector arguments for certain series attributes and support line_z and fill_z on GR, PyPlot, Plotly(JS) and PGFPlots
- Automatic scientific notation for tick labels
- Allow to set the theme in PLOTS_DEFAULTS
- Implement plots_heatmap seriestype providing a Plots recipe for heatmaps
## 0.16.0
- fix 3D plotting in PyPlot
- Infinite objects
## 0.15.1
- fix scientific notation for labels in GR
- fix labels with logscale
- fix image cropping with GR
- fix grouping of annotations
- fix annotations in Plotly
- allow saving notebook with plots as pdf from IJulia
- fix fillrange and ribbon for step recipes
- implement native ticks that respond to zoom
- fix bar plot with one bar
- contour labels and colorbar fixes
- interactive linked axis for PyPlot
- add `NamedTuple` syntax to group with named legend
- use bar recipe in Plotly
- implement categorical ticks
## 0.15.0
- improve resolution of png output of GR with savefig()
- add check for ticks=nothing
- allow transparency in heatmaps
- fix line_z for GR
- fix legendcolor for pyplot
- fix pyplot ignoring alpha values of images
- don't let `abline!` change subplot limits
- update showtheme recipe
## 0.14.2
- fix plotly bar lines bug
- allow passing multiple series to `ribbon`
- add a new example for `line_z`
## 0.14.1
- Add linestyle argument to the legend
- Plotly: bar_width and stroke_width support for bar plots
- abline! does not change axis limits
- Fix default log scale ticks in GR backend
- Use the :fontsize keys so the scalefontsizes command works
- Prepare support for new PlotTheme type in PlotThemes
## 0.14.0
- remove use of imagemagick; saving gifs now requires ffmpeg
- improvements to ffmpeg gif quality and speed
- overhaul of fonts, allows setting fonts in recipes and with magic arguments
- added `camera` attribute to control camera position for 3d plots
- added `showaxis` attribute to control which axes to display
- improvements of polar plots axes, and better backend consistency
- changed the 'spy' recipe back to using heatmap
- added `scatterpath` seriestype
- allow plotlyjs to save svg
- add `reset_defaults()` function to reset plot defaults
- update syntax to 0.6
- make `fill = true` fill to 0 rather than to 1
- use new `@df` syntax in StatsPlots examples
- allow changing the color of legend box
- implement `title_location` for gr
- add `hline` marker to pgfplots - fixes errorbars
- pyplot legends now show marker types
- pyplot colorbars take font style from y axis
- pyplot tickmarks color the same as axis color
- allow setting linewidth for contour in gr
- allow legend to be outside plot area for pgfplots
- expand axis extrema for heatmap
- extendg grid lines to axis limits
- fix `line_z` for pyplot and gr
- fixed colorbar problem for flipped axes with gr
- fix marker_z for 3d plots in gr
- fix `weights` functionality for histograms
- fix gr annotations with colorbar
- fix aspect ratio in gr
- fix "hidden window" problem after savefig in gr
- fix pgfplots logscale ticks error
- fix pgfplots legends symbols
- fix axis linking for plotlyjs
- fix plotting of grayscale images
## 0.13.1
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
- export `pct` and `px` from Plots.PlotMeasures
## 0.13.0
- support `plotattributes` rather than `d` in recipes
- no longer export `w`, `h` and names from Measures.jl; use `using Plots.PlotMeasures` to get these names back
- `bar_width` now depends on the minimum distance between bars, not the mean
- better automatic x axis limits for plotting Functions
- `tick_direction` attribute now allows ticks to be on the inside of the plot border
- removed a bug where `p1 = plot(randn(10)); plot(p1, p2)` made `display(p1)` impossible
- allow `plot([])` to generate an empty plot
- add `origin` framestyle
- ensure finite bin number on histograms with only one unique value
- better automatic histogram bins for 2d histograms
- more informative error message on passing unsupported seriestype in a recipe
- allow grouping in user recipes
- GR now has `line_z` and `fill_z` attributes for determining the color of shapes and lines
- change GR default view angle for 3D plots to match that of PyPlot
- fix `clims` on GR
- fix `marker_z` for plotly backend
- implement `framestyle` for plotly
- fix logscale bug error for values < 1e-16 on pyplot
- fix an issue on pyplot where >1 colorbar would be shown if there was >1 series
- fix `writemime` for eps
## 0.12.4
- added a new `framestyle` argument with choices: :box, :semi, :axes, :grid and :none
- changed the default bar width to 0.8
- added working ribbon to plotly backend
- ensure that automatic ticks always generate 4 to 8 ticks
- group now groups keyword arguments of the same length as the input
- allow passing DateTime objects as ticks
- allow specifying the number of ticks as an integre
- fix bug on errorbars in gr
- fixed some but not all world age issues
- better margin with room for text
- added a `match` option for linecolor
- better error message un unsupported series types
- add a 'stride' keyword for the pyplot backend
## 0.12.3
- new grid line style defaults
- `grid` is now an axis attribute and a magic argument: it is now possible to modify the grid line style, alpha and line width
- Enforce plot order in user recipes
- import `plot!` from RecipesBase
- GR no longer automatically handles _ and ^ in texts
- fix GR colorbar for scatter plots
#### 0.12.2
- fix an issue with Juno/PlotlyJS compatibility on new installations
- fix markers not showing up in seriesrecipes using :scatter
- don't use pywrap in the pyplot backend
- improve the bottom margin for the gr backend
#### 0.12.1
- fix deprecation warnings
- switch from FixedSizeArrays to StaticArrays.FixedSizeArrays
- drop FactCheck in tests
- remove julia 0.5 compliant uses of transpose operator
- fix GR heatmap bugs
- fix GR guide padding
- improve legend markers in GR
- add surface alpha for Plotly(JS)
- add fillrange to Plotly(JS)
- allow usage of Matplotlib 1.5 with PyPlot
- fix GLVisualize for julia 0.6
- conform to changes in InspectDR
#### 0.12.0
- 0.6 only
#### 0.11.3
- add HDF5 backend
- GR replaces PyPlot as first-choice backend
- support for legend position in GR
- smaller markers in GR
- better viewport size in GR
- fix glvisualize support
- remove bug with three-argument method of `text`
- `legendtitle` attribute added
- add test for `spy`
#### 0.11.0
- julia 0.6 compatibility
- matplotlib 2.0 compatibility
- add inspectdr backend
- improved histogram functionality:
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
- support for log scale axes with histograms
- support for plotting `StatsBase.Histogram`
- allowing bins to be specified as `:sturges`, `:rice`, `:scott` or :fd
- allow `normalization` to be specified as :density (for unequal bins) or :pdf (sum to 1)
- add a `plotattr` function to access documentation for Plots attribute
- add `fill_z` attribute for pyplot
- add colorbar_title to plotlyjs
- enable standalone window for plotlyjs
- improved support for pgfplots, ticks rotation, clims, series_annotations
- restore colorbars for GR
- better axis labels for heatmap in GR
- better marker sizes in GR
- fix color representation in GR
- update GR legend
- fix image bug on GR
- fix glvisualize dependencies
- set dotted grid lines for pyplot
- several improvements to inspectdr
- improved tick positions for TimeType x axes
- support for improved color gradient capability in PlotUtils
- add a showlibrary recipe to display color libraries
- add a showgradient recipe to display color gradients
- add `vectorfield` as an alias for `quiver`
- use `PlotUtils.adaptedgrid` for functions
#### 0.9.5
- added dependency on PlotThemes
- set_theme --> theme
- remove Compat from REQUIRE
- warning for DataFrames without StatsPlots
- closeall exported and implemented for gr/pyplot
- fix DateTime recipe
- reset theme with theme(:none)
- fix link_axes! for nested subplots
- fix plotly lims for log scale
#### 0.9.4
- optimizations surrounding Subplot.series_list
- better Atom support, support plotlyjs
- gr:
- gks_wstype defaults and gr_set_output
- heatmap uses GR.drawimage
- histogram2d puts NaN for zeros
- improved support of NaN in heatmaps
- rebuilt spy recipes to output scatters with marker_z set
- deprecate png support in plotly... point to plotlyjs
- fixes:
- axis widen with lims set
- reset_extrema, setxyz
- bar plot widen
- better tick padding
- consistent tick rotation
- consistent aspect_ratio
- pyplot dpi
- plotly horizontal bars
- handle series attributes when combining subplots
- gr images transposed
- converted Date/DateTime to new type recipe approach for arrays
- issues closed include: #505 #513 #479 #523 #526 #529
#### 0.9.3
- support pdf and eps in plotlyjs backend
- allow curly after grid: `@layout [a b; grid(4,4){0.8h}]`
- add_backend redesign
#### 0.9.2
- glvisualize backend (@SimonDanisch)
- too much to list! ready for alpha testing
- Volume and volume seriestype
- Atom: support for PlotPane and proper gui display
- gr:
- clims
- aspect ratio
- pgfplots:
- fixes for ticks, axes, and more
- pyplot:
- font families
- colorbar guide
- pixel marker
- unicodeplots
- basic support for shapes
- improved add_backend
- refactor of is_supported methods
- element-wise type recipes (see https://github.com/tbreloff/Plots.jl/issues/460#issuecomment-248428908)
- several other fixes/improvements
#### 0.9.1
- Pkg.dir --> dirname (@tkelman)
- `axis = nothing` magic
- fixes:
- clim for line_z
- sticks default range for log scale
- rotate method
- pyplot heatmap
- spurious scale warnings
- gr image/alpha
- plotly.js path
- orientation extrema
- bar, reset orientation
- switch transpose_z to use permutedims
- skinny x/+ markers
- ticks in pgfplots
- eps in savefig (@anriseth)
- add_backend convenience
- type recipes for Date/DateTime (@maximsch2)
- mirror attribute and twinx convenience
- Axis.sp --> Axis.sps
- recipe postprocessing for allowing aliases and magic args in recipe bodies
#### 0.9.0
- fixes to cycle
- add back single function recipe: `plot!(cos)`
- new axis formatter attribute... accepts functions to convert numbers to strings
- fix for inset plots
- GR:
- fillrange fix
- annotations fix
- force double buffering in display
--- ---
## 0.8 ## 0.8 (current master/dev)
#### 0.8.2 (backported bug fixes for julia 0.4)
- plotly ticks fix
- unicodeplots size fix
- remove mkdir call in tests
#### 0.8.1
- manual drawing of axes/ticks/labels
- get_ticks uses optimize_ticks and Showoff
- changed PLOTS_DEFAULTS to be a global variable, not ENV key
- parameterized Segments for pushing tuples
- fix to axis extrema for Bool/nothing
- GR:
- manually draw 2D axes... fixes several issues and missing features
- fontsize fix
- PGFPlots: pass axis syle
#### 0.8.0 #### 0.8.0
- added dependency on PlotUtils - added dependency on PlotUtils
- BREAKING: removed DataFrames support (now in StatsPlots.jl) - BREAKING: removed DataFrames support (now in StatPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl) - BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
- GR: - GR:
- inline iterm2 support - inline iterm2 support
- trisurface support - trisurface support
@ -749,7 +204,7 @@ Many updates, min julia 1.0
- z-axis keywords - z-axis keywords
- 3D indexing overhaul: `push!`, `append!` support - 3D indexing overhaul: `push!`, `append!` support
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots) - matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
- `const KW = Dict{Symbol,Any}` used in place of splatting in many places - `typealias KW Dict{Symbol,Any}` used in place of splatting in many places
- png generation for plotly backend using wkhtmltoimage - png generation for plotly backend using wkhtmltoimage
- `normalize` and `weights` keywords - `normalize` and `weights` keywords
- background/foreground subcategories for fine-tuning of looks - background/foreground subcategories for fine-tuning of looks

View File

@ -1,93 +0,0 @@
name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"]
version = "1.29.0"
[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Contour = "d38c429a-6771-53c6-b99e-75d170b6e991"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PlotThemes = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
RecipesPipeline = "01d81517-befc-4cb6-b9ec-a95719d0359c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Scratch = "6c6a2e73-6563-6170-7368-637461726353"
Showoff = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
UnicodeFun = "1cfade01-22cf-5700-b092-accc4b62d6e1"
Unzip = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d"
[compat]
Contour = "0.5"
FFMPEG = "0.2 - 0.4"
FixedPointNumbers = "0.6 - 0.8"
GR = "0.64"
GeometryBasics = "0.2, 0.3.1, 0.4"
JSON = "0.21, 1"
Latexify = "0.14 - 0.15"
Measures = "0.3"
NaNMath = "0.3, 1"
PGFPlotsX = "1"
PlotThemes = "2, 3"
PlotUtils = "1"
PlotlyBase = "0.7"
PlotlyJS = "0.18"
PyPlot = "2"
RecipesBase = "1.2"
RecipesPipeline = "0.5"
Reexport = "0.2, 1.0"
Requires = "1"
Scratch = "1"
Showoff = "0.3.1, 1.0"
StatsBase = "0.32 - 0.33"
UnicodeFun = "0.4"
UnicodePlots = "2.10"
Unzip = "0.1"
julia = "1.6"
[extras]
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
Gaston = "4b11ee91-296f-5714-9832-002c20994614"
Gtk = "4c0ca9eb-093a-5379-98c5-f87ac0bbbf44"
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
[targets]
test = ["Colors", "Distributions", "FileIO", "Gaston", "Gtk", "ImageMagick", "Images", "InspectDR", "LibGit2", "OffsetArrays", "PGFPlotsX", "PlotlyJS", "PlotlyBase", "PyPlot", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]

View File

@ -1,30 +1,13 @@
# Plots # Plots
[gh-ci-img]: https://github.com/JuliaPlots/Plots.jl/workflows/ci/badge.svg?branch=master [![Build Status](https://travis-ci.org/tbreloff/Plots.jl.svg?branch=master)](https://travis-ci.org/tbreloff/Plots.jl)
[gh-ci-url]: https://github.com/JuliaPlots/Plots.jl/actions?query=workflow%3Aci [![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
<!-- [![codecov.io](http://codecov.io/github/tbreloff/Plots.jl/coverage.svg?branch=master)](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg #### Author: Thomas Breloff (@tbreloff)
[pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html
[gitter-img]: https://badges.gitter.im/tbreloff/Plots.jl.svg
[gitter-url]: https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
[docs-url]: https://docs.juliaplots.org/stable/
[![][gh-ci-img]][gh-ci-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)
[![][docs-img]][docs-url]
[![Codecov](https://codecov.io/gh/JuliaPlots/Plots.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaPlots/Plots.jl)
[![Plots Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/Plots)](https://pkgs.genieframework.com?packages=Plots)
[![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)
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)
Plots is a plotting API and toolset. My goals with the package are: Plots is a plotting API and toolset. My goals with the package are:
@ -35,3 +18,5 @@ Plots is a plotting API and toolset. My goals with the package are:
- **Consistent**. Don't commit to one graphics package, use the same code everywhere. - **Consistent**. Don't commit to one graphics package, use the same code everywhere.
- **Lightweight**. Very few dependencies. - **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it. - **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
View the [full documentation](http://juliaplots.github.io).

9
REQUIRE Normal file
View File

@ -0,0 +1,9 @@
julia 0.4
RecipesBase
PlotUtils
Reexport
Compat
FixedSizeArrays
Measures
Showoff

29
appveyor.yml Normal file
View File

@ -0,0 +1,29 @@
environment:
matrix:
# Releases
- JULIAVERSION: "stable/win32"
- JULIAVERSION: "stable/win64"
# Nightlies
- JULIAVERSION: "download/win32"
- JULIAVERSION: "download/win64"
notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false
install:
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile($("http://status.julialang.org/"+$env:JULIAVERSION), "C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo(); Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
test_script:
# - C:\projects\julia\bin\julia -e "Pkg.test(\"Plots\")"
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"

View File

@ -1,5 +0,0 @@
[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"

View File

@ -1,10 +0,0 @@
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

@ -1,13 +0,0 @@
github_checks:
annotations: false
ignore:
- "src/backends/inspectdr.jl"
- "src/backends/orca.jl"
- "src/backends/pgfplots.jl"
- "src/backends/plotly.jl"
- "src/backends/plotlyjs.jl"
- "src/backends/pyplot.jl"
- "src/backends/web.jl"
- "src/fileio.jl"
- "src/ijulia.jl"

View File

@ -1,451 +0,0 @@
# 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{(:parent,), Tuple{Subplot{GRBackend}}},Type{Subplot},GRBackend})
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(areaplot)),Any,typeof(areaplot),Any,Vararg{Any, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:foreground_color_grid, :grid, :gridalpha, :gridstyle, :gridlinewidth), Tuple{RGBA{Float64}, Bool, Float64, Symbol, Int64}},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{(: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{(:minorgrid, :scale, :guide), Tuple{Bool, 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), Tuple{Symbol, Symbol, Int64}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_set_font)),NamedTuple{(:rotation, :color), Tuple{Int64, RGBA{Float64}}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Vector{Int64}})
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, Tuple{String, Any, Any, Any}}}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{Matrix{Any}, AbsoluteLength}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{GRBackend},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},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},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},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,Irrational{}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Plot{GRBackend},Function,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{GRBackend},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
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}},Vector{Float64}})
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!),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},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{PlotlyBackend},Vector{Int64},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!),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},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{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},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{(:aspect_ratio, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{String},Vector{String},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bar_width, :alpha, :color, :fillto, :label, :seriestype), Tuple{Float64, Float64, Vector{Symbol}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}, String, Symbol}},typeof(plot),Vector{Float64}})
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, :title, :xlabel, :ylabel, :zlabel, :legend, :margin, :seriestype), Tuple{Tuple{Vector{Int64}, Vector{Int64}, Vector{Int64}}, String, String, String, String, Symbol, AbsoluteLength, Symbol}},typeof(plot),Vector{Int64},Vector{Int64},Vector{Int64}})
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}},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill_z, :alpha, :label, :bar_width, :seriestype), Tuple{StepRange{Int64, Int64}, Vector{Float64}, String, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Int64},Vector{Int64}})
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, :legend, :seriestype), Tuple{String, Symbol, Symbol}},typeof(plot),Vector{Int64}})
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,Float64})
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{(:layout, :group, :linetype, :linecolor), Tuple{Matrix{Any}, 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},Plot{GRBackend}})
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},Plot{PlotlyBackend}})
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{Matrix{Any}, AbsoluteLength}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}, 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{Matrix{Any}, 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{Matrix{Any}, 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{Matrix{Any}, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{GRBackend},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},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},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},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,Int64,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},Matrix{Int64}})
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},Vector{Float64}})
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{(:seriescolor, :fillalpha), Tuple{Matrix{Symbol}, Matrix{Float64}}},typeof(plot),AreaPlot})
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),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{DateTime},UnitRange{Int64},Matrix{Float64}})
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},Vector{Float64}})
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, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xmirror, :ymirror, :zmirror, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
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{(:zcolor, :m, :leg, :cbar, :w), Tuple{StepRange{Int64, Int64}, Tuple{Int64, Float64, Symbol, Stroke}, Bool, Bool, Int64}},typeof(plot),Vector{Float64},Vector{Float64},UnitRange{Int64}})
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{:hline}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:hspan}},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{: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{:vspan}},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_sliced_series_attributes!),Plot{GRBackend},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_sliced_series_attributes!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}}})
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.unzip),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
Base.precompile(Tuple{typeof(_bin_centers),Vector{Float64}})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Float64},String})
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),UnitRange{Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},StepRange{Int64, Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Int64},StepRange{Int64, Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Int64},UnitRange{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,Vector{Plot}})
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64},Tuple{Int64, Float64}})
Base.precompile(Tuple{typeof(default),Symbol,Bool})
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_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
Base.precompile(Tuple{typeof(fakedata),Int64,Int64})
Base.precompile(Tuple{typeof(fakedata),MersenneTwister,Int64,Vararg{Int64, N} where N})
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),SubArray{Symbol, 1, Vector{Symbol}, Tuple{UnitRange{Int64}}, true},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{PlotlyBackend},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, Int64, Int64, 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_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,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
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,Float64,Tuple{Float64, Float64},Int64,Int64,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_markers),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},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,UnitRange{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,UnitRange{Int64},Vector{Float64},Vector{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_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_3d_axis_angle),Vector{Float64},Float64,Float64,Symbol})
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Float64}, 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),Subplot{GRBackend},Symbol,Tuple{Vector{Int64}, 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_text),Float64,Float64,String})
Base.precompile(Tuple{typeof(gr_text_size),String})
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, Int64, Int64, 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),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})
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
Base.precompile(Tuple{typeof(layout_args),NamedTuple{(:label, :blank), Tuple{Symbol, Bool}}})
Base.precompile(Tuple{typeof(layout_args),NamedTuple{(:label, :width, :height), Tuple{Symbol, Symbol, Float64}}})
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})
Base.precompile(Tuple{typeof(plot!),Plot,Plot,Plot,Vararg{Plot, N} where N})
Base.precompile(Tuple{typeof(plot),Any,Any})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}, N} where N})
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
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},Symbol})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
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(push!),Segments{Tuple{Float64, Float64, Float64}},Tuple{Int64, Int64, Float64},Tuple{Int64, Int64, Float64}})
Base.precompile(Tuple{typeof(resetfontsizes)})
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
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{AbsoluteLength},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{RGBA{Float64}},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(title!),AbstractString})
Base.precompile(Tuple{typeof(vline!),Any})
Base.precompile(Tuple{typeof(warn_on_attr_dim_mismatch),Series,Vector{Float64},Vector{Float64},Nothing,Base.Iterators.Flatten{Vector{Tuple{SeriesSegment}}}})
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
isdefined(Plots, Symbol("#166#167")) && Base.precompile(Tuple{getfield(Plots, Symbol("#166#167")),Any})
isdefined(Plots, Symbol("#2#6")) && Base.precompile(Tuple{getfield(Plots, Symbol("#2#6")),UnitRange{Int64}})
isdefined(Plots, Symbol("#295#331")) && Base.precompile(Tuple{getfield(Plots, Symbol("#295#331"))})
isdefined(Plots, Symbol("#316#352")) && Base.precompile(Tuple{getfield(Plots, Symbol("#316#352"))})
isdefined(Plots, Symbol("#add_major_or_minor_segments#100")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#100")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#101")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#101")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
let fbody = try __lookup_kwbody__(which(font, (Font,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(font),Font,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(gr_polyline, (Vector{Float64},Vector{Float64},typeof(GR.fillarea),))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Symbol,Symbol,typeof(gr_polyline),Vector{Float64},Vector{Float64},typeof(GR.fillarea),))
end
end
let fbody = try __lookup_kwbody__(which(gr_set_font, (Font,Subplot{GRBackend},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Symbol,Symbol,RGBA{Float64},Float64,typeof(gr_set_font),Font,Subplot{GRBackend},))
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(plot!, (Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Plot,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Plot,Plot,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Plot,Plot,Plot,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,Plot,Vararg{Plot, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Plot,Plot,Plot,Vararg{Plot, 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(scatter, (Any,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(scatter),Any,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

@ -1,487 +0,0 @@
# 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{(: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(areaplot)),Any,typeof(areaplot),Any,Vararg{Any}})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:flip,), Tuple{Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:foreground_color_grid, :grid, :gridalpha, :gridstyle, :gridlinewidth), Tuple{RGBA{Float64}, Bool, Float64, Symbol, Int64}},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{(: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{(:minorgrid, :scale, :guide), Tuple{Bool, Symbol, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:minorgrid,), Tuple{Bool}},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{(: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}, Int64},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), Tuple{Symbol, Symbol, Int64}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_set_font)),NamedTuple{(:rotation, :color), Tuple{Int64, RGBA{Float64}}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(lens!)),Any,typeof(lens!),Any,Vararg{Any}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Plot{GRBackend},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Vector{Int64}})
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, Tuple{String, Any, Any, Any}}}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{Matrix{Any}, AbsoluteLength}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
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,Irrational{}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Plot{GRBackend},Function,Float64,Vararg{Any}})
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}, Int64},Vector{Float64}})
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}, Int64},Vector{Float64}})
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}, Int64},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},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{PlotlyBackend},Vector{Int64},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!),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},Vector{Float64},Vararg{Any}})
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{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},typeof(plot!),Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},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},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bar_width, :alpha, :color, :fillto, :label, :seriestype), Tuple{Float64, Float64, Vector{Symbol}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, String, Symbol}},typeof(plot),Vector{Float64}})
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}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:connections, :title, :xlabel, :ylabel, :zlabel, :legend, :margin, :seriestype), Tuple{Tuple{Vector{Int64}, Vector{Int64}, Vector{Int64}}, String, String, String, String, Symbol, AbsoluteLength, Symbol}},typeof(plot),Vector{Int64},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill, :seriestype), Tuple{Bool, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill_z, :alpha, :label, :bar_width, :seriestype), Tuple{StepRange{Int64, Int64}, Vector{Float64}, String, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Int64},Vector{Int64}})
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, :legend, :seriestype), Tuple{String, Symbol, Symbol}},typeof(plot),Vector{Int64}})
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,Float64})
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{Matrix{Any}, 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},Plot{GRBackend}})
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},Plot{PlotlyBackend}})
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{Matrix{Any}, AbsoluteLength}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
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{Matrix{Any}, 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{Matrix{Any}, 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{Matrix{Any}, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
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},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,Int64,Vararg{Any}})
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}, Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line_z, :linewidth, :legend), Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, 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}, Int64},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}, Int64},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}, Int64},UnitRange{Int64},Matrix{Int64}})
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},Vector{Float64}})
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}, Int64}}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:ribbon,), Tuple{Tuple{LinRange{Float64, Int64}, LinRange{Float64, Int64}}}},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{(:seriescolor, :fillalpha), Tuple{Matrix{Symbol}, Matrix{Float64}}},typeof(plot),AreaPlot})
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),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{DateTime},UnitRange{Int64},Matrix{Float64}})
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},Vector{Float64}})
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, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xmirror, :ymirror, :zmirror, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
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{(:zcolor, :m, :leg, :cbar, :w), Tuple{StepRange{Int64, Int64}, Tuple{Int64, Float64, Symbol, Stroke}, Bool, Bool, Int64}},typeof(plot),Vector{Float64},Vector{Float64},UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(portfoliocomposition)),Any,typeof(portfoliocomposition),Any,Vararg{Any}})
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{Core.kwftype(typeof(yaxis!)),Any,typeof(yaxis!),Any,Any})
Base.precompile(Tuple{Type{GridLayout},Int64,Vararg{Int64}})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},AbstractVector{<:GeometryBasics.Point}})
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{:hline}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:hspan}},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{:spy}},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{:vspan}},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.preprocess_axis_args!),Plot{GRBackend},Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_axis_args!),Plot{PlotlyBackend},Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(RecipesPipeline.process_sliced_series_attributes!),Plot{GRBackend},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_sliced_series_attributes!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}}})
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.unzip),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Float64},String})
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}, Int64}},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),UnitRange{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(_cycle),Vector{Int64},StepRange{Int64, Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Int64},UnitRange{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}, Int64},Vector{Float64}})
Base.precompile(Tuple{typeof(_replace_markershape),Vector{Symbol}})
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(annotate!),AbstractVector{<:Tuple}})
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,Vector{Plot}})
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Vector{Float64},Tuple{Int64, Float64}})
Base.precompile(Tuple{typeof(discrete_value!),Axis,Vector{Union{Missing, Float64}}})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64},Vararg{Vector{Float64}}})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
Base.precompile(Tuple{typeof(fakedata),Int64,Int64})
Base.precompile(Tuple{typeof(fakedata),TaskLocalRNG,Int64,Vararg{Int64}})
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),SubArray{Symbol, 1, Vector{Symbol}, Tuple{UnitRange{Int64}}, true},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{PlotlyBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_ticks),StepRange{Int64, Int64},Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Float64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),UnitRange{Int64},Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any}})
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, Int64, Int64, 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_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},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,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
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,Float64,Tuple{Float64, Float64},Int64,Int64,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},Int64,Int64})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,UnitRange{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,Base.OneTo{Int64},Vector{Float64},Nothing,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Vector{Float64},Nothing,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,UnitRange{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,UnitRange{Int64},Vector{Float64},Nothing,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,UnitRange{Int64},Vector{Float64},Vector{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_segments),Series,Vector{Float64},Vector{Float64},Nothing,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Vector{Int64},Vector{Int64},Nothing,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_3d_axis_angle),Vector{Float64},Float64,Float64,Symbol})
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),Subplot{GRBackend},Symbol,Tuple{Vector{Int64}, 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_text),Float64,Float64,String})
Base.precompile(Tuple{typeof(gr_text_size),String})
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, Int64, Int64, 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),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),UnitRange{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol})
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
Base.precompile(Tuple{typeof(layout_args),Matrix{Any}})
Base.precompile(Tuple{typeof(layout_args),NamedTuple{(:label, :blank), Tuple{Symbol, Bool}}})
Base.precompile(Tuple{typeof(layout_args),NamedTuple{(:label, :width, :height), Tuple{Symbol, Symbol, Float64}}})
Base.precompile(Tuple{typeof(make_fillrange_side),UnitRange{Int64},LinRange{Float64, Int64}})
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),Float64,Float64,Int64})
Base.precompile(Tuple{typeof(partialcircle),Int64,Float64,Int64})
Base.precompile(Tuple{typeof(plot!),Any})
Base.precompile(Tuple{typeof(plot!),Plot,Plot,Plot,Vararg{Plot}})
Base.precompile(Tuple{typeof(plot),Any,Any})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
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},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
Base.precompile(Tuple{typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend}})
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},Bool})
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{GRBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
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(quiver_using_arrows),DefaultsDict})
Base.precompile(Tuple{typeof(resetfontsizes)})
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
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{AbsoluteLength},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}})
Base.precompile(Tuple{typeof(text),String,Symbol})
Base.precompile(Tuple{typeof(title!),AbstractString})
Base.precompile(Tuple{typeof(vline!),Any})
Base.precompile(Tuple{typeof(warn_on_attr_dim_mismatch),Series,Vector{Float64},Vector{Float64},Nothing,Base.Iterators.Flatten{Vector{Tuple{SeriesSegment}}}})
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any}})
Base.precompile(Tuple{typeof(xgrid!),Plot{PlotlyBackend},Symbol,Vararg{Any}})
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
isdefined(Plots, Symbol("#168#169")) && Base.precompile(Tuple{getfield(Plots, Symbol("#168#169")),Any})
isdefined(Plots, Symbol("#170#171")) && Base.precompile(Tuple{getfield(Plots, Symbol("#170#171")),Any})
isdefined(Plots, Symbol("#2#6")) && Base.precompile(Tuple{getfield(Plots, Symbol("#2#6")),UnitRange{Int64}})
isdefined(Plots, Symbol("#301#337")) && Base.precompile(Tuple{getfield(Plots, Symbol("#301#337"))})
isdefined(Plots, Symbol("#322#358")) && Base.precompile(Tuple{getfield(Plots, Symbol("#322#358"))})
isdefined(Plots, Symbol("#add_major_or_minor_segments#102")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#102")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#103")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#103")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
let fbody = try __lookup_kwbody__(which(annotate!, (AbstractVector{<:Tuple},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(annotate!),AbstractVector{<:Tuple},))
end
end
let fbody = try __lookup_kwbody__(which(font, (Font,Vararg{Any},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(font),Font,Vararg{Any},))
end
end
let fbody = try __lookup_kwbody__(which(gr_polyline, (Vector{Float64},Vector{Float64},typeof(GR.fillarea),))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Symbol,Symbol,typeof(gr_polyline),Vector{Float64},Vector{Float64},typeof(GR.fillarea),))
end
end
let fbody = try __lookup_kwbody__(which(gr_set_font, (Font,Subplot{GRBackend},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Symbol,Symbol,RGBA{Float64},Float64,typeof(gr_set_font),Font,Subplot{GRBackend},))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Any,Vararg{Any},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot!),Any,Vararg{Any},))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot!),Plot,Plot,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot!),Plot,Plot,Plot,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Plot,Plot,Plot,Vararg{Plot},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot!),Plot,Plot,Plot,Vararg{Plot},))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot),Any,))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,Vararg{Any},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(plot),Any,Vararg{Any},))
end
end
let fbody = try __lookup_kwbody__(which(title!, (AbstractString,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(title!),AbstractString,))
end
end
let fbody = try __lookup_kwbody__(which(yaxis!, (Any,Vararg{Any},))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Pairs{Symbol, V, Tuple{Vararg{Symbol, N}}, NamedTuple{names, T}} where {V, N, names, T<:Tuple{Vararg{Any, N}}},typeof(yaxis!),Any,Vararg{Any},))
end
end
end

View File

@ -1,282 +0,0 @@
# 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
function _precompile_()
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
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}},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{(:formatter,), Tuple{typeof(datetimeformatter)}},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{(:lims,), Tuple{Tuple{Int64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:ticks,), Tuple{Nothing}},typeof(attr!),Axis})
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(gr_polyline)),NamedTuple{(:arrowside, :arrowstyle), Tuple{Symbol, Symbol}},typeof(gr_polyline),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},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), Tuple{Symbol, Symbol, Int64}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(gr_set_font)),NamedTuple{(:rotation, :color), Tuple{Int64, RGBA{Float64}}},typeof(gr_set_font),Font,Subplot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :label, :seriestype), Tuple{Float64, String, Symbol}},typeof(plot!),Vector{Int64}})
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, Tuple{String, Any, Any, Any}}}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:c, :lw, :label), Tuple{Symbol, Int64, String}},typeof(plot!),Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{Matrix{Any}, AbsoluteLength}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Bool}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:legend,), Tuple{Symbol}},typeof(plot!),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend},Vararg{Plot{PlotlyBackend}}})
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,Irrational{}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:lw, :color), Tuple{Int64, Symbol}},typeof(plot!),Plot{GRBackend},Function,Float64,Vararg{Any}})
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}, Int64},Vector{Float64}})
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}, Int64},Vector{Float64}})
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}, Int64},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},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{PlotlyBackend},Vector{Int64},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!),Vector{Int64},Vector{Float64}})
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},Vector{Float64},Vararg{Any}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:yaxis, :minorgrid), Tuple{Tuple{String, Symbol}, Bool}},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{(:aspect_ratio, :seriestype), Tuple{Int64, Symbol}},typeof(plot),Vector{String},Vector{String},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:bar_width, :alpha, :color, :fillto, :label, :seriestype), Tuple{Float64, Float64, Vector{Symbol}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, String, Symbol}},typeof(plot),Vector{Float64}})
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}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:connections, :title, :xlabel, :ylabel, :zlabel, :legend, :margin, :seriestype), Tuple{Tuple{Vector{Int64}, Vector{Int64}, Vector{Int64}}, String, String, String, String, Symbol, AbsoluteLength, Symbol}},typeof(plot),Vector{Int64},Vector{Int64},Vector{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill, :seriestype), Tuple{Bool, Symbol}},typeof(plot),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:fill_z, :alpha, :label, :bar_width, :seriestype), Tuple{StepRange{Int64, Int64}, Vector{Float64}, String, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Int64},Vector{Int64}})
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, :legend, :seriestype), Tuple{String, Symbol, Symbol}},typeof(plot),Vector{Int64}})
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,Float64})
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{(:layout, :group, :linetype, :linecolor), Tuple{Matrix{Any}, 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},Plot{GRBackend}})
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},Plot{PlotlyBackend}})
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, :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{Matrix{Any}, 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{Matrix{Any}, 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{Matrix{Any}, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout,), Tuple{Tuple{Int64, Int64}}},typeof(plot),Plot{PlotlyBackend},Plot{PlotlyBackend},Plot{PlotlyBackend}})
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},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,Int64,Vararg{Any}})
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}, Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:line_z, :linewidth, :legend), Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, 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}, Int64},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}, Int64},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}, Int64},UnitRange{Int64},Matrix{Int64}})
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},Vector{Float64}})
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{Tuple{LinRange{Float64, Int64}, LinRange{Float64, Int64}}}},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),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:seriestype,), Tuple{Symbol}},typeof(plot),Vector{DateTime},UnitRange{Int64},Matrix{Float64}})
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},Vector{Float64}})
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, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :xmirror, :ymirror, :zmirror, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, Bool, Bool, Bool, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:title, :zlabel, :grid, :ylabel, :minorgrid, :xlabel, :seriestype), Tuple{String, String, Bool, String, Bool, String, Symbol}},typeof(plot),Vector{Float64},Vector{Float64},Function})
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{(:zcolor, :m, :leg, :cbar, :w), Tuple{StepRange{Int64, Int64}, Tuple{Int64, Float64, Symbol, Stroke}, Bool, Bool, Int64}},typeof(plot),Vector{Float64},Vector{Float64},UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(portfoliocomposition)),Any,typeof(portfoliocomposition),Any,Vararg{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{Core.kwftype(typeof(yaxis!)),Any,typeof(yaxis!),Any,Any})
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{: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{:hline}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Type{Val{:hspan}},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{: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{:vspan}},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_sliced_series_attributes!),Plot{GRBackend},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_sliced_series_attributes!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.unzip),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
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},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(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Vector{Float64}})
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},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(annotate!),AbstractVector{<:Tuple}})
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,Vector{Plot}})
Base.precompile(Tuple{typeof(convert_to_polar),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Vector{Float64},Tuple{Int64, Float64}})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64},Vararg{Vector{Float64}}})
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
Base.precompile(Tuple{typeof(fakedata),Int64,Int64})
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),SubArray{Symbol, 1, Vector{Symbol}, Tuple{UnitRange{Int64}}, true},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_series_color),Vector{Symbol},Subplot{PlotlyBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(get_ticks),StepRange{Int64, Int64},Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Float64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),Symbol,Vector{Float64},Vector{Any},Tuple{Int64, Int64},Vararg{Any}})
Base.precompile(Tuple{typeof(get_ticks),UnitRange{Int64},Vector{Float64},Vector{Any},Tuple{Float64, Float64},Vararg{Any}})
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, Int64, Int64, 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_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},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,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
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,Float64,Tuple{Float64, Float64},Int64,Int64,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_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_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_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Int64}, 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_set_gradient),PlotUtils.ContinuousColorGradient})
Base.precompile(Tuple{typeof(gr_text),Float64,Float64,String})
Base.precompile(Tuple{typeof(gr_text_size),String})
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, Int64, Int64, 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),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),UnitRange{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol})
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
Base.precompile(Tuple{typeof(is_marker_supported),GRBackend,Vector{Symbol}})
Base.precompile(Tuple{typeof(layout_args),Matrix{Any}})
Base.precompile(Tuple{typeof(link_axes!),GridLayout,Symbol})
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!),Plot,Plot,Plot,Vararg{Plot}})
Base.precompile(Tuple{typeof(plot),Any,Any})
Base.precompile(Tuple{typeof(plot),Plot{GRBackend},Plot{GRBackend},Plot{GRBackend},Vararg{Plot{GRBackend}}})
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}})
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Matrix{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(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText,Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol},Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Symbol, Int64, String},Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{GRBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText,Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,PlotText})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol},Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Int64, Symbol, Symbol}})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Symbol, Int64, String},Font})
Base.precompile(Tuple{typeof(process_annotation),Subplot{PlotlyBackend},Int64,Float64,Tuple{String, Symbol, Int64, String}})
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(push!),Segments{Tuple{Float64, Float64, Float64}},Tuple{Float64, Int64, Int64},Tuple{Float64, Int64, Int64}})
Base.precompile(Tuple{typeof(resetfontsizes)})
Base.precompile(Tuple{typeof(scalefontsizes),Float64})
Base.precompile(Tuple{typeof(series_annotations),Vector{Any}})
Base.precompile(Tuple{typeof(slice_arg),Matrix{AbsoluteLength},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{Bool},Int64})
Base.precompile(Tuple{typeof(slice_arg),Matrix{Int64},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(title!),AbstractString})
Base.precompile(Tuple{typeof(update_child_bboxes!),GridLayout})
Base.precompile(Tuple{typeof(update_clims),Float64,Float64,SubArray{Int64, 1, Vector{Int64}, Tuple{UnitRange{Int64}}, true},typeof(ignorenan_extrema)})
Base.precompile(Tuple{typeof(warn_on_attr_dim_mismatch),Series,Vector{Float64},Vector{Float64},Nothing,Base.Iterators.Flatten{Vector{Tuple{SeriesSegment}}}})
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any}})
Base.precompile(Tuple{typeof(xgrid!),Plot{PlotlyBackend},Symbol,Vararg{Any}})
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
isdefined(Plots, Symbol("#2#6")) && Base.precompile(Tuple{getfield(Plots, Symbol("#2#6")),UnitRange{Int64}})
isdefined(Plots, Symbol("#322#358")) && Base.precompile(Tuple{getfield(Plots, Symbol("#322#358"))})
isdefined(Plots, Symbol("#add_major_or_minor_segments#102")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#102")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#103")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#103")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
end

View File

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

View File

@ -1,6 +0,0 @@
include("snoop_bot_config.jl")
snoop_bench(
botconfig,
joinpath(@__DIR__, "precompile_script.jl"),
)

View File

@ -1,6 +0,0 @@
include("snoop_bot_config.jl")
snoop_bot(
botconfig,
joinpath(@__DIR__, "precompile_script.jl"),
)

View File

@ -1,7 +0,0 @@
using CompileBot
botconfig = BotConfig(
"Plots",
version = ["1.6", "1.7", "1.8", "nightly"], # <<< keep these versions in sync with .github/workflows/SnoopCompile.yml
# else_version = "nightly",
)

8
deps/build.jl vendored Normal file
View File

@ -0,0 +1,8 @@
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
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)
end

4
pushtomaster.sh Executable file
View File

@ -0,0 +1,4 @@
git checkout master
git merge --ff-only dev
git push origin master
git checkout dev

View File

@ -1,74 +1,46 @@
__precompile__()
module Plots module Plots
using Pkg using Compat
if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel"))
@eval Base.Experimental.@optlevel 1
end
if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@max_methods"))
@eval Base.Experimental.@max_methods 1
end
const _plots_project = Pkg.Types.read_project(normpath(@__DIR__, "..", "Project.toml"))
const _current_plots_version = _plots_project.version
const _plots_compats = _plots_project.compat
function _check_compat(sim::Module)
sim_str = string(sim)
if !haskey(_plots_compats, sim_str)
return nothing
end
be_v = Pkg.Types.read_project(joinpath(Base.pkgdir(sim), "Project.toml")).version
be_c = _plots_compats[sim_str]
if be_c isa String # julia 1.6
if !(be_v in Pkg.Types.semver_spec(be_c))
@warn "$sim $be_v is not compatible with this version of Plots. The declared compatibility is $(be_c)."
end
else
if isempty(intersect(be_v, be_c.val))
@warn "$sim $be_v is not compatible with this version of Plots. The declared compatibility is $(be_c.str)."
end
end
end
using Reexport using Reexport
# @reexport using Colors
import GeometryBasics # using Requires
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random, Unzip using FixedSizeArrays
using SparseArrays
using FFMPEG
@reexport using RecipesBase @reexport using RecipesBase
import RecipesBase: plot, plot!, animate, is_explicit, grid
using Base.Meta using Base.Meta
@reexport using PlotUtils @reexport using PlotUtils
@reexport using PlotThemes
import UnicodeFun
import StatsBase
import Downloads
import Showoff import Showoff
import JSON
using Requires
#! format: off
export export
AbstractPlot,
Plot,
Subplot,
AbstractLayout,
GridLayout,
grid, grid,
EmptyLayout,
bbox, bbox,
plotarea, plotarea,
@layout,
AVec,
AMat,
KW, KW,
wrap, wrap,
theme, set_theme,
add_theme,
plot, plot,
plot!, plot!,
attr!,
current, current,
default, default,
with, with,
twinx,
@userplot,
@shorthands,
pie, pie,
pie!, pie!,
@ -88,46 +60,44 @@ export
yflip!, yflip!,
xaxis!, xaxis!,
yaxis!, yaxis!,
xgrid!,
ygrid!,
xlims,
ylims,
zlims,
savefig, savefig,
png, png,
gui, gui,
inline,
closeall,
backend, backend,
backends, backends,
backend_name, backend_name,
backend_object,
aliases, aliases,
dataframes,
Shape, Shape,
text, text,
font, font,
Axis,
stroke, stroke,
brush, brush,
Surface, Surface,
OHLC, OHLC,
arrow, arrow,
Segments, Segments,
Formatted,
debugplots,
supported_args,
supported_types,
supported_styles,
supported_markers,
is_subplot_supported,
Animation, Animation,
frame, frame,
gif, gif,
mov,
mp4,
webm,
animate,
@animate, @animate,
@gif, @gif,
spy,
test_examples, test_examples,
iter_segments, iter_segments,
coords, coords,
@ -137,146 +107,150 @@ export
rotate, rotate,
rotate!, rotate!,
center, center,
P2,
P3,
BezierCurve, BezierCurve,
curve_points,
plotattr, directed_curve
scalefontsize,
scalefontsizes,
resetfontsizes
#! format: on
# ---------------------------------------------------------
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
ignorenan_minimum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.minimum(x)
ignorenan_minimum(x) = Base.minimum(x)
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
ignorenan_maximum(x) = Base.maximum(x)
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
ignorenan_mean(x) = Statistics.mean(x)
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
# to cater for block matrices, Base.transpose is recursive.
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
# This solves this issue, internally in Plots at least.
# commented out on the insistence of the METADATA maintainers
#Base.transpose(x::Symbol) = x
#Base.transpose(x::String) = x
# --------------------------------------------------------- # ---------------------------------------------------------
import Measures import Measures
module PlotMeasures import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
import Measures typealias BBox Measures.Absolute2DBox
import Measures: export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct,Float64}(1.0)
Base.convert(::Type{<:Measure}, x::Float64) = x * pct
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
end
using .PlotMeasures
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
# --------------------------------------------------------- # ---------------------------------------------------------
import RecipesPipeline
import RecipesPipeline:
SliceIt,
DefaultsDict,
Formatted,
AbstractSurface,
Surface,
Volume,
is3d,
is_surface,
needs_3d_axes,
group_as_matrix, # for StatsPlots
reset_kw!,
pop_kw!,
scale_func,
inverse_scale_func,
dateformatter,
datetimeformatter,
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-2.6.3.min.js"
include("types.jl") include("types.jl")
include("utils.jl") include("utils.jl")
include("colorbars.jl")
include("axes.jl")
include("args.jl")
include("components.jl") include("components.jl")
include("consts.jl") include("axes.jl")
include("backends.jl")
include("args.jl")
include("themes.jl") include("themes.jl")
include("plot.jl") include("plot.jl")
include("pipeline.jl") include("pipeline.jl")
include("series.jl")
include("layouts.jl") include("layouts.jl")
include("subplots.jl") include("subplots.jl")
include("recipes.jl") include("recipes.jl")
include("animation.jl") include("animation.jl")
include("output.jl")
include("examples.jl") include("examples.jl")
include("arg_desc.jl") include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
include("ijulia.jl")
include("fileio.jl")
include("init.jl")
include("legend.jl")
include("backends/plotly.jl")
include("backends/gr.jl")
include("backends/web.jl")
include("shorthands.jl") # ---------------------------------------------------------
let PlotOrSubplot = Union{Plot,Subplot} # define and export shorthand plotting method definitions
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...) macro shorthands(funcname::Symbol)
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...) funcname2 = Symbol(funcname, "!")
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...) esc(quote
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...) export $funcname, $funcname2
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...) $funcname(args...; kw...) = plot(args...; kw..., seriestype = $(quot(funcname)))
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...) $funcname2(args...; kw...) = plot!(args...; kw..., seriestype = $(quot(funcname)))
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin, xmax), kw...) end)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin, ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin, zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks, labels), kw...)
global yticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks, labels), kw...)
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
end end
@shorthands scatter
@shorthands bar
@shorthands barh
@shorthands histogram
@shorthands histogram2d
@shorthands density
@shorthands heatmap
@shorthands hexbin
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands ohlc
@shorthands contour
@shorthands contourf
@shorthands contour3d
@shorthands surface
@shorthands wireframe
@shorthands path3d
@shorthands scatter3d
@shorthands boxplot
@shorthands violin
@shorthands quiver
@shorthands curves
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
title!(plt::Plot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
xlims!(plt::Plot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::Plot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::Plot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
yticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
xticks!{T<:Real,S<:AbstractString}(plt::Plot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::Plot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
annotate!(plt::Plot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::Plot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
xflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::Plot, args...; kw...) = plot!(plt; xaxis = args, kw...)
yaxis!(plt::Plot, args...; kw...) = plot!(plt; yaxis = args, kw...)
# --------------------------------------------------------- # ---------------------------------------------------------
const CURRENT_BACKEND = CurrentBackend(:none) const CURRENT_BACKEND = CurrentBackend(:none)
const PLOTS_SEED = 1234
include("precompile_includer.jl") function __init__()
setup_ijulia()
setup_atom()
if isdefined(Main, :PLOTS_DEFAULTS)
for (k,v) in Main.PLOTS_DEFAULTS
default(k, v)
end
end
end
# ---------------------------------------------------------
# if VERSION >= v"0.4.0-dev+5512"
# include("precompile.jl")
# _precompile_()
# end
# ---------------------------------------------------------
end # module end # module

View File

@ -1,160 +1,75 @@
"Represents an animation object"
struct Animation immutable Animation
dir::String dir::Compat.ASCIIString
frames::Vector{String} frames::Vector{Compat.ASCIIString}
end end
function Animation() function Animation()
tmpdir = convert(String, mktempdir()) tmpdir = convert(Compat.ASCIIString, mktempdir())
Animation(tmpdir, String[]) Animation(tmpdir, Compat.ASCIIString[])
end end
""" function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
frame(animation[, plot])
Add a plot (the current plot if not specified) to an existing animation
"""
function frame(anim::Animation, plt::P = current()) where {P<:AbstractPlot}
i = length(anim.frames) + 1 i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i) filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename)) png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename) push!(anim.frames, filename)
end end
giffn() = (isijulia() ? "tmp.gif" : tempname() * ".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname() * ".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname() * ".mp4")
webmfn() = (isijulia() ? "tmp.webm" : tempname() * ".webm")
mutable struct FrameIterator
itr
every::Int
kw
end
FrameIterator(itr; every = 1, kw...) = FrameIterator(itr, every, kw)
"""
Animate from an iterator which returns the plot args each iteration.
"""
function animate(fitr::FrameIterator, fn = giffn(); kw...)
anim = Animation()
for (i, plotargs) in enumerate(fitr.itr)
if mod1(i, fitr.every) == 1
plot(wraptuple(plotargs)...; fitr.kw...)
frame(anim)
end
end
gif(anim, fn; kw...)
end
# most things will implement this
function animate(obj, fn = giffn(); every = 1, fps = 20, loop = 0, kw...)
animate(FrameIterator(obj, every, kw), fn; fps = fps, loop = loop)
end
# ----------------------------------------------- # -----------------------------------------------
"Wraps the location of an animated gif so that it can be displayed" "Wraps the location of an animated gif so that it can be displayed"
struct AnimatedGif immutable AnimatedGif
filename::String filename::Compat.ASCIIString
end end
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end] function gif(anim::Animation, fn = (isijulia() ? "tmp.gif" : tempname()*".gif"); fps::Integer = 20)
fn = abspath(fn)
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim, fn; kw...) try
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim, fn, false; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim, fn, false; kw...)
webm(anim::Animation, fn = webmfn(); kw...) = buildanimation(anim, fn, false; kw...)
ffmpeg_framerate(fps) = "$fps" # high quality
ffmpeg_framerate(fps::Rational) = "$(fps.num)/$(fps.den)" speed = round(Int, 100 / fps)
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
include(file)
end
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
run(`convert -delay $speed -loop 0 $(joinpath(anim.dir, "*.png")) -alpha off $fn`)
function buildanimation( catch err
anim::Animation, warn("""Tried to create gif using convert (ImageMagick), but got error: $err
fn::AbstractString, ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
is_animated_gif::Bool = true; Will try ffmpeg, but it's lower quality...)""")
fps::Real = 20,
loop::Integer = 0, # low quality
variable_palette::Bool = false, run(`ffmpeg -v 0 -framerate $fps -i $(anim.dir)/%06d.png -y $fn`)
verbose = false, # run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
show_msg::Bool = true,
)
if length(anim.frames) == 0
throw(ArgumentError("Cannot build empty animations"))
end end
fn = abspath(expanduser(fn)) info("Saved animation to ", fn)
animdir = anim.dir
framerate = ffmpeg_framerate(fps)
verbose_level = (verbose isa Int ? verbose : verbose ? 32 : 16) # "error"
if is_animated_gif
if variable_palette
# generate a colorpalette for each frame for highest quality, but larger filesize
palette = "palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`,
)
else
# generate a colorpalette first so ffmpeg does not have to guess it
ffmpeg_exe(
`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`,
)
# then apply the palette to get better results
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`,
)
end
else
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`,
)
end
show_msg && @info("Saved animation to ", fn)
AnimatedGif(fn) AnimatedGif(fn)
end end
# write out html to view the gif
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
ext = file_extension(agif.filename)
if ext == "gif"
html =
"<img src=\"data:image/gif;base64," *
base64encode(read(agif.filename)) *
"\" />"
elseif ext in ("mov", "mp4", "webm")
mimetype = ext == "mov" ? "video/quicktime" : "video/$ext"
html =
"<video controls><source src=\"data:$mimetype;base64," *
base64encode(read(agif.filename)) *
"\" type = \"$mimetype\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end
write(io, html)
return nothing # write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
function Base.writemime(io::IO, ::MIME"text/html", agif::AnimatedGif)
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />")
end end
# Only gifs can be shown via image/gif
Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif"
function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif)
open(fio -> write(io, fio), agif.filename)
end
# ----------------------------------------------- # -----------------------------------------------
function _animate(forloop::Expr, args...; callgif = false) function _animate(forloop::Expr, args...; callgif = false)
if forloop.head (:for, :while) if forloop.head != :for
error("@animate macro expects a for- or while-block. got: $(forloop.head)") error("@animate macro expects a for-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
animsym = gensym("anim") animsym = gensym("anim")
countersym = gensym("counter") countersym = gensym("counter")
freqassert = :()
block = forloop.args[2] block = forloop.args[2]
# create filter # create filter
@ -167,7 +82,7 @@ function _animate(forloop::Expr, args...; callgif = false)
# filter every `freq` frames (starting with the first frame) # filter every `freq` frames (starting with the first frame)
@assert n == 2 @assert n == 2
freq = args[2] freq = args[2]
freqassert = :(@assert isa($freq, Integer) && $freq > 0) @assert isa(freq, Integer) && freq > 0
:(mod1($countersym, $freq) == 1) :(mod1($countersym, $freq) == 1)
elseif args[1] == :when elseif args[1] == :when
@ -179,23 +94,17 @@ function _animate(forloop::Expr, args...; callgif = false)
error("Unsupported animate filter: $args") error("Unsupported animate filter: $args")
end end
push!(block.args, :( push!(block.args, :(if $filterexpr; frame($animsym); end))
if $filterexpr
Plots.frame($animsym)
end
))
push!(block.args, :($countersym += 1)) push!(block.args, :($countersym += 1))
# add a final call to `gif(anim)`? # add a final call to `gif(anim)`?
retval = callgif ? :(Plots.gif($animsym)) : animsym retval = callgif ? :(gif($animsym)) : animsym
# full expression: # full expression:
esc(quote esc(quote
$freqassert # if filtering, check frequency is an Integer > 0 $animsym = Animation() # init animation object
$animsym = Plots.Animation() # init animation object $countersym = 1 # init iteration counter
let $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration $forloop # for loop, saving a frame after each iteration
end
$retval # return the animation object, or the gif $retval # return the animation object, or the gif
end) end)
end end
@ -222,11 +131,11 @@ Collect one frame per for-block iteration and return an `Animation` object.
Example: Example:
``` ```
p = plot(1) p = plot(1)
anim = @animate for x=0:0.1:5 anim = @animate for x=0:0.1:5
push!(p, 1, sin(x)) push!(p, 1, sin(x))
end end
gif(anim) gif(anim)
``` ```
""" """
macro animate(forloop::Expr, args...) macro animate(forloop::Expr, args...)

View File

@ -1,192 +1,110 @@
const _arg_desc = KW( const _arg_desc = KW(
# series args # series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.", :label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot", :seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.", :seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.", :seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)", :linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
:linewidth => "Number. Width of the line (in pixels)", :linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).", :linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.", :linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.", :fillrange => "Number or AbstractVector. Fills area from this to y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.", :fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.", :fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).", :markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
:fillstyle => "Symbol. Style of the fill area. `nothing` (the default) means solid fill. Choose from :/, :\\, :|, :-, :+, :x", :markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.", :markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.", :markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers", :markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)", :markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokewidth => "Number. Width of the marker stroke (border) in pixels", :markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:seriescolor`.",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.", :markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.", :bins => "Integer, NTuple{2,Integer}, AbstractVector. For histogram-types, defines the number of bins, or the edges, of the histogram.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`", :smooth => "Bool. Add a regression line?",
:smooth => "Bool. Add a regression line?", :group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`", :x => "Various. Input data. First Dimension",
:x => "Various. Input data. First Dimension", :y => "Various. Input data. Second Dimension",
:y => "Various. Input data. Second Dimension", :z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.", :marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.", :line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).", :levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.", :orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:levels => "Integer (number of contours) or AbstractVector (contour values). Determines contour levels for a contour type.", :bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:permute => "Tuple{Symbol,Symbol}. Permutes data and axis properties of the axes given in the tuple. E.g. (:x, :y).", :bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:orientation => "Symbol. (deprecated) Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", :bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)", :xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).", :yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?", :ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)", :quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)", :arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.", :normalize => "Bool. Should normalize histogram types? Trying for area == 1.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.", :weights => "AbstractVector. Used in histogram types for weighted counts.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.", :contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).", :match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:weights => "AbstractVector. Used in histogram types for weighted counts.", :subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default)", :series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.", :primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:contour_labels => "Bool. Show labels at the contour lines?", :hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
:z_order => "Symbol or Integer. :front (default), :back or index of position where 1 is farest in the background.",
# plot args # plot args
:plot_title => "String. Title for the whole plot (not the subplots)", :plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
:plot_titlevspan => "Number in [0,1]. Vertical span of the whole plot title (fraction of the plot height)", :background_color => "Color Type. Base color for all backgrounds.",
:background_color => "Color Type. Base color for all backgrounds.", :background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)", :foreground_color => "Color Type. Base color for all foregrounds.",
: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).", :overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).", :html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.", :inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.", :dpi => "Number. Dots Per Inch of output figures",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots", :display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:dpi => "Number. Dots Per Inch of output figures", :extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes",
# subplot args # subplot args
:title => "String. Subplot title.", :title => "String. Subplot title.",
:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`", :title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefontfamily => "String or Symbol. Font family of subplot title.", :titlefont => "Font. Font of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.", :background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center", :background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center", :background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:titlefontrotation => "Real. Font rotation of subplot title", :foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:titlefontcolor => "Color Type. Font color of subplot title", :foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.", :foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:legend_background_color => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.", :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", :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.",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.", :legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
:legend_foreground_color => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", :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)",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", :clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
: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.", :legendfont => "Font. Font of legend items.",
:legend_position => "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)", :grid => "Bool. Show the grid lines?",
:legend_column => "Integer. Number of columns in the legend. `-1` stands for maximum number of colums (horizontal legend).", :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.",
:legend_title_font => "Font. Font of the legend title.", :projection => "Symbol or String. '3d' or 'polar'",
:legend_font_family => "String or Symbol. Font family of legend entries.", :aspect_ratio => "Symbol (:equal) or Number (width to height ratio of plot area).",
:legend_font_pointsize => "Integer. Font pointsize of legend entries.", :margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:legend_font_halign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center", :left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:legend_font_valign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center", :top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:legend_font_rotation => "Real. Font rotation of legend entries", :right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:legend_font_color => "Color Type. Font color of legend entries", :bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:legend_title => "String. Legend title.", :subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:legend_title_font_family => "String or Symbol. Font family of the legend title.",
:legend_title_font_pointsize => "Integer. Font pointsize the legend title.", # axis args
:legend_title_font_halign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center", :guide => "String. Axis guide (label).",
:legend_title_font_valign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center", :lims => "NTuple{2,Number}. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).",
:legend_title_font_rotation => "Real. Font rotation of the legend title", :ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:legend_title_font_color => "Color Type. Font color of the legend title", :scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
: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)", :rotation => "Number. Degrees rotation of tick labels.",
:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.", :flip => "Bool. Should we flip (reverse) the axis?",
:colorbar_fontfamily => "String or Symbol. Font family of colobar entries.", :tickfont => "Font. Font of axis tick labels.",
:colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", :guidefont => "Font. Font of axis guide (label).",
:colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.", :foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.", :foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries", :foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`", :foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:legend_font => "Font. Font of legend items.",
:legend_titlefont => "Font. Font of the legend title.",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String, PlotText (created with `text(args...)`), or a tuple of arguments to `text` (e.g., `(\"Label\", 8, :red, :top)`). Add one-off text annotations at the x,y coordinates.",
:annotationfontfamily => "String or Symbol. Font family of annotations.",
:annotationfontsize => "Integer. Font pointsize of annotations.",
:annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.",
:annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.",
:annotationrotation => "Float. Rotation of annotations in degrees.",
:annotationcolor => "Colorant or :match. Color of annotations.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
:guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => """
NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).
`:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]
`:symmetric` sets the limits to be symmetric around zero.
Set widen=true to widen the specified limits (as occurs when lims are not specified).
""",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in`, `:out` or `:none`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => """
Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders.
Defaults to `:auto`, which widens unless limits were manually set.
""",
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
) )

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

208
src/backends/bokeh.jl Normal file
View File

@ -0,0 +1,208 @@
# https://github.com/bokeh/Bokeh.jl
supported_args(::BokehBackend) = merge_with_base_supported([
# :annotations,
# :axis,
# :background_color,
:linecolor,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
:group,
# :label,
# :layout,
# :legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
# :linealpha,
:markershape,
:markercolor,
:markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :bins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
:size,
:title,
# :window_title,
:x,
# :xguide,
# :xlims,
# :xticks,
:y,
# :yguide,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface,
# :levels,
])
supported_types(::BokehBackend) = [:path, :scatter]
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::BokehBackend) = [:identity, :ln]
is_subplot_supported(::BokehBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::BokehBackend; kw...)
@eval begin
warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
end
const _glyphtypes = KW(
:circle => :Circle,
:rect => :Square,
:diamond => :Diamond,
:utriangle => :Triangle,
:dtriangle => :InvertedTriangle,
# :pentagon =>
# :hexagon =>
# :heptagon =>
# :octagon =>
:cross => :Cross,
:xcross => :X,
:star5 => :Asterisk,
)
function bokeh_glyph_type(d::KW)
st = d[:seriestype]
mt = d[:markershape]
if st == :scatter && mt == :none
mt = :circle
end
# if we have a marker, use that
if st == :scatter || mt != :none
return _glyphtypes[mt]
end
# otherwise return a line
return :Line
end
function get_stroke_vector(linestyle::Symbol)
dash = 12
dot = 3
gap = 2
linestyle == :solid && return Int[]
linestyle == :dash && return Int[dash, gap]
linestyle == :dot && return Int[dot, gap]
linestyle == :dashdot && return Int[dash, gap, dot, gap]
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
error("unsupported linestyle: ", linestyle)
end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::BokehBackend, d::KW)
function _create_backend_figure(plt::Plot{BokehBackend})
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
datacolumns = Bokeh.BokehDataSet[]
tools = Bokeh.tools()
filename = tempname() * ".html"
title = plt.attr[:title]
w, h = plt.attr[:size]
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
# legend = plt.attr[:legend] ? xxxx : nothing
legend = nothing
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
# Plot(bplt, pkg, 0, d, KW[])
end
# function _series_added(::BokehBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{BokehBackend}, series::Series)
bdata = Dict{Symbol, Vector}(:x => collect(series.d[:x]), :y => collect(series.d[:y]))
glyph = Bokeh.Bokehjs.Glyph(
glyphtype = bokeh_glyph_type(d),
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
linewidth = d[:linewidth], # shape's stroke width or line width
fillcolor = webcolor(d[:markercolor]),
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
dash = get_stroke_vector(d[:linestyle])
)
legend = nothing # TODO
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
# push!(plt.seriesargs, d)
# plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot_object(plt::Plot{BokehBackend}, d::KW)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{BokehBackend}, i::Int)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y]
# end
#
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y] = xy
# plt
# end
# ----------------------------------------------------------------
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
Bokeh.showplot(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
# # TODO: display/show the subplot
# end

View File

@ -1,744 +0,0 @@
# https://github.com/sisl/PGFPlots.jl
# significant contributions by: @pkofod
# --------------------------------------------------------------------------------------
# COV_EXCL_START
const _pgfplots_linestyles = KW(
:solid => "solid",
:dash => "dashed",
:dot => "dotted",
:dashdot => "dashdotted",
:dashdotdot => "dashdotdotted",
)
const _pgfplots_markers = KW(
:none => "none",
:cross => "+",
:xcross => "x",
:+ => "+",
:x => "x",
:utriangle => "triangle*",
:dtriangle => "triangle*",
:circle => "*",
:rect => "square*",
:star5 => "star",
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
:hline => "-",
:vline => "|",
)
const _pgfplots_legend_pos = KW(
:bottomleft => "south west",
:bottomright => "south east",
:topright => "north east",
:topleft => "north west",
:outertopright => "outer north east",
)
const _pgf_series_extrastyle = KW(
:steppre => "const plot mark right",
:stepmid => "const plot mark mid",
:steppost => "const plot",
:sticks => "ycomb",
:ysticks => "ycomb",
:xsticks => "xcomb",
)
# PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor
const _pgf_annotation_halign = KW(:center => "", :left => "right", :right => "left")
const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
const _pgf_framestyle_defaults = Dict(:semi => :box)
function pgf_framestyle(style::Symbol)
if style in _pgf_framestyles
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
@warn(
"Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead."
)
default_style
end
end
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
function pgf_color(c::Colorant)
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
cstr, alpha(c)
end
function pgf_color(grad::ColorGradient)
# Can't handle ColorGradient here, fallback to defaults.
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316, 0.97868012)
cstr, 1
end
# Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c))
end, ", ")
end
pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
function pgf_fillstyle(plotattributes, i = 1)
cstr, a = pgf_color(get_fillcolor(plotattributes, i))
fa = get_fillalpha(plotattributes, i)
if fa !== nothing
a = fa
end
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
cstr, a = pgf_color(plot_color(color, α))
"""
color = $cstr,
draw opacity = $a,
line width = $linewidth,
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
end
function pgf_linestyle(plotattributes, i = 1)
lw = pgf_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i)
lc = get_linecolor(plotattributes, i)
la = get_linealpha(plotattributes, i)
ls = get_linestyle(plotattributes, i)
return pgf_linestyle(lw, lc, la, ls)
end
function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
fs = fontsize * thickness_scaling
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
end
function pgf_marker(plotattributes, i = 1)
shape = _cycle(plotattributes[:markershape], i)
cstr, a = pgf_color(
plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)),
)
cstr_stroke, a_stroke = pgf_color(
plot_color(
get_markerstrokecolor(plotattributes, i),
get_markerstrokealpha(plotattributes, i),
),
)
return string(
"mark = $(get(_pgfplots_markers, shape, "*")),\n",
"mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),\n",
plotattributes[:seriestype] == :scatter ? "only marks,\n" : "",
"mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid"))
}",
)
end
function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1)
# Construct the style string.
# Currently supports color and orientation
cstr, a = pgf_color(val.font.color)
push!(
o,
PGFPlots.Plots.Node(
val.str, # Annotation Text
x,
y,
style = """
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation),
font=$(pgf_font(val.font.pointsize, thickness_scaling))
""",
),
)
end
# --------------------------------------------------------------------------------------
function pgf_series(sp::Subplot, series::Series)
plotattributes = series.plotattributes
st = plotattributes[:seriestype]
series_collection = PGFPlots.Plot[]
# function args
args = if st == :contour
plotattributes[:z].surf, plotattributes[:x], plotattributes[:y]
elseif RecipesPipeline.is3d(st)
plotattributes[:x], plotattributes[:y], plotattributes[:z]
elseif st == :straightline
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif ispolar(sp)
theta, r = plotattributes[:x], plotattributes[:y]
rad2deg.(theta), r
else
plotattributes[:x], plotattributes[:y]
end
# PGFPlots can't handle non-Vector?
# args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
# collect(a)
# else
# a
# end, args)
if st in (:contour, :histogram2d)
style = []
kw = KW()
push!(style, pgf_linestyle(plotattributes))
push!(style, pgf_marker(plotattributes))
push!(style, "forget plot")
kw[:style] = join(style, ',')
func = if st == :histogram2d
PGFPlots.Histogram2
else
kw[:labels] = series[:contour_labels]
kw[:levels] = series[:levels]
PGFPlots.Contour
end
push!(series_collection, func(args...; kw...))
else
# series segments
segments = iter_segments(series)
for (i, rng) in enumerate(segments)
style = []
kw = KW()
push!(style, pgf_linestyle(plotattributes, i))
push!(style, pgf_marker(plotattributes, i))
if st == :shape
push!(style, pgf_fillstyle(plotattributes, i))
end
# add to legend?
if i == 1 && sp[:legend_position] != :none && should_add_to_legend(series)
if plotattributes[:fillrange] !== nothing
push!(style, "forget plot")
push!(series_collection, pgf_fill_legend_hack(plotattributes, args))
else
kw[:legendentry] = plotattributes[:label]
if st == :shape # || plotattributes[:fillrange] !== nothing
push!(style, "area legend")
end
end
else
push!(style, "forget plot")
end
seg_args = (arg[rng] for arg in args)
# include additional style, then add to the kw
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
# add fillrange
if series[:fillrange] !== nothing && st != :shape
push!(
series_collection,
pgf_fillrange_series(
series,
i,
_cycle(series[:fillrange], rng),
seg_args...,
),
)
end
# build/return the series object
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
else
PGFPlots.Linear
end
push!(series_collection, func(seg_args...; kw...))
end
end
series_collection
end
function pgf_fillrange_series(series, i, fillrange, args...)
st = series[:seriestype]
style = []
kw = KW()
push!(style, "line width = 0")
push!(style, "draw opacity = 0")
push!(style, pgf_fillstyle(series, i))
push!(style, pgf_marker(series, i))
push!(style, "forget plot")
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
func = RecipesPipeline.is3d(series) ? PGFPlots.Linear3 : PGFPlots.Linear
return func(pgf_fillrange_args(fillrange, args...)...; kw...)
end
function pgf_fillrange_args(fillrange, x, y)
n = length(x)
x_fill = [x; x[n:-1:1]; x[1]]
y_fill = [y; _cycle(fillrange, n:-1:1); y[1]]
return x_fill, y_fill
end
function pgf_fillrange_args(fillrange, x, y, z)
n = length(x)
x_fill = [x; x[n:-1:1]; x[1]]
y_fill = [y; y[n:-1:1]; x[1]]
z_fill = [z; _cycle(fillrange, n:-1:1); z[1]]
return x_fill, y_fill, z_fill
end
function pgf_fill_legend_hack(plotattributes, args)
style = []
kw = KW()
push!(style, pgf_linestyle(plotattributes, 1))
push!(style, pgf_marker(plotattributes, 1))
push!(style, pgf_fillstyle(plotattributes, 1))
push!(style, "area legend")
kw[:legendentry] = plotattributes[:label]
kw[:style] = join(style, ',')
st = plotattributes[:seriestype]
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
else
PGFPlots.Linear
end
return func(([arg[1]] for arg in args)...; kw...)
end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
axis = sp[get_attr_symbol(letter, :axis)]
style = []
kw = KW()
# turn off scaled ticks
push!(style, "scaled $(letter) ticks = false")
# set to supported framestyle
framestyle = pgf_framestyle(sp[:framestyle])
# axis guide
kw[get_attr_symbol(letter, :label)] = axis[:guide]
# axis label position
labelpos = ""
if letter == :x && axis[:guide_position] == :top
labelpos = "at={(0.5,1)},above,"
elseif letter == :y && axis[:guide_position] == :right
labelpos = "at={(1,0.5)},below,"
end
# Add label font
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
push!(
style,
string(
letter,
"label style = {",
labelpos,
"font = ",
pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
axis[:guidefontrotation],
"}",
),
)
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
# scale
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
kw[get_attr_symbol(letter, :mode)] = "log"
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
end
# ticks on or off
if axis[:ticks] in (nothing, false, :none) || framestyle == :none
push!(style, "$(letter)majorticks=false")
end
# grid on or off
if axis[:grid] && framestyle != :none
push!(style, "$(letter)majorgrids = true")
else
push!(style, "$(letter)majorgrids = false")
end
# limits
# TODO: support zlims
if letter != :z
lims =
ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
axis_limits(sp, letter)
kw[get_attr_symbol(letter, :min)] = lims[1]
kw[get_attr_symbol(letter, :max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
ticks = get_ticks(sp, axis)
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
tick_values =
ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] :
ticks[1]
push!(style, string(letter, "tick = {", join(tick_values, ","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = Vector{String}(undef, length(ticks[2]))
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
tick_labels[i] = string(base, "^", power)
end
push!(
style,
string(letter, "ticklabels = {\$", join(tick_labels, "\$,\$"), "\$}"),
)
elseif axis[:showaxis]
tick_labels =
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
if axis[:formatter] in (:scientific, :auto)
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
end
push!(style, string(letter, "ticklabels = {", join(tick_labels, ","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
end
push!(
style,
string(
letter,
"tick align = ",
(axis[:tick_direction] == :out ? "outside" : "inside"),
),
)
cstr, α = pgf_color(plot_color(axis[:tickfontcolor]))
push!(
style,
string(
letter,
"ticklabel style = {font = ",
pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
axis[:tickfontrotation],
"}",
),
)
push!(
style,
string(
letter,
" grid style = {",
pgf_linestyle(
pgf_thickness_scaling(sp) * axis[:gridlinewidth],
axis[:foreground_color_grid],
axis[:gridalpha],
axis[:gridstyle],
),
"}",
),
)
end
# framestyle
if framestyle in (:axes, :origin)
axispos = framestyle == :axes ? "left" : "middle"
if axis[:draw_arrow]
push!(style, string("axis ", letter, " line = ", axispos))
else
# the * after line disables the arrow at the axis
push!(style, string("axis ", letter, " line* = ", axispos))
end
end
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(
style,
string(
"extra ",
letter,
" tick style = {grid = major, major grid style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
axis[:foreground_color_border],
1.0,
),
"}}",
),
)
end
if !axis[:showaxis]
push!(style, "separate axis lines")
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
else
push!(
style,
string(
letter,
" axis line style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
axis[:foreground_color_border],
1.0,
),
"}",
),
)
end
# return the style list and KW args
style, kw
end
# ----------------------------------------------------------------
function _update_plot_object(plt::Plot{PGFPlotsBackend})
plt.o = PGFPlots.Axis[]
# Obtain the total height of the plot by extracting the maximal bottom
# coordinate from the bounding box.
total_height = bottom(bbox(plt.layout))
for sp in plt.subplots
# first build the PGFPlots.Axis object
style = ["unbounded coords=jump"]
kw = KW()
# add to style/kw for each axis
for letter in (:x, :y, :z)
if letter != :z || RecipesPipeline.is3d(sp)
axisstyle, axiskw = pgf_axis(sp, letter)
append!(style, axisstyle)
merge!(kw, axiskw)
end
end
# bounding box values are in mm
# note: bb origin is top-left, pgf is bottom-left
# A round on 2 decimal places should be enough precision for 300 dpi
# plots.
bb = bbox(sp)
push!(
style,
"""
xshift = $(left(bb).value)mm,
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""",
)
kw[:width] = "$(width(bb).value)mm"
kw[:height] = "$(height(bb).value)mm"
if sp[:title] != ""
kw[:title] = "$(sp[:title])"
cstr, α = pgf_color(plot_color(sp[:titlefontcolor]))
push!(
style,
string(
"title style = {font = ",
pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
sp[:titlefontrotation],
"}",
),
)
end
if get_aspect_ratio(sp) in (1, :equal)
kw[:axisEqual] = "true"
end
legpos = sp[:legend_position]
if haskey(_pgfplots_legend_pos, legpos)
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
cstr, bg_alpha = pgf_color(plot_color(sp[:legend_background_color]))
fg_alpha = alpha(plot_color(sp[:legend_foreground_color]))
push!(
style,
string(
"legend style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
sp[:legend_foreground_color],
fg_alpha,
"solid",
),
",",
"fill = $cstr,",
"fill opacity = $bg_alpha,",
"text opacity = $(alpha(plot_color(sp[:legend_font_color]))),",
"font = ",
pgf_font(sp[:legend_font_pointsize], pgf_thickness_scaling(sp)),
"}",
),
)
if any(s[:seriestype] == :contour for s in series_list(sp))
kw[:view] = "{0}{90}"
kw[:colorbar] = !(sp[:colorbar] in (:none, :off, :hide, false))
elseif RecipesPipeline.is3d(sp)
azim, elev = sp[:camera]
kw[:view] = "{$(azim)}{$(elev)}"
end
axisf = PGFPlots.Axis
if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis
#make radial axis vertical
kw[:xmin] = 90
kw[:xmax] = 450
end
# Search series for any gradient. In case one series uses a gradient set
# the colorbar and colomap.
# The reasoning behind doing this on the axis level is that pgfplots
# colorbar seems to only works on axis level and needs the proper colormap for
# correctly displaying it.
# It's also possible to assign the colormap to the series itself but
# then the colormap needs to be added twice, once for the axis and once for the
# series.
# As it is likely that all series within the same axis use the same
# colormap this should not cause any problem.
for series in series_list(sp)
for col in (:markercolor, :fillcolor, :linecolor)
if typeof(series.plotattributes[col]) == ColorGradient
push!(
style,
"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}",
)
if sp[:colorbar] == :none
kw[:colorbar] = "false"
else
kw[:colorbar] = "true"
end
# goto is needed to break out of col and series for
@goto colorbar_end
end
end
end
@label colorbar_end
push!(style, "colorbar style={title=$(sp[:colorbar_title])}")
o = axisf(; style = join(style, ","), kw...)
# add the series object to the PGFPlots.Axis
for series in series_list(sp)
push!.(Ref(o), pgf_series(sp, series))
# add series annotations
anns = series[:series_annotations]
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
pgf_add_annotation!(
o,
xi,
yi,
PlotText(str, fnt),
pgf_thickness_scaling(series),
)
end
end
# add the annotations
for ann in sp[:annotations]
pgf_add_annotation!(
o,
locate_annotation(sp, ann...)...,
pgf_thickness_scaling(sp),
)
end
# add the PGFPlots.Axis to the list
push!(plt.o, o)
end
end
function _show(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
show(io, mime, plt.o)
end
function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
# prepare the object
pgfplt = PGFPlots.plot(plt.o)
# save a pdf
fn = tempname() * ".pdf"
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
write(io, read(open(fn), String))
# cleanup
PGFPlots.cleanup(plt.o)
end
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
fn = tempname() * ".tex"
PGFPlots.save(
fn,
backend_object(plt),
include_preamble = plt.attr[:tex_output_standalone],
)
write(io, read(open(fn), String))
end
function _display(plt::Plot{PGFPlotsBackend})
# prepare the object
pgfplt = PGFPlots.plot(plt.o)
# save an svg
fn = string(tempname(), ".svg")
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
# show it
open_browser_window(fn)
# cleanup
PGFPlots.cleanup(plt.o)
end
# COV_EXCL_STOP

744
src/backends/gadfly.jl Normal file
View File

@ -0,0 +1,744 @@
# https://github.com/dcjones/Gadfly.jl
supported_args(::GadflyBackend) = merge_with_base_supported([
:annotations,
:background_color, :foreground_color, :color_palette,
:group, :label, :seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :n, :nc, :nr, :layout, :smooth,
:title, :window_title, :show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
:z,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
])
supported_types(::GadflyBackend) = [
:path,
:scatter, :hexbin,
:bar,
:contour, :shape
]
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
is_subplot_supported(::GadflyBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GadflyBackend; kw...)
@eval begin
import Gadfly, Compose
export Gadfly, Compose
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
end
end
# ---------------------------------------------------------------------------
# immutable MissingVec <: AbstractVector{Float64} end
# Base.size(v::MissingVec) = (1,)
# Base.getindex(v::MissingVec, i::Integer) = 0.0
function createGadflyPlotObject(d::KW)
gplt = Gadfly.Plot()
gplt.mapping = Dict()
gplt.data_source = Gadfly.DataFrames.DataFrame()
# gplt.layers = gplt.layers[1:0]
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]),
Gadfly.Guide.ylabel(d[:yguide]),
Gadfly.Guide.title(d[:title])]
gplt
end
# ---------------------------------------------------------------------------
function getLineGeom(d::KW)
st = d[:seriestype]
xbins, ybins = maketuple(d[:bins])
if st == :hexb
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
elseif st == :histogram2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif st == :histogram
Gadfly.Geom.histogram(bincount = xbins,
orientation = isvertical(d) ? :vertical : :horizontal,
position = d[:bar_position] == :stack ? :stack : :dodge)
elseif st == :path
Gadfly.Geom.path
elseif st in (:bar, :sticks)
Gadfly.Geom.bar
elseif st == :steppost
Gadfly.Geom.step
elseif st == :steppre
Gadfly.Geom.step(direction = :vh)
elseif st == :hline
Gadfly.Geom.hline
elseif st == :vline
Gadfly.Geom.vline
elseif st == :contour
Gadfly.Geom.contour(levels = d[:levels])
# elseif st == :shape
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
nothing
end
end
function get_extra_theme_args(d::KW, k::Symbol)
# gracefully handles old Gadfly versions
extra_theme_args = KW()
try
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k])
catch err
if string(err) == "UndefVarError(:get_stroke_vector)"
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
else
rethrow()
end
end
extra_theme_args
end
function getGadflyLineTheme(d::KW)
st = d[:seriestype]
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
Gadfly.Theme(;
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
line_width = (st == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
lowlight_color = x->RGB(fc), # fill/ribbon
lowlight_opacity = alpha(fc), # fill/ribbon
bar_highlight = RGB(lc), # bars
get_extra_theme_args(d, :linestyle)...
)
end
# add a line as a new layer
function addGadflyLine!(plt::Plot, numlayers::Int, d::KW, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms..., getGadflyLineTheme(d))
kwargs = KW()
st = d[:seriestype]
# add a fill?
if d[:fillrange] != nothing && st != :contour
fillmin, fillmax = map(makevec, maketuple(d[:fillrange]))
nmin, nmax = length(fillmin), length(fillmax)
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
push!(gfargs, Gadfly.Geom.ribbon)
end
if st in (:hline, :vline)
kwargs[st == :hline ? :yintercept : :xintercept] = d[:y]
else
if st == :sticks
w = 0.01 * mean(diff(d[:x]))
kwargs[:xmin] = d[:x] - w
kwargs[:xmax] = d[:x] + w
elseif st == :contour
kwargs[:z] = d[:z].surf
addGadflyContColorScale(plt, d[:linecolor])
end
kwargs[:x] = d[st == :histogram ? :y : :x]
kwargs[:y] = d[:y]
end
# # add the layer
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
get_shape(sym::Symbol) = _shapes[sym]
get_shape(shape::Shape) = shape
# extract the underlying ShapeGeometry object(s)
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
getMarkerGeom(other) = gadflyshape(get_shape(other))
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
function getMarkerGeom(d::KW)
if d[:seriestype] == :shape
Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
getMarkerGeom(d[:markershape])
end
end
function getGadflyMarkerTheme(d::KW, attr::KW)
c = getColor(d[:markercolor])
α = d[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
ms = d[:markersize]
ms = if typeof(ms) <: AVec
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
mean(ms) * Gadfly.px
else
ms * Gadfly.px
end
Gadfly.Theme(;
default_color = c,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
highlight_width = d[:markerstrokewidth] * Gadfly.px,
line_width = d[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(d, :markerstrokestyle)...
)
end
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
plt.attr[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = default_gradient()
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d))
kwargs = KW()
# handle continuous color scales for the markers
zcolor = d[:marker_z]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, d[:markercolor])
end
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
function addToGadflyLegend(plt::Plot, d::KW)
if plt.attr[:legend] != :none && d[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", @compat(AbstractString)[], Color[]))
end
# now add the series to the legend
for guide in gplt.guides
if isa(guide, Gadfly.Guide.ManualColorKey)
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
foundit = false
# extend the label if we found this color
for i in 1:length(guide.colors)
if RGB(c) == guide.colors[i]
guide.labels[i] *= ", " * d[:label]
foundit = true
end
end
# didn't find the color, so add a new entry into the legend
if !foundit
push!(guide.labels, d[:label])
push!(guide.colors, c)
end
end
end
end
end
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
function addGadflySeries!(plt::Plot, d::KW)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
smooth = getGadflySmoothing(d[:smooth])
# lines
geom = getLineGeom(d)
if geom != nothing
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
smooth = Any[] # don't add a regression for markers too
end
# special handling for ohlc and scatter
st = d[:seriestype]
# if st == :ohlc
# error("Haven't re-implemented after refactoring")
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
elseif st == :scatter && d[:markershape] == :none
d[:markershape] = :circle
end
# markers
if d[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...))
end
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
# now save the layers that apply to this series
d[:gadflylayers] = layers
prepend!(gplt.layers, layers)
end
# ---------------------------------------------------------------------------
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
# # colorgroup
# z = d[:z]
# # handle line segments of different colors
# cscheme = d[:linecolor]
# if isa(cscheme, ColorVector)
# # create a color scale, and set the color group to the index of the color
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
# colorgroup = [(:linecolor, cs), (:group, grp)]
# ---------------------------------------------------------------------------
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
ticks == :auto && return
# remove the ticks?
if ticks in (:none, false, nothing)
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
end
ttype = ticksType(ticks)
# just the values... put ticks here, but use standard labels
if ttype == :ticks
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
# set the ticks and the labels
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
elseif ttype == :ticks_and_labels
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
# # TODO add xtick_label function (given tick, return label??)
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
# filterGadflyScale(gplt, isx)
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
# labelmap = Dict(zip(ticks...))
# labelfunc = val -> labelmap[val]
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
filterGadflyScale(gplt, isx)
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
push!(gplt.scales, gfunc(labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
end
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
function getGadflyScaleFunction(d::KW, isx::Bool)
scalekey = isx ? :xscale : :yscale
hasScaleKey = haskey(d, scalekey)
if hasScaleKey
scale = d[scalekey]
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
end
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
end
function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
gfunc, hasScaleKey, func = getGadflyScaleFunction(d, isx)
# do we want to add min/max limits for the axis?
limsym = isx ? :xlims : :ylims
limargs = Any[]
# map :auto to nothing, otherwise add to limargs
lims = get(d, limsym, :auto)
if lims == :auto
lims = nothing
else
if limsType(lims) == :limits
push!(limargs, (:minvalue, min(lims...)))
push!(limargs, (:maxvalue, max(lims...)))
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
end
# replace any current scales with this one
if hasScaleKey || !isempty(limargs)
filterGadflyScale(gplt, isx)
push!(gplt.scales, gfunc(; limargs...))
end
lims, func
end
function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
if isa(gplt.coord, Gadfly.Coord.Cartesian)
gplt.coord = Gadfly.Coord.cartesian(
gplt.coord.xvars,
gplt.coord.yvars;
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
xflip = get(d, :xflip, gplt.coord.xflip),
yflip = get(d, :yflip, gplt.coord.yflip),
fixed = gplt.coord.fixed,
aspect_ratio = gplt.coord.aspect_ratio,
raster = gplt.coord.raster
)
else
gplt.coord = Gadfly.Coord.Cartesian(
xflip = get(d, :xflip, false),
yflip = get(d, :yflip, false)
)
end
end
function findGuideAndSet(gplt, t::DataType, args...; kw...) #s::@compat(AbstractString))
for (i,guide) in enumerate(gplt.guides)
if isa(guide, t)
gplt.guides[i] = t(args...; kw...)
end
end
end
function updateGadflyGuides(plt::Plot, d::KW)
gplt = getGadflyContext(plt)
haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title]))
haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide]))
haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide]))
xlims, xfunc = addGadflyLimitsScale(gplt, d, true)
ylims, yfunc = addGadflyLimitsScale(gplt, d, false)
ticks = get(d, :xticks, :auto)
if ticks == :none
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(d, :yticks, :auto)
if ticks == :none
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
updateGadflyAxisFlips(gplt, d, xlims, ylims, xfunc, yfunc)
end
function updateGadflyPlotTheme(plt::Plot, d::KW)
kwargs = KW()
# colors
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
map(s -> getColor(d[s]), (
:background_color_inside,
:foreground_color_grid,
:foreground_color_text,
:foreground_color_guide,
:foreground_color_legend
))
# # hide the legend?
leg = d[d[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(d, :grid, true)
kwargs[:grid_color] = gridcolor
end
# fonts
tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont]
getGadflyContext(plt).theme = Gadfly.Theme(;
background_color = insidecolor,
minor_label_color = textcolor,
minor_label_font = tfont.family,
minor_label_font_size = tfont.pointsize * Gadfly.pt,
major_label_color = guidecolor,
major_label_font = gfont.family,
major_label_font_size = gfont.pointsize * Gadfly.pt,
key_title_color = guidecolor,
key_title_font = gfont.family,
key_title_font_size = gfont.pointsize * Gadfly.pt,
key_label_color = legendcolor,
key_label_font = lfont.family,
key_label_font_size = lfont.pointsize * Gadfly.pt,
plot_padding = 1 * Gadfly.mm,
kwargs...
)
end
# ----------------------------------------------------------------
function createGadflyAnnotationObject(x, y, val::@compat(AbstractString))
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, val)
))
end
function createGadflyAnnotationObject(x, y, txt::PlotText)
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, txt.str, halign, valign, rotations...),
Compose.font(string(txt.font.family)),
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
Compose.stroke(txt.font.color),
Compose.fill(txt.font.color)
))
end
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::GadflyBackend, d::KW)
# gplt = createGadflyPlotObject(d)
# Plot(gplt, pkg, 0, d, KW[])
# end
function _create_backend_figure(plt::Plot{GadflyBackend})
createGadflyPlotObject(plt.attr)
end
# plot one data series
# function _series_added(::GadflyBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{GadflyBackend}, series::Series)
# first clear out the temporary layer
gplt = getGadflyContext(plt)
if gplt.layers[1].geom.tag == :remove
gplt.layers = gplt.layers[2:end]
end
addGadflySeries!(plt, series.d)
# push!(plt.seriesargs, d)
# plt
end
function _update_plot_object(plt::Plot{GadflyBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
# ----------------------------------------------------------------
# accessors for x/y data
# TODO: need to save all the layer indices which apply to this series
function getGadflyMappings(plt::Plot, i::Integer)
@assert i > 0 && i <= plt.n
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
end
function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer)
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
# isbefore && return false # wait until after plotting to create the subplots
# subplt.o = nothing
# true
# end
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
# function buildGadflySubplotContext(subplt::Subplot)
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
#
# # add the Plot object to the row
# push!(row, getGadflyContext(subplt.plts[i]))
#
# # add the row
# if c == ncols(subplt.layout, r)
# push!(rows, Gadfly.hstack(row...))
# row = Any[]
# end
# end
#
# # stack the rows
# Gadfly.vstack(rows...)
# end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
# -------------------------------------------------------------------------
function dowritemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.writemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
func = getGadflyWriteFunc($mime())
dowritemime(io, func, plt)
end
end
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
setGadflyDisplaySize(plt.attr[:size]...)
display(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
# ctx = buildGadflySubplotContext(subplt)
#
# # taken from Gadfly since I couldn't figure out how to do it directly
#
# filename = string(Gadfly.tempname(), ".html")
# output = open(filename, "w")
#
# plot_output = IOBuffer()
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
# Compose.default_graphic_height, false), ctx)
# plotsvg = takebuf_string(plot_output)
#
# write(output,
# """
# <!DOCTYPE html>
# <html>
# <head>
# <title>Gadfly Plot</title>
# <meta charset="utf-8">
# </head>
# <body>
# <script charset="utf-8">
# $(readall(Compose.snapsvgjs))
# </script>
# <script charset="utf-8">
# $(readall(Gadfly.gadflyjs))
# </script>
# $(plotsvg)
# </body>
# </html>
# """)
# close(output)
# Gadfly.open_file(filename)
# end

View File

@ -0,0 +1,93 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
immutable ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
new(shape, tag)
end
end
# TODO: add for PR
# const shape = ShapeGeometry
function Gadfly.element_aesthetics(::ShapeGeometry)
[:x, :y, :size, :color]
end
# Generate a form for a shape geometry.
#
# Args:
# geom: shape geometry.
# theme: the plot's theme.
# aes: aesthetics.
#
# Returns:
# A compose Form.
#
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
# TODO: add for PR
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
# element_aesthetics(geom)...)
default_aes = Gadfly.Aesthetics()
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
default_aes.size = Compose.Measure[theme.default_point_size]
aes = Gadfly.inherit(aes, default_aes)
lw_hover_scale = 10
lw_ratio = theme.line_width / aes.size[1]
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
ctx = Compose.compose!(
Compose.context(),
make_polygon(geom, aes.x, aes.y, aes.size),
Compose.fill(aes.color),
Compose.linewidth(theme.highlight_width))
if aes.color_key_continuous != nothing && aes.color_key_continuous
Compose.compose!(ctx,
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
else
Compose.compose!(ctx,
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
for c in aes.color]))
end
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
end
function gadflyshape(sv::Shape)
ShapeGeometry(Any[vertices(sv)])
end
function gadflyshape(sv::AVec{Shape})
ShapeGeometry(Any[vertices(s) for s in sv])
end
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs))
T = Tuple{Compose.Measure, Compose.Measure}
polys = Array(Vector{T}, n)
for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
# ---------------------------------------------------------------------------------------------

View File

@ -1,604 +0,0 @@
# https://github.com/mbaz/Gaston.
should_warn_on_unsupported(::GastonBackend) = false
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{GastonBackend})
state_handle = Gaston.nexthandle() # for now all the figures will be kept
plt.o = Gaston.newfigure(state_handle)
end
function _before_layout_calcs(plt::Plot{GastonBackend})
# Initialize all the subplots first
plt.o.subplots = Gaston.SubPlot[]
n1 = n2 = 0
if length(plt.inset_subplots) > 0
n1, sps = gaston_get_subplots(0, plt.inset_subplots, plt.layout)
gaston_init_subplots(plt, sps)
end
if length(plt.subplots) > 0
n2, sps = gaston_get_subplots(0, plt.subplots, plt.layout)
end
if (n = n1 + n2) != length(plt.subplots)
@error "Gaston: $n != $(length(plt.subplots))"
end
plt.o.layout = gaston_init_subplots(plt, sps)
# Then add the series (curves in gaston)
for series in plt.series_list
gaston_add_series(plt, series)
end
for sp in plt.subplots
sp === nothing && continue
for ann in sp[:annotations]
x, y, val = locate_annotation(sp, ann...)
sp.o.axesconf *= "\nset label '$(val.str)' at $x,$y $(gaston_font(val.font))"
end
end
nothing
end
function _update_min_padding!(sp::Subplot{GastonBackend})
sp.minpad = 0mm, 0mm, 0mm, 0mm
nothing
end
function _update_plot_object(plt::Plot{GastonBackend})
# respect the layout ratio
dat = gaston_multiplot_pos_size(plt.layout, (0, 0, 1, 1))
gaston_multiplot_pos_size!(dat)
nothing
end
for (mime, term) in (
"application/eps" => "epscairo",
"image/eps" => "epslatex",
"application/pdf" => "pdfcairo",
"application/postscript" => "postscript",
"image/png" => "png",
"image/svg+xml" => "svg",
"text/latex" => "tikz",
"application/x-tex" => "epslatex",
"text/plain" => "dumb",
)
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GastonBackend})
term = String($term)
tmpfile = "$(Gaston.tempname()).$term"
Gaston.save(
term = term,
output = tmpfile,
handle = plt.o.handle,
saveopts = gaston_saveopts(plt),
)
while !isfile(tmpfile)
end # avoid race condition with read in next line
write(io, read(tmpfile))
rm(tmpfile, force = true)
nothing
end
end
_display(plt::Plot{GastonBackend}) = display(plt.o)
# --------------------------------------------
# These functions are gaston specific
# --------------------------------------------
function gaston_saveopts(plt::Plot{GastonBackend})
saveopts = String["size $(join(plt.attr[:size], ","))"]
push!(
saveopts,
gaston_font(
plottitlefont(plt),
rot = false,
align = false,
color = false,
scale = 1,
),
)
push!(saveopts, "background $(gaston_color(plt.attr[:background_color]))")
# push!(saveopts, "title '$(plt.attr[:window_title])'")
# Scale all plot elements to match Plots.jl DPI standard
scaling = plt.attr[:dpi] / Plots.DPI
push!(saveopts, "fontscale $scaling lw $scaling dl $scaling") # ps $scaling
return join(saveopts, " ")
end
function gaston_get_subplots(n, plt_subplots, layout)
nr, nc = size(layout)
sps = Array{Any}(nothing, nr, nc)
for r in 1:nr, c in 1:nc # NOTE: col major
l = layout[r, c]
if l isa GridLayout
n, sub = gaston_get_subplots(n, plt_subplots, l)
sps[r, c] = size(sub) == (1, 1) ? only(sub) : sub
else
sps[r, c] = get(l.attr, :blank, false) ? nothing : plt_subplots[n += 1]
end
end
return n, sps
end
function gaston_init_subplots(plt, sps)
sz = nr, nc = size(sps)
for c in 1:nc, r in 1:nr # NOTE: row major
sp = sps[r, c]
if sp isa Subplot || sp === nothing
gaston_init_subplot(plt, sp)
else
gaston_init_subplots(plt, sp)
sz = max.(sz, size(sp))
end
end
return sz
end
function gaston_init_subplot(
plt::Plot{GastonBackend},
sp::Union{Nothing,Subplot{GastonBackend}},
)
if sp === nothing
push!(plt.o.subplots, sp)
else
dims =
RecipesPipeline.is3d(sp) ||
sp.attr[:projection] == "3d" ||
needs_any_3d_axes(sp) ? 3 : 2
any_label = false
for series in series_list(sp)
if dims == 2 && series[:seriestype] (:heatmap, :contour)
dims = 3 # we need heatmap/contour to use splot, not plot
end
any_label |= should_add_to_legend(series)
end
sp.o = Gaston.Plot(
dims = dims,
curves = [],
axesconf = gaston_parse_axes_args(plt, sp, dims, any_label),
)
push!(plt.o.subplots, sp.o)
end
nothing
end
function gaston_multiplot_pos_size(layout, parent_xy_wh)
nr, nc = size(layout)
dat = Array{Any}(nothing, nr, nc)
for r in 1:nr, c in 1:nc
l = layout[r, c]
# width and height (pct) are multiplicative (parent)
w = layout.widths[c].value * parent_xy_wh[3]
h = layout.heights[r].value * parent_xy_wh[4]
if isa(l, EmptyLayout)
dat[r, c] = (c - 1) * w, (r - 1) * h, w, h, nothing
else
# previous position (origin)
prev_r = r > 1 ? dat[r - 1, c] : nothing
prev_c = c > 1 ? dat[r, c - 1] : nothing
prev_r isa Array && (prev_r = prev_r[end, end])
prev_c isa Array && (prev_c = prev_c[end, end])
x = prev_c !== nothing ? prev_c[1] + prev_c[3] : parent_xy_wh[1]
y = prev_r !== nothing ? prev_r[2] + prev_r[4] : parent_xy_wh[2]
if l isa GridLayout
sub = gaston_multiplot_pos_size(l, (x, y, w, h))
dat[r, c] = size(sub) == (1, 1) ? only(sub) : sub
else
dat[r, c] = x, y, w, h, l
end
end
end
return dat
end
function gaston_multiplot_pos_size!(dat)
nr, nc = size(dat)
for r in 1:nr, c in 1:nc
xy_wh_sp = dat[r, c]
if xy_wh_sp isa Array
gaston_multiplot_pos_size!(xy_wh_sp)
elseif xy_wh_sp isa Tuple
x, y, w, h, sp = xy_wh_sp
sp === nothing && continue
sp.o === nothing && continue
# gnuplot screen coordinates: bottom left at 0,0 and top right at 1,1
sp.o.axesconf = "set origin $x, $(1 - y - h)\nset size $w, $h\n" * sp.o.axesconf
end
end
nothing
end
function gaston_add_series(plt::Plot{GastonBackend}, series::Series)
sp = series[:subplot]
gsp = sp.o
x, y, z = series[:x], series[:y], series[:z]
st = series[:seriestype]
curves = []
if gsp.dims == 2 && z === nothing
for (n, seg) in enumerate(series_segments(series, st; check = true))
i, rng = seg.attr_index, seg.range
fr = _cycle(series[:fillrange], 1:length(x[rng]))
for sc in gaston_seriesconf!(sp, series, i, n == 1)
push!(curves, Gaston.Curve(x[rng], y[rng], nothing, fr, sc))
end
end
else
if z isa Surface
z = z.surf
if st == :image
z = reverse(Float32.(Gray.(z)), dims = 1) # flip y axis
nr, nc = size(z)
if (ly = length(y)) == 2 && ly != nr
y = collect(range(y[1], y[2], length = nr))
end
if (lx = length(x)) == 2 && lx != nc
x = collect(range(x[1], x[2], length = nc))
end
end
length(x) == size(z, 2) + 1 && (x = (x[1:(end - 1)] + x[2:end]) / 2)
length(y) == size(z, 1) + 1 && (y = (y[1:(end - 1)] + y[2:end]) / 2)
end
if st == :mesh3d
x, y, z = mesh3d_triangles(x, y, z, series[:connections])
end
for sc in gaston_seriesconf!(sp, series, 1, true)
push!(curves, Gaston.Curve(x, y, z, nothing, sc))
end
end
for c in curves
append = length(gsp.curves) > 0
push!(gsp.curves, c)
Gaston.write_data(c, gsp.dims, gsp.datafile, append = append)
end
nothing
end
function gaston_seriesconf!(
sp::Subplot{GastonBackend},
series::Series,
i::Int,
add_to_legend::Bool,
)
#=
gnuplot abbreviations (see gnuplot/src/set.c)
---------------------------------------------
dl: dashlength
dt: dashtype
fc: fillcolor
fs: fillstyle
lc: linecolor
lp: linespoints
ls: linestyle
lt: linetype
lw: linewidth
pi: pointinterval
pn: pointnumber
ps: pointscale
pt: pointtype
tc: textcolor
w: with
=#
gsp = sp.o
st = series[:seriestype]
extra = []
add_to_legend &= should_add_to_legend(series)
curveconf = String[add_to_legend ? "title '$(series[:label])'" : "notitle"]
clims = get_clims(sp, series)
if st (:scatter, :scatter3d)
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
pt, ps, mc = gaston_mk_ms_mc(series, clims, i)
push!(curveconf, "w points pt $pt ps $ps lc $mc")
elseif st (:path, :straightline, :path3d)
fr = series[:fillrange]
fc = gaston_color(get_fillcolor(series, i), get_fillalpha(series, i))
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
if fr !== nothing # filled curves, but not filled curves with markers
push!(
curveconf,
"w filledcurves fc $fc fs solid border lc $lc lw $lw dt $dt,'' w lines lc $lc lw $lw dt $dt",
)
elseif series[:markershape] == :none # simplepath
push!(curveconf, "w lines lc $lc dt $dt lw $lw")
else
pt, ps, mc = gaston_mk_ms_mc(series, clims, i)
push!(curveconf, "w lp lc $mc dt $dt lw $lw pt $pt ps $ps")
end
elseif st == :shape
fc = gaston_color(get_fillcolor(series, i), get_fillalpha(series, i))
lc, _ = gaston_lc_ls_lw(series, clims, i)
push!(curveconf, "w filledcurves fc $fc fs solid border lc $lc")
elseif st (:steppre, :stepmid, :steppost)
step = if st == :steppre
"fsteps"
elseif st == :stepmid
"histeps"
elseif st == :steppost
"steps"
end
push!(curveconf, "w $step")
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
push!(extra, "w points lc $lc dt $dt lw $lw notitle")
elseif st == :image
palette = gaston_palette(series[:seriescolor])
gsp.axesconf *= "\nset palette model RGB defined $palette"
push!(curveconf, "w image pixels")
elseif st (:contour, :contour3d)
push!(curveconf, "w lines")
st == :contour && (gsp.axesconf *= "\nset view map\nunset surface") # 2D
levels = join(map(string, collect(contour_levels(series, clims))), ", ")
gsp.axesconf *= "\nset contour base\nset cntrparam levels discrete $levels"
elseif st (:surface, :heatmap)
push!(curveconf, "w pm3d")
palette = gaston_palette(series[:seriescolor])
gsp.axesconf *= "\nset palette model RGB defined $palette"
st == :heatmap && (gsp.axesconf *= "\nset view map")
elseif st (:wireframe, :mesh3d)
lc, dt, lw = gaston_lc_ls_lw(series, clims, i)
push!(curveconf, "w lines lc $lc dt $dt lw $lw")
elseif st == :quiver
push!(curveconf, "w vectors filled")
else
@warn "Gaston: $st is not implemented yet"
end
return [join(curveconf, " "), extra...]
end
function gaston_parse_axes_args(
plt::Plot{GastonBackend},
sp::Subplot{GastonBackend},
dims::Int,
any_label::Bool,
)
# axesconf = String["set margins 2, 2, 2, 2"] # left, right, bottom, top
axesconf = String[]
polar = ispolar(sp) && dims == 2 # cannot splot in polar coordinates
for letter in (:x, :y, :z)
(letter == :z && dims == 2) && continue
axis = sp.attr[get_attr_symbol(letter, :axis)]
# label names
push!(
axesconf,
"set $(letter)label '$(axis[:guide])' $(gaston_font(guidefont(axis)))",
)
mirror = axis[:mirror] ? "mirror" : "nomirror"
if axis[:scale] == :identity
logscale, base = "nologscale", ""
elseif axis[:scale] == :log10
logscale, base = "logscale", "10"
elseif axis[:scale] == :log2
logscale, base = "logscale", "2"
elseif axis[:scale] == :ln
logscale, base = "logscale", "e"
end
push!(axesconf, "set $logscale $letter $base")
# handle ticks
if polar
push!(axesconf, "set size square\nunset $(letter)tics")
else
push!(
axesconf,
"set $(letter)tics $(mirror) $(axis[:tick_direction]) $(gaston_font(tickfont(axis)))",
)
# major tick locations
if axis[:ticks] != :native
if axis[:flip]
hi, lo = axis_limits(sp, letter)
else
lo, hi = axis_limits(sp, letter)
end
push!(axesconf, "set $(letter)range [$lo:$hi]")
ticks = get_ticks(sp, axis)
gaston_set_ticks!(axesconf, ticks, letter, "", "")
if axis[:minorticks] != :native
minor_ticks = get_minor_ticks(sp, axis, ticks)
gaston_set_ticks!(axesconf, minor_ticks, letter, "m", "add")
end
end
end
if axis[:grid]
push!(axesconf, "set grid " * (polar ? "polar" : "$(letter)tics"))
axis[:minorgrid] &&
push!(axesconf, "set grid " * (polar ? "polar" : "m$(letter)tics"))
end
ratio = get_aspect_ratio(sp)
if ratio != :none
ratio == :equal && (ratio = -1)
push!(axesconf, "set size ratio $ratio")
end
end
gaston_set_legend!(axesconf, sp, any_label)
if hascolorbar(sp)
push!(axesconf, "set cbtics $(gaston_font(colorbartitlefont(sp)))")
end
if sp[:title] !== nothing
push!(axesconf, "set title '$(sp[:title])' $(gaston_font(titlefont(sp)))")
end
if polar
push!(axesconf, "unset border\nset polar\nset border polar")
tmin, tmax = axis_limits(sp, :x, false, false)
rmin, rmax = axis_limits(sp, :y, false, false)
rticks = get_ticks(sp, :y)
if (ttype = ticksType(rticks)) == :ticks
gaston_ticks = string.(rticks)
elseif ttype == :ticks_and_labels
gaston_ticks = String["'$l' $t" for (t, l) in zip(rticks...)]
end
push!(
axesconf,
"set rtics ( " *
join(gaston_ticks, ", ") *
" ) $(gaston_font(tickfont(sp.attr[:yaxis])))",
)
push!(axesconf, "set trange [$(min(0, tmin)):$(max(2π, tmax))]")
push!(axesconf, "set rrange [$rmin:$rmax]")
push!(
axesconf,
"set ttics 0,30 format \"%g\".GPVAL_DEGREE_SIGN $(gaston_font(tickfont(sp.attr[:xaxis])))",
)
push!(axesconf, "set mttics 3")
end
return join(axesconf, "\n")
end
function gaston_set_ticks!(axesconf, ticks, letter, maj_min, add)
ticks == :auto && return
if ticks (:none, nothing, false)
push!(axesconf, "unset $(maj_min)$(letter)tics")
return
end
gaston_ticks = String[]
if (ttype = ticksType(ticks)) == :ticks
tick_locs = @view ticks[:]
for i in eachindex(tick_locs)
tick = if maj_min == "m"
"'' $(tick_locs[i]) 1" # see gnuplot manual 'Mxtics'
else
"$(tick_locs[i])"
end
push!(gaston_ticks, tick)
end
elseif ttype == :ticks_and_labels
tick_locs = @view ticks[1][:]
tick_labels = @view ticks[2][:]
for i in eachindex(tick_locs)
lab = gaston_enclose_tick_string(tick_labels[i])
push!(gaston_ticks, "'$lab' $(tick_locs[i])")
end
else
gaston_ticks = nothing
@error "Gaston: invalid input for $(maj_min)$(letter)ticks: $ticks"
end
if gaston_ticks !== nothing
push!(axesconf, "set $(letter)tics $add (" * join(gaston_ticks, ", ") * ")")
end
nothing
end
function gaston_set_legend!(axesconf, sp, any_label)
leg = sp[:legend_position]
if sp[:legend_position] (:none, :inline) && any_label
leg == :best && (leg = :topright)
push!(
axesconf,
"set key " * (occursin("outer", string(leg)) ? "outside" : "inside"),
)
for position in ("top", "bottom", "left", "right")
occursin(position, string(leg)) && push!(axesconf, "set key $position")
end
push!(axesconf, "set key $(gaston_font(legendfont(sp), rot=false, align=false))")
if sp[:legend_title] !== nothing
# NOTE: cannot use legendtitlefont(sp) as it will override legendfont
push!(axesconf, "set key title '$(sp[:legend_title])'")
end
push!(axesconf, "set key box lw 1 opaque")
push!(axesconf, "set border back")
else
push!(axesconf, "set key off")
end
nothing
end
# --------------------------------------------
# Helpers
# --------------------------------------------
gaston_halign(k) = (left = :left, hcenter = :center, right = :right)[k]
gaston_valign(k) = (top = :top, vcenter = :center, bottom = :bottom)[k]
gaston_alpha(alpha) = alpha === nothing ? 0 : alpha
gaston_lc_ls_lw(series::Series, clims, i::Int) = (
gaston_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
gaston_linestyle(get_linestyle(series, i)),
get_linewidth(series, i),
)
gaston_mk_ms_mc(series::Series, clims, i::Int) = (
gaston_marker(_cycle(series[:markershape], i), get_markeralpha(series, i)),
_cycle(series[:markersize], i) * 1.3 / 5,
gaston_color(get_markercolor(series, clims, i), get_markeralpha(series, i)),
)
function gaston_font(f; rot = true, align = true, color = true, scale = 1)
font = String["font '$(f.family),$(round(Int, scale * f.pointsize))'"]
align && push!(font, "$(gaston_halign(f.halign))")
rot && push!(font, "rotate by $(f.rotation)")
color && push!(font, "textcolor $(gaston_color(f.color))")
return join(font, " ")
end
function gaston_palette(gradient)
palette = String[]
n = -1
for rgba in gradient # FIXME: naive conversion, inefficient ?
push!(palette, "$(n += 1) $(rgba.r) $(rgba.g) $(rgba.b)")
end
return '(' * join(palette, ", ") * ')'
end
function gaston_marker(marker, alpha)
# NOTE: :rtriangle, :ltriangle, :hexagon, :heptagon, :octagon seems unsupported by gnuplot
filled = gaston_alpha(alpha) == 0
marker == :none && return -1
marker == :pixel && return 0
marker (:+, :cross) && return 1
marker (:x, :xcross) && return 2
marker == :star5 && return 3
marker == :rect && return filled ? 5 : 4
marker == :circle && return filled ? 7 : 6
marker == :utriangle && return filled ? 9 : 8
marker == :dtriangle && return filled ? 11 : 10
marker == :diamond && return filled ? 13 : 12
marker == :pentagon && return filled ? 15 : 14
@warn "Gaston: unsupported marker $marker"
return 1
end
function gaston_color(col, alpha = 0)
col = single_color(col) # in case of gradients
col = alphacolor(col, gaston_alpha(alpha)) # add a default alpha if non existent
return "rgb '#$(hex(col, :aarrggbb))'"
end
function gaston_linestyle(style)
style == :solid && return "1"
style == :dash && return "2"
style == :dot && return "3"
style == :dashdot && return "4"
style == :dashdotdot && return "5"
end
function gaston_enclose_tick_string(tick_string)
findfirst("^", tick_string) === nothing && return tick_string
base, power = split(tick_string, "^")
return "$base^{$power}"
end

319
src/backends/glvisualize.jl Normal file
View File

@ -0,0 +1,319 @@
# [WEBSITE]
supported_args(::GLVisualizeBackend) = merge_with_base_supported([
# :annotations,
# :background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid, :foreground_color_legend, :foreground_color_title,
# :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
# :label,
# :linecolor, :linestyle, :linewidth, :linealpha,
# :markershape, :markercolor, :markersize, :markeralpha,
# :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
# :fillrange, :fillcolor, :fillalpha,
# :bins, :bar_width, :bar_edges, :bar_position,
# :title, :title_location, :titlefont,
# :window_title,
# :guide, :lims, :ticks, :scale, :flip, :rotation,
# :tickfont, :guidefont, :legendfont,
# :grid, :legend, :colorbar,
# :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
# :polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
# :match_dimensions,
# :clims,
# :inset_subplots,
])
supported_types(::GLVisualizeBackend) = [:surface, :scatter, :scatter3d, :path, :path3d, :shape]
supported_styles(::GLVisualizeBackend) = [:auto, :solid]
supported_markers(::GLVisualizeBackend) = vcat([:none, :auto, :circle], collect(keys(_gl_marker_map)))
supported_scales(::GLVisualizeBackend) = [:identity]
is_subplot_supported(::GLVisualizeBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize, GeometryTypes, GLAbstraction, GLWindow
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0
export GLVisualize
# # TODO: remove this when PlotUtils is registered
# import PlotUtils
end
end
# ---------------------------------------------------------------------------
# initialize the figure/window
function _create_backend_figure(plt::Plot{GLVisualizeBackend})
# init a screen
screen = if isdefined(GLVisualize, :ROOT_SCREEN)
GLVisualize.ROOT_SCREEN
else
s = GLVisualize.glscreen()
@async GLVisualize.renderloop(s)
s
end
empty!(screen)
screen
end
# ---------------------------------------------------------------------------
# size as a percentage of the window size
function gl_relative_size(plt::Plot{GLVisualizeBackend}, msize::Number)
winsz = min(plt[:size]...)
Float32(msize / winsz)
end
const _gl_marker_map = KW(
:rect => '■',
:star5 => '★',
:diamond => '◆',
:hexagon => '⬢',
:cross => '✚',
:xcross => '❌',
:utriangle => '▲',
:dtriangle => '▼',
:pentagon => '⬟',
:octagon => '⯄',
:star4 => '✦',
:star6 => '✶',
:star8 => '✷',
:vline => '┃',
:hline => '━',
)
# create a marker/shape type
function gl_marker(shape::Symbol, msize::Number, _3d::Bool)
GeometryTypes.HyperSphere((_3d ? Point3f0 : Point2f0)(0), msize)
end
gl_color(c::RGBA{Float32}) = c
# convert to RGBA
function gl_color(c, a=nothing)
@show c, a
c = convertColor(c, a)
@show c
RGBA{Float32}(c)
end
function gl_viewport(bb, rect)
l, b, bw, bh = bb
rw, rh = rect.w, rect.h
GLVisualize.SimpleRectangle(
round(Int, rect.x + rw * l),
round(Int, rect.y + rh * b),
round(Int, rw * bw),
round(Int, rh * bh)
)
end
gl_make_points(x, y) = Point2f0[Point2f0(x[i], y[i]) for i=1:length(x)]
gl_make_points(x, y, z) = Point3f0[Point3f0(x[i], y[i], z[i]) for i=1:length(x)]
function gl_draw_lines_2d(x, y, color, linewidth, sp_screen)
color = gl_color(color)
thickness = Float32(linewidth)
for rng in iter_segments(x, y)
n = length(rng)
n < 2 && continue
pts = gl_make_points(x[rng], y[rng])
@show pts, n
viz = GLVisualize.visualize(
pts,
n==2 ? :linesegment : :lines,
color = color,
thickness = thickness
)
GLVisualize.view(viz, sp_screen, camera=:orthographic_pixel)
end
end
function gl_draw_lines_3d(x, y, z, color, linewidth, sp_screen)
color = gl_color(color)
thickness = Float32(linewidth)
for rng in iter_segments(x, y, z)
n = length(rng)
n < 2 && continue
pts = gl_make_points(x[rng], y[rng], z[rng])
viz = GLVisualize.visualize(
pts,
n==2 ? :linesegment : :lines,
color=color,
thickness = thickness
)
GLVisualize.view(viz, sp_screen, camera=:perspective)
end
end
function gl_annotate(sp::Subplot{GLVisualizeBackend}, x, y, txt::PlotText)
end
function gl_draw_axes_2d(sp::Subplot{GLVisualizeBackend})
sp_screen = sp.o
xaxis = sp[:xaxis]
xmin, xmax = axis_limits(xaxis)
yaxis = sp[:yaxis]
ymin, ymax = axis_limits(yaxis)
# x axis
xsegs, ysegs = Segments(), Segments()
ticksz = 0.03*(ymax-ymin)
push!(xsegs, [xmin,xmax]); push!(ysegs, [ymin,ymin])
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
push!(xsegs, [tick,tick]); push!(ysegs, [ymin,ymin+ticksz])
# TODO: add the ticklabel
end
gl_draw_lines_2d(xsegs.pts, ysegs.pts, xaxis[:foreground_color_border], 1, sp_screen)
# y axis
xsegs, ysegs = Segments(), Segments()
push!(xsegs, [xmin,xmin]); push!(ysegs, [ymin,ymax])
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
push!(xsegs, [xmin,xmin+ticksz]); push!(ysegs, [tick,tick])
# TODO: add the ticklabel
end
gl_draw_lines_2d(xsegs.pts, ysegs.pts, yaxis[:foreground_color_border], 1, sp_screen)
end
# ---------------------------------------------------------------------------
# draw everything
function gl_display(plt::Plot{GLVisualizeBackend})
screen = plt.o
sw, sh = plt[:size]
sw, sh = sw*px, sh*px
for (name, sp) in plt.spmap
_3d = is3d(sp)
camera = _3d ? :perspective : :orthographic_pixel
# camera = :perspective
# initialize the sub-screen for this subplot
# note: we create a lift function to update the size on resize
rel_bbox = bbox_to_pcts(bbox(sp), sw, sh)
f = rect -> gl_viewport(rel_bbox, rect)
sp_screen = GLVisualize.Screen(
screen,
name = name,
area = GLVisualize.const_lift(f, screen.area)
)
sp.o = sp_screen
if !is3d(sp)
# gl_draw_axes_2d(sp)
end
# loop over the series and add them to the subplot
for series in series_list(sp)
d = series.d
st = d[:seriestype]
x, y = map(Float32, d[:x]), map(Float32, d[:y])
msize = gl_relative_size(plt, d[:markersize])
if st == :surface
# TODO: can pass just the ranges and surface
ismatrix(x) || (x = repmat(x', length(y), 1))
ismatrix(y) || (y = repmat(y, 1, length(x)))
z = transpose_z(d, map(Float32, d[:z].surf), false)
viz = GLVisualize.visualize((x, y, z), :surface)
GLVisualize.view(viz, sp_screen, camera = camera)
else
# paths, scatters, and shape
_3d && (z = map(Float32, d[:z]))
# paths?
lw = d[:linewidth]
if lw > 0
c = gl_color(d[:linecolor], d[:linealpha])
if _3d
gl_draw_lines_3d(x, y, z, c, lw, sp_screen)
else
gl_draw_lines_2d(x, y, c, lw, sp_screen)
end
end
# markers?
if st in (:scatter, :scatter3d) || d[:markershape] != :none
extrakw = KW()
c = gl_color(d[:markercolor], d[:markeralpha])
# get the marker
shape = d[:markershape]
shape = get(_gl_marker_map, shape, shape)
marker = if isa(shape, Char)
# extrakw[:scale] = Vec2f0(_3d ? 0.6*d[:markersize] : msize)
extrakw[:scale] = Vec2f0(msize)
shape
else
gl_marker(d[:markershape], msize, _3d)
end
if !_3d
extrakw[:billboard] = true
end
points = _3d ? gl_make_points(x,y,z) : gl_make_points(x,y)
viz = GLVisualize.visualize(
(marker, points);
color = c,
extrakw...
)
GLVisualize.view(viz, sp_screen, camera = camera)
# TODO: might need to switch to these forms later?
# GLVisualize.visualize((marker ,(x, y, z)))
#GLVisualize.visualize((marker , map(Point3f0, zip(x, y, z),
# billboard=true
#))
end
if st == :shape
for rng in iter_segments(x, y)
pts = Point2f0[Point2f0(x[i], y[i]) for i in rng]
@show pts
mesh = GeometryTypes.GLNormalMesh(pts)
@show mesh
if !isempty(GeometryTypes.faces(mesh))
viz = GLVisualize.visualize(
mesh,
color = gl_color(d[:fillcolor], d[:fillalpha])
)
GLVisualize.view(viz, sp_screen, camera = camera)
end
end
end
end
end
GLAbstraction.center!(sp_screen, camera)
end
# TODO: render one frame at a time? (no renderloop)
# GLWindow.render_frame(screen)
end
# ----------------------------------------------------------------
function _update_plot_object(plt::Plot{GLVisualizeBackend})
gl_display(plt)
end
# function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
# # TODO: write a png to io
# end
function _display(plt::Plot{GLVisualizeBackend})
end

File diff suppressed because it is too large Load Diff

View File

@ -1,645 +0,0 @@
#HDF5 Plots: Save/replay plots to/from HDF5
#-------------------------------------------------------------------------------
#==Usage
===============================================================================
Write to .hdf5 file using:
p = plot(...)
Plots.hdf5plot_write(p, "plotsave.hdf5")
Read from .hdf5 file using:
pyplot() #Must first select backend
pread = Plots.hdf5plot_read("plotsave.hdf5")
display(pread)
==#
#==TODO
===============================================================================
1. Support more features.
- GridLayout known not to be working.
2. Improve error handling.
- Will likely crash if file format is off.
3. Save data in a folder parallel to "plot".
- Will make it easier for users to locate data.
- Use HDF5 reference to link data?
4. Develop an actual versioned file format.
- Should have some form of backward compatibility.
- Should be reliable for archival purposes.
5. Fix construction of plot object with hdf5plot_read.
- Layout doesn't seem to get transferred well (ex: `Plots._examples[40]`).
- Not building object correctly when backends do not natively support
a certain feature (ex: :steppre)
- No support for CategoricalArrays.* structures. But they appear to be
brought into `Plots._examples[25,30]` through DataFrames.jl - so we can't
really reference them in this code.
==#
"""
_hdf5_implementation
Create module (namespace) for implementing HDF5 "plots".
(Avoid name collisions, while keeping names short)
"""
module _hdf5_implementation #Tools required to implements HDF5 "plots"
import Dates
#Plots.jl imports HDF5 to main:
import ..HDF5
import ..HDF5: Group, Dataset
import ..Colors, ..Colorant
import ..PlotUtils.ColorSchemes.ColorScheme
import ..HDF5Backend
import ..HDF5PLOT_MAP_STR2TELEM, ..HDF5PLOT_MAP_TELEM2STR
import ..HDF5Plot_PlotRef, ..HDF5PLOT_PLOTREF
import ..BoundingBox, ..Extrema, ..Length
import ..RecipesPipeline.datetimeformatter
import ..PlotUtils.ColorPalette,
..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient
import ..Surface, ..Shape, ..Arrow
import ..GridLayout, ..RootLayout
import ..Font, ..PlotText, ..SeriesAnnotations
import ..Axis, ..Subplot, ..Plot
import ..AKW, ..KW, ..DefaultsDict
import .._axis_defaults
import ..plot, ..plot!
#Types that already have built-in HDF5 support (just write out natively):
const HDF5_SupportedTypes = Union{Number,String}
#TODO: Types_HDF5Support
#Dispatch types:
struct CplxTuple end #Identifies a "complex" tuple structure (not merely numbers)
#HDF5 reader will auto-detect type correctly:
struct HDF5_AutoDetect end #See HDF5_SupportedTypes
#==
===============================================================================#
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
#(Used to add type information as an HDF5 string attribute)
#(Also used to dispatch appropriate read function through _read_typed())
_telem2str = Dict{String,Type}(
"NOTHING" => Nothing,
"SYMBOL" => Symbol,
"RGBA" => Colorant, #Write out any Colorant to an #RRGGBBAA string
"TUPLE" => Tuple,
"CTUPLE" => CplxTuple,
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Array{Any} (because Array{T<:Union{Number, String}} natively supported by HDF5)
#Sub-structure types:
"T_DATETIMEFORMATTER" => typeof(datetimeformatter),
#Sub-structure types:
"DEFAULTSDICT" => DefaultsDict,
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
"PLOTTEXT" => PlotText,
"SHAPE" => Shape,
"ARROW" => Arrow,
"COLORSCHEME" => ColorScheme,
"COLORPALETTE" => ColorPalette,
"CONT_COLORGRADIENT" => ContinuousColorGradient,
"CAT_COLORGRADIENT" => CategoricalColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
"SUBPLOT" => Subplot,
)
merge!(HDF5PLOT_MAP_STR2TELEM, _telem2str) #Faster to create than push!()??
merge!(
HDF5PLOT_MAP_TELEM2STR,
Dict{Type,String}(v => k for (k, v) in HDF5PLOT_MAP_STR2TELEM),
)
end
#==Helper functions
===============================================================================#
h5plotpath(plotname::String) = "plots/$plotname"
#Version info
#NOTE: could cache output, but we seem to not want const declarations in backend files.
function _get_Plots_versionstr()
#Adds to load up time... Maybe a more efficient way??
try
deps = Pkg.dependencies()
uuid = Base.UUID("91a5bcdd-55d7-5caf-9e0b-520d859cae80") #Plots.jl
vinfo = deps[uuid].version
return "Source: Plots.jl v$vinfo"
catch
now = string(Dates.now()) #Use time in case it can help recover plot
return "Source: Plots.jl v? - $now"
end
end
function _hdf5_merge!(dest::AKW, src::AKW)
for (k, v) in src
if isa(v, Axis)
_hdf5_merge!(dest[k].plotattributes, v.plotattributes)
else
dest[k] = v
end
end
return
end
#_type_for_map returns the type to use with HDF5PLOT_MAP_TELEM2STR[], in case it is not concrete:
_type_for_map(::Type{T}) where {T} = T #Catch-all
_type_for_map(::Type{T}) where {T<:BoundingBox} = BoundingBox
_type_for_map(::Type{T}) where {T<:ColorScheme} = ColorScheme
_type_for_map(::Type{T}) where {T<:Surface} = Surface
#==Read/write things like type name in attributes
===============================================================================#
function _write_datatype_attr(ds::Union{Group,Dataset}, ::Type{T}) where {T}
typestr = HDF5PLOT_MAP_TELEM2STR[T]
HDF5.attributes(ds)["TYPE"] = typestr
end
function _read_datatype_attr(ds::Union{Group,Dataset})
if !Base.haskey(HDF5.attributes(ds), "TYPE")
return HDF5_AutoDetect
end
typestr = HDF5.read(HDF5.attributes(ds)["TYPE"])
return HDF5PLOT_MAP_STR2TELEM[typestr]
end
#Type parameter attributes:
function _write_typeparam_attr(ds::Dataset, v::Length{T}) where {T}
HDF5.attributes(ds)["TYPEPARAM"] = string(T) #Need to add units for Length
end
_read_typeparam_attr(ds::Dataset) = HDF5.read(HDF5.attributes(ds)["TYPEPARAM"])
function _write_length_attr(grp::Group, v::Vector) #of a vector
HDF5.attributes(grp)["LENGTH"] = length(v)
end
_read_length_attr(::Type{Vector}, grp::Group) = HDF5.read(HDF5.attributes(grp)["LENGTH"])
function _write_size_attr(grp::Group, v::Array) #of an array
HDF5.attributes(grp)["SIZE"] = [size(v)...]
end
_read_size_attr(::Type{Array}, grp::Group) =
tuple(HDF5.read(HDF5.attributes(grp)["SIZE"])...)
#==_write_typed(): Simple (leaf) datatypes. (Labels with type name.)
===============================================================================#
#= No: write out struct instead!
function _write_typed(grp::Group, name::String, v::T) where T
tstr = string(T)
path = HDF5.name(grp) * "/" * name
@info("Type not supported: $tstr\npath: $path")
return
end
=#
#Default behaviour: Assumes value is supported by HDF5 format
function _write_typed(grp::Group, name::String, v::HDF5_SupportedTypes)
grp[name] = v
return #No need to _write_datatype_attr
end
function _write_typed(grp::Group, name::String, v::Nothing)
grp[name] = "nothing" #Redundancy check/easier to read HDF5 file
_write_datatype_attr(grp[name], Nothing)
end
function _write_typed(grp::Group, name::String, v::Symbol)
grp[name] = String(v)
_write_datatype_attr(grp[name], Symbol)
end
function _write_typed(grp::Group, name::String, v::Colorant)
vstr = "#" * Colors.hex(v, :RRGGBBAA)
grp[name] = vstr
_write_datatype_attr(grp[name], Colorant)
end
function _write_typed(grp::Group, name::String, v::Extrema)
grp[name] = [v.emin, v.emax] #More compact than writing struct
_write_datatype_attr(grp[name], Extrema)
end
function _write_typed(grp::Group, name::String, v::Length)
grp[name] = v.value
_write_datatype_attr(grp[name], Length)
_write_typeparam_attr(grp[name], v)
end
function _write_typed(grp::Group, name::String, v::typeof(datetimeformatter))
grp[name] = string(v) #Just write something that helps reader
_write_datatype_attr(grp[name], typeof(datetimeformatter))
end
function _write_typed(grp::Group, name::String, v::Array{T}) where {T<:Number} #Default for arrays
grp[name] = v
return #No need to _write_datatype_attr
end
function _write_typed(grp::Group, name::String, v::AbstractRange)
_write_typed(grp, name, collect(v)) #For now
end
#== Helper functions for writing complex data structures
===============================================================================#
#Write an array using HDF5 hierarchy (when not using simple numeric eltype):
function _write_harray(grp::Group, name::String, v::Array)
sgrp = HDF5.create_group(grp, name)
sz = size(v)
lidx = LinearIndices(sz)
for iter in eachindex(v)
coord = lidx[iter]
elem = v[iter]
idxstr = join(coord, "_")
_write_typed(sgrp, "v$idxstr", elem)
end
_write_size_attr(sgrp, v)
end
#Write Dict without tagging with type:
function _write(grp::Group, name::String, d::AbstractDict)
sgrp = HDF5.create_group(grp, name)
for (k, v) in d
kstr = string(k)
_write_typed(sgrp, kstr, v)
end
return
end
#Write out arbitrary `struct`s:
function _writestructgeneric(grp::Group, obj::T) where {T}
for fname in fieldnames(T)
v = getfield(obj, fname)
_write_typed(grp, String(fname), v)
end
return
end
#==_write_typed(): More complex structures. (Labels with type name.)
===============================================================================#
#Catch-all (default behaviour for `struct`s):
function _write_typed(grp::Group, name::String, v::T) where {T}
#NOTE: need "name" parameter so that call signature is same with built-ins
MT = _type_for_map(T)
try #Check to see if type is supported
typestr = HDF5PLOT_MAP_TELEM2STR[MT]
catch
@warn("HDF5Plots does not yet support structs of type `$MT`\n\n$grp")
return
end
#If attribute is supported and no writer is defined, then this should work:
objgrp = HDF5.create_group(grp, name)
_write_datatype_attr(objgrp, MT)
_writestructgeneric(objgrp, v)
end
function _write_typed(grp::Group, name::String, v::Array{T}) where {T}
_write_harray(grp, name, v)
_write_datatype_attr(grp[name], Array) #{Any}
end
function _write_typed(grp::Group, name::String, v::Tuple, ::Type{ELT}) where {ELT<:Number} #Basic Tuple
_write_typed(grp, name, [v...])
_write_datatype_attr(grp[name], Tuple)
end
function _write_typed(grp::Group, name::String, v::Tuple, ::Type) #CplxTuple
_write_harray(grp, name, [v...])
_write_datatype_attr(grp[name], CplxTuple)
end
_write_typed(grp::Group, name::String, v::Tuple) = _write_typed(grp, name, v, eltype(v))
function _write_typed(grp::Group, name::String, v::Dict)
#=
tstr = string(Dict)
path = HDF5.name(grp) * "/" * name
@info("Type not supported: $tstr\npath: $path")
return
=#
#No support for structures with Dicts yet
end
function _write_typed(grp::Group, name::String, d::DefaultsDict) #Typically for plot attributes
_write(grp, name, d)
_write_datatype_attr(grp[name], DefaultsDict)
end
function _write_typed(grp::Group, name::String, v::Axis)
sgrp = HDF5.create_group(grp, name)
#Ignore: sps::Vector{Subplot}
_write_typed(sgrp, "plotattributes", v.plotattributes)
_write_datatype_attr(sgrp, Axis)
end
function _write_typed(grp::Group, name::String, v::Subplot)
#Not for use in main "Plot.subplots[]" hierarchy. Just establishes reference with subplot_index.
sgrp = HDF5.create_group(grp, name)
_write_typed(sgrp, "index", v[:subplot_index])
_write_datatype_attr(sgrp, Subplot)
return
end
function _write_typed(grp::Group, name::String, v::Plot)
#Don't write plot references
end
#==_write(): Write out more complex structures
NOTE: No need to write out type information (inferred from hierarchy)
===============================================================================#
function _write(grp::Group, sp::Subplot{HDF5Backend})
_write_typed(grp, "attr", sp.attr)
listgrp = HDF5.create_group(grp, "series_list")
_write_length_attr(listgrp, sp.series_list)
for (i, series) in enumerate(sp.series_list)
#Just write .plotattributes part:
_write(listgrp, "$i", series.plotattributes)
end
return
end
function _write(grp::Group, plt::Plot{HDF5Backend})
_write_typed(grp, "attr", plt.attr)
listgrp = HDF5.create_group(grp, "subplots")
_write_length_attr(listgrp, plt.subplots)
for (i, sp) in enumerate(plt.subplots)
sgrp = HDF5.create_group(listgrp, "$i")
_write(sgrp, sp)
end
return
end
function hdf5plot_write(
plt::Plot{HDF5Backend},
path::AbstractString;
name::String = "_unnamed",
)
HDF5.h5open(path, "w") do file
HDF5.write_dataset(file, "VERSION_INFO", _get_Plots_versionstr())
grp = HDF5.create_group(file, h5plotpath(name))
_write(grp, plt)
end
end
#== _read(): Read data, but not type information.
===============================================================================#
#Types with built-in HDF5 support:
_read(::Type{HDF5_AutoDetect}, ds::Dataset) = HDF5.read(ds)
function _read(::Type{Nothing}, ds::Dataset)
nstr = "nothing"
v = HDF5.read(ds)
if nstr != v
path = HDF5.name(ds)
throw(Meta.ParseError("_read(::Nothing, ::Group): Read $v != $nstr:\n$path"))
end
return nothing
end
_read(::Type{Symbol}, ds::Dataset) = Symbol(HDF5.read(ds))
_read(::Type{Colorant}, ds::Dataset) = parse(Colorant, HDF5.read(ds))
_read(::Type{Tuple}, ds::Dataset) = tuple(HDF5.read(ds)...)
function _read(::Type{Extrema}, ds::Dataset)
v = HDF5.read(ds)
return Extrema(v[1], v[2])
end
function _read(::Type{Length}, ds::Dataset)
TUNIT = Symbol(_read_typeparam_attr(ds))
v = HDF5.read(ds)
T = typeof(v)
return Length{TUNIT,T}(v)
end
_read(::Type{typeof(datetimeformatter)}, ds::Dataset) = datetimeformatter
#== Helper functions for reading in complex data structures
===============================================================================#
#When type is unknown, _read_typed() figures it out:
function _read_typed(grp::Group, name::String)
ds = grp[name]
t = _read_datatype_attr(ds)
return _read(t, ds)
end
#_readstructgeneric: Needs object values to be written out with _write_typed():
function _readstructgeneric(::Type{T}, grp::Group) where {T}
vlist = Array{Any}(nothing, fieldcount(T))
for (i, fname) in enumerate(fieldnames(T))
vlist[i] = _read_typed(grp, String(fname))
end
return T(vlist...)
end
#Read KW from group:
function _read(::Type{KW}, grp::Group)
d = KW()
gkeys = keys(grp)
for k in gkeys
try
v = _read_typed(grp, k)
d[Symbol(k)] = v
catch e
@show e
@show grp
@warn("Could not read field $k")
end
end
return d
end
#== _read(): More complex structures.
===============================================================================#
#Catch-all (default behaviour for `struct`s):
_read(T::Type, grp::Group) = _readstructgeneric(T, grp)
function _read(::Type{Array}, grp::Group) #Array{Any}
sz = _read_size_attr(Array, grp)
if tuple(0) == sz
return []
end
result = Array{Any}(undef, sz)
lidx = LinearIndices(sz)
for iter in eachindex(result)
coord = lidx[iter]
idxstr = join(coord, "_")
result[iter] = _read_typed(grp, "v$idxstr")
end
#Hack: Implicitly make Julia detect element type.
# (Should probably write it explicitly to file)
result = [elem for elem in result] #Potentially make more specific
return reshape(result, sz)
end
_read(::Type{CplxTuple}, grp::Group) = tuple(_read(Array, grp)...)
function _read(::Type{GridLayout}, grp::Group)
#parent = _read_typed(grp, "parent") #Can't use generic reader
parent = RootLayout() #TODO: support parent???
minpad = _read_typed(grp, "minpad")
bbox = _read_typed(grp, "bbox")
grid = _read_typed(grp, "grid")
widths = _read_typed(grp, "widths")
heights = _read_typed(grp, "heights")
attr = KW() #TODO support attr: _read_typed(grp, "attr")
return GridLayout(parent, minpad, bbox, grid, widths, heights, attr)
end
#Defaults depends on context. So: user must constructs with defaults, then read.
function _read(::Type{DefaultsDict}, grp::Group)
#User should set DefaultsDict.defaults to one of:
# _plot_defaults, _subplot_defaults, _axis_defaults, _series_defaults
path = HDF5.name(ds)
@warn(
"Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot."
)
end
function _read(::Type{Axis}, grp::Group)
#1st arg appears to be ref to subplots. Seems to work without it.
return Axis([], DefaultsDict(_read(KW, grp["plotattributes"]), _axis_defaults))
end
function _read(::Type{Subplot}, grp::Group)
#Not for use in main "Plot.subplots[]" hierarchy. Just establishes reference with subplot_index.
idx = _read_typed(grp, "index")
return HDF5PLOT_PLOTREF.ref.subplots[idx]
end
#== _read(): Main plot structures
===============================================================================#
function _read(grp::Group, sp::Subplot)
listgrp = HDF5.open_group(grp, "series_list")
nseries = _read_length_attr(Vector, listgrp)
for i in 1:nseries
sgrp = HDF5.open_group(listgrp, "$i")
seriesinfo = _read(KW, sgrp)
plot!(sp, seriesinfo[:x], seriesinfo[:y]) #Add data & create data structures
_hdf5_merge!(sp.series_list[end].plotattributes, seriesinfo)
end
#Perform after adding series... otherwise values get overwritten:
agrp = HDF5.open_group(grp, "attr")
_hdf5_merge!(sp.attr, _read(KW, agrp))
return sp
end
function _read_plot(grp::Group)
listgrp = HDF5.open_group(grp, "subplots")
n = _read_length_attr(Vector, listgrp)
#Construct new plot, +allocate subplots:
plt = plot(layout = n)
HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout"
agrp = HDF5.open_group(grp, "attr")
_hdf5_merge!(plt.attr, _read(KW, agrp))
for (i, sp) in enumerate(plt.subplots)
sgrp = HDF5.open_group(listgrp, "$i")
_read(sgrp, sp)
end
return plt
end
function hdf5plot_read(path::AbstractString; name::String = "_unnamed")
HDF5.h5open(path, "r") do file
grp = HDF5.open_group(file, h5plotpath("_unnamed"))
return _read_plot(grp)
end
end
end #module _hdf5_implementation
#==Implement Plots.jl backend interface for HDF5Backend
===============================================================================#
is_marker_supported(::HDF5Backend, shape::Shape) = true
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{HDF5Backend})
#Do nothing
end
# ---------------------------------------------------------------------------
# # this is called early in the pipeline, use it to make the plot current or something
# function _prepare_plot_object(plt::Plot{HDF5Backend})
# end
# ---------------------------------------------------------------------------
# Set up the subplot within the backend object.
function _initialize_subplot(plt::Plot{HDF5Backend}, sp::Subplot{HDF5Backend})
#Do nothing
end
# ---------------------------------------------------------------------------
# Add one series to the underlying backend object.
# Called once per series
# NOTE: Seems to be called when user calls plot()... even if backend
# plot, sp.o has not yet been constructed...
function _series_added(plt::Plot{HDF5Backend}, series::Series)
#Do nothing
end
# ---------------------------------------------------------------------------
# When series data is added/changed, this callback can do dynamic updates to the backend object.
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
function _series_updated(plt::Plot{HDF5Backend}, series::Series)
#Do nothing
end
# ---------------------------------------------------------------------------
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
# Set the (left, top, right, bottom) minimum padding around the plot area
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
function _update_plot_object(plt::Plot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
@warn(msg)
return
end
#==Interface actually required to use HDF5Backend
===============================================================================#
hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) =
_hdf5_implementation.hdf5plot_write(plt, path)
hdf5plot_write(path::AbstractString) = _hdf5_implementation.hdf5plot_write(current(), path)
hdf5plot_read(path::AbstractString) = _hdf5_implementation.hdf5plot_read(path)
#Last line

186
src/backends/immerse.jl Normal file
View File

@ -0,0 +1,186 @@
# https://github.com/JuliaGraphics/Immerse.jl
supported_args(::ImmerseBackend) = supported_args(GadflyBackend())
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
is_subplot_supported(::ImmerseBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::ImmerseBackend; kw...)
@eval begin
import Immerse, Gadfly, Compose, Gtk
export Immerse, Gadfly, Compose, Gtk
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
end
end
function createImmerseFigure(d::KW)
w,h = d[:size]
figidx = Immerse.figure(; name = d[:window_title], width = w, height = h)
Immerse.Figure(figidx)
end
# ----------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::ImmerseBackend, d::KW)
# # create the underlying Gadfly.Plot object
# gplt = createGadflyPlotObject(d)
#
# # save both the Immerse.Figure and the Gadfly.Plot
# Plot((nothing,gplt), pkg, 0, d, KW[])
# end
function _create_backend_figure(plt::Plot{ImmerseBackend})
(nothing, createGadflyPlotObject(plt.attr))
end
# # plot one data series
# function _series_added(::ImmerseBackend, plt::Plot, d::KW)
# addGadflySeries!(plt, d)
# push!(plt.seriesargs, d)
# plt
# end
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
addGadflySeries!(plt, series.d)
end
function _update_plot_object(plt::Plot{ImmerseBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
# ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer)
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
# return false
# # isbefore && return false
# end
#
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
# # create the Gtk window with vertical box vsep
# d = getattr(subplt,1)
# w,h = d[:size]
# vsep = Gtk.GtkBoxLeaf(:v)
# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h)
#
# figindices = []
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# for (i,(r,c)) in enumerate(subplt.layout)
# plt = subplt.plts[i]
#
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
#
# # add the plot's box to the row
# push!(row, box)
#
# # create the figure and store the index returned for destruction later
# figidx = Immerse.figure(canvas)
# push!(figindices, figidx)
#
# fig = Immerse.figure(figidx)
# plt.o = (fig, plt.o[2])
#
# # add the row
# if c == ncols(subplt.layout, r)
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# end
#
# end
#
# # destructor... clean up plots
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
#
# subplt.o = win
# true
# end
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
fig, gplt = plt.o
if fig == nothing
fig = createImmerseFigure(plt.attr)
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
plt.o = (fig, gplt)
end
Immerse.figure(fig.figno; displayfig = false)
display(gplt)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
#
# # if we haven't created the window yet, do it
# if subplt.o == nothing
# showSubplotObject(subplt)
# end
#
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
# for plt in subplt.plts
# fig, gplt = plt.o
# Immerse.figure(fig.figno; displayfig = false)
# display(gplt)
# end
#
# # o is the window... show it
# showall(subplt.o)
# end

View File

@ -1,574 +0,0 @@
# https://github.com/ma-laforge/InspectDR.jl
#=TODO:
Tweak scale factor for width & other sizes
Not supported by InspectDR:
:foreground_color_grid
:foreground_color_border
:polar,
Add in functionality to Plots.jl:
:aspect_ratio,
=#
should_warn_on_unsupported(::InspectDRBackend) = false
is_marker_supported(::InspectDRBackend, shape::Shape) = true
#Do we avoid Map to avoid possible pre-comile issues?
function _inspectdr_mapglyph(s::Symbol)
s == :rect && return :square
return s
end
function _inspectdr_mapglyph(s::Shape)
x, y = coords(s)
return InspectDR.GlyphPolyline(x, y)
end
# py_marker(markers::AVec) = map(py_marker, markers)
function _inspectdr_mapglyph(markers::AVec)
@warn("Vectors of markers are currently unsupported in InspectDR.")
_inspectdr_mapglyph(markers[1])
end
_inspectdr_mapglyphsize(v::Real) = v
function _inspectdr_mapglyphsize(v::Vector)
@warn("Vectors of marker sizes are currently unsupported in InspectDR.")
_inspectdr_mapglyphsize(v[1])
end
_inspectdr_mapcolor(v::Colorant) = v
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
@warn("Color gradients are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(g.colors[div(1 + end, 2)])
end
function _inspectdr_mapcolor(v::AVec)
@warn("Vectors of colors are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(v[div(1 + end, 2)])
end
#Hack: suggested point size does not seem adequate relative to plot size, for some reason.
_inspectdr_mapptsize(v) = 1.5 * v
function _inspectdr_add_annotations(plot, x, y, val)
#What kind of annotation is this?
end
#plot::InspectDR.Plot2D
function _inspectdr_add_annotations(plot, x, y, val::PlotText)
vmap = Dict{Symbol,Symbol}(:top => :t, :bottom => :b) #:vcenter
hmap = Dict{Symbol,Symbol}(:left => :l, :right => :r) #:hcenter
align = Symbol(get(vmap, val.font.valign, :c), get(hmap, val.font.halign, :c))
fnt = InspectDR.Font(
val.font.family,
val.font.pointsize,
color = _inspectdr_mapcolor(val.font.color),
)
ann = InspectDR.atext(
texmath2unicode(val.str),
x = x,
y = y,
font = fnt,
angle = val.font.rotation,
align = align,
)
InspectDR.add(plot, ann)
return
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)
#TODO: Support :asinh, :sqrt
kwargs = yaxis ? (:tgtmajor => 8, :tgtminor => 2) : () #More grid lines on y-axis
if :log2 == s
return InspectDR.AxisScale(:log2; kwargs...)
elseif :log10 == s
return InspectDR.AxisScale(:log10; kwargs...)
elseif :ln == s
return InspectDR.AxisScale(:ln; kwargs...)
else #identity
return InspectDR.AxisScale(:lin; kwargs...)
end
end
# ---------------------------------------------------------------------------
#Glyph used when plotting "Shape"s:
INSPECTDR_GLYPH_SHAPE =
InspectDR.GlyphPolyline(2 * InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y)
mutable struct InspecDRPlotRef
mplot::Union{Nothing,InspectDR.Multiplot}
gui::Union{Nothing,InspectDR.GtkPlot}
end
_inspectdr_getmplot(::Any) = nothing
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
push!(_initialized_backends, :inspectdr)
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
gplot = _inspectdr_getgui(plt.o)
#:overwrite_figure: want to reuse current figure
if plt[:overwrite_figure] && mplot !== nothing
mplot.subplots = [] #Reset
if gplot !== nothing #Ensure still references current plot
gplot.src = mplot
end
else #want new one:
mplot = InspectDR.Multiplot()
gplot = nothing #Will be created later
end
#break link with old subplots
for sp in plt.subplots
sp.o = nothing
end
return InspecDRPlotRef(mplot, gplot)
end
# ---------------------------------------------------------------------------
# # this is called early in the pipeline, use it to make the plot current or something
# function _prepare_plot_object(plt::Plot{InspectDRBackend})
# end
# ---------------------------------------------------------------------------
# Set up the subplot within the backend object.
function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend})
plot = sp.o
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot
return
end
plot.data = []
plot.userannot = [] #Clear old markers/text annotation/polyline "annotation"
return plot
end
# ---------------------------------------------------------------------------
# Add one series to the underlying backend object.
# Called once per series
# NOTE: Seems to be called when user calls plot()... even if backend
# plot, sp.o has not yet been constructed...
function _series_added(plt::Plot{InspectDRBackend}, series::Series)
st = series[:seriestype]
sp = series[:subplot]
plot = sp.o
clims = get_clims(sp, series)
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot
return
end
_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x, y = if st == :straightline
straightline_data(series)
else
_vectorize(series[:x]), _vectorize(series[:y])
end
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
Θ = x
r = y
x = r .* cos.(Θ)
y = r .* sin.(Θ)
end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
nx = length(x)
ny = length(y)
if nx < ny
series[:x] = Float64[x[mod1(i, nx)] for i in 1:ny]
elseif ny > nx
series[:y] = Float64[y[mod1(i, ny)] for i in 1:nx]
end
#= TODO: Eventually support
series[:fillcolor] #I think this is fill under line
zorder = series[:series_plotindex]
For st in :shape:
zorder = series[:series_plotindex],
=#
if st in (:shape,)
x, y = shape_data(series)
nmax = 0
for (i, rng) in enumerate(iter_segments(x, y))
nmax = i
if length(rng) > 1
linewidth = series[:linewidth]
c = plot_color(get_linecolor(series), get_linealpha(series))
linecolor = _inspectdr_mapcolor(_cycle(c, i))
c = plot_color(get_fillcolor(series), get_fillalpha(series))
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
line = InspectDR.line(style = :solid, width = linewidth, color = linecolor)
apline = InspectDR.PolylineAnnotation(
x[rng],
y[rng],
line = line,
fillcolor = fillcolor,
)
InspectDR.add(plot, apline)
end
end
i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth]
c = plot_color(get_linecolor(series), get_linealpha(series))
linecolor = _inspectdr_mapcolor(_cycle(c, i))
c = plot_color(get_fillcolor(series), get_fillalpha(series))
fillcolor = _inspectdr_mapcolor(_cycle(c, i))
wfrm = InspectDR.add(plot, Float64[], Float64[], id = series[:label])
wfrm.line = InspectDR.line(
style = :none,
width = linewidth, #linewidth affects glyph
)
wfrm.glyph = InspectDR.glyph(
shape = INSPECTDR_GLYPH_SHAPE,
size = 8,
color = linecolor,
fillcolor = fillcolor,
)
end
elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost)
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth:
_style = (0 == linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id = series[:label])
wfrm.line = InspectDR.line(
style = _style,
width = series[:linewidth],
color = plot_color(get_linecolor(series), get_linealpha(series)),
)
#InspectDR does not control markerstrokewidth independently.
if :none == _style
#Use this property only if no line is displayed:
wfrm.line.width = series[:markerstrokewidth]
end
wfrm.glyph = InspectDR.glyph(
shape = _inspectdr_mapglyph(series[:markershape]),
size = _inspectdr_mapglyphsize(series[:markersize]),
color = _inspectdr_mapcolor(
plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
),
fillcolor = _inspectdr_mapcolor(
plot_color(get_markercolor(series, clims), get_markeralpha(series)),
),
)
end
# this is all we need to add the series_annotations text
anns = series[:series_annotations]
for (xi, yi, str, fnt) in EachAnn(anns, x, y)
_inspectdr_add_annotations(plot, xi, yi, PlotText(str, fnt))
end
return
end
# ---------------------------------------------------------------------------
# When series data is added/changed, this callback can do dynamic updates to the backend object.
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
function _series_updated(plt::Plot{InspectDRBackend}, series::Series)
#Nothing to do
end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
plot = sp.o
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
ygrid_show = yaxis[:grid]
strip.grid = InspectDR.GridRect(
vmajor = xgrid_show, # vminor=xgrid_show,
hmajor = ygrid_show, # hminor=ygrid_show,
)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
if ispolar(sp)
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
rmax = NaNMath.max(abs(ymin), abs(ymax))
xmin, xmax = -rmax, rmax
ymin, ymax = -rmax, rmax
end
plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
#Set current extents = full extents (needed for _eval(strip.grid,...))
plot.xext = plot.xext_full
strip.yext = strip.yext_full
_inspectdr_setticks(sp, plot, strip, xaxis, yaxis)
a = plot.annotation
a.title = texmath2unicode(sp[:title])
a.xlabel = texmath2unicode(xaxis[:guide])
a.ylabels = [texmath2unicode(yaxis[:guide])]
#Modify base layout of new object:
l = plot.layout.defaults = deepcopy(InspectDR.defaults.plotlayout)
#IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots.
#Works because plot uses defaults (not user-overwritten `layout.values`)
l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l.font_title = InspectDR.Font(
sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor]),
)
#Cannot independently control fonts of axes with InspectDR:
l.font_axislabel = InspectDR.Font(
xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor]),
)
l.font_ticklabel = InspectDR.Font(
xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor]),
)
l.enable_legend = (sp[:legend_position] != :none)
#l.halloc_legend = 150 #TODO: compute???
l.font_legend = InspectDR.Font(
sp[:legend_font_family],
_inspectdr_mapptsize(sp[:legend_font_pointsize]),
color = _inspectdr_mapcolor(sp[:legend_font_color]),
)
l.frame_legend.fillcolor = _inspectdr_mapcolor(sp[:legend_background_color])
#_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
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot
return
end
mplot.title = plt[:plot_title]
if "" == mplot.title
#Don't use window_title... probably not what you want.
#mplot.title = plt[:window_title]
end
mplot.layout[:frame].fillcolor = _inspectdr_mapcolor(plt[:background_color_outside])
mplot.layout[:frame] = mplot.layout[:frame] #register changes
resize!(mplot.subplots, length(plt.subplots))
nsubplots = length(plt.subplots)
for (i, sp) in enumerate(plt.subplots)
if !isassigned(mplot.subplots, i)
mplot.subplots[i] = InspectDR.Plot2D()
end
sp.o = mplot.subplots[i]
plot = sp.o
_initialize_subplot(plt, sp)
_inspectdr_setupsubplot(sp)
# add the annotations
for ann in sp[:annotations]
_inspectdr_add_annotations(plot, ann...)
end
end
#Do not yet support absolute plot positionning.
#Just try to make things look more-or less ok:
if nsubplots <= 1
mplot.layout[:ncolumns] = 1
elseif nsubplots <= 4
mplot.layout[:ncolumns] = 2
elseif nsubplots <= 6
mplot.layout[:ncolumns] = 3
elseif nsubplots <= 12
mplot.layout[:ncolumns] = 4
else
mplot.layout[:ncolumns] = 5
end
for series in plt.series_list
_series_added(plt, series)
end
return
end
# ----------------------------------------------------------------
# Set the (left, top, right, bottom) minimum padding around the plot area
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{InspectDRBackend})
plot = sp.o
if !isa(plot, InspectDR.Plot2D)
return sp.minpad
end
#Computing plotbounds with 0-BoundingBox returns required padding:
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0, 0, 0, 0))
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
#TODO: possibly zero-out items not in use??
# add in the user-specified margin to InspectDR padding:
leftpad = abs(bb.xmin) * px + sp[:left_margin]
toppad = abs(bb.ymin) * px + sp[:top_margin]
rightpad = abs(bb.xmax) * px + sp[:right_margin]
bottompad = abs(bb.ymax) * px + sp[:bottom_margin]
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
function _update_plot_object(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot
return
end
mplot.bblist = InspectDR.BoundingBox[]
for (i, sp) in enumerate(plt.subplots)
figw, figh = sp.plt[:size]
pcts = bbox_to_pcts(sp.bbox, figw * px, figh * px)
_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
gplot = _inspectdr_getgui(plt.o)
if nothing == gplot
return
end
gplot.src = mplot #Ensure still references current plot
InspectDR.refresh(gplot)
return
end
# ----------------------------------------------------------------
_inspectdr_show(io::IO, mime::MIME, ::Nothing, w, h) =
throw(ErrorException("Cannot show(::IO, ...) plot - not yet generated"))
function _inspectdr_show(io::IO, mime::MIME, mplot, w, h)
InspectDR._show(io, mime, mplot, Float64(w), Float64(h))
end
function _show(io::IO, mime::MIME{Symbol("image/png")}, plt::Plot{InspectDRBackend})
dpi = plt[:dpi] # TODO: support
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
end
for (mime, fmt) in (
"image/svg+xml" => "svg",
"application/eps" => "eps",
"image/eps" => "eps",
# "application/postscript" => "ps", # TODO: support once Cairo supports PSSurface
"application/pdf" => "pdf",
)
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{InspectDRBackend})
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
end
end
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot
return
end
gplot = _inspectdr_getgui(plt.o)
if nothing == gplot
gplot = display(InspectDR.GtkDisplay(), mplot)
else
#redundant... Plots.jl will call _update_plot_object:
#InspectDR.refresh(gplot)
end
plt.o = InspecDRPlotRef(mplot, gplot)
return gplot
end

327
src/backends/pgfplots.jl Normal file
View File

@ -0,0 +1,327 @@
# https://github.com/sisl/PGFPlots.jl
# significant contributions by: @pkofod
supported_args(::PGFPlotsBackend) = merge_with_base_supported([
# :annotations,
# :background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
# :foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
:title,
# :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
# :colorbar,
# :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
# :polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
])
supported_types(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
supported_styles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::PGFPlotsBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
supported_scales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10]
is_subplot_supported(::PGFPlotsBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
end
end
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
:solid => "solid",
:dash => "dashed",
:dot => "dotted",
:dashdot => "dashdotted",
:dashdotdot => "dashdotdotted",
)
const _pgfplots_markers = KW(
:none => "none",
:cross => "+",
:xcross => "x",
:utriangle => "triangle*",
:dtriangle => "triangle*",
:circle => "*",
:rect => "square*",
:star5 => "star",
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
)
const _pgfplots_legend_pos = KW(
:bottomleft => "south west",
:bottomright => "south east",
:topright => "north east",
:topleft => "north west",
)
const _pgf_series_extrastyle = KW(
:steppre => "const plot mark right",
:stepmid => "const plot mark mid",
:steppost => "const plot",
:sticks => "ycomb",
:ysticks => "ycomb",
:xsticks => "xcomb",
)
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
function pgf_color(c)
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
cstr, alpha(c)
end
function pgf_fillstyle(d::KW)
cstr,a = pgf_color(d[:fillcolor])
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d::KW)
cstr,a = pgf_color(d[:linecolor])
"""
color = $cstr,
draw opacity=$a,
line width=$(d[:linewidth]),
$(get(_pgfplots_linestyles, d[:linestyle], "solid"))"""
end
function pgf_marker(d::KW)
shape = d[:markershape]
cstr, a = pgf_color(d[:markercolor])
cstr_stroke, a_stroke = pgf_color(d[:markerstrokecolor])
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(0.5 * d[:markersize]),
mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(d[:markerstrokewidth]),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, d[:markerstrokestyle], "solid"))
}"""
end
# --------------------------------------------------------------------------------------
function pgf_series(sp::Subplot, series::Series)
d = series.d
st = d[:seriestype]
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
if d[:fillrange] != nothing
push!(style, pgf_fillstyle(d))
end
# add to legend?
if sp[:legend] != :none && should_add_to_legend(series)
kw[:legendentry] = d[:label]
end
# function args
args = if st == :contour
d[:z].surf, d[:x], d[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
else
d[:x], d[:y]
end
# PGFPlots can't handle non-Vector?
args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
collect(a)
else
a
end, args)
# for (i,a) in enumerate(args)
# if typeof(a) <: AbstractVector && typeof(a) != Vector
# args[i] = collect(a)
# end
# end
# include additional style, then add to the kw
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
# build/return the series object
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
elseif st == :histogram2d
PGFPlots.Histogram2
elseif st == :contour
PGFPlots.Contour
else
PGFPlots.Linear
end
func(args...; kw...)
end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
axis = sp[Symbol(letter,:axis)]
style = []
kw = KW()
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
# scale
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
kw[Symbol(letter,:mode)] = "log"
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
end
# ticks on or off
if axis[:ticks] in (nothing, false)
push!(style, "$(letter)majorticks=false")
end
# limits
# TODO: support zlims
if letter != :z
lims = axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
# return the style list and KW args
style, kw
end
# ----------------------------------------------------------------
function _make_pgf_plot!(plt::Plot)
plt.o = PGFPlots.Axis[]
for sp in plt.subplots
# first build the PGFPlots.Axis object
style = ["unbounded coords=jump"]
kw = KW()
# add to style/kw for each axis
for letter in (:x, :y, :z)
if letter != :z || is3d(sp)
axisstyle, axiskw = pgf_axis(sp, letter)
merge!(kw, axiskw)
for sty in axisstyle
push!(style, sty)
end
end
end
# bounding box values are in mm
# note: bb origin is top-left, pgf is bottom-left
bb = bbox(sp)
push!(style, """
xshift = $(left(bb).value)mm,
yshift = $((height(bb) - (bottom(bb))).value)mm,
width = $(width(bb).value)mm,
height = $(height(bb).value)mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""")
if sp[:title] != ""
push!(style, "title = $(sp[:title])")
end
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true"
end
legpos = sp[:legend]
if haskey(_pgfplots_legend_pos, legpos)
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
o = PGFPlots.Axis(; style = style, kw...)
# add the series object to the PGFPlots.Axis
for series in series_list(sp)
push!(o, pgf_series(sp, series))
end
# add the PGFPlots.Axis to the list
push!(plt.o, o)
end
end
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
writemime(io, mime, plt.o)
end
function _writemime(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
# prepare the object
pgfplt = PGFPlots.plot(plt.o)
# save a pdf
fn = tempname()*".pdf"
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
write(io, readall(open(fn)))
# cleanup
PGFPlots.cleanup(plt.o)
end
function _display(plt::Plot{PGFPlotsBackend})
# prepare the object
_make_pgf_plot!(plt)
pgfplt = PGFPlots.plot(plt.o)
# save an svg
fn = string(tempname(), ".svg")
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
# show it
open_browser_window(fn)
# cleanup
PGFPlots.cleanup(plt.o)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,55 +1,78 @@
# https://github.com/sglyon/PlotlyJS.jl
# ------------------------------------------------------------------------------ # https://github.com/spencerlyon2/PlotlyJS.jl
function plotlyjs_syncplot(plt::Plot{PlotlyJSBackend}) supported_args(::PlotlyJSBackend) = supported_args(PlotlyBackend())
plt[:overwrite_figure] && closeall() supported_types(::PlotlyJSBackend) = supported_types(PlotlyBackend())
plt.o = PlotlyJS.plot() supported_styles(::PlotlyJSBackend) = supported_styles(PlotlyBackend())
traces = PlotlyJS.GenericTrace[] supported_markers(::PlotlyJSBackend) = supported_markers(PlotlyBackend())
for series_dict in plotly_series(plt) supported_scales(::PlotlyJSBackend) = supported_scales(PlotlyBackend())
plotly_type = pop!(series_dict, :type) is_subplot_supported(::PlotlyJSBackend) = true
series_dict[:transpose] = false is_string_supported(::PlotlyJSBackend) = true
push!(traces, PlotlyJS.GenericTrace(plotly_type; series_dict...))
# --------------------------------------------------------------------------------------
function _initialize_backend(::PlotlyJSBackend; kw...)
@eval begin
import PlotlyJS
export PlotlyJS
end end
PlotlyJS.addtraces!(plt.o, traces...)
layout = plotly_layout(plt) # # override IJulia inline display
w, h = plt[:size] # if isijulia()
PlotlyJS.relayout!(plt.o, layout, width = w, height = h) # IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
return plt.o # end
end end
# ------------------------------------------------------------------------------ # ---------------------------------------------------------------------------
for (mime, fmt) in (
"application/pdf" => "pdf", function _create_backend_figure(plt::Plot{PlotlyJSBackend})
"image/png" => "png", PlotlyJS.plot()
"image/svg+xml" => "svg",
"image/eps" => "eps",
)
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) =
PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt)
end end
# Use the Plotly implementation for json and html:
_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) =
plotly_show_js(io, plt)
html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt) function _series_added(plt::Plot{PlotlyJSBackend}, series::Series)
html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt) syncplot = plt.o
pdicts = plotly_series(plt, series)
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = for pdict in pdicts
write(io, embeddable_html(plt)) typ = pop!(pdict, :type)
gt = PlotlyJS.GenericTrace(typ; pdict...)
_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt)) PlotlyJS.addtraces!(syncplot, gt)
function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend})
return PlotlyJS.WebIO.render(plotlyjs_syncplot(plt))
end
function closeall(::PlotlyJSBackend)
if !isplotnull() && isa(current().o, PlotlyJS.SyncPlot)
close(current().o)
end end
end end
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyJSBackend}) = true function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y))
PlotlyJS.restyle!(
plt.o,
findfirst(plt.series_list, series),
KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
)
end
# ----------------------------------------------------------------
function _update_plot_object(plt::Plot{PlotlyJSBackend})
pdict = plotly_layout(plt)
syncplot = plt.o
w,h = plt[:size]
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
end
# ----------------------------------------------------------------
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
writemime(io, MIME("text/html"), plt.o)
end
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
tmpfn = tempname() * ".png"
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
function _display(plt::Plot{PlotlyJSBackend})
display(plt.o)
end

File diff suppressed because it is too large Load Diff

310
src/backends/qwt.jl Normal file
View File

@ -0,0 +1,310 @@
# https://github.com/tbreloff/Qwt.jl
supported_args(::QwtBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:pos,
:title,
:window_title,
:guide, :lims, :ticks, :scale,
])
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supported_scales(::QwtBackend) = [:identity, :log10]
is_subplot_supported(::QwtBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::QwtBackend; kw...)
@eval begin
warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
end
# -------------------------------
@compat const _qwtAliases = KW(
:bins => :heatmap_n,
:fillrange => :fillto,
:linewidth => :width,
:markershape => :marker,
:hexbin => :heatmap,
:path => :line,
:steppost => :step,
:steppre => :stepinverted,
:star5 => :star1,
:star8 => :star2,
)
function fixcolors(d::KW)
for (k,v) in d
if typeof(v) <: ColorScheme
d[k] = getColor(v)
end
end
end
function replaceQwtAliases(d, s)
if haskey(_qwtAliases, d[s])
d[s] = _qwtAliases[d[s]]
end
end
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
d = KW(kw)
st = d[:seriestype]
if st == :scatter
d[:seriestype] = :none
if d[:markershape] == :none
d[:markershape] = :circle
end
elseif st in (:hline, :vline)
addLineMarker(plt, d)
d[:seriestype] = :none
d[:markershape] = :circle
d[:markersize] = 1
if st == :vline
d[:x], d[:y] = d[:y], d[:x]
end
elseif !iscreating && st == :bar
d = barHack(; kw...)
elseif !iscreating && st == :histogram
d = barHack(; histogramHack(; kw...)...)
end
replaceQwtAliases(d, :seriestype)
replaceQwtAliases(d, :markershape)
for k in keys(d)
if haskey(_qwtAliases, k)
d[_qwtAliases[k]] = d[k]
end
end
d[:x] = collect(d[:x])
d[:y] = collect(d[:y])
d
end
# function _create_plot(pkg::QwtBackend, d::KW)
function _create_backend_figure(plt::Plot{QwtBackend})
fixcolors(plt.attr)
dumpdict(plt.attr,"\n\n!!! plot")
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
# plt = Plot(o, pkg, 0, d, KW[])
# plt
end
# function _series_added(::QwtBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{QwtBackend}, series::Series)
d = adjustQwtKeywords(plt, false; series.d...)
fixcolors(d)
dumpdict(d,"\n\n!!! plot!")
Qwt.oplot(plt.o; d...)
# push!(plt.seriesargs, d)
# plt
end
# ----------------------------------------------------------------
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
lims = get(d, isx ? :xlims : :ylims, nothing)
ticks = get(d, isx ? :xticks : :yticks, nothing)
w = plt.o.widget
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
if typeof(lims) <: @compat(Union{Tuple,AVec}) && length(lims) == 2
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: Range
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
scalesym = isx ? :xscale : :yscale
if haskey(d, scalesym)
scaletype = d[scalesym]
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
end
end
function _update_plot_object(plt::Plot{QwtBackend}, d::KW)
haskey(d, :title) && Qwt.title(plt.o, d[:title])
haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide])
haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide])
updateLimsAndTicks(plt, d, true)
updateLimsAndTicks(plt, d, false)
end
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
end
# ----------------------------------------------------------------
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
for yi in d[:y]
marker = Qwt.QWT.QwtPlotMarker()
ishorizontal = (d[:seriestype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
marker[:attach](plt.o.widget)
end
# marker[:setValue](x, y)
# marker[:setLabel](Qwt.QWT.QwtText(val))
# marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
qwttext = Qwt.QWT.QwtText(val.str)
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
marker[:setLabel](qwttext)
marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
marker[:setLabel](Qwt.QWT.QwtText(val))
marker[:attach](plt.o.widget)
end
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createQwtAnnotation(plt, ann...)
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{QwtBackend}, i::Int)
series = plt.o.lines[i]
series.x, series.y
end
function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer)
series = plt.o.lines[i]
series.x, series.y = xy
plt
end
# -------------------------------
# savepng(::QwtBackend, plt::AbstractPlot, fn::@compat(AbstractString), args...) = Qwt.savepng(plt.o, fn)
# -------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
# isbefore && return false
# i = 0
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
# push!(row, subplt.plts[i].o)
# if c == ncols(subplt.layout, r)
# push!(rows, Qwt.hsplitter(row...))
# row = Any[]
# end
# end
# # for rowcnt in subplt.layout.rowcounts
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
# # i += rowcnt
# # end
# subplt.o = Qwt.vsplitter(rows...)
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
# true
# end
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
for series in plt.o.lines
_expand_limits(lims, isx ? series.x : series.y)
end
end
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
write(io, readall("/tmp/dfskjdhfkh.png"))
end
# function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
# write(io, readall("/tmp/dfskjdhfkh.png"))
# end
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.showwidget(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.showwidget(subplt.o)
# end

View File

@ -3,9 +3,14 @@
# [ADD BACKEND WEBSITE] # [ADD BACKEND WEBSITE]
import [PkgName] function _initialize_backend(::[PkgName]Backend; kw...)
export [PkgName] @eval begin
push!(_initialized_backends, [pgkname]::Symbol) import [PkgName]
export [PkgName]
# todo: other initialization that needs to be eval-ed
end
# todo: other initialization
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -49,7 +54,7 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations]) # Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
function _update_plot_object(plt::Plot{[PkgName]Backend}) function _update_plot_object(plt::Plot{[PkgName]Backend})
end end
@ -62,7 +67,7 @@ end
# "image/png" => "png", # "image/png" => "png",
# "application/postscript" => "ps", # "application/postscript" => "ps",
# "image/svg+xml" => "svg" # "image/svg+xml" => "svg"
function _show(io::IO, ::MIME"image/png", plt::Plot{[PkgName]Backend}) function _writemime(io::IO, ::MIME"image/png", plt::Plot{[PkgName]Backend})
end end
# Display/show the plot (open a GUI window, or browser page, for example). # Display/show the plot (open a GUI window, or browser page, for example).

View File

@ -1,373 +1,163 @@
# https://github.com/JuliaPlots/UnicodePlots.jl
const _canvas_map = ( # https://github.com/Evizero/UnicodePlots.jl
braille = UnicodePlots.BrailleCanvas,
density = UnicodePlots.DensityCanvas,
heatmap = UnicodePlots.HeatmapCanvas,
lookup = UnicodePlots.LookupCanvas,
ascii = UnicodePlots.AsciiCanvas,
block = UnicodePlots.BlockCanvas,
dot = UnicodePlots.DotCanvas,
)
should_warn_on_unsupported(::UnicodePlotsBackend) = false supported_args(::UnicodePlotsBackend) = merge_with_base_supported([
:label,
:legend,
:seriescolor,
:seriesalpha,
:linestyle,
:markershape,
:bins,
:title,
:guide, :lims,
])
supported_types(::UnicodePlotsBackend) = [
:path, :scatter,
:histogram2d
]
supported_styles(::UnicodePlotsBackend) = [:auto, :solid]
supported_markers(::UnicodePlotsBackend) = [:none, :auto, :circle]
supported_scales(::UnicodePlotsBackend) = [:identity]
is_subplot_supported(::UnicodePlotsBackend) = true
function _before_layout_calcs(plt::Plot{UnicodePlotsBackend})
plt.o = UnicodePlots.Plot[]
up_width = UnicodePlots.DEFAULT_WIDTH[]
up_height = UnicodePlots.DEFAULT_HEIGHT[]
has_layout = prod(size(plt.layout)) > 1 # don't warn on unsupported... there's just too many warnings!!
warnOnUnsupported_args(pkg::UnicodePlotsBackend, d::KW) = nothing
# --------------------------------------------------------------------------------------
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot, width, height)
plt.o = []
for sp in plt.subplots for sp in plt.subplots
sp_kw = sp[:extra_kwargs]
xaxis = sp[:xaxis] xaxis = sp[:xaxis]
yaxis = sp[:yaxis] yaxis = sp[:yaxis]
xlim = collect(axis_limits(sp, :x)) xlim = axis_limits(xaxis)
ylim = collect(axis_limits(sp, :y)) ylim = axis_limits(yaxis)
zlim = collect(axis_limits(sp, :z))
F = float(eltype(xlim))
# We set x/y to have a single point, # make vectors
# since we need to create the plot with some data. xlim = [xlim[1], xlim[2]]
# Since this point is at the bottom left corner of the plot, ylim = [ylim[1], ylim[2]]
# it should be hidden by consecutive plotting commands.
x = Vector{F}(xlim)
y = Vector{F}(ylim)
z = Vector{F}(zlim)
# create a plot window with xlim/ylim set, # we set x/y to have a single point, since we need to create the plot with some data.
# but the X/Y vectors are outside the bounds # since this point is at the bottom left corner of the plot, it shouldn't actually be shown
canvas = if (up_c = get(sp_kw, :canvas, :auto)) === :auto x = Float64[xlim[1]]
isijulia() ? :ascii : :braille y = Float64[ylim[1]]
else
up_c
end
border = if (up_b = get(sp_kw, :border, :auto)) === :auto # create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
isijulia() ? :ascii : :solid canvas_type = isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
else o = UnicodePlots.Plot(x, y, canvas_type;
up_b
end
# blank plots will not be shown
width = has_layout && isempty(series_list(sp)) ? 0 : get(sp_kw, :width, up_width)
height = get(sp_kw, :height, up_height)
plot_3d = is3d(sp)
blend = get(sp_kw, :blend, true)
grid = xaxis[:grid] && yaxis[:grid]
quiver = contour = false
for series in series_list(sp)
st = series[:seriestype]
blend &= get(series[:extra_kwargs], :blend, true)
quiver |= series[:arrow] isa Arrow # post-pipeline detection (:quiver -> :path)
contour |= st === :contour
if st === :histogram2d
xlim = ylim = (0, 0)
elseif st === :spy || st === :heatmap
width = height = 0
grid = false
end
end
grid &= !(quiver || contour)
blend &= !(quiver || contour)
plot_3d && (xlim = ylim = (0, 0)) # determined using projection
azimuth, elevation = sp[:camera] # PyPlot: azimuth = -60 & elevation = 30
projection = plot_3d ? get(sp_kw, :projection, :orthographic) : nothing
kw = (
compact = true,
title = texmath2unicode(sp[:title]),
xlabel = texmath2unicode(xaxis[:guide]),
ylabel = texmath2unicode(yaxis[:guide]),
grid = grid,
blend = blend,
height = height,
width = width, width = width,
xscale = xaxis[:scale], height = height,
yscale = yaxis[:scale], title = sp[:title],
border = border,
xlim = xlim, xlim = xlim,
ylim = ylim, ylim = ylim,
# 3d border = isijulia() ? :ascii : :solid
projection = projection,
elevation = elevation,
azimuth = azimuth,
zoom = get(sp_kw, :zoom, 1),
up = get(sp_kw, :up, :z),
) )
o = UnicodePlots.Plot(x, y, plot_3d ? z : nothing, _canvas_map[canvas]; kw...) # set the axis labels
for series in series_list(sp) UnicodePlots.xlabel!(o, xaxis[:guide])
o = addUnicodeSeries!( UnicodePlots.ylabel!(o, yaxis[:guide])
sp,
o,
kw,
series,
sp[:legend_position] !== :none,
plot_3d,
)
end
for ann in sp[:annotations]
x, y, val = locate_annotation(sp, ann...)
o = UnicodePlots.annotate!(
o,
x,
y,
texmath2unicode(val.str);
color = up_color(val.font.color),
halign = val.font.halign,
valign = val.font.valign,
)
end
push!(plt.o, o) # save the object
end
end
up_color(col::UnicodePlots.UserColorType) = col
up_color(col::RGBA) =
(c = convert(ARGB32, col); map(Int, (red(c).i, green(c).i, blue(c).i)))
up_color(col) = :auto
function up_cmap(series)
rng = range(0, 1, length = length(UnicodePlots.COLOR_MAP_DATA[:viridis]))
[(red(c), green(c), blue(c)) for c in get(get_colorgradient(series), rng)]
end
# add a single series
function addUnicodeSeries!(
sp::Subplot{UnicodePlotsBackend},
up::UnicodePlots.Plot,
kw,
series,
addlegend::Bool,
plot_3d::Bool,
)
st = series[:seriestype]
se_kw = series[:extra_kwargs]
# get the series data and label
x, y = if st === :straightline
straightline_data(series)
elseif st === :shape
shape_data(series)
else
series[:x], series[:y]
end
if ispolar(sp) || ispolar(series)
return UnicodePlots.polarplot(x, y)
end
# special handling (src/interface)
fix_ar = get(se_kw, :fix_ar, true)
if st === :histogram2d
return UnicodePlots.densityplot(x, y; kw...)
elseif st === :spy
return UnicodePlots.spy(Array(series[:z]); fix_ar = fix_ar, kw...)
elseif st in (:contour, :heatmap) # 2D
colormap = get(se_kw, :colormap, :none)
kw = (
kw...,
zlabel = sp[:colorbar_title],
colormap = colormap === :none ? up_cmap(series) : colormap,
colorbar = hascolorbar(sp),
)
if st === :contour
isfilledcontour(series) &&
@warn "Plots(UnicodePlots): filled contour is not implemented"
return UnicodePlots.contourplot(
x,
y,
Array(series[:z]);
kw...,
levels = series[:levels],
)
elseif st === :heatmap
return UnicodePlots.heatmap(Array(series[:z]); fix_ar = fix_ar, kw...)
end
elseif st in (:surface, :wireframe) # 3D
colormap = get(se_kw, :colormap, :none)
lines = get(se_kw, :lines, st === :wireframe)
zscale = get(se_kw, :zscale, :identity)
kw = (
kw...,
zlabel = sp[:colorbar_title],
colormap = colormap === :none ? up_cmap(series) : colormap,
colorbar = hascolorbar(sp),
color = st === :wireframe ? up_color(get_linecolor(series, 1)) : nothing,
zscale = zscale,
lines = lines,
)
return UnicodePlots.surfaceplot(x, y, Array(series[:z]); kw...)
elseif st === :mesh3d
return UnicodePlots.lineplot!(
up,
mesh3d_triangles(x, y, series[:z], series[:connections])...,
)
end
# now use the ! functions to add to the plot # now use the ! functions to add to the plot
if st in (:path, :path3d, :straightline, :shape, :mesh3d) for series in series_list(sp)
addUnicodeSeries!(o, series.d, sp[:legend] != :none, xlim, ylim)
end
# save the object
push!(plt.o, o)
end
end
# add a single series
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = d[:seriestype]
if st == :histogram2d
UnicodePlots.densityplot!(o, d[:x], d[:y])
return
end
if st == :path
func = UnicodePlots.lineplot! func = UnicodePlots.lineplot!
series_kw = (; head_tail = series[:arrow] isa Arrow ? series[:arrow].side : nothing) elseif st == :scatter || d[:markershape] != :none
elseif st in (:scatter, :scatter3d) || series[:markershape] !== :none
func = UnicodePlots.scatterplot! func = UnicodePlots.scatterplot!
series_kw = (; marker = series[:markershape])
else else
error("Plots(UnicodePlots): series type $st not supported") error("Linestyle $st not supported by UnicodePlots")
end end
label = addlegend ? series[:label] : "" # get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
label = addlegend ? d[:label] : ""
for (n, segment) in enumerate(series_segments(series, st; check = true)) # if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
i, rng = segment.attr_index, segment.range color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
lc = get_linecolor(series, i)
up = func(
up,
x[rng],
y[rng],
plot_3d ? series[:z][rng] : nothing;
color = up_color(lc),
name = n == 1 ? label : "",
series_kw...,
)
end
for (xi, yi, str, fnt) in EachAnn(series[:series_annotations], x, y) # add the series
up = UnicodePlots.annotate!( func(o, x, y; color = color, name = label)
up,
xi,
yi,
str;
color = up_color(fnt.color),
halign = fnt.halign,
valign = fnt.valign,
)
end
up
end end
# ------------------------------------------------------------------------------------------ # -------------------------------
function _show(io::IO, ::MIME"image/png", plt::Plot{UnicodePlotsBackend}) # since this is such a hack, it's only callable using `png`... should error during normal `writemime`
prepare_output(plt) function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
nr, nc = size(plt.layout) fn = addExtension(fn, "png")
s1 = zeros(Int, nr, nc)
s2 = zeros(Int, nr, nc) # make some whitespace and show the plot
canvas_type = nothing println("\n\n\n\n\n\n")
imgs = [] gui(plt)
sps = 0
for r in 1:nr # @osx_only begin
for c in 1:nc @compat @static if is_apple()
if (l = plt.layout[r, c]) isa GridLayout && size(l) != (1, 1) # BEGIN HACK
error("Plots(UnicodePlots): complex nested layout is currently unsupported")
else # wait while the plot gets drawn
img = UnicodePlots.png_image(plt.o[sps += 1]) sleep(0.5)
canvas_type = eltype(img)
h, w = size(img) # use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
s1[r, c] = h # TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
s2[r, c] = w run(`screencapture -R50,600,700,420 $fn`)
push!(imgs, img)
end # END HACK (phew)
end return
end
if canvas_type !== nothing
m1 = maximum(s1; dims = 2)
m2 = maximum(s2; dims = 1)
img = zeros(canvas_type, sum(m1), sum(m2))
sps = 0
n1 = 1
for r in 1:nr
n2 = 1
for c in 1:nc
sp = imgs[sps += 1]
h, w = size(sp)
img[n1:(n1 + (h - 1)), n2:(n2 + (w - 1))] = sp
n2 += m2[c]
end
n1 += m1[r]
end
stream = UnicodePlots.FileIO.Stream{UnicodePlots.FileIO.format"PNG"}(io)
UnicodePlots.FileIO.save(stream, img)
end end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end
# -------------------------------
# we don't do very much for subplots... just stack them vertically
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
w, h = plt[:size]
plt.attr[:color_palette] = [RGB(0,0,0)]
rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
end
function _writemime(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
map(show, plt.o)
nothing nothing
end end
Base.show(plt::Plot{UnicodePlotsBackend}) = show(stdout, plt)
Base.show(io::IO, plt::Plot{UnicodePlotsBackend}) = _show(io, MIME("text/plain"), plt)
# NOTE: _show(...) must be kept for Base.showable (src/output.jl)
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
prepare_output(plt)
nr, nc = size(plt.layout)
if nr == 1 && nc == 1 # fast path
n = length(plt.o)
for (i, p) in enumerate(plt.o)
show(io, p)
i < n && println(io)
end
else
have_color = Base.get_have_color()
buf = IOContext(PipeBuffer(), :color => have_color)
lines_colored = Array{Union{Nothing,Vector{String}}}(undef, nr, nc)
lines_uncolored = have_color ? similar(lines_colored) : lines_colored
l_max = zeros(Int, nr)
w_max = zeros(Int, nc)
sps = 0
for r in 1:nr
lmax = 0
for c in 1:nc
if (l = plt.layout[r, c]) isa GridLayout && size(l) != (1, 1)
error(
"Plots(UnicodePlots): complex nested layout is currently unsupported",
)
else
if get(l.attr, :blank, false)
lines_colored[r, c] = lines_uncolored[r, c] = nothing
else
sp = plt.o[sps += 1]
show(buf, sp)
colored = read(buf, String)
lines_colored[r, c] = lu = lc = split(colored, '\n')
if have_color
uncolored = UnicodePlots.no_ansi_escape(colored)
lines_uncolored[r, c] = lu = split(uncolored, '\n')
end
lmax = max(length(lc), lmax)
w_max[c] = max(maximum(length.(lu)), w_max[c])
end
end
end
l_max[r] = lmax
end
empty = String[' '^w for w in w_max]
for r in 1:nr
for n in 1:l_max[r]
for c in 1:nc
pre = c == 1 ? '\0' : ' '
lc = lines_colored[r, c]
if lc === nothing || length(lc) < n
print(io, pre, empty[c])
else
lu = lines_uncolored[r, c]
print(io, pre, lc[n], ' '^(w_max[c] - length(lu[n])))
end
end
n < l_max[r] && println(io)
end
r < nr && println(io)
end
end
nothing
end
# we only support MIME"text/plain", hence display(...) falls back to plain-text on stdout
function _display(plt::Plot{UnicodePlotsBackend}) function _display(plt::Plot{UnicodePlotsBackend})
show(stdout, plt) unicodeplots_rebuild(plt)
println(stdout) map(show, plt.o)
nothing
end end

View File

@ -3,16 +3,13 @@
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl # CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
function standalone_html(
plt::AbstractPlot; function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
title::AbstractString = get(plt.attr, :window_title, "Plots.jl"),
)
""" """
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>$title</title> <title>$title</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
$(html_head(plt)) $(html_head(plt))
</head> </head>
<body> <body>
@ -22,21 +19,17 @@ function standalone_html(
""" """
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() @compat @static if is_apple()
return run(`open $(filename)`) return run(`open $(filename)`)
end end
@static if Sys.islinux() || Sys.isbsd() # Sys.isbsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681 @compat @static if is_linux()
return run(`xdg-open $(filename)`) return run(`xdg-open $(filename)`)
end end
@static if Sys.iswindows() @compat @static if is_windows()
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`) return run(`$(ENV["COMSPEC"]) /c start $(filename)`)
end end
@warn("Unknown OS... cannot open browser window.") warn("Unknown OS... cannot open browser window.")
end end
function write_temp_html(plt::AbstractPlot) function write_temp_html(plt::AbstractPlot)
@ -49,25 +42,16 @@ function write_temp_html(plt::AbstractPlot)
end end
function standalone_html_window(plt::AbstractPlot) function standalone_html_window(plt::AbstractPlot)
old = use_local_dependencies[] # save state to restore afterwards
# if we open a browser ourself, we can host local files, so
# when we have a local plotly downloaded this is the way to go!
use_local_dependencies[] =
plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
filename = write_temp_html(plt) filename = write_temp_html(plt)
open_browser_window(filename) open_browser_window(filename)
# restore for other backends
use_local_dependencies[] = old
end end
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html # uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
function html_to_png(html_fn, png_fn, w, h) function html_to_png(html_fn, png_fn, w, h)
run( run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`)
`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`,
)
end end
function show_png_from_html(io::IO, plt::AbstractPlot) function writemime_png_from_html(io::IO, plt::AbstractPlot)
# write html to a temporary file # write html to a temporary file
html_fn = write_temp_html(plt) html_fn = write_temp_html(plt)

272
src/backends/winston.jl Normal file
View File

@ -0,0 +1,272 @@
# https://github.com/nolta/Winston.jl
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
supported_args(::WinstonBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:title,
:window_title,
:guide, :lims, :scale,
])
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::WinstonBackend) = [:identity, :log10]
is_subplot_supported(::WinstonBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::WinstonBackend; kw...)
@eval begin
# ENV["WINSTON_OUTPUT"] = "gtk"
warn("Winston is no longer supported... many features will likely be broken.")
import Winston, Gtk
export Winston, Gtk
end
end
# ---------------------------------------------------------------------------
## dictionaries for conversion of Plots.jl names to Winston ones.
@compat const winston_linestyle = KW(:solid=>"solid",
:dash=>"dash",
:dot=>"dotted",
:dashdot=>"dotdashed"
)
@compat const winston_marker = KW(:none=>".",
:rect => "square",
:circle=>"circle",
:diamond=>"diamond",
:utriangle=>"triangle",
:dtriangle=>"down-triangle",
:cross => "plus",
:xcross => "cross",
:star5 => "asterisk"
)
function _before_update(plt::Plot{WinstonBackend})
Winston.ghf(plt.o)
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{WinstonBackend})
Winston.FramedPlot(
title = plt.attr[:title],
xlabel = plt.attr[:xguide],
ylabel = plt.attr[:yguide]
)
end
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
function addRegressionLineWinston(d::KW, wplt)
xs, ys = regressionXY(d[:x], d[:y])
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
end
function getWinstonItems(plt::Plot)
if isa(plt.o, Winston.FramedPlot)
wplt = plt.o
window, canvas = nothing, nothing
else
window, canvas, wplt = plt.o
end
window, canvas, wplt
end
function _series_added(plt::Plot{WinstonBackend}, series::Series)
d = series.d
window, canvas, wplt = getWinstonItems(plt)
# until we call it normally, do the hack
if d[:seriestype] == :bar
d = barHack(;d...)
end
e = KW()
e[:color] = getColor(d[:linecolor])
e[:linewidth] = d[:linewidth]
e[:kind] = winston_linestyle[d[:linestyle]]
e[:symbolkind] = winston_marker[d[:markershape]]
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
e[:symbolsize] = d[:markersize] / 5
# pos # (Int,Int), move the enclosing window to this position
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
if d[:seriestype] == :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
elseif d[:seriestype] == :path
x, y = d[:x], d[:y]
Winston.add(wplt, Winston.Curve(x, y; e...))
fillrange = d[:fillrange]
if fillrange != nothing
if isa(fillrange, AbstractVector)
y2 = fillrange
else
y2 = Float64[fillrange for yi in y]
end
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(d[:fillcolor])))
end
elseif d[:seriestype] == :scatter
if d[:markershape] == :none
d[:markershape] = :circle
end
# elseif d[:seriestype] == :step
# fn = Winston.XXX
# elseif d[:seriestype] == :stepinverted
# fn = Winston.XXX
elseif d[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(d[:x], d[:y]; e...))
# elseif d[:seriestype] == :dots
# fn = Winston.XXX
# elseif d[:seriestype] == :histogram2d
# fn = Winston.XXX
# elseif d[:seriestype] == :hexbin
# fn = Winston.XXX
elseif d[:seriestype] == :histogram
hst = hist(d[:y], d[:bins])
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
# elseif d[:seriestype] == :bar
# # fn = Winston.XXX
else
error("seriestype $(d[:seriestype]) not supported by Winston.")
end
# markershape
if d[:markershape] != :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
end
# optionally add a regression line
d[:smooth] && d[:seriestype] != :histogram && addRegressionLineWinston(d, wplt)
# push!(plt.seriesargs, d)
# plt
end
# ----------------------------------------------------------------
@compat const _winstonNames = KW(
:xlims => :xrange,
:ylims => :yrange,
:xscale => :xlog,
:yscale => :ylog,
)
function _update_plot_object(plt::Plot{WinstonBackend}, d::KW)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xguide, :yguide, :title, :xlims, :ylims)
if haskey(d, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k])
end
end
for k in (:xscale, :yscale)
if haskey(d, k)
islogscale = d[k] == :log10
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
end
end
end
# ----------------------------------------------------------------
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::@compat(AbstractString))
Winston.text(x, y, val)
end
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
# end
# ----------------------------------------------------------------
function addWinstonLegend(plt::Plot, wplt)
if plt.attr[:legend] != :none
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
end
end
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
addWinstonLegend(plt, wplt)
writemime(io, "image/png", wplt)
end
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
if window == nothing
if Winston.output_surface != :gtk
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
end
# initialize window
w,h = plt.attr[:size]
canvas = Gtk.GtkCanvasLeaf()
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
plt.o = (window, canvas, wplt)
end
addWinstonLegend(plt, wplt)
Winston.display(canvas, wplt)
Gtk.showall(window)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
# # TODO: display/show the Subplot object
# end

View File

@ -1,105 +0,0 @@
# 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
get_clims(sp::Subplot)::Tuple{Float64,Float64} =
haskey(sp.attr, :clims_calculated) ? sp[:clims_calculated] : update_clims(sp)
get_clims(series::Series)::Tuple{Float64,Float64} =
haskey(series.plotattributes, :clims_calculated) ?
series[:clims_calculated]::Tuple{Float64,Float64} : update_clims(series)
get_clims(sp::Subplot, series::Series)::Tuple{Float64,Float64} =
series[:colorbar_entry] ? get_clims(sp) : get_clims(series)
function update_clims(sp::Subplot, op = process_clims(sp[:clims]))::Tuple{Float64,Float64}
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]::Bool
zmin, zmax = _update_clims(zmin, zmax, update_clims(series, op)...)
else
update_clims(series, op)
end
end
return sp[:clims_calculated] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
update_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. The value is stored as a series property, which is retrieved by `get_clims`.
"""
function update_clims(series::Series, op = ignorenan_extrema)::Tuple{Float64,Float64}
zmin, zmax = Inf, -Inf
# keeping this unrolled has higher performance
if series[:seriestype] _z_colored_series && series[:z] !== nothing
zmin, zmax = update_clims(zmin, zmax, series[:z], op)
end
if series[:line_z] !== nothing
zmin, zmax = update_clims(zmin, zmax, series[:line_z], op)
end
if series[:marker_z] !== nothing
zmin, zmax = update_clims(zmin, zmax, series[:marker_z], op)
end
if series[:fill_z] !== nothing
zmin, zmax = update_clims(zmin, zmax, series[:fill_z], op)
end
return series[:clims_calculated] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
update_clims(zmin, zmax, vals::AbstractSurface, op)::Tuple{Float64,Float64} =
update_clims(zmin, zmax, vals.surf, op)
update_clims(zmin, zmax, vals::Any, op)::Tuple{Float64,Float64} =
_update_clims(zmin, zmax, op(vals)...)
update_clims(zmin, zmax, ::Nothing, ::Any)::Tuple{Float64,Float64} = zmin, zmax
_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 in [: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
update_clims(sp)
end

View File

@ -1,20 +1,19 @@
const P2 = GeometryBasics.Point2{Float64}
const P3 = GeometryBasics.Point3{Float64}
const _haligns = :hcenter, :left, :right
const _valigns = :vcenter, :top, :bottom
nanpush!(a::AVec{P2}, b) = (push!(a, P2(NaN, NaN)); push!(a, b)) typealias P2 FixedSizeArrays.Vec{2,Float64}
nanappend!(a::AVec{P2}, b) = (push!(a, P2(NaN, NaN)); append!(a, b)) typealias P3 FixedSizeArrays.Vec{3,Float64}
nanpush!(a::AVec{P3}, b) = (push!(a, P3(NaN, NaN, NaN)); push!(a, b))
nanappend!(a::AVec{P3}, b) = (push!(a, P3(NaN, NaN, NaN)); append!(a, b)) nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle) nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
# ------------------------------------------------------------- # -------------------------------------------------------------
struct Shape{X<:Number,Y<:Number} immutable Shape
x::Vector{X} x::Vector{Float64}
y::Vector{Y} y::Vector{Float64}
# 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]))
@ -23,41 +22,42 @@ struct Shape{X<:Number,Y<:Number}
# end # end
# end # end
end end
Shape(verts::AVec) = Shape(unzip(verts)...)
"""
Shape(x, y)
Shape(vertices)
Construct a polygon to be plotted
"""
Shape(verts::AVec) = Shape(RecipesPipeline.unzip(verts)...)
Shape(s::Shape) = deepcopy(s)
get_xs(shape::Shape) = shape.x get_xs(shape::Shape) = shape.x
get_ys(shape::Shape) = shape.y get_ys(shape::Shape) = shape.y
vertices(shape::Shape) = collect(zip(shape.x, shape.y)) vertices(shape::Shape) = collect(zip(shape.x, shape.y))
#deprecated
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object" function shape_coords(shape::Shape)
coords(shape::Shape) = shape.x, shape.y shape.x, shape.y
end
coords(shapes::AVec{<:Shape}) = unzip(map(coords, shapes)) function shape_coords(shapes::AVec{Shape})
length(shapes) == 0 && return zeros(0), zeros(0)
xs = map(get_xs, shapes)
ys = map(get_ys, shapes)
x, y = map(copy, shape_coords(shapes[1]))
for shape in shapes[2:end]
nanappend!(x, shape.x)
nanappend!(y, shape.y)
end
x, y
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`"
partialcircle(start_θ, end_θ, n = 20, r = 1) = function partialcircle(start_θ, end_θ, n = 20, r=1)
[(r * cos(u), r * sin(u)) for u in range(start_θ, stop = end_θ, length = n)] @compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)" "interleave 2 vectors into each other (like a zipper's teeth)"
function weave(x, y; ordering = Vector[x, y]) function weave(x,y; ordering = Vector[x,y])
ret = eltype(x)[] ret = eltype(x)[]
done = false done = false
while !done while !done
for o in ordering for o in ordering
try try
push!(ret, popfirst!(o)) push!(ret, shift!(o))
catch
end end
end end
done = isempty(x) && isempty(y) done = isempty(x) && isempty(y)
@ -65,83 +65,97 @@ 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 * π
z2 = z1 + π / (n) z2 = z1 + π / (n)
outercircle = partialcircle(z1, z1 + 2π, n + 1, radius) outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
innercircle = partialcircle(z2, z2 + 2π, n + 1, 0.4radius) innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
Shape(weave(outercircle, innercircle)) Shape(weave(outercircle, innercircle)[1:end-2])
end end
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle" "create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
makeshape(n; offset = -0.5, radius = 1.0) = function makeshape(n; offset = -0.5, radius = 1.0)
Shape(partialcircle(offset * π, offset * π + 2π, n + 1, radius)) z = offset * π
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
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
outercircle = partialcircle(z1, z1 + 2π, 9, radius) outercircle = partialcircle(z1, z1 + 2π, 9, radius)
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius) innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
Shape( Shape(weave(outercircle, innercircle,
weave( ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
outercircle,
innercircle,
ordering = Vector[outercircle, innercircle, outercircle],
),
)
end end
from_polar(angle, dist) = P2(dist * cos(angle), dist * sin(angle))
makearrowhead(angle; h = 2.0, w = 0.4, tip = from_polar(angle, h)) = Shape( from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
P2[
(0, 0), function makearrowhead(angle; h = 2.0, w = 0.4)
from_polar(angle - 0.5π, w) - tip, tip = from_polar(angle, h)
from_polar(angle + 0.5π, w) - tip, Shape(P2[(0,0), from_polar(angle - 0.5π, w) - tip,
(0, 0), from_polar(angle + 0.5π, w) - tip, (0,0)])
], end
)
const _shape_keys = Symbol[
:circle,
:rect,
:star5,
:diamond,
:hexagon,
:cross,
:xcross,
:utriangle,
:dtriangle,
:pentagon,
:heptagon,
:octagon,
:star4,
:star6,
:star7,
:star8,
:vline,
:hline,
]
const _shapes = KW( const _shapes = KW(
:circle => makeshape(20), :circle => makeshape(20),
:rect => makeshape(4, offset = -0.25), :rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4), :diamond => makeshape(4),
:utriangle => makeshape(3, offset = 0.5), :utriangle => makeshape(3),
:dtriangle => makeshape(3, offset = -0.5), :dtriangle => makeshape(3, offset=0.5),
:rtriangle => makeshape(3, offset = 0.0),
:ltriangle => makeshape(3, offset = 1.0),
:pentagon => makeshape(5), :pentagon => makeshape(5),
:hexagon => makeshape(6), :hexagon => makeshape(6),
:heptagon => makeshape(7), :heptagon => makeshape(7),
:octagon => makeshape(8), :octagon => makeshape(8),
:cross => makecross(offset = -0.25), :cross => makecross(offset=-0.25),
:xcross => makecross(), :xcross => makecross(),
:vline => Shape([(0, 1), (0, -1)]), :vline => Shape([(0,1),(0,-1)]),
:hline => Shape([(1, 0), (-1, 0)]), :hline => Shape([(1,0),(-1,0)]),
) )
for n in 4:8 for n in [4,5,6,7,8]
_shapes[Symbol("star$n")] = makestar(n) _shapes[Symbol("star$n")] = makestar(n)
end end
Shape(k::Symbol) = deepcopy(_shapes[k])
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon # uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
"return the centroid of a Shape"
function center(shape::Shape) function center(shape::Shape)
x, y = coords(shape) x, y = shape_coords(shape)
n = length(x) n = length(x)
A, Cx, Cy = 0, 0, 0 A, Cx, Cy = 0.0, 0.0, 0.0
for i in 1:n for i=1:n
ip1 = i == n ? 1 : i + 1 ip1 = i==n ? 1 : i+1
A += x[i] * y[ip1] - x[ip1] * y[i] A += x[i] * y[ip1] - x[ip1] * y[i]
end end
A *= 0.5 A *= 0.5
for i in 1:n for i=1:n
ip1 = i == n ? 1 : i + 1 ip1 = i==n ? 1 : i+1
m = (x[i] * y[ip1] - x[ip1] * y[i]) m = (x[i] * y[ip1] - x[ip1] * y[i])
Cx += (x[i] + x[ip1]) * m Cx += (x[i] + x[ip1]) * m
Cy += (y[i] + y[ip1]) * m Cy += (y[i] + y[ip1]) * m
@ -149,71 +163,67 @@ function center(shape::Shape)
Cx / 6A, Cy / 6A Cx / 6A, Cy / 6A
end end
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape)) function Base.scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
sx, sy = coords(shape) sx, sy = shape_coords(shape)
cx, cy = c cx, cy = c
for i in eachindex(sx) for i=1:length(sx)
sx[i] = (sx[i] - cx) * x + cx sx[i] = (sx[i] - cx) * x + cx
sy[i] = (sy[i] - cy) * y + cy sy[i] = (sy[i] - cy) * y + cy
end end
shape shape
end end
""" function Base.scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
scale(shape, x, y = x, c = center(shape)) shapecopy = deepcopy(shape)
scale!(shape, x, y = x, c = center(shape)) scale!(shape, x, y, c)
end
Scale shape by a factor.
"""
scale(shape::Shape, x::Real, y::Real = x, c = center(shape)) =
scale!(deepcopy(shape), x, y, c)
function translate!(shape::Shape, x::Real, y::Real = x) function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape) sx, sy = shape_coords(shape)
for i in eachindex(sx) for i=1:length(sx)
sx[i] += x sx[i] += x
sy[i] += y sy[i] += y
end end
shape shape
end end
""" function translate(shape::Shape, x::Real, y::Real = x)
translate(shape, x, y = x) shapecopy = deepcopy(shape)
translate!(shape, x, y = x) translate!(shape, x, y)
end
Translate a Shape in space. function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
""" (x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx
translate(shape::Shape, x::Real, y::Real = x) = translate!(deepcopy(shape), x, y) end
rotate_x(x::Real, y::Real, θ::Real, centerx::Real, centery::Real) = function rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
((x - centerx) * cos(θ) - (y - centery) * sin(θ) + centerx) (y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery
end
rotate_y(x::Real, y::Real, θ::Real, centerx::Real, centery::Real) = function rotate(x::Real, y::Real, θ::Real, c = center(shape))
((y - centery) * cos(θ) + (x - centerx) * sin(θ) + centery) cx, cy = c
rotate_x(x, y, Θ, cx, cy), rotate_y(x, y, Θ, cx, cy)
end
rotate(x::Real, y::Real, θ::Real, c) = (rotate_x(x, y, θ, c...), rotate_y(x, y, θ, c...)) function rotate!(shape::Shape, Θ::Real, c = center(shape))
x, y = shape_coords(shape)
function rotate!(shape::Shape, θ::Real, c = center(shape)) cx, cy = c
x, y = coords(shape) for i=1:length(x)
for i in eachindex(x) x[i] = rotate_x(x[i], y[i], Θ, cx, cy)
xi = rotate_x(x[i], y[i], θ, c...) y[i] = rotate_y(x[i], y[i], Θ, cx, cy)
yi = rotate_y(x[i], y[i], θ, c...)
x[i], y[i] = xi, yi
end end
shape shape
end end
"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)
x_new = rotate_x.(x, y, θ, c...)
y_new = rotate_y.(x, y, θ, c...)
Shape(x_new, y_new)
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
mutable struct Font
immutable Font
family::AbstractString family::AbstractString
pointsize::Int pointsize::Int
halign::Symbol halign::Symbol
@ -222,35 +232,19 @@ mutable struct Font
color::Colorant color::Colorant
end end
""" "Create a Font from a list of unordered features"
font(args...) function font(args...)
Create a Font from a list of features. Values may be specified either as
arguments (which are distinguished by type/value) or as keyword arguments.
# Arguments
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
- `pointsize`: Integer. Size of font in points
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
- `color`: Colorant or Symbol
# Examples
```julia-repl
julia> font(8)
julia> font(family="serif", halign=:center, rotation=45.0)
```
"""
function font(args...; kw...)
# defaults # defaults
family = "sans-serif" family = "Helvetica"
pointsize = 14 pointsize = 14
halign = :hcenter halign = :hcenter
valign = :vcenter valign = :vcenter
rotation = 0 rotation = 0.0
color = colorant"black" color = colorant"black"
for arg in args for arg in args
T = typeof(arg) T = typeof(arg)
@assert arg !== :match
if T == Font if T == Font
family = arg.family family = arg.family
@ -262,9 +256,9 @@ function font(args...; kw...)
elseif arg == :center elseif arg == :center
halign = :hcenter halign = :hcenter
valign = :vcenter valign = :vcenter
elseif arg _haligns elseif arg in (:hcenter, :left, :right)
halign = arg halign = arg
elseif arg _valigns elseif arg in (:vcenter, :top, :bottom)
valign = arg valign = arg
elseif T <: Colorant elseif T <: Colorant
color = arg color = arg
@ -274,128 +268,52 @@ function font(args...; kw...)
catch catch
family = string(arg) family = string(arg)
end end
elseif T <: Integer elseif typeof(arg) <: Integer
pointsize = arg pointsize = arg
elseif T <: Real elseif typeof(arg) <: Real
rotation = convert(Float64, arg) rotation = convert(Float64, arg)
else else
@warn "Unused font arg: $arg ($T)" warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
for sym in keys(kw)
if sym == :family
family = string(kw[sym])
elseif sym == :pointsize
pointsize = kw[sym]
elseif sym == :halign
halign = kw[sym]
halign == :center && (halign = :hcenter)
@assert halign _haligns
elseif sym == :valign
valign = kw[sym]
valign == :center && (valign = :vcenter)
@assert valign _valigns
elseif sym == :rotation
rotation = kw[sym]
elseif sym == :color
color = parse(Colorant, kw[sym])
else
@warn "Unused font kwarg: $sym"
end end
end end
Font(family, pointsize, halign, valign, rotation, color) Font(family, pointsize, halign, valign, rotation, color)
end end
function scalefontsize(k::Symbol, factor::Number)
f = default(k)
f = round(Int, factor * f)
default(k, f)
end
"""
scalefontsizes(factor::Number)
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)
for k in keys(merge(_initial_plt_fontsizes, _initial_sp_fontsizes))
scalefontsize(k, factor)
end
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
scalefontsize(get_attr_symbol(letter, k), factor)
end
end
end
"""
scalefontsizes()
Resets font sizes to initial default values.
"""
function scalefontsizes()
for k in keys(merge(_initial_plt_fontsizes, _initial_sp_fontsizes))
f = default(k)
if k in keys(_initial_fontsizes)
factor = f / _initial_fontsizes[k]
scalefontsize(k, 1.0 / factor)
end
end
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
if k in keys(_initial_fontsizes)
f = default(get_attr_symbol(letter, k))
factor = f / _initial_fontsizes[k]
scalefontsize(get_attr_symbol(letter, k), 1.0 / factor)
end
end
end
end
resetfontsizes() = scalefontsizes()
"Wrap a string with font info" "Wrap a string with font info"
struct PlotText immutable PlotText
str::AbstractString str::AbstractString
font::Font font::Font
end end
PlotText(str) = PlotText(string(str), font()) PlotText(str) = PlotText(string(str), font())
"""
text(string, args...; kw...)
Create a PlotText object wrapping a string with font info, for plot annotations.
`args` and `kw` are passed to `font`.
"""
text(t::PlotText) = t text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f) text(str::AbstractString, f::Font) = PlotText(str, f)
text(str, args...; kw...) = PlotText(string(str), font(args...; kw...)) function text(str, args...)
PlotText(string(str), font(args...))
end
annotations(::Void) = []
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
Base.length(t::PlotText) = length(t.str)
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
struct Stroke # -----------------------------------------------------------------------
immutable Stroke
width width
color color
alpha alpha
style style
end end
"""
stroke(args...; alpha = nothing)
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing) function stroke(args...; alpha = nothing)
width = 1 width = nothing
color = :black color = nothing
style = :solid style = nothing
for arg in args for arg in args
T = typeof(arg) T = typeof(arg)
@ -408,29 +326,29 @@ function stroke(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString elseif T <: Symbol || T <: AbstractString
try try
color = parse(Colorant, string(arg)) color = parse(Colorant, string(arg))
catch
end end
elseif allAlphas(arg) elseif allAlphas(arg)
alpha = arg alpha = arg
elseif allReals(arg) elseif allReals(arg)
width = arg width = arg
else else
@warn "Unused stroke arg: $arg ($(typeof(arg)))" warn("Unused stroke arg: $arg ($(typeof(arg)))")
end end
end end
Stroke(width, color, alpha, style) Stroke(width, color, alpha, style)
end end
struct Brush
immutable Brush
size # fillrange, markersize, or any other sizey attribute size # fillrange, markersize, or any other sizey attribute
color color
alpha alpha
end end
function brush(args...; alpha = nothing) function brush(args...; alpha = nothing)
size = 1 size = nothing
color = :black color = nothing
for arg in args for arg in args
T = typeof(arg) T = typeof(arg)
@ -440,14 +358,13 @@ function brush(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString elseif T <: Symbol || T <: AbstractString
try try
color = parse(Colorant, string(arg)) color = parse(Colorant, string(arg))
catch
end end
elseif allAlphas(arg) elseif allAlphas(arg)
alpha = arg alpha = arg
elseif allReals(arg) elseif allReals(arg)
size = arg size = arg
else else
@warn "Unused brush arg: $arg ($(typeof(arg)))" warn("Unused brush arg: $arg ($(typeof(arg)))")
end end
end end
@ -456,223 +373,35 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
mutable struct SeriesAnnotations
strs::AVec # the labels/names
font::Font
baseshape::Union{Shape,AVec{Shape},Nothing}
scalefactor::Tuple
end
_text_label(lab::Tuple, font) = text(lab[1], font, lab[2:end]...)
_text_label(lab::PlotText, font) = lab
_text_label(lab, font) = text(lab, font)
series_annotations(anns::AMat) = map(series_annotations, anns)
series_annotations(scalar) = series_annotations([scalar])
series_annotations(anns::SeriesAnnotations) = anns
series_annotations(::Nothing) = nothing
function series_annotations(strs::AVec, args...)
fnt = font()
shp = nothing
scalefactor = 1, 1
for arg in args
if isa(arg, Shape) || (isa(arg, AVec) && eltype(arg) == Shape)
shp = arg
elseif isa(arg, Font)
fnt = arg
elseif isa(arg, Symbol) && haskey(_shapes, arg)
shp = _shapes[arg]
elseif isa(arg, Number)
scalefactor = arg, arg
elseif is_2tuple(arg)
scalefactor = arg
elseif isa(arg, AVec)
strs = collect(zip(strs, arg))
else
@warn "Unused SeriesAnnotations arg: $arg ($(typeof(arg)))"
end
end
# if scalefactor != 1
# for s in get(shp)
# scale!(s, scalefactor, scalefactor, (0, 0))
# end
# end
SeriesAnnotations([_text_label(s, fnt) for s in strs], fnt, shp, scalefactor)
end
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
# msw, msh = anns.scalefactor
# ms = series[:markersize]
# msw, msh = if isa(ms, AVec)
# 1, 1
# elseif is_2tuple(ms)
# ms
# else
# ms, ms
# end
# @show msw msh
if anns !== nothing && anns.baseshape !== nothing
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw, msh = anns.scalefactor
msize = Float64[]
shapes = Vector{Shape}(undef, length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs, i)
# get the width and height of the string (in mm)
sw, sh = text_size(str, anns.font.pointsize)
# how much to scale the base shape?
# note: it's a rough assumption that the shape fills the unit box [-1, -1, 1, 1],
# so we scale the length-2 shape by 1/2 the total length
scalar = (backend() == PyPlotBackend() ? 1.7 : 1.0)
xscale = 0.5to_pixels(sw) * scalar
yscale = 0.5to_pixels(sh) * scalar
# we save the size of the larger direction to the markersize list,
# and then re-scale a copy of baseshape to match the w/h ratio
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(anns.baseshape, i)
shapes[i] =
scale(baseshape, msw * xscale / maxscale, msh * yscale / maxscale, (0, 0))
end
series[:markershape] = shapes
series[:markersize] = msize
end
return
end
mutable struct EachAnn
anns
x
y
end
function Base.iterate(ea::EachAnn, i = 1)
if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y)
return
end
tmp = _cycle(ea.anns.strs, i)
str, fnt = if isa(tmp, PlotText)
tmp.str, tmp.font
else
tmp, ea.anns.font
end
((_cycle(ea.x, i), _cycle(ea.y, i), str, fnt), i + 1)
end
# -----------------------------------------------------------------------
annotations(anns::AMat) = map(annotations, anns)
annotations(sa::SeriesAnnotations) = sa
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
annotations(::Nothing) = []
_annotationfont(sp::Subplot) = Plots.font(;
family = sp[:annotationfontfamily],
pointsize = sp[:annotationfontsize],
halign = sp[:annotationhalign],
valign = sp[:annotationvalign],
rotation = sp[:annotationrotation],
color = sp[:annotationcolor],
)
_annotation(sp::Subplot, font, lab, pos...; alphabet = "abcdefghijklmnopqrstuvwxyz") = (
pos...,
lab == :auto ? text("($(alphabet[sp[:subplot_index]]))", font) : _text_label(lab, font),
)
# Expand arrays of coordinates, positions and labels into individual annotations
# and make sure labels are of type PlotText
function process_annotation(sp::Subplot, xs, ys, labs, font = _annotationfont(sp))
anns = []
labs = makevec(labs)
xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs)
ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys)
for i in 1:max(xlength, ylength, length(labs))
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
x = typeof(x) <: TimeType ? Dates.value(x) : x
y = typeof(y) <: TimeType ? Dates.value(y) : y
push!(anns, _annotation(sp, font, lab, x, y))
end
anns
end
function process_annotation(
sp::Subplot,
positions::Union{AVec{Symbol},Symbol,Tuple},
labs,
font = _annotationfont(sp),
)
anns = []
positions, labs = makevec(positions), makevec(labs)
for i in 1:max(length(positions), length(labs))
pos, lab = _cycle(positions, i), _cycle(labs, i)
push!(anns, _annotation(sp, font, lab, get(_positionAliases, pos, pos)))
end
anns
end
_relative_position(xmin, xmax, pos::Length{:pct}) = xmin + pos.value * (xmax - xmin)
# Give each annotation coordinates based on specified position
function locate_annotation(
sp::Subplot,
pos::Symbol,
label::PlotText;
position_multiplier = Dict{Symbol,Tuple{Float64,Float64}}(
:topleft => (0.1pct, 0.9pct),
:topcenter => (0.5pct, 0.9pct),
:topright => (0.9pct, 0.9pct),
:bottomleft => (0.1pct, 0.1pct),
:bottomcenter => (0.5pct, 0.1pct),
:bottomright => (0.9pct, 0.1pct),
),
)
x, y = position_multiplier[pos]
(
_relative_position(axis_limits(sp, :x)..., x),
_relative_position(axis_limits(sp, :y)..., y),
label,
)
end
locate_annotation(sp::Subplot, x, y, label::PlotText) = (x, y, label)
locate_annotation(sp::Subplot, x, y, z, label::PlotText) = (x, y, z, label)
locate_annotation(sp::Subplot, rel::NTuple{2,<:Number}, label::PlotText) = (
_relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct),
_relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct),
label,
)
locate_annotation(sp::Subplot, rel::NTuple{3,<:Number}, label::PlotText) = (
_relative_position(axis_limits(sp, :x)..., rel[1] * Plots.pct),
_relative_position(axis_limits(sp, :y)..., rel[2] * Plots.pct),
_relative_position(axis_limits(sp, :z)..., rel[3] * Plots.pct),
label,
)
# -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)" "type which represents z-values for colors and sizes (and anything else that might come up)"
struct ZValues immutable ZValues
values::Vector{Float64} values::Vector{Float64}
zrange::Tuple{Float64,Float64} zrange::Tuple{Float64,Float64}
end end
function zvalues( function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (minimum(values), maximum(values)))
values::AVec{T},
zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)),
) where {T<:Real}
ZValues(collect(float(values)), map(Float64, zrange)) ZValues(collect(float(values)), map(Float64, zrange))
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
abstract AbstractSurface
"represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface
surf::M
end
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for yi in y, xi in x])
Base.Array(surf::Surface) = surf.surf
for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end
Base.copy(surf::Surface) = Surface{typeof(surf.surf)}(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T)
function expand_extrema!(a::Axis, surf::Surface) function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema] ex = a[:extrema]
for vi in surf.surf for vi in surf.surf
@ -682,44 +411,28 @@ function expand_extrema!(a::Axis, surf::Surface)
end end
"For the case of representing a surface as a function of x/y... can possibly avoid allocations." "For the case of representing a surface as a function of x/y... can possibly avoid allocations."
struct SurfaceFunction <: AbstractSurface immutable SurfaceFunction <: AbstractSurface
f::Function f::Function
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# # I don't want to clash with ValidatedNumerics, but this would be nice:
# ..(a::T, b::T) = (a, b)
# -----------------------------------------------------------------------
# style is :open or :closed (for now) # style is :open or :closed (for now)
struct Arrow immutable Arrow
style::Symbol style::Symbol
side::Symbol # :head (default), :tail, or :both
headlength::Float64 headlength::Float64
headwidth::Float64 headwidth::Float64
end end
"""
arrow(args...)
Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
`side` (`:head`, `:tail` or `:both`), `headlength` and `headwidth`
"""
function arrow(args...) function arrow(args...)
style = :simple style = :simple
side = :head headlength = 0.3
headlength = headwidth = 0.3 headwidth = 0.3
setlength = false setlength = false
for arg in args for arg in args
T = typeof(arg) T = typeof(arg)
if T == Symbol if T == Symbol
if arg in (:head, :tail, :both)
side = arg
else
style = arg style = arg
end
elseif T <: Number elseif T <: Number
# first we apply to both, but if there's more, then only change width after the first number # first we apply to both, but if there's more, then only change width after the first number
headwidth = Float64(arg) headwidth = Float64(arg)
@ -730,20 +443,21 @@ function arrow(args...)
elseif T <: Tuple && length(arg) == 2 elseif T <: Tuple && length(arg) == 2
headlength, headwidth = Float64(arg[1]), Float64(arg[2]) headlength, headwidth = Float64(arg[1]), Float64(arg[2])
else else
@warn "Skipped arrow arg $arg" warn("Skipped arrow arg $arg")
end end
end end
Arrow(style, side, headlength, headwidth) Arrow(style, headlength, headwidth)
end end
# allow for do-block notation which gets called on every valid start/end pair which # allow for do-block notation which gets called on every valid start/end pair which
# we need to draw an arrow # we need to draw an arrow
function add_arrows(func::Function, x::AVec, y::AVec) function add_arrows(func::Function, x::AVec, y::AVec)
for i in 2:length(x) for i=2:length(x)
xyprev = (x[i - 1], y[i - 1]) xyprev = (x[i-1], y[i-1])
xy = (x[i], y[i]) xy = (x[i], y[i])
if ok(xyprev) && ok(xy) if ok(xyprev) && ok(xy)
if i == length(x) || !ok(x[i + 1], y[i + 1]) if i==length(x) || !ok(x[i+1], y[i+1])
# add the arrow from xyprev to xy # add the arrow from xyprev to xy
func(xyprev, xy) func(xyprev, xy)
end end
@ -751,46 +465,58 @@ function add_arrows(func::Function, x::AVec, y::AVec)
end end
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"create a BezierCurve for plotting"
mutable struct BezierCurve{T<:GeometryBasics.Point} type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T} control_points::Vector{T}
end end
function (bc::BezierCurve)(t::Real) @compat function (bc::BezierCurve)(t::Real)
p = zero(P2) p = zero(P2)
n = length(bc.control_points) - 1 n = length(bc.control_points)-1
for i in 0:n for i in 0:n
p += bc.control_points[i + 1] * binomial(n, i) * (1 - t)^(n - i) * t^i p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
end end
p p
end end
@deprecate curve_points coords Base.mean(x::Real, y::Real) = 0.5*(x+y)
Base.mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps)
coords(curve::BezierCurve, n::Integer = 30; range = [0, 1]) = curve_points(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
map(curve, Base.range(first(range), stop = last(range), length = n))
function extrema_plus_buffer(v, buffmult = 0.2) # build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
vmin, vmax = ignorenan_extrema(v) # may create a loop if necessary. Assumes the view is [0,1]
vdiff = vmax - vmin function directed_curve(p::P2, q::P2; xview = 0:1, yview = 0:1)
buffer = vdiff * buffmult mn = mean(p, q)
vmin - buffer, vmax + buffer diff = q - p
minx, maxx = minimum(xview), maximum(xview)
miny, maxy = minimum(yview), maximum(yview)
diffpct = P2(diff[1] / (maxx - minx),
diff[2] / (maxy - miny))
# these points give the initial/final "rise"
# vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0)))
vertical_offset = P2(0, max(0.15, 0.5norm(diff)))
upper_control = p + vertical_offset
lower_control = q - vertical_offset
# try to figure out when to loop around vs just connecting straight
# TODO: choose loop direction based on sign of p[1]??
# x_close_together = abs(diffpct[1]) <= 0.05
p_is_higher = diff[2] <= 0
inside_control_points = if p_is_higher
# add curve points which will create a loop
sgn = mn[1] < 0.5 * (maxx + minx) ? -1 : 1
inside_offset = P2(0.3 * (maxx - minx), 0)
additional_offset = P2(sgn * diff[1], 0) # make it even loopier
[upper_control + sgn * (inside_offset + max(0, additional_offset)),
lower_control + sgn * (inside_offset + max(0, -additional_offset))]
else
[]
end end
### Legend BezierCurve([p, upper_control, inside_control_points..., lower_control, q])
end
@add_attributes subplot struct Legend
background_color = :match
foreground_color = :match
position = :best
title = nothing
font::Font = font(8)
title_font::Font = font(11)
column = 1
end :match = (
:legend_font_family,
:legend_font_color,
:legend_title_font_family,
:legend_title_font_color,
)

View File

@ -1,88 +0,0 @@
const _deprecated_attributes = Dict{Symbol,Symbol}(:orientation => :permute)
const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults]
const _initial_defaults = deepcopy(_all_defaults)
const _initial_axis_defaults = deepcopy(_axis_defaults)
# add defaults for the letter versions
const _axis_defaults_byletter = KW()
function reset_axis_defaults_byletter!()
for letter in (:x, :y, :z)
_axis_defaults_byletter[letter] = KW()
for (k, v) in _axis_defaults
_axis_defaults_byletter[letter][k] = v
end
end
end
reset_axis_defaults_byletter!()
# to be able to reset font sizes to initial values
const _initial_plt_fontsizes =
Dict(:plot_titlefontsize => _plot_defaults[:plot_titlefontsize])
const _initial_sp_fontsizes = Dict(
:titlefontsize => _subplot_defaults[:titlefontsize],
:legend_font_pointsize => _subplot_defaults[:legend_font_pointsize],
:legend_title_font_pointsize => _subplot_defaults[:legend_title_font_pointsize],
:annotationfontsize => _subplot_defaults[:annotationfontsize],
:colorbar_tickfontsize => _subplot_defaults[:colorbar_tickfontsize],
:colorbar_titlefontsize => _subplot_defaults[:colorbar_titlefontsize],
)
const _initial_ax_fontsizes = Dict(
:tickfontsize => _axis_defaults[:tickfontsize],
:guidefontsize => _axis_defaults[:guidefontsize],
)
const _initial_fontsizes =
merge(_initial_plt_fontsizes, _initial_sp_fontsizes, _initial_ax_fontsizes)
const _internal_args =
[:plot_object, :series_plotindex, :markershape_to_add, :letter, :idxfilter]
const _axis_args = Set(keys(_axis_defaults))
const _series_args = Set(keys(_series_defaults))
const _subplot_args = Set(keys(_subplot_defaults))
const _plot_args = Set(keys(_plot_defaults))
const _magic_axis_args = [:axis, :tickfont, :guidefont, :grid, :minorgrid]
const _magic_subplot_args =
[:title_font, :legend_font, :legend_title_font, :plot_title_font, :colorbar_titlefont]
const _magic_series_args = [:line, :marker, :fill]
const _all_magic_args =
Set(union(_magic_axis_args, _magic_series_args, _magic_subplot_args))
const _all_axis_args = union(_axis_args, _magic_axis_args)
const _lettered_all_axis_args =
Set([Symbol(letter, kw) for letter in (:x, :y, :z) for kw in _all_axis_args])
const _all_subplot_args = union(_subplot_args, _magic_subplot_args)
const _all_series_args = union(_series_args, _magic_series_args)
const _all_plot_args = _plot_args
const _all_args =
union(_lettered_all_axis_args, _all_subplot_args, _all_series_args, _all_plot_args)
# add all pluralized forms to the _keyAliases dict
for arg in _all_args
add_aliases(arg, makeplural(arg))
end
# fill symbol cache
for letter in (:x, :y, :z)
_attrsymbolcache[letter] = Dict{Symbol,Symbol}()
for k in _axis_args
# populate attribute cache
lk = Symbol(letter, k)
_attrsymbolcache[letter][k] = lk
# allow the underscore version too: xguide or x_guide
add_aliases(lk, Symbol(letter, "_", k))
end
for k in (_magic_axis_args..., :(_discrete_indices))
_attrsymbolcache[letter][k] = Symbol(letter, k)
end
end
# add all non_underscored forms to the _keyAliases
add_non_underscore_aliases!(_keyAliases)

File diff suppressed because it is too large Load Diff

415
src/deprecated/colors.jl Normal file
View File

@ -0,0 +1,415 @@
abstract ColorScheme
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
export
cgrad
cgrad() = default_gradient()
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
colors = ColorGradient(arg, alpha=alpha).colors
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(linspace(1,10,30))
elseif scale == :log2
log2(linspace(1,2,30))
elseif scale == :ln
log(linspace(1,pi,30))
elseif scale in (:exp, :exp10)
(exp10(linspace(0,1,30)) - 1) / 9
else
linspace(0, 1, length(colors))
end
ColorGradient(colors, values)
end
# --------------------------------------------------------------
getColor(scheme::ColorScheme) = getColor(scheme, 1)
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme{T<:Colorant}(cs::AVec{T}; kw...) = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
# --------------------------------------------------------------
convertColor(c::AbstractString) = parse(Colorant, c)
convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
convertColor(v::Void) = RGBA(0,0,0,0)
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
function convertColor(c, α::Real)
c = convertColor(c)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::Void) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
# --------------------------------------------------------------
function darken(c, v=0.1)
rgba = convert(RGBA, c)
r = max(0, min(rgba.r - v, 1))
g = max(0, min(rgba.g - v, 1))
b = max(0, min(rgba.b - v, 1))
RGBA(r,g,b,rgba.alpha)
end
function lighten(c, v=0.3)
darken(c, -v)
end
# --------------------------------------------------------------
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
const _gradients = KW(
:blues => [colorant"lightblue", colorant"darkblue"],
:reds => [colorant"lightpink", colorant"darkred"],
:greens => [colorant"lightgreen", colorant"darkgreen"],
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
:rainbow => _rainbowColors,
:lightrainbow => map(lighten, _rainbowColors),
:darkrainbow => map(darken, _rainbowColors),
:darktest => _testColors,
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors{C<:Colorant}(name::Symbol, colors::AVec{C})
_gradients[name] = colors
end
include("color_gradients.jl")
default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
immutable ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient{S<:Real}(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
# # otherwise interpolate evenly between the minval and maxval
# minval, maxval = minimum(vals), maximum(vals)
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(linspace(0, 1, length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
new(convertColor(cs, alpha), vals)
end
end
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s]
if vals == 0:0
vals = linspace(0, 1, length(cs))
end
ColorGradient(cs, vals; kw...)
end
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
function ColorGradient(grad::ColorGradient; alpha = nothing)
ColorGradient(convertColor(grad.colors, alpha), grad.values)
end
# anything else just gets the default gradient
function ColorGradient(cw; alpha=nothing)
ColorGradient(default_gradient(), alpha=alpha)
end
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
function getColorZ(gradient::ColorGradient, z::Real)
cs = gradient.colors
vs = gradient.values
n = length(cs)
@assert n > 0 && n == length(vs)
# can we just return the first color?
if z <= vs[1] || n == 1
return cs[1]
end
# find the bounding colors and interpolate
for i in 2:n
if z <= vs[i]
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
end
end
# if we get here, return the last color
cs[end]
end
getColorVector(gradient::ColorGradient) = gradient.colors
# for 0.3
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
rgb1 = RGBA(c1)
rgb2 = RGBA(c2)
r = interpolate(rgb1.r, rgb2.r, w)
g = interpolate(rgb1.g, rgb2.g, w)
b = interpolate(rgb1.b, rgb2.b, w)
a = interpolate(rgb1.alpha, rgb2.alpha, w)
RGBA(r, g, b, a)
end
function interpolate(v1::Real, v2::Real, w::Real)
(1-w) * v1 + w * v2
end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
immutable ColorFunction <: ColorScheme
f::Function
end
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
immutable ColorZFunction <: ColorScheme
f::Function
end
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
immutable ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
immutable ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Void) = c.c
# --------------------------------------------------------------
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
# move closer to lighter/darker depending on background value
function adjustAway(val, bgval, vmin=0., vmax=100.)
if bgval < 0.5 * (vmax+vmin)
tmp = max(val, bgval)
return 0.5 * (tmp + max(tmp, vmax))
else
tmp = min(val, bgval)
return 0.5 * (tmp + min(tmp, vmin))
end
end
# borrowed from http://stackoverflow.com/a/1855903:
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
isdark(c::Colorant) = lightnessLevel(c) < 0.5
islight(c::Colorant) = !isdark(c)
function convertHexToRGB(h::Unsigned)
mask = 0x0000FF
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
end
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
const _masterColorList = [
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
]
const _allColors = map(convertHexToRGB, _masterColorList)
const _darkColors = filter(isdark, _allColors)
const _lightColors = filter(islight, _allColors)
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
const _defaultNumColors = 17
# --------------------------------------------------------------
# Methods to automatically generate gradients for color selection based on
# background color and a short list of seed colors
# here are some magic constants that could be changed if you really want
const _lightness_darkbg = [80.0]
const _lightness_lightbg = [60.0]
const _lch_c_const = [60]
function adjust_lch(color, l, c)
lch = convert(LCHab, color)
convert(RGB, LCHab(l, c, lch.h))
end
function lightness_from_background(bgcolor)
bglight = convert(LCHab, bgcolor).l
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
end
function gradient_from_list(cs)
zvalues = Plots.get_zvalues(length(cs))
indices = sortperm(zvalues)
sorted_colors = map(RGBA, cs[indices])
sorted_zvalues = zvalues[indices]
ColorGradient(sorted_colors, sorted_zvalues)
end
function generate_colorgradient(bgcolor = colorant"white";
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
lightness = lightness_from_background(bgcolor),
chroma = _lch_c_const[1],
n = _defaultNumColors)
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
colors = distinguishable_colors(n,
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=linspace(0, 340, 20)
)[2:end]
gradient_from_list(colors)
end
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
grad = if palette == :auto
generate_colorgradient(bgcolor)
else
ColorGradient(palette)
end
zrng = get_zvalues(numcolors)
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette{C<:Colorant}(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
palette
end
# ----------------------------------------------------------------------------------
function getpctrange(n::Int)
n > 0 || error()
n == 1 && return zeros(1)
zs = [0.0, 1.0]
for i in 3:n
sorted = sort(zs)
diffs = diff(sorted)
widestj = 0
widest = 0.0
for (j,d) in enumerate(diffs)
if d > widest
widest = d
widestj = j
end
end
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
end
zs
end
function get_zvalues(n::Int)
offsets = getpctrange(ceil(Int,n/4)+1)/4
offsets = vcat(offsets[1], offsets[3:end])
zvalues = Float64[]
for offset in offsets
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
end
vcat(zvalues[1], 1.0, zvalues[2:n-1])
end
# ----------------------------------------------------------------------------------
make255(x) = round(Int, 255 * x)
function webcolor(c::Color)
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
end
function webcolor(c::TransparentColor)
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
end
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
webcolor(c) = webcolor(convertColor(c))
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
# ----------------------------------------------------------------------------------
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, sp::Subplot, n::Int)
if c == :auto
c = autopick(sp[:color_palette], n)
end
# c should now be a subtype of ColorScheme
colorscheme(c)
end

View File

@ -0,0 +1,63 @@
# TODO:
"""
- load Contours.jl similar to DataFrames
- method to build grid from x/y/z vectors
- method to wrap contours creation
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
"""
# # ----------------------------------------------------------
# # ----------------------------------------------------------
# immutable Vertex
# x::Float64
# y::Float64
# z::Float64
# end
# immutable Edge
# v::Vertex
# u::Vertex
# end
# # ----------------------------------------------------------
# # one rectangle's z-values and the center vertex
# # z is ordered: topleft, topright, bottomright, bottomleft
# immutable GridRect
# z::Vector{Float64}
# center::Vertex
# data::Vector{Vertex}
# end
# type Grid
# xs::Vector{Float64}
# ys::Vector{Float64}
# rects::Matrix{GridRect}
# end
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
# vs = sort(v)
# end
# # the goal here is to create the vertical and horizontal partitions
# # which define the grid, so that the data is somewhat evenly split
# function bucketData(x, y, z)
# end
# function buildGrid(x, y, z)
# # create
# end

View File

@ -0,0 +1,99 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
function convertToAnyVector(args...)
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
end
# --------------------------------------------------------------------
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
nobigs(v::AVec{BigInt}) = map(Int64, v)
nobigs(v) = v
@noinline function compute_xyz(x, y, z)
x = compute_x(x,y,z)
y = compute_y(x,y,z)
z = compute_z(x,y,z)
nobigs(x), nobigs(y), nobigs(z)
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
_fileio_load(@nospecialize(filename::AbstractString)) =
FileIO.load(filename::AbstractString)
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) =
FileIO.save(filename::AbstractString, x)
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = _fileio_load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
_fileio_save(pngfn, s)
# now write from the file
write(io, read(open(pngfn), String))
end
const PDFBackends =
Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}

View File

@ -1,59 +0,0 @@
const use_local_dependencies = Ref(false)
const use_local_plotlyjs = Ref(false)
function _init_ijulia_plotting()
# IJulia is more stable with local file
use_local_plotlyjs[] =
plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
ENV["MPLBACKEND"] = "Agg"
end
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] =
Dict(:data => plotly_series(plt), :layout => plotly_layout(plt))
out
end
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] =
Dict(:data => plotly_series(plt), :layout => plotly_layout(plt))
out
end
function _ijulia_display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
_ijulia__extra_mime_info!(plt, out)
elseif output_type == :pdf
mime = "application/pdf"
out[mime] = base64encode(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
out
end

View File

@ -1,115 +0,0 @@
using REPL
using Scratch
const plotly_local_file_path = Ref{Union{Nothing,String}}(nothing)
function _plots_defaults()
if isdefined(Main, :PLOTS_DEFAULTS)
copy(Dict{Symbol,Any}(Main.PLOTS_DEFAULTS))
else
Dict{Symbol,Any}()
end
end
function __init__()
user_defaults = _plots_defaults()
if haskey(user_defaults, :theme)
theme(pop!(user_defaults, :theme); user_defaults...)
else
default(; user_defaults...)
end
insert!(
Base.Multimedia.displays,
findlast(
x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay,
Base.Multimedia.displays,
) + 1,
PlotsDisplay(),
)
atreplinit(
i -> begin
while PlotsDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
insert!(
Base.Multimedia.displays,
findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1,
PlotsDisplay(),
)
end,
)
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin
fn = joinpath(@__DIR__, "backends", "hdf5.jl")
include(fn)
end
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" begin
fn = joinpath(@__DIR__, "backends", "inspectdr.jl")
include(fn)
end
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" begin
fn = joinpath(@__DIR__, "backends", "deprecated", "pgfplots.jl")
include(fn)
end
@require PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" begin
fn = joinpath(@__DIR__, "backends", "plotlybase.jl")
include(fn)
end
@require PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925" begin
fn = joinpath(@__DIR__, "backends", "pgfplotsx.jl")
include(fn)
end
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" begin
fn = joinpath(@__DIR__, "backends", "plotlyjs.jl")
include(fn)
end
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" begin
fn = joinpath(@__DIR__, "backends", "pyplot.jl")
include(fn)
end
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" begin
fn = joinpath(@__DIR__, "backends", "unicodeplots.jl")
include(fn)
end
@require Gaston = "4b11ee91-296f-5714-9832-002c20994614" begin
fn = joinpath(@__DIR__, "backends", "gaston.jl")
include(fn)
end
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
if IJulia.inited
_init_ijulia_plotting()
IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt)
end
end
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global plotly_local_file_path[] =
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
if !isfile(plotly_local_file_path[])
Downloads.download(
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
plotly_local_file_path[],
)
end
use_local_plotlyjs[] = true
end
use_local_dependencies[] = use_local_plotlyjs[]
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) =
_show_pdfbackends(io, mime, plt)
end
end

View File

@ -1,9 +1,41 @@
# NOTE: (0,0) is the top-left !!! # NOTE: (0,0) is the top-left !!!
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
to_pixels(m::AbsoluteLength) = m.value / 0.254 to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm const _cbar_width = 5mm
@compat Base.:.*(m::Measure, n::Number) = m * n
@compat Base.:.*(n::Number, m::Measure) = m * n
@compat Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
@compat 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{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs
# @compat Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
# @compat Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
# @compat Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
# @compat Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
@compat Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
@compat Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
@compat Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
@compat 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]
@ -12,11 +44,11 @@ right(bbox::BoundingBox) = left(bbox) + width(bbox)
bottom(bbox::BoundingBox) = top(bbox) + height(bbox) bottom(bbox::BoundingBox) = top(bbox) + height(bbox)
Base.size(bbox::BoundingBox) = (width(bbox), height(bbox)) Base.size(bbox::BoundingBox) = (width(bbox), height(bbox))
# Base.:*{T,N}(m1::Length{T,N}, m2::Length{T,N}) = Length{T,N}(m1.value * m2.value) # @compat Base.:*{T,N}(m1::Length{T,N}, m2::Length{T,N}) = Length{T,N}(m1.value * m2.value)
ispositive(m::Measure) = m.value > 0 ispositive(m::Measure) = m.value > 0
# union together bounding boxes # union together bounding boxes
function Base.:+(bb1::BoundingBox, bb2::BoundingBox) @compat function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
# empty boxes don't change the union # empty boxes don't change the union
ispositive(width(bb1)) || return bb2 ispositive(width(bb1)) || return bb2
ispositive(height(bb1)) || return bb2 ispositive(height(bb1)) || return bb2
@ -27,7 +59,7 @@ function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
t = min(top(bb1), top(bb2)) t = min(top(bb1), top(bb2))
r = max(right(bb1), right(bb2)) r = max(right(bb1), right(bb2))
b = max(bottom(bb1), bottom(bb2)) b = max(bottom(bb1), bottom(bb2))
BoundingBox(l, t, r - l, b - t) BoundingBox(l, t, r-l, b-t)
end end
# this creates a bounding box in the parent's scope, where the child bounding box # this creates a bounding box in the parent's scope, where the child bounding box
@ -53,7 +85,7 @@ end
# convert a bounding box from absolute coords to percentages... # convert a bounding box from absolute coords to percentages...
# returns an array of percentages of figure size: [left, bottom, width, height] # returns an array of percentages of figure size: [left, bottom, width, height]
function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true) function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
mms = Float64[f(bb).value for f in (left, bottom, width, height)] mms = Float64[f(bb).value for f in (left,bottom,width,height)]
if flipy if flipy
mms[2] = figh.value - mms[2] # flip y when origin in bottom-left mms[2] = figh.value - mms[2] # flip y when origin in bottom-left
end end
@ -61,34 +93,7 @@ function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
end end
function Base.show(io::IO, bbox::BoundingBox) function Base.show(io::IO, bbox::BoundingBox)
print( print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
io,
"BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}",
)
end
# -----------------------------------------------------------
# points combined by x/y, pct, and length
mutable struct MixedMeasures
xy::Float64
pct::Float64
len::AbsoluteLength
end
function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
xy = mix.xy
pct = mix.pct
if mix.len != 0mm
f = (letter == :x ? width : height)
totlen = f(plotarea(sp))
pct += mix.len / totlen
end
if pct != 0
amin, amax = axis_limits(sp, letter)
xy += pct * (amax - amin)
end
xy
end end
# ----------------------------------------------------------- # -----------------------------------------------------------
@ -102,25 +107,18 @@ make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m make_measure_vert(m::Measure) = m
"""
bbox(x, y, w, h [,originargs...])
bbox(layout)
Create a bounding box for plotting
"""
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...) function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...) oargs = vcat(oarg1, originargs...)
orighor = :left orighor = :left
origver = :top origver = :top
for oarg in oargs for oarg in oargs
if oarg == :center if oarg in (:left, :right)
orighor = origver = oarg
elseif oarg in (:left, :right, :hcenter)
orighor = oarg orighor = oarg
elseif oarg in (:top, :bottom, :vcenter) elseif oarg in (:top, :bottom)
origver = oarg origver = oarg
else else
@warn("Unused origin arg in bbox construction: $oarg") warn("Unused origin arg in bbox construction: $oarg")
end end
end end
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver) bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
@ -134,15 +132,11 @@ function bbox(x, y, width, height; h_anchor = :left, v_anchor = :top)
height = make_measure_vert(height) height = make_measure_vert(height)
left = if h_anchor == :left left = if h_anchor == :left
x x
elseif h_anchor in (:center, :hcenter)
0.5w - 0.5width + x
else else
1w - x - width 1w - x - width
end end
top = if v_anchor == :top top = if v_anchor == :top
y y
elseif v_anchor in (:center, :vcenter)
0.5h - 0.5height + y
else else
1h - y - height 1h - y - height
end end
@ -162,8 +156,7 @@ parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout)) # padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
update_position!(layout::AbstractLayout) = nothing update_position!(layout::AbstractLayout) = nothing
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm, 0mm, 0mm, 0mm]) = update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
nothing
left(layout::AbstractLayout) = left(bbox(layout)) left(layout::AbstractLayout) = left(bbox(layout))
top(layout::AbstractLayout) = top(bbox(layout)) top(layout::AbstractLayout) = top(bbox(layout))
@ -190,9 +183,8 @@ bottompad(layout::AbstractLayout) = 0mm
# RootLayout # RootLayout
# this is the parent of the top-level layout # this is the parent of the top-level layout
struct RootLayout <: AbstractLayout end immutable RootLayout <: AbstractLayout end
Base.show(io::IO, layout::RootLayout) = Base.show_default(io, layout)
Base.parent(::RootLayout) = nothing Base.parent(::RootLayout) = nothing
parent_bbox(::RootLayout) = defaultbox parent_bbox(::RootLayout) = defaultbox
bbox(::RootLayout) = defaultbox bbox(::RootLayout) = defaultbox
@ -201,7 +193,7 @@ bbox(::RootLayout) = defaultbox
# EmptyLayout # EmptyLayout
# contains blank space # contains blank space
mutable struct EmptyLayout <: AbstractLayout type EmptyLayout <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
bbox::BoundingBox bbox::BoundingBox
attr::KW # store label, width, and height for initialization attr::KW # store label, width, and height for initialization
@ -209,7 +201,7 @@ mutable struct EmptyLayout <: AbstractLayout
end end
EmptyLayout(parent = RootLayout(); kw...) = EmptyLayout(parent, defaultbox, KW(kw)) EmptyLayout(parent = RootLayout(); kw...) = EmptyLayout(parent, defaultbox, KW(kw))
Base.size(layout::EmptyLayout) = (0, 0) Base.size(layout::EmptyLayout) = (0,0)
Base.length(layout::EmptyLayout) = 0 Base.length(layout::EmptyLayout) = 0
Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing
@ -219,7 +211,7 @@ _update_min_padding!(layout::EmptyLayout) = nothing
# GridLayout # GridLayout
# nested, gridded layout with optional size percentages # nested, gridded layout with optional size percentages
mutable struct GridLayout <: AbstractLayout type GridLayout <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox bbox::BoundingBox
@ -229,48 +221,33 @@ mutable struct GridLayout <: AbstractLayout
attr::KW attr::KW
end end
"""
grid(args...; kw...)
Create a grid layout for subplots. `args` specify the dimensions, e.g.
`grid(3,2, widths = (0.6,0.4))` creates a grid with three rows and two
columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...) grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout( function GridLayout(dims...;
dims...;
parent = RootLayout(), parent = RootLayout(),
widths = zeros(dims[2]), widths = zeros(dims[2]),
heights = zeros(dims[1]), heights = zeros(dims[1]),
kw..., kw...)
) grid = Matrix{AbstractLayout}(dims...)
grid = Matrix{AbstractLayout}(undef, dims...)
layout = GridLayout( layout = GridLayout(
parent, parent,
(20mm, 5mm, 2mm, 10mm), (20mm, 5mm, 2mm, 10mm),
defaultbox, defaultbox,
grid, grid,
Measure[w * pct for w in widths], Measure[w*pct for w in widths],
Measure[h * pct for h in heights], Measure[h*pct for h in heights],
# convert(Vector{Float64}, widths), # convert(Vector{Float64}, widths),
# convert(Vector{Float64}, heights), # convert(Vector{Float64}, heights),
KW(kw), KW(kw))
) fill!(grid, EmptyLayout(layout))
for i in eachindex(grid)
grid[i] = EmptyLayout(layout)
end
layout layout
end end
Base.size(layout::GridLayout) = size(layout.grid) Base.size(layout::GridLayout) = size(layout.grid)
Base.length(layout::GridLayout) = length(layout.grid) Base.length(layout::GridLayout) = length(layout.grid)
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r, c] Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c]
function Base.setindex!(layout::GridLayout, v, r::Int, c::Int) function Base.setindex!(layout::GridLayout, v, r::Int, c::Int)
layout.grid[r, c] = v layout.grid[r,c] = v
end
function Base.setindex!(layout::GridLayout, v, ci::CartesianIndex)
layout.grid[ci] = v
end end
leftpad(layout::GridLayout) = layout.minpad[1] leftpad(layout::GridLayout) = layout.minpad[1]
@ -278,6 +255,7 @@ toppad(layout::GridLayout) = layout.minpad[2]
rightpad(layout::GridLayout) = layout.minpad[3] rightpad(layout::GridLayout) = layout.minpad[3]
bottompad(layout::GridLayout) = layout.minpad[4] bottompad(layout::GridLayout) = layout.minpad[4]
# here's how this works... first we recursively "update the minimum padding" (which # here's how this works... first we recursively "update the minimum padding" (which
# means to calculate the minimum size needed from the edge of the subplot to plot area) # means to calculate the minimum size needed from the edge of the subplot to plot area)
# for the whole layout tree. then we can compute the "padding borders" of this # for the whole layout tree. then we can compute the "padding borders" of this
@ -289,13 +267,14 @@ bottompad(layout::GridLayout) = layout.minpad[4]
function _update_min_padding!(layout::GridLayout) function _update_min_padding!(layout::GridLayout)
map(_update_min_padding!, layout.grid) map(_update_min_padding!, layout.grid)
layout.minpad = ( layout.minpad = (
maximum(map(leftpad, layout.grid[:, 1])), maximum(map(leftpad, layout.grid[:,1])),
maximum(map(toppad, layout.grid[1, :])), maximum(map(toppad, layout.grid[1,:])),
maximum(map(rightpad, layout.grid[:, end])), maximum(map(rightpad, layout.grid[:,end])),
maximum(map(bottompad, layout.grid[end, :])), maximum(map(bottompad, layout.grid[end,:]))
) )
end end
function update_position!(layout::GridLayout) function update_position!(layout::GridLayout)
map(update_position!, layout.grid) map(update_position!, layout.grid)
end end
@ -314,9 +293,7 @@ function recompute_lengths(v)
end end
leftover = 1.0pct - tot leftover = 1.0pct - tot
if cnt > 1 && leftover.value <= 0 if cnt > 1 && leftover.value <= 0
error( error("Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover")
"Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover",
)
end end
# now fill in the blanks # now fill in the blanks
@ -324,22 +301,26 @@ function recompute_lengths(v)
end 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)
minpad_bottom = map(bottompad, layout.grid) minpad_bottom = map(bottompad, layout.grid)
# @show minpad_left minpad_top minpad_right minpad_bottom
# get the max horizontal (left and right) padding over columns, # get the max horizontal (left and right) padding over columns,
# and max vertical (bottom and top) padding over rows # and max vertical (bottom and top) padding over rows
# TODO: add extra padding here # TODO: add extra padding here
pad_left = maximum(minpad_left, dims = 1) pad_left = maximum(minpad_left, 1)
pad_top = maximum(minpad_top, dims = 2) pad_top = maximum(minpad_top, 2)
pad_right = maximum(minpad_right, dims = 1) pad_right = maximum(minpad_right, 1)
pad_bottom = maximum(minpad_bottom, dims = 2) pad_bottom = maximum(minpad_bottom, 2)
# @show pad_left pad_top pad_right pad_bottom
# make sure the perimeter match the parent # make sure the perimeter match the parent
pad_left[1] = max(pad_left[1], minimum_perimeter[1]) pad_left[1] = max(pad_left[1], minimum_perimeter[1])
@ -350,36 +331,37 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm,
# scale this up to the total padding in each direction # scale this up to the total padding in each direction
total_pad_horizontal = sum(pad_left + pad_right) total_pad_horizontal = sum(pad_left + pad_right)
total_pad_vertical = sum(pad_top + pad_bottom) total_pad_vertical = sum(pad_top + pad_bottom)
# @show total_pad_horizontal total_pad_vertical
# now we can compute the total plot area in each direction # now we can compute the total plot area in each direction
total_plotarea_horizontal = width(layout) - total_pad_horizontal total_plotarea_horizontal = width(layout) - total_pad_horizontal
total_plotarea_vertical = height(layout) - total_pad_vertical total_plotarea_vertical = height(layout) - total_pad_vertical
# @show total_plotarea_horizontal total_plotarea_vertical
# recompute widths/heights # recompute widths/heights
layout.widths = recompute_lengths(layout.widths) layout.widths = recompute_lengths(layout.widths)
layout.heights = recompute_lengths(layout.heights) layout.heights = recompute_lengths(layout.heights)
# @show layout.widths layout.heights
# normalize widths/heights so they sum to 1 # normalize widths/heights so they sum to 1
# denom_w = sum(layout.widths) # denom_w = sum(layout.widths)
# denom_h = sum(layout.heights) # denom_h = sum(layout.heights)
# @show layout.widths layout.heights denom_w, denom_h
# we have all the data we need... lets compute the plot areas and set the bounding boxes # we have all the data we need... lets compute the plot areas and set the bounding boxes
for r in 1:nr, c in 1:nc for r=1:nr, c=1:nc
child = layout[r, c] child = layout[r,c]
# get the top-left corner of this child... the first one is top-left of the parent (i.e. layout) # get the top-left corner of this child... the first one is top-left of the parent (i.e. layout)
child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c - 1].bbox)) child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox))
child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r - 1, c].bbox)) child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox))
# compute plot area # compute plot area
plotarea_left = child_left + pad_left[c] plotarea_left = child_left + pad_left[c]
plotarea_top = child_top + pad_top[r] plotarea_top = child_top + pad_top[r]
plotarea_width = total_plotarea_horizontal * layout.widths[c] plotarea_width = total_plotarea_horizontal * layout.widths[c]
plotarea_height = total_plotarea_vertical * layout.heights[r] plotarea_height = total_plotarea_vertical * layout.heights[r]
plotarea!( plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height))
child,
BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height),
)
# compute child bbox # compute child bbox
child_width = pad_left[c] + plotarea_width + pad_right[c] child_width = pad_left[c] + plotarea_width + pad_right[c]
@ -389,10 +371,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm,
# 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] : pad_left[c], c == 1 ? layout.minpad[1] : 0mm,
r == 1 ? layout.minpad[2] : pad_top[r], r == 1 ? layout.minpad[2] : 0mm,
c == nc ? layout.minpad[3] : pad_right[c], c == nc ? layout.minpad[3] : 0mm,
r == nr ? layout.minpad[4] : pad_bottom[r], r == nr ? layout.minpad[4] : 0mm
] ]
# recursively update the child's children # recursively update the child's children
@ -405,23 +387,21 @@ end
function update_inset_bboxes!(plt::Plot) function update_inset_bboxes!(plt::Plot)
for sp in plt.inset_subplots for sp in plt.inset_subplots
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox]) p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
# @show bbox(sp.parent) sp[:relative_bbox] p_area
plotarea!(sp, p_area) plotarea!(sp, p_area)
bbox!( bbox!(sp, bbox(
sp,
bbox(
left(p_area) - leftpad(sp), left(p_area) - leftpad(sp),
top(p_area) - toppad(sp), top(p_area) - toppad(sp),
width(p_area) + leftpad(sp) + rightpad(sp), width(p_area) + leftpad(sp) + rightpad(sp),
height(p_area) + toppad(sp) + bottompad(sp), height(p_area) + toppad(sp) + bottompad(sp)
), ))
)
end end
end end
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
calc_num_subplots(layout::AbstractLayout) = get(layout.attr, :blank, false) ? 0 : 1 calc_num_subplots(layout::AbstractLayout) = 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
@ -449,16 +429,14 @@ end
# constructors # constructors
# pass the layout arg through # pass the layout arg through
function layout_args(plotattributes::AKW) function layout_args(d::KW)
layout_args(plotattributes[:layout]) layout_args(get(d, :layout, default(:layout)))
end end
function layout_args(plotattributes::AKW, n_override::Integer) function layout_args(d::KW, n_override::Integer)
layout, n = layout_args(n_override, get(plotattributes, :layout, n_override)) layout, n = layout_args(get(d, :layout, n_override))
if n != n_override if n != n_override
error( error("When doing layout, n != n_override. You're probably trying to force existing plots into a layout that doesn't fit them.")
"When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.",
)
end end
layout, n layout, n
end end
@ -468,45 +446,17 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n GridLayout(nr, nc), n
end end
function layout_args(sztup::NTuple{2,Integer}) function layout_args{I<:Integer}(sztup::NTuple{2,I})
nr, nc = sztup nr, nc = sztup
GridLayout(nr, nc), nr * nc GridLayout(nr, nc), nr*nc
end end
layout_args(n_override::Integer, n::Integer) = layout_args(n) function layout_args{I<:Integer}(sztup::NTuple{3,I})
layout_args(n, sztup::NTuple{2,Integer}) = layout_args(sztup)
function layout_args(n, sztup::Tuple{Colon,Integer})
nc = sztup[2]
nr = ceil(Int, n / nc)
GridLayout(nr, nc), n
end
function layout_args(n, sztup::Tuple{Integer,Colon})
nr = sztup[1]
nc = ceil(Int, n / nr)
GridLayout(nr, nc), n
end
function layout_args(sztup::NTuple{3,Integer})
n, nr, nc = sztup n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc) nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n GridLayout(nr, nc), n
end end
layout_args(nt::NamedTuple) = EmptyLayout(; nt...), 1
function layout_args(m::AbstractVecOrMat)
sz = size(m)
nr = sz[1]
nc = get(sz, 2, 1)
gl = GridLayout(nr, nc)
for ci in CartesianIndices(m)
gl[ci] = layout_args(m[ci])[1]
end
layout_args(gl)
end
# compute number of subplots # compute number of subplots
function layout_args(layout::GridLayout) function layout_args(layout::GridLayout)
# recursively get the size of the grid # recursively get the size of the grid
@ -514,63 +464,49 @@ function layout_args(layout::GridLayout)
layout, n layout, n
end end
layout_args(n_override::Integer, layout::Union{AbstractVecOrMat,GridLayout}) =
layout_args(layout)
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh") layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
function build_layout(args...) function build_layout(args...)
layout, n = layout_args(args...) layout, n = layout_args(args...)
build_layout(layout, n, Array{Plot}(undef, 0)) build_layout(layout, n)
end end
# n is the number of subplots... # # just a single subplot
function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot}) # function build_layout(sp::Subplot, n::Integer)
# sp, Subplot[sp], SubplotMap(gensym() => sp)
# end
# n is the number of subplots... build a grid and initialize the inner subplots recursively
function build_layout(layout::GridLayout, n::Integer)
nr, nc = size(layout) nr, nc = size(layout)
subplots = Subplot[] subplots = Subplot[]
spmap = SubplotMap() spmap = SubplotMap()
empty = isempty(plts)
i = 0 i = 0
for r in 1:nr, c in 1:nc for r=1:nr, c=1:nc
l = layout[r, c] l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false) if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
if empty sp = Subplot(backend(), parent=layout)
# initialize the inner subplots recursively layout[r,c] = sp
sp = Subplot(backend(), parent = layout)
layout[r, c] = sp
push!(subplots, sp) push!(subplots, sp)
spmap[attr(l, :label, gensym())] = sp spmap[attr(l,:label,gensym())] = sp
inc = 1
else
# build a layout from a list of existing Plot objects
plt = popfirst!(plts) # grab the first plot out of the list
layout[r, c] = plt.layout
append!(subplots, plt.subplots)
merge!(spmap, plt.spmap)
inc = length(plt.subplots)
end
if get(l.attr, :width, :auto) != :auto if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l, :width) layout.widths[c] = attr(l,:width)
end end
if get(l.attr, :height, :auto) != :auto if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l, :height) layout.heights[r] = attr(l,:height)
end end
i += inc i += 1
elseif isa(l, GridLayout) elseif isa(l, GridLayout)
# sub-grid # sub-grid
if get(l.attr, :width, :auto) != :auto l, sps, m = build_layout(l, n-i)
layout.widths[c] = attr(l, :width)
end
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l, :height)
end
l, sps, m = build_layout(l, n - i, plts)
append!(subplots, sps) append!(subplots, sps)
merge!(spmap, m) merge!(spmap, m)
i += length(sps) i += length(sps)
elseif isa(l, Subplot) && empty elseif isa(l, Subplot)
error("Subplot exists. Cannot re-use existing layout. Please make a new one.") error("Subplot exists. Cannot re-use existing layout. Please make a new one.")
end end
i >= n && break # only add n subplots i >= n && break # only add n subplots
@ -579,44 +515,159 @@ function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot})
layout, subplots, spmap layout, subplots, spmap
end end
# ------------------------------------------------------------------------- # build a layout from a list of existing Plot objects
# TODO... much of the logic overlaps with the method above... can we merge?
# make all reference the same axis extrema/values. function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
# merge subplot lists. nr, nc = size(layout)
function link_axes!(axes::Axis...) subplots = Subplot[]
a1 = axes[1] spmap = SubplotMap()
for i in 2:length(axes) i = 0
a2 = axes[i] for r=1:nr, c=1:nc
expand_extrema!(a1, ignorenan_extrema(a2)) l = layout[r,c]
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map) if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
a2[k] = a1[k] plt = shift!(plts) # grab the first plot out of the list
layout[r,c] = plt.layout
append!(subplots, plt.subplots)
merge!(spmap, plt.spmap)
if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l,:width)
end end
if get(l.attr, :height, :auto) != :auto
# make a2's subplot list refer to a1's and add any missing values layout.heights[r] = attr(l,:height)
sps2 = a2.sps
for sp in sps2
sp in a1.sps || push!(a1.sps, sp)
end end
a2.sps = a1.sps i += length(plt.subplots)
elseif isa(l, GridLayout)
# sub-grid
l, sps, m = build_layout(l, numsp-i, plts)
append!(subplots, sps)
merge!(spmap, m)
i += length(sps)
end
i >= numsp && break # only add n subplots
end
layout, subplots, spmap
end
# ----------------------------------------------------------------------
# @layout macro
function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
# dump(v)
# something like {0.2w}?
if v.head == :call && v.args[1] == :*
num = v.args[2]
if length(v.args) == 3 && isa(num, Number)
units = v.args[3]
if units == :h
return kw[:h] = num*pct
elseif units == :w
return kw[:w] = num*pct
elseif units in (:pct, :px, :mm, :cm, :inch)
idx == 1 && (kw[:w] = v)
(idx == 2 || nidx == 1) && (kw[:h] = v)
# return kw[idx == 1 ? :w : :h] = v
end
end
end
error("Couldn't match layout curly (idx=$idx): $v")
end
function add_layout_pct!(kw::KW, v::Number, idx::Integer)
# kw[idx == 1 ? :w : :h] = v*pct
idx == 1 && (kw[:w] = v*pct)
(idx == 2 || nidx == 1) && (kw[:h] = v*pct)
end
isrow(v) = isa(v, Expr) && v.head in (:hcat,:row)
iscol(v) = isa(v, Expr) && v.head == :vcat
rowsize(v) = isrow(v) ? length(v.args) : 1
function create_grid(expr::Expr)
if iscol(expr)
create_grid_vcat(expr)
elseif isrow(expr)
:(let cell = GridLayout(1, $(length(expr.args)))
$([:(cell[1,$i] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
elseif expr.head == :curly
create_grid_curly(expr)
else
# if it's something else, just return that (might be an existing layout?)
expr
end end
end end
# figure out which subplots to link function create_grid_vcat(expr::Expr)
function link_subplots(a::AbstractArray{AbstractLayout}, axissym::Symbol) rowsizes = map(rowsize, expr.args)
subplots = [] rmin, rmax = extrema(rowsizes)
for l in a if rmin > 0 && rmin == rmax
if isa(l, Subplot) # we have a grid... build the whole thing
push!(subplots, l) # note: rmin is the number of columns
elseif isa(l, GridLayout) && size(l) == (1, 1) nr = length(expr.args)
push!(subplots, l[1, 1]) nc = rmin
body = Expr(:block)
for r=1:nr
arg = expr.args[r]
if isrow(arg)
for (c,item) in enumerate(arg.args)
push!(body.args, :(cell[$r,$c] = $(create_grid(item))))
end
else
push!(body.args, :(cell[$r,1] = $(create_grid(arg))))
end
end
:(let cell = GridLayout($nr, $nc)
$body
cell
end)
else
# otherwise just build one row at a time
:(let cell = GridLayout($(length(expr.args)), 1)
$([:(cell[$i,1] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
end
end
function create_grid_curly(expr::Expr)
s = expr.args[1]
kw = KW()
for (i,arg) in enumerate(expr.args[2:end])
add_layout_pct!(kw, arg, i, length(expr.args)-1)
end
# @show kw
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
end
function create_grid(s::Symbol)
:(EmptyLayout(label = $(QuoteNode(s)), blank = $(s == :_)))
end
macro layout(mat::Expr)
create_grid(mat)
end
# -------------------------------------------------------------------------
# make all reference the same axis extrema/values
function link_axes!(axes::Axis...)
a1 = axes[1]
for i=2:length(axes)
a2 = axes[i]
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
a2[k] = a1[k]
end end
end end
subplots
end end
# for some vector or matrix of layouts, filter only the Subplots and link those axes # for some vector or matrix of layouts, filter only the Subplots and link those axes
function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol) function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
subplots = link_subplots(a, axissym) subplots = filter(l -> isa(l, Subplot), a)
axes = [sp.attr[axissym] for sp in subplots] axes = [sp.attr[axissym] for sp in subplots]
if length(axes) > 0 if length(axes) > 0
link_axes!(axes...) link_axes!(axes...)
@ -624,19 +675,20 @@ function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
end end
# don't do anything for most layout types # don't do anything for most layout types
function link_axes!(l::AbstractLayout, link::Symbol) end function link_axes!(l::AbstractLayout, link::Symbol)
end
# process a GridLayout, recursively linking axes according to the link symbol # process a GridLayout, recursively linking axes according to the link symbol
function link_axes!(layout::GridLayout, link::Symbol) function link_axes!(layout::GridLayout, link::Symbol)
nr, nc = size(layout) nr, nc = size(layout)
if link in (:x, :both) if link in (:x, :both)
for c in 1:nc for c=1:nc
link_axes!(layout.grid[:, c], :xaxis) link_axes!(layout.grid[:,c], :xaxis)
end end
end end
if link in (:y, :both) if link in (:y, :both)
for r in 1:nr for r=1:nr
link_axes!(layout.grid[r, :], :yaxis) link_axes!(layout.grid[r,:], :yaxis)
end end
end end
if link == :square if link == :square
@ -657,27 +709,3 @@ function link_axes!(layout::GridLayout, link::Symbol)
link_axes!(l, link) link_axes!(l, link)
end end
end end
# -------------------------------------------------------------------------
"Adds a new, empty subplot overlayed on top of `sp`, with a mirrored y-axis and linked x-axis."
function twinx(sp::Subplot)
plot!(
sp.plt,
inset = (sp[:subplot_index], bbox(0, 0, 1, 1)),
right_margin = sp[:right_margin],
left_margin = sp[:left_margin],
top_margin = sp[:top_margin],
bottom_margin = sp[:bottom_margin],
)
twinsp = sp.plt.subplots[end]
twinsp[:xaxis][:grid] = false
twinsp[:yaxis][:grid] = false
twinsp[:xaxis][:showaxis] = false
twinsp[:yaxis][:mirror] = true
twinsp[:background_color_inside] = RGBA{Float64}(0, 0, 0, 0)
link_axes!(sp[:xaxis], twinsp[:xaxis])
twinsp
end
twinx(plt::Plot = current()) = twinx(plt[1])

View File

@ -1,57 +0,0 @@
"""
```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

@ -1,236 +1,203 @@
defaultOutputFormat(plt::Plot) = "png" defaultOutputFormat(plt::Plot) = "png"
function png(plt::Plot, fn::AbstractString) function png(plt::Plot, fn::AbstractString)
open(addExtension(fn, "png"), "w") do io fn = addExtension(fn, "png")
show(io, MIME("image/png"), plt) io = open(fn, "w")
end writemime(io, MIME("image/png"), plt)
close(io)
end end
png(fn::AbstractString) = png(current(), fn) png(fn::AbstractString) = png(current(), fn)
function svg(plt::Plot, fn::AbstractString) function svg(plt::Plot, fn::AbstractString)
open(addExtension(fn, "svg"), "w") do io fn = addExtension(fn, "svg")
show(io, MIME("image/svg+xml"), plt) io = open(fn, "w")
end writemime(io, MIME("image/svg+xml"), plt)
close(io)
end end
svg(fn::AbstractString) = svg(current(), fn) svg(fn::AbstractString) = svg(current(), fn)
function pdf(plt::Plot, fn::AbstractString) function pdf(plt::Plot, fn::AbstractString)
open(addExtension(fn, "pdf"), "w") do io fn = addExtension(fn, "pdf")
show(io, MIME("application/pdf"), plt) io = open(fn, "w")
end writemime(io, MIME("application/pdf"), plt)
close(io)
end end
pdf(fn::AbstractString) = pdf(current(), fn) pdf(fn::AbstractString) = pdf(current(), fn)
function ps(plt::Plot, fn::AbstractString) function ps(plt::Plot, fn::AbstractString)
open(addExtension(fn, "ps"), "w") do io fn = addExtension(fn, "ps")
show(io, MIME("application/postscript"), plt) io = open(fn, "w")
end writemime(io, MIME("application/postscript"), plt)
close(io)
end end
ps(fn::AbstractString) = ps(current(), fn) ps(fn::AbstractString) = ps(current(), fn)
function eps(plt::Plot, fn::AbstractString)
open(addExtension(fn, "eps"), "w") do io
show(io, MIME("image/eps"), plt)
end
end
eps(fn::AbstractString) = eps(current(), fn)
function tex(plt::Plot, fn::AbstractString) function tex(plt::Plot, fn::AbstractString)
open(addExtension(fn, "tex"), "w") do io fn = addExtension(fn, "tex")
show(io, MIME("application/x-tex"), plt) io = open(fn, "w")
end writemime(io, MIME("application/x-tex"), plt)
close(io)
end end
tex(fn::AbstractString) = tex(current(), fn) tex(fn::AbstractString) = tex(current(), fn)
function json(plt::Plot, fn::AbstractString)
open(addExtension(fn, "json"), "w") do io
show(io, MIME("application/vnd.plotly.v1+json"), plt)
end
end
json(fn::AbstractString) = json(current(), fn)
function html(plt::Plot, fn::AbstractString)
open(addExtension(fn, "html"), "w") do io
show(io, MIME("text/html"), plt)
end
end
html(fn::AbstractString) = html(current(), fn)
function txt(plt::Plot, fn::AbstractString; color::Bool = true)
open(addExtension(fn, "txt"), "w") do io
show(IOContext(io, :color => color), MIME("text/plain"), plt)
end
end
txt(fn::AbstractString) = txt(current(), fn)
# ---------------------------------------------------------------- # ----------------------------------------------------------------
const _savemap = Dict(
@compat const _savemap = Dict(
"png" => png, "png" => png,
"svg" => svg, "svg" => svg,
"pdf" => pdf, "pdf" => pdf,
"ps" => ps, "ps" => ps,
"eps" => eps,
"tex" => tex, "tex" => tex,
"json" => json, )
"html" => html,
"tikz" => tex,
"txt" => txt,
)
for out in Symbol.(unique(values(_savemap))) function getExtension(fn::AbstractString)
@eval @doc """ pieces = split(fn, ".")
$($out)([plot,], filename) length(pieces) > 1 || error("Can't extract file extension: ", fn)
Save plot as $($out)-file. ext = pieces[end]
""" $out haskey(_savemap, ext) || error("Invalid file extension: ", fn)
ext
end end
const _extension_map = Dict("tikz" => "tex")
function addExtension(fn::AbstractString, ext::AbstractString) function addExtension(fn::AbstractString, ext::AbstractString)
oldfn, oldext = splitext(fn) try
oldext = chop(oldext, head = 1, tail = 0) oldext = getExtension(fn)
if get(_extension_map, oldext, oldext) == ext if oldext == ext
return fn return fn
else else
return string(fn, ".", ext) return "$fn.$ext"
end
catch
return "$fn.$ext"
end end
end end
"""
savefig([plot,] filename)
Save a Plot (the current plot if `plot` is not passed) to file. The file
type is inferred from the file extension. All backends support png and pdf
file types, some also support svg, ps, eps, html and tex.
"""
function savefig(plt::Plot, fn::AbstractString) function savefig(plt::Plot, fn::AbstractString)
fn = abspath(expanduser(fn))
# get the extension # get the extension
_, ext = splitext(fn) local ext
ext = chop(ext, head = 1, tail = 0) try
if isempty(ext) ext = getExtension(fn)
catch
# if we couldn't extract the extension, add the default
ext = defaultOutputFormat(plt) ext = defaultOutputFormat(plt)
fn = addExtension(fn, ext)
end end
# save it # save it
if haskey(_savemap, ext) func = get(_savemap, ext) do
func = _savemap[ext] error("Unsupported extension $ext with filename ", fn)
return func(plt, fn)
else
error("Invalid file extension: ", fn)
end end
func(plt, fn)
end end
savefig(fn::AbstractString) = savefig(current(), fn) savefig(fn::AbstractString) = savefig(current(), fn)
# --------------------------------------------------------- # ---------------------------------------------------------
"""
gui([plot])
Display a plot using the backends' gui window
"""
gui(plt::Plot = current()) = display(PlotsDisplay(), plt) gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
# IJulia only... inline display
function inline(plt::Plot = current())
isijulia() || error("inline() is IJulia-only")
Main.IJulia.clear_output(true)
display(Main.IJulia.InlineDisplay(), plt)
end
function Base.display(::PlotsDisplay, plt::Plot) function Base.display(::PlotsDisplay, plt::Plot)
prepare_output(plt) prepare_output(plt)
_display(plt) _display(plt)
end end
_do_plot_show(plt, showval::Bool) = showval && gui(plt) # override the REPL display to open a gui window
function _do_plot_show(plt, showval::Symbol) Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
showval == :gui && gui(plt)
showval in (:inline, :ijulia) && inline(plt)
end
# --------------------------------------------------------- # ---------------------------------------------------------
const _best_html_output_type = const _mimeformats = Dict(
KW(:pyplot => :png, :unicodeplots => :txt, :plotlyjs => :html, :plotly => :html) "application/eps" => "eps",
"image/eps" => "eps",
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg",
"text/plain" => "txt",
)
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
)
# a backup for html... passes to svg or png depending on the html_output_format arg # a backup for html... passes to svg or png depending on the html_output_format arg
function _show(io::IO, ::MIME"text/html", plt::Plot) function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
output_type = Symbol(plt.attr[:html_output_format]) output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg) output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end end
if output_type == :png if output_type == :png
# @info("writing png to html output") # info("writing png to html output")
print( print(io, "<img src=\"data:image/png;base64,", base64encode(writemime, MIME("image/png"), plt), "\" />")
io,
"<img src=\"data:image/png;base64,",
base64encode(show, MIME("image/png"), plt),
"\" />",
)
elseif output_type == :svg elseif output_type == :svg
# @info("writing svg to html output") # info("writing svg to html output")
show(io, MIME("image/svg+xml"), plt) writemime(io, MIME("image/svg+xml"), plt)
elseif output_type == :txt elseif output_type == :txt
show(io, MIME("text/plain"), plt) writemime(io, MIME("text/plain"), plt)
else else
error("only png or svg allowed. got: $(repr(output_type))") error("only png or svg allowed. got: $output_type")
end end
end end
# delegate showable to _show instead function _writemime(io::IO, m, plt::Plot)
function Base.showable(m::M, plt::P) where {M<:MIME,P<:Plot} warn("_writemime is not defined for this backend. m=", string(m))
return hasmethod(_show, Tuple{IO,M,P})
end end
function _display(plt::Plot) 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 keys(_mimeformats)
"text/html", @eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
"text/latex",
"image/png",
"image/eps",
"image/svg+xml",
"application/eps",
"application/pdf",
"application/postscript",
"application/x-tex",
"application/vnd.plotly.v1+json",
)
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
if haskey(io, :juno_plotsize)
showjuno(io, m, plt)
else
prepare_output(plt) prepare_output(plt)
_show(io, m, plt) _writemime(io, m, plt)
end
return nothing
end end
end end
Base.showable(::MIME"text/html", plt::Plot{UnicodePlotsBackend}) = false # Pluto
Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) = # ---------------------------------------------------------
showjuno(io, MIME("text/html"), plt) # A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
if is_installed("FileIO")
@eval import FileIO
function _writemime(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = FileIO.load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
FileIO.save(pngfn, s)
# now write from the file
write(io, readall(open(pngfn)))
end
end
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
# function html_output_format(fmt) # function html_output_format(fmt)
# if fmt == "png" # if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot) # @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
# print(io, "<img src=\"data:image/png;base64,", base64(show, MIME("image/png"), plt), "\" />") # print(io, "<img src=\"data:image/png;base64,", base64(writemime, MIME("image/png"), plt), "\" />")
# end # end
# elseif fmt == "svg" # elseif fmt == "svg"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot) # @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
# show(io, MIME("image/svg+xml"), plt) # writemime(io, MIME("image/svg+xml"), plt)
# end # end
# else # else
# error("only png or svg allowed. got: $fmt") # error("only png or svg allowed. got: $fmt")
@ -239,32 +206,71 @@ closeall() = closeall(backend())
# #
# html_output_format("svg") # html_output_format("svg")
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
const _ijulia_output = Compat.ASCIIString["text/html"]
function setup_ijulia()
# override IJulia inline display
if isijulia()
@eval begin
import IJulia
export set_ijulia_output
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
end
function IJulia.display_dict(plt::Plot)
global _ijulia_output
Dict{Compat.ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
end
# default text/plain passes to html... handles Interact issues
function Base.writemime(io::IO, m::MIME"text/plain", plt::Plot)
writemime(io, MIME("text/html"), plt)
end
end
set_ijulia_output("text/html")
end
end
# --------------------------------------------------------- # ---------------------------------------------------------
# Atom PlotPane # Atom PlotPane
# --------------------------------------------------------- # ---------------------------------------------------------
function showjuno(io::IO, m, plt)
dpi = plt[:dpi]
jratio = get(io, :juno_dpi_ratio, 1) function setup_atom()
# @require Atom begin
if isatom() && get(ENV, "PLOTS_USE_ATOM_PLOTPANE", false) in (true, 1, "1", "true", "yes")
# @eval import Atom, Media
@eval import Atom
plt[:dpi] = jratio * Plots.DPI # # connects the render function
# for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
# Atom.Media.media(Plot{T}, Atom.Media.Plot)
# end
Atom.Media.media(Plot, Atom.Media.Graphical)
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
prepare_output(plt) # Atom.displaysize(::Plot) = (535, 379)
try # Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))"
_showjuno(io, m, plt)
finally # this is like "display"... sends an html div with the plot to the PlotPane
plt[:dpi] = dpi function Atom.Media.render(pane::Atom.PlotPane, plt::Plot)
@show "here"
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
end
# # force text/plain to output to the PlotPane
# function Base.writemime(io::IO, ::MIME"text/plain", plt::Plot)
# # writemime(io::IO, MIME("text/html"), plt)
# Atom.Media.render(pane)
# end
# function Atom.Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
# html = Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
# end
end end
end end
function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
if Symbol(plt.attr[:html_output_format]) :svg
throw(MethodError(show, (typeof(m), typeof(plt))))
else
_show(io, m, plt)
end
end
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot) = false
_showjuno(io::IO, m, plt) = _show(io, m, plt)

View File

@ -1,60 +1,103 @@
# RecipesPipeline API
## Warnings
function RecipesPipeline.warn_on_recipe_aliases!( # ------------------------------------------------------------------
plt::Plot, # preprocessing
plotattributes::AKW,
recipe_type::Symbol, function command_idx(kw_list::AVec{KW}, kw::KW)
@nospecialize(args) Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
) end
pkeys = keys(plotattributes)
for k in pkeys function _expand_seriestype_array(d::KW, args)
dk = get(_keyAliases, k, nothing) sts = get(d, :seriestype, :path)
if dk !== nothing if typeof(sts) <: AbstractArray
kv = RecipesPipeline.pop_kw!(plotattributes, k) delete!(d, :seriestype)
if dk pkeys RecipeData[begin
plotattributes[dk] = kv dc = copy(d)
end dc[:seriestype] = sts[r,:]
end RecipeData(dc, args)
end for r=1:size(sts,1)]
else
RecipeData[RecipeData(copy(d), args)]
end end
end end
## Grouping function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
# the grouping mechanism is a recipe on a GroupBy object
# we simply add the GroupBy object to the front of the args list to allow
# the recipe to be applied
if haskey(d, :group)
args = (extractGroupArgs(d[:group], args...), args...)
end
RecipesPipeline.splittable_attribute(plt::Plot, key, val::SeriesAnnotations, len) = # if we were passed a vector/matrix of seriestypes and there's more than one row,
RecipesPipeline.splittable_attribute(plt, key, val.strs, len) # we want to duplicate the inputs, once for each seriestype row.
if !isempty(args)
append!(still_to_process, _expand_seriestype_array(d, args))
end
function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations, indices) # remove subplot and axis args from d... they will be passed through in the kw_list
split_strs = RecipesPipeline.split_attribute(plt, key, val.strs, indices) if !isempty(args)
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor) for (k,v) in d
end for defdict in (_subplot_defaults,
_axis_defaults,
## Preprocessing attributes _axis_defaults_byletter)
function RecipesPipeline.preprocess_axis_args!(plt::Plot, plotattributes, letter) if haskey(defdict, k)
# Fix letter for seriestypes that are x only but data gets passed as y delete!(d, k)
if treats_y_as_x(get(plotattributes, :seriestype, :path)) end
if get(plotattributes, :orientation, :vertical) == :vertical end
letter = :x
end end
end end
plotattributes[:letter] = letter args
RecipesPipeline.preprocess_axis_args!(plt, plotattributes)
end end
RecipesPipeline.preprocess_attributes!(plt::Plot, plotattributes) = # ------------------------------------------------------------------
RecipesPipeline.preprocess_attributes!(plotattributes) # in src/args.jl # user recipes
RecipesPipeline.is_axis_attribute(plt::Plot, attr) = is_axis_attr_noletter(attr) # in src/args.jl
RecipesPipeline.is_subplot_attribute(plt::Plot, attr) = is_subplot_attr(attr) # in src/args.jl function _process_userrecipes(plt::Plot, d::KW, args)
still_to_process = RecipeData[]
args = _preprocess_args(d, args, still_to_process)
## User recipes # for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a queue of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue
# for processing.
kw_list = KW[]
while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes)
next_series = shift!(still_to_process)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for recipedata in rd_list
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(recipedata) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
end
function RecipesPipeline.process_userrecipe!(plt::Plot, kw_list, kw) if isempty(recipedata.args)
_process_userrecipe(plt, kw_list, recipedata)
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
end
end
# don't allow something else to handle it
d[:smooth] = false
kw_list
end
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
# when the arg tuple is empty, that means there's nothing left to recursively
# process... finish up and add to the kw_list
kw = recipedata.d
_preprocess_userrecipe(kw) _preprocess_userrecipe(kw)
warn_on_unsupported_scales(plt.backend, kw) warnOnUnsupported_scales(plt.backend, kw)
# add the plot index # add the plot index
plt.n += 1 plt.n += 1
kw[:series_plotindex] = plt.n kw[:series_plotindex] = plt.n
@ -65,43 +108,35 @@ function RecipesPipeline.process_userrecipe!(plt::Plot, kw_list, kw)
return return
end end
function _preprocess_userrecipe(kw::AKW) function _preprocess_userrecipe(kw::KW)
_add_markershape(kw) _add_markershape(kw)
if get(kw, :permute, default(:permute)) != :none # if there was a grouping, filter the data here
l1, l2 = kw[:permute] _filter_input_data!(kw)
for k in _axis_args
k1 = _attrsymbolcache[l1][k]
k2 = _attrsymbolcache[l2][k]
kwk = keys(kw)
if k1 in kwk || k2 in kwk
kw[k1], kw[k2] = get(kw, k2, default(k2)), get(kw, k1, default(k1))
end
end
end
# map marker_z if it's a Function # map marker_z if it's a Function
if isa(get(kw, :marker_z, default(:marker_z)), Function) if isa(get(kw, :marker_z, nothing), Function)
# TODO: should this take y and/or z as arguments? # TODO: should this take y and/or z as arguments?
kw[:marker_z] = kw[:marker_z] = map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) :
map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
end end
# map line_z if it's a Function # map line_z if it's a Function
if isa(get(kw, :line_z, default(:line_z)), Function) if isa(get(kw, :line_z, nothing), Function)
kw[:line_z] = kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) :
map(kw[:line_z], kw[:x], kw[:y], kw[:z])
end end
# convert a ribbon into a fillrange
if get(kw, :ribbon, nothing) != nothing
make_fillrange_from_ribbon(kw)
end
return return
end end
function _add_errorbar_kw(kw_list::Vector{KW}, kw::AKW) function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
# handle error bars by creating new recipedata data... these will have # handle error bars by creating new recipedata data... these will have
# the same recipedata index as the recipedata they are copied from # the same recipedata index as the recipedata they are copied from
for esym in (:xerror, :yerror, :zerror) for esym in (:xerror, :yerror)
if get(kw, esym, nothing) !== nothing if get(kw, esym, nothing) != nothing
# we make a copy of the KW and apply an errorbar recipe # we make a copy of the KW and apply an errorbar recipe
errkw = copy(kw) errkw = copy(kw)
errkw[:seriestype] = esym errkw[:seriestype] = esym
@ -112,89 +147,75 @@ function _add_errorbar_kw(kw_list::Vector{KW}, kw::AKW)
end end
end end
function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW) function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
# handle smoothing by adding a new series # handle smoothing by adding a new series
if get(kw, :smooth, false) if get(kw, :smooth, false)
x, y = kw[:x], kw[:y] x, y = kw[:x], kw[:y]
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y) β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
sx = [ignorenan_minimum(x), ignorenan_maximum(x)] sx = [minimum(x), maximum(x)]
sy = β .* sx .+ α sy = β * sx + α
push!( push!(kw_list, merge(copy(kw), KW(
kw_list,
merge(
copy(kw),
KW(
:seriestype => :path, :seriestype => :path,
:x => sx, :x => sx,
:y => sy, :y => sy,
:fillrange => nothing, :fillrange => nothing,
:label => "", :label => "",
:primary => false, :primary => false,
), )))
),
)
end end
end end
RecipesPipeline.get_axis_limits(plt::Plot, letter) = axis_limits(plt[1], letter, false) # ------------------------------------------------------------------
# plot recipes
## Plot recipes # Grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes).
RecipesPipeline.type_alias(plt::Plot) = get(_typeAliases, st, st) # If we applied a "plot recipe" without error, then add the returned datalist's KWs,
# otherwise we just add the original KW.
## Plot setup function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_process::Vector{KW})
if !isa(get(kw, :seriestype, nothing), Symbol)
function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list) # seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
_plot_setup(plt, plotattributes, kw_list) push!(kw_list, kw)
_subplot_setup(plt, plotattributes, kw_list) return
return nothing end
try
st = kw[:seriestype]
st = kw[:seriestype] = get(_typeAliases, st, st)
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
for data in datalist
if data.d[:seriestype] == st
error("Plot recipe $st returned the same seriestype: $(data.d)")
end
push!(still_to_process, data.d)
end
catch err
if isa(err, MethodError)
push!(kw_list, kw)
else
rethrow()
end
end
return
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
for kw in kw_list # ------------------------------------------------------------------
rib = get(kw, :ribbon, default(:ribbon)) # setup plot and subplot
fr = get(kw, :fillrange, default(:fillrange))
# map ribbon if it's a Function
if rib isa Function
kw[:ribbon] = map(rib, kw[:x])
end
# convert a ribbon into a fillrange
if rib !== nothing
make_fillrange_from_ribbon(kw)
# map fillrange if it's a Function
elseif fr !== nothing && fr isa Function
kw[:fillrange] = map(fr, kw[:x])
end
end
return nothing
end
# TODO: Should some of this logic be moved to RecipesPipeline? function _plot_setup(plt::Plot, d::KW, 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
for kw in kw_list, (k, v) in kw for kw in kw_list, (k,v) in kw
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k)) haskey(_plot_defaults, k) && (d[k] = pop!(kw, k))
end end
# TODO: init subplots here # TODO: init subplots here
_update_plot_args(plt, plotattributes) _update_plot_args(plt, d)
if !plt.init if !plt.init
plt.o = Base.invokelatest(_create_backend_figure, plt) plt.o = _create_backend_figure(plt)
# create the layout and subplots from the inputs # create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr) plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
for (idx, sp) in enumerate(plt.subplots) for (idx,sp) in enumerate(plt.subplots)
sp.plt = plt sp.plt = plt
sp.attr[:subplot_index] = idx sp.attr[:subplot_index] = idx
end end
@ -202,9 +223,10 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
plt.init = true plt.init = true
end end
# handle inset subplots # handle inset subplots
insets = plt[:inset_subplots] insets = plt[:inset_subplots]
if insets !== nothing if insets != nothing
if !(typeof(insets) <: AVec) if !(typeof(insets) <: AVec)
insets = [insets] insets = [insets]
end end
@ -218,18 +240,17 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
else else
parent = plt.layout parent = plt.layout
end end
sp = Subplot(backend(), parent = parent) sp = Subplot(backend(), parent=parent)
sp.plt = plt sp.plt = plt
push!(plt.subplots, sp)
push!(plt.inset_subplots, sp)
sp.attr[:relative_bbox] = bb sp.attr[:relative_bbox] = bb
sp.attr[:subplot_index] = length(plt.subplots) sp.attr[:subplot_index] = length(plt.subplots)
push!(plt.subplots, sp)
push!(plt.inset_subplots, sp)
end end
end end
plt[:inset_subplots] = nothing
end end
function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# we'll keep a map of subplot to an attribute override dict. # we'll keep a map of subplot to an attribute override dict.
# Subplot/Axis attributes set by a user/series recipe apply only to the # Subplot/Axis attributes set by a user/series recipe apply only to the
# Subplot object which they belong to. # Subplot object which they belong to.
@ -238,150 +259,47 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
for kw in kw_list for kw in kw_list
# get the Subplot object to which the series belongs. # get the Subplot object to which the series belongs.
sps = get(kw, :subplot, :auto) sps = get(kw, :subplot, :auto)
sp = get_subplot( sp = get_subplot(plt, cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
plt,
_cycle(
sps == :auto ? plt.subplots : plt.subplots[sps],
series_idx(kw_list, kw),
),
)
kw[:subplot] = sp kw[:subplot] = sp
# extract subplot/axis attributes from kw and add to sp_attr # extract subplot/axis attributes from kw and add to sp_attr
attr = KW() attr = KW()
for (k, v) in collect(kw) for (k,v) in kw
if is_subplot_attr(k) || is_axis_attr(k) if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
attr[k] = pop!(kw, k)
end
if haskey(_axis_defaults, k)
v = pop!(kw, k) v = pop!(kw, k)
if sps isa AbstractArray && v isa AbstractArray && length(v) == length(sps) for letter in (:x,:y,:z)
v = v[series_idx(kw_list, kw)] attr[Symbol(letter,k)] = v
end end
attr[k] = v
end
if is_axis_attr_noletter(k)
v = pop!(kw, k)
if sps isa AbstractArray && v isa AbstractArray && length(v) == length(sps)
v = v[series_idx(kw_list, kw)]
end
for letter in (:x, :y, :z)
attr[get_attr_symbol(letter, k)] = v
end
end
end
for k in (:scale,), letter in (:x, :y, :z)
# Series recipes may need access to this information
lk = get_attr_symbol(letter, k)
if haskey(attr, lk)
kw[lk] = attr[lk]
end end
end end
sp_attrs[sp] = attr sp_attrs[sp] = attr
end end
_add_plot_title!(plt)
# override subplot/axis args. `sp_attrs` take precendence # override subplot/axis args. `sp_attrs` take precendence
for (idx, sp) in enumerate(plt.subplots) for (idx,sp) in enumerate(plt.subplots)
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx attr = merge(d, get(sp_attrs, sp, KW()))
merge(plotattributes, get(sp_attrs, sp, KW()))
else
get(sp_attrs, sp, KW())
end
_update_subplot_args(plt, sp, attr, idx, false) _update_subplot_args(plt, sp, attr, idx, false)
end end
# do we need to link any axes together? # do we need to link any axes together?
link_axes!(plt.layout, plt[:link]) link_axes!(plt.layout, plt[:link])
return nothing
end
function series_idx(kw_list::AVec{KW}, kw::AKW)
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
end
function _add_plot_title!(plt)
plot_title = plt[:plot_title]
plot_titleindex = nothing
if plot_title != ""
# make new subplot for plot title
if plt[:plot_titleindex] == 0
the_layout = plt.layout
vspan = plt[:plot_titlevspan]
plt.layout = grid(2, 1, heights = (vspan, 1 - vspan))
plt.layout.grid[1, 1] =
subplot = Subplot(plt.backend, parent = plt.layout[1, 1])
plt.layout.grid[2, 1] = the_layout
subplot.plt = plt
top = plt.backend isa PyPlotBackend ? nothing : 0mm
bot = 0mm
plt[:force_minpad] = nothing, top, nothing, bot
subplot[:subplot_index] = last(plt.subplots)[:subplot_index] + 1
plt[:plot_titleindex] = subplot[:subplot_index]
subplot[:framestyle] = :none
subplot[:margin] = 0px
push!(plt.subplots, subplot)
end
# propagate arguments plt[:plot_titleXXX] --> subplot[:titleXXX]
plot_titleindex = plt[:plot_titleindex]
subplot = plt.subplots[plot_titleindex]
for sym in filter(x -> startswith(string(x), "plot_title"), keys(_plot_defaults))
subplot[Symbol(string(sym)[(length("plot_") + 1):end])] = plt[sym]
end
end
return plot_titleindex
end
## Series recipes
function RecipesPipeline.slice_series_attributes!(plt::Plot, kw_list, kw)
sp::Subplot = kw[:subplot]
# in series attributes given as vector with one element per series,
# select the value for current series
_slice_series_args!(kw, plt, sp, series_idx(kw_list, kw))
return nothing
end
RecipesPipeline.series_defaults(plt::Plot) = _series_defaults # in args.jl
RecipesPipeline.is_seriestype_supported(plt::Plot, st) = is_seriestype_supported(st)
function RecipesPipeline.add_series!(plt::Plot, plotattributes)
sp = _prepare_subplot(plt, plotattributes)
if plotattributes[:permute] != :none
letter1, letter2 = plotattributes[:permute]
if plotattributes[:markershape] == :hline &&
(plotattributes[:permute] == (:x, :y) || plotattributes[:permute] == (:y, :x))
plotattributes[:markershape] = :vline
elseif plotattributes[:markershape] == :vline && (
plotattributes[:permute] == (:x, :y) || plotattributes[:permute] == (:y, :x)
)
plotattributes[:markershape] = :hline
end
plotattributes[letter1], plotattributes[letter2] =
plotattributes[letter2], plotattributes[letter1]
end
_expand_subplot_extrema(sp, plotattributes, plotattributes[:seriestype])
_update_series_attributes!(plotattributes, plt, sp)
_add_the_series(plt, sp, plotattributes)
end end
# getting ready to add the series... last update to subplot from anything # getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes # that might have been added during series recipes
function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T} function _prepare_subplot{T}(plt::Plot{T}, d::KW)
st::Symbol = plotattributes[:seriestype] st::Symbol = d[:seriestype]
sp::Subplot{T} = plotattributes[:subplot] sp::Subplot{T} = d[:subplot]
sp_idx = get_subplot_index(plt, sp) sp_idx = get_subplot_index(plt, sp)
_update_subplot_args(plt, sp, plotattributes, sp_idx, true) _update_subplot_args(plt, sp, d, sp_idx, true)
st = _override_seriestype_check(plotattributes, st) st = _override_seriestype_check(d, st)
# change to a 3d projection for this subplot? # change to a 3d projection for this subplot?
if ( if is3d(st)
RecipesPipeline.needs_3d_axes(st) ||
(st == :quiver && plotattributes[:z] !== nothing)
)
sp.attr[:projection] = "3d" sp.attr[:projection] = "3d"
end end
@ -393,74 +311,89 @@ function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T}
sp sp
end end
function _override_seriestype_check(plotattributes::AKW, st::Symbol) # ------------------------------------------------------------------
# series types
function _override_seriestype_check(d::KW, 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, :quiver)) if !is3d(st)
z = plotattributes[:z] z = d[:z]
if ( if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
z !== nothing &&
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
)
st = (st == :scatter ? :scatter3d : :path3d) st = (st == :scatter ? :scatter3d : :path3d)
plotattributes[:seriestype] = st d[:seriestype] = st
end end
end end
st st
end end
function needs_any_3d_axes(sp::Subplot) function _prepare_annotations(sp::Subplot, d::KW)
any( # strip out series annotations (those which are based on series x/y coords)
RecipesPipeline.needs_3d_axes( # and add them to the subplot attr
_override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype]), sp_anns = annotations(sp[:annotations])
) for s in series_list(sp) anns = annotations(pop!(d, :series_annotations, []))
) if length(anns) > 0
x, y = d[:x], d[:y]
nx, ny, na = map(length, (x,y,anns))
n = max(nx, ny, na)
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
end
sp.attr[:annotations] = vcat(sp_anns, anns)
end end
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol) function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
# adjust extrema and discrete info # adjust extrema and discrete info
if st == :image if st == :image
xmin, xmax = ignorenan_extrema(plotattributes[:x]) w, h = size(d[:z])
ymin, ymax = ignorenan_extrema(plotattributes[:y]) expand_extrema!(sp[:xaxis], (0,w))
expand_extrema!(sp[:xaxis], (xmin, xmax)) expand_extrema!(sp[:yaxis], (0,h))
expand_extrema!(sp[:yaxis], (ymin, ymax)) sp[:yaxis].d[:flip] = true
elseif !(st in (:histogram, :bins2d, :histogram2d)) elseif !(st in (:pie, :histogram, :histogram2d))
expand_extrema!(sp, plotattributes) expand_extrema!(sp, d)
end
# expand for zerolines (axes through origin)
if sp[:framestyle] in (:origin, :zerolines)
expand_extrema!(sp[:xaxis], 0.0)
expand_extrema!(sp[:yaxis], 0.0)
end end
end end
function _add_the_series(plt, sp, plotattributes) function _add_the_series(plt, d)
extra_kwargs = warn_on_unsupported_args(plt.backend, plotattributes) warnOnUnsupported_args(plt.backend, d)
if (kw = plt[:extra_kwargs]) isa AbstractDict warnOnUnsupported(plt.backend, d)
plt[:extra_plot_kwargs] = get(kw, :plot, KW()) series = Series(d)
sp[:extra_kwargs] = get(kw, :subplot, KW())
plotattributes[:extra_kwargs] = get(kw, :series, KW())
elseif plt[:extra_kwargs] == :plot
plt[:extra_plot_kwargs] = extra_kwargs
elseif plt[:extra_kwargs] == :subplot
sp[:extra_kwargs] = extra_kwargs
elseif plt[:extra_kwargs] == :series
plotattributes[:extra_kwargs] = extra_kwargs
else
ArgumentError("Unsupported type for extra keyword arguments")
end
warn_on_unsupported(plt.backend, plotattributes)
series = Series(plotattributes)
push!(plt.series_list, series) push!(plt.series_list, series)
z_order = plotattributes[:z_order]
if z_order == :front
push!(sp.series_list, series)
elseif z_order == :back
pushfirst!(sp.series_list, series)
elseif z_order isa Integer
insert!(sp.series_list, z_order, series)
else
@error "Wrong type $(typeof(z_order)) for attribute z_order"
end
_series_added(plt, series) _series_added(plt, series)
_update_subplot_colorbars(sp) end
# -------------------------------------------------------------------------------
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
function _process_seriesrecipe(plt::Plot, d::KW)
# replace seriestype aliases
st = Symbol(d[:seriestype])
st = d[:seriestype] = get(_typeAliases, st, st)
# shapes shouldn't have fillrange set
if d[:seriestype] == :shape
d[:fillrange] = nothing
end
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
if st in supported_types()
sp = _prepare_subplot(plt, d)
_prepare_annotations(sp, d)
_expand_subplot_extrema(sp, d, st)
_add_the_series(plt, d)
else
# get a sub list of series for this seriestype
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
# assuming there was no error, recursively apply the series recipes
for data in datalist
if isa(data, RecipeData)
_process_seriesrecipe(plt, data.d)
else
warn("Unhandled recipe: $(data)")
break
end
end
end
nothing
end end

View File

@ -1,63 +1,25 @@
mutable struct CurrentPlot type CurrentPlot
nullableplot::Union{AbstractPlot,Nothing} nullableplot::Nullable{AbstractPlot}
end end
const CURRENT_PLOT = CurrentPlot(nothing) const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
isplotnull() = CURRENT_PLOT.nullableplot === nothing isplotnull() = isnull(CURRENT_PLOT.nullableplot)
"""
current()
Returns the Plot object for the current plot
"""
function current() function current()
if isplotnull() if isplotnull()
error("No current plot/subplot") error("No current plot/subplot")
end end
CURRENT_PLOT.nullableplot get(CURRENT_PLOT.nullableplot)
end end
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot) current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(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))
function Base.show(io::IO, plt::Plot) Base.show(io::IO, plt::Plot) = print(io, string(plt))
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
@ -65,6 +27,7 @@ convertSeriesIndex(plt::Plot, n::Int) = n
# --------------------------------------------------------- # ---------------------------------------------------------
""" """
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one: The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
@ -75,42 +38,36 @@ 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. See the documentation for more info.
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")`.
""" """
# this creates a new plot with args/kw and sets it to be the current plot
function plot(args...; kw...) function plot(args...; kw...)
@nospecialize d = KW(kw)
# this creates a new plot with args/kw and sets it to be the current plot preprocessArgs!(d)
plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes)
# create an empty Plot then process # create an empty Plot then process
plt = Plot() plt = Plot()
# plt.user_attr = plotattributes # plt.user_attr = d
_plot!(plt, plotattributes, args) _plot!(plt, d, args)
end end
# build a new plot from existing plots # build a new plot from existing plots
# note: we split into plt1, plt2 and plts_tail so we can dispatch correctly # note: we split into plt1 and plts_tail so we can dispatch correctly
plot(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) = function plot(plt1::Plot, plts_tail::Plot...; kw...)
plot!(deepcopy(plt1), deepcopy(plt2), deepcopy.(plts_tail)...; kw...) d = KW(kw)
function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) preprocessArgs!(d)
@nospecialize
plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes)
# build our plot vector from the args # build our plot vector from the args
n = length(plts_tail) + 2 n = length(plts_tail) + 1
plts = Array{Plot}(undef, n) plts = Array(Plot, n)
plts[1] = plt1 plts[1] = plt1
plts[2] = plt2 for (i,plt) in enumerate(plts_tail)
for (i, plt) in enumerate(plts_tail) plts[i+1] = plt
plts[i + 2] = plt
end end
# compute the layout # compute the layout
layout = layout_args(plotattributes, n)[1] layout = layout_args(d, n)[1]
num_sp = sum([length(p.subplots) for p in plts]) num_sp = sum([length(p.subplots) for p in plts])
# create a new plot object, with subplot list/map made of existing subplots. # create a new plot object, with subplot list/map made of existing subplots.
@ -121,32 +78,19 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
# TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot # TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot
# TODO: replace this with proper processing from a merged user_attr KW # TODO: replace this with proper processing from a merged user_attr KW
# update plot args, first with existing plots, then override with plotattributes # update plot args, first with existing plots, then override with d
for p in plts for p in plts
_update_plot_args(plt, copy(p.attr)) _update_plot_args(plt, p.attr)
plt.n += p.n plt.n += p.n
end end
_update_plot_args(plt, plotattributes) _update_plot_args(plt, d)
# pass new plot to the backend # pass new plot to the backend
plt.o = _create_backend_figure(plt) plt.o = _create_backend_figure(plt)
plt.init = true plt.init = true
series_attr = KW() # create the layout and initialize the subplots
for (k, v) in plotattributes
if is_series_attr(k)
series_attr[k] = pop!(plotattributes, k)
end
end
# create the layout
plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts)) plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts))
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# initialize the subplots
cmdidx = 1
for (idx, sp) in enumerate(plt.subplots) for (idx, sp) in enumerate(plt.subplots)
_initialize_subplot(plt, sp) _initialize_subplot(plt, sp)
serieslist = series_list(sp) serieslist = series_list(sp)
@ -156,29 +100,31 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
sp.plt = plt sp.plt = plt
sp.attr[:subplot_index] = idx sp.attr[:subplot_index] = idx
for series in serieslist for series in serieslist
merge!(series.plotattributes, series_attr)
_slice_series_args!(series.plotattributes, plt, sp, cmdidx)
push!(plt.series_list, series) push!(plt.series_list, series)
_series_added(plt, series) _series_added(plt, series)
cmdidx += 1
end end
end end
ttl_idx = _add_plot_title!(plt)
# first apply any args for the subplots # first apply any args for the subplots
for (idx, sp) in enumerate(plt.subplots) for (idx,sp) in enumerate(plt.subplots)
_update_subplot_args(plt, sp, idx == ttl_idx ? KW() : plotattributes, idx, false) _update_subplot_args(plt, sp, d, idx, false)
end end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# finish up # finish up
current(plt) current(plt)
_do_plot_show(plt, get(plotattributes, :show, default(:show))) if get(d, :show, default(:show))
gui()
end
plt plt
end 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()
@ -189,13 +135,11 @@ function plot!(args...; kw...)
end 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
plot(plt::Plot, args...; kw...) = plot!(deepcopy(plt), args...; kw...)
function plot!(plt::Plot, args...; kw...) function plot!(plt::Plot, args...; kw...)
@nospecialize d = KW(kw)
plotattributes = KW(kw) preprocessArgs!(d)
RecipesPipeline.preprocess_attributes!(plotattributes) # merge!(plt.user_attr, d)
# merge!(plt.user_attr, plotattributes) _plot!(plt, d, args)
_plot!(plt, plotattributes, args)
end end
# ------------------------------------------------------------------------------- # -------------------------------------------------------------------------------
@ -203,21 +147,83 @@ end
# this is the core plotting function. recursively apply recipes to build # this is the core plotting function. recursively apply recipes to build
# 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, d::KW, args::Tuple)
@nospecialize # d[:plot_object] = plt
RecipesPipeline.recipe_pipeline!(plt, plotattributes, args)
# --------------------------------
# "USER RECIPES"
# --------------------------------
kw_list = _process_userrecipes(plt, d, args)
# --------------------------------
# "PLOT RECIPES"
# --------------------------------
# "plot recipe", which acts like a series type, and is processed before
# the plot layout is created, which allows for setting layouts and other plot-wide attributes.
# we get inputs which have been fully processed by "user recipes" and "type recipes",
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.
still_to_process = kw_list
kw_list = KW[]
while !isempty(still_to_process)
next_kw = shift!(still_to_process)
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
end
# --------------------------------
# Plot/Subplot/Layout setup
# --------------------------------
_plot_setup(plt, d, kw_list)
_subplot_setup(plt, d, kw_list)
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
# --------------------------------
# "SERIES RECIPES"
# --------------------------------
for kw in kw_list
sp::Subplot = kw[:subplot]
# idx = get_subplot_index(plt, sp)
# # we update subplot args in case something like the color palatte is part of the recipe
# _update_subplot_args(plt, sp, kw, idx, true)
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, sp, command_idx(kw_list,kw))
# now we have a fully specified series, with colors chosen. we must recursively handle
# series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype,
# we check for a recipe that will convert that series type into one made up of lower-level components.
# For example, a histogram is just a bar plot with binned data, a bar plot is really a filled step plot,
# and a step plot is really just a path. So any backend that supports drawing a path will implicitly
# be able to support step, bar, and histogram plots (and any recipes that use those components).
_process_seriesrecipe(plt, kw)
end
# --------------------------------
current(plt) current(plt)
_do_plot_show(plt, plt[:show])
return plt # do we want to force display?
if plt[:show]
gui(plt)
end
plt
end end
# we're getting ready to display/output. prep for layout calcs, then update # we're getting ready to display/output. prep for layout calcs, then update
# the plot object after # the plot object after
function prepare_output(plt::Plot) function prepare_output(plt::Plot)
_before_layout_calcs(plt) _before_layout_calcs(plt)
w, h = plt.attr[:size] w, h = plt.attr[:size]
plt.layout.bbox = BoundingBox(0mm, 0mm, w * px, h * px) plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
# One pass down and back up the tree to compute the minimum padding # One pass down and back up the tree to compute the minimum padding
# of the children on the perimeter. This is an backend callback. # of the children on the perimeter. This is an backend callback.
@ -226,17 +232,6 @@ function prepare_output(plt::Plot)
_update_min_padding!(sp) _update_min_padding!(sp)
end end
# spedific to :plot_title see _add_plot_title!
force_minpad = get(plt, :force_minpad, ())
if !isempty(force_minpad)
for i in eachindex(plt.layout.grid)
plt.layout.grid[i].minpad = Tuple(
i === nothing ? j : i for
(i, j) in zip(force_minpad, plt.layout.grid[i].minpad)
)
end
end
# now another pass down, to update the bounding boxes # now another pass down, to update the bounding boxes
update_child_bboxes!(plt.layout) update_child_bboxes!(plt.layout)
@ -247,13 +242,7 @@ function prepare_output(plt::Plot)
_update_plot_object(plt) _update_plot_object(plt)
end end
""" function prepared_object(plt::Plot)
backend_object(plot)
Returns the backend representation of a Plot object.
Returns `nothing` if the backend does not support this.
"""
function backend_object(plt::Plot)
prepare_output(plt) prepare_output(plt)
plt.o plt.o
end end
@ -262,12 +251,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(plt.subplots, sp))
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(plt.subplots, sp))
end end
# --------------------------------------------------------------------

View File

@ -1,79 +0,0 @@
const _attribute_defaults = Dict(
:Series => _series_defaults,
:Subplot => _subplot_defaults,
:Plot => _plot_defaults,
:Axis => _axis_defaults,
)
attrtypes() = join(keys(_attribute_defaults), ", ")
attributes(attrtype::Symbol) = sort(collect(keys(_attribute_defaults[attrtype])))
function lookup_aliases(attrtype, attribute)
attribute = Symbol(attribute)
attribute = in(attribute, keys(_keyAliases)) ? _keyAliases[attribute] : attribute
in(attribute, keys(_attribute_defaults[attrtype])) && return attribute
error("There is no attribute named $attribute in $attrtype")
end
"""
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
"""
function plotattr()
println(
"Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())",
)
end
function plotattr(attrtype::Symbol)
in(attrtype, keys(_attribute_defaults)) || error("Viable options are $(attrtypes())")
println("Defined $attrtype attributes are:\n$(join(attributes(attrtype), ", "))")
end
function plotattr(attribute::AbstractString)
attribute = Symbol(attribute)
attribute = in(attribute, keys(_keyAliases)) ? _keyAliases[attribute] : attribute
for (k, v) in _attribute_defaults
if in(attribute, keys(v))
return plotattr(k, "$attribute")
end
end
error("There is no attribute named $attribute")
end
printnothing(x) = x
printnothing(x::Nothing) = "nothing"
function plotattr(attrtype::Symbol, attribute::AbstractString)
in(attrtype, keys(_attribute_defaults)) ||
ArgumentError("`attrtype` must match one of $(attrtypes())")
attribute = Symbol(lookup_aliases(attrtype, attribute))
desc = get(_arg_desc, attribute, "")
first_period_idx = findfirst(isequal('.'), desc)
if isnothing(first_period_idx)
typedesc = ""
desc = strip(desc)
else
typedesc = desc[1:(first_period_idx - 1)]
desc = strip(desc[(first_period_idx + 1):end])
end
als = keys(filter(x -> x[2] == attribute, _keyAliases)) |> collect |> sort
als = join(map(string, als), ", ")
def = _attribute_defaults[attrtype][attribute]
# Looks up the different elements and plots them
println(
"$(printnothing(attribute)) ",
typedesc == "" ? "" : "{$(printnothing(typedesc))}",
"\n",
als == "" ? "" : "$(printnothing(als))\n",
"\n$(printnothing(desc))\n",
"$(printnothing(attrtype)) attribute, ",
def == "" ? "" : " default: $(printnothing(def))",
)
end

468
src/precompile.jl Normal file
View File

@ -0,0 +1,468 @@
function _precompile_()
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
precompile(Plots.py_add_series, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Function,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Plots.OHLC, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.LinSpace{Float64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, DataFrames.DataFrame,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Int64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Function, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{ASCIIString, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.FloatRange{Float64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 2},))
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Int64,))
precompile(Plots._before_layout_calcs, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Int64,))
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.setup_ijulia, ())
precompile(Plots.call, (Type{Plots.Plot{Plots.UnicodePlotsBackend}}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.create_grid_vcat, (Expr,))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.update_child_bboxes!, (Plots.GridLayout, Array{Measures.Length{:mm, Float64}, 1},))
precompile(Plots.preprocessArgs!, (Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.Plot{Plots.PyPlotBackend}}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.fix_xy_lengths!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._update_min_padding!, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.warnOnUnsupported_args, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots.build_layout, (Plots.GridLayout, Int64,))
precompile(Plots.build_layout, (Plots.GridLayout, Int64, Array{Plots.Plot, 1},))
precompile(Plots.warnOnUnsupported, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
precompile(Plots.link_axes!, (Plots.GridLayout, Symbol,))
precompile(Plots.warnOnUnsupported, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots._update_plot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.font, (Int64,))
precompile(Plots.recompute_lengths, (Array{Measures.Measure, 1},))
precompile(Plots._update_plot_object, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.font, (Symbol,))
precompile(Plots.create_grid, (Expr,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Void, Int64,))
precompile(Plots.pickDefaultBackend, ())
precompile(Plots.default_should_widen, (Plots.Axis,))
precompile(Plots.setup_atom, ())
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Symbol, Int64,))
precompile(Plots.my_hist_2d, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1}, Int64,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, ASCIIString, Int64,))
precompile(Plots.create_grid_curly, (Expr,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Bool, Int64,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Int64,))
precompile(Plots.my_hist, (Array{Any, 1}, Array{Float64, 1}, Int64,))
precompile(Plots.getpctrange, (Int64,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1},))
precompile(Plots.default, (Symbol,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
precompile(Plots.pie_labels, (Plots.Subplot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Measures.Length{:mm, Float64}, Int64,))
precompile(Plots.py_path, (Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots._update_min_padding!, (Plots.GridLayout,))
precompile(Plots.warnOnUnsupported_scales, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Plots.Font, Int64,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Tuple{Int64, Int64}, Symbol,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Array{Any, 1}, Int64,))
precompile(Plots.default, (Symbol, Tuple{Int64, Int64},))
precompile(Plots.warnOnUnsupported_scales, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots.axis_limits, (Plots.Axis, Bool,))
precompile(Plots.default, (Symbol, Bool,))
precompile(Plots.getColorZ, (Plots.ColorGradient, Float64,))
precompile(Plots._update_plot_args, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.Surface}, Function, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
precompile(Plots.font, (Symbol,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64}, Symbol,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.UnicodePlotsBackend,))
precompile(Plots.extractGroupArgs, (Array{ASCIIString, 1}, Array{Float64, 1},))
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.PyPlotBackend,))
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.extractGroupArgs, (Array{Union{UTF8String, ASCIIString}, 1},))
precompile(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(Plots.plot, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.py_marker, (Plots.Shape,))
precompile(Plots.getindex, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.getindex, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.discrete_value!, (Plots.Axis, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots.prepare_output, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.update_inset_bboxes!, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.add_layout_pct!, (Base.Dict{Symbol, Any}, Expr, Int64, Int64,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
precompile(Plots.call, (Type{Plots.Shape}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 2},))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout}, Plots.RootLayout,))
precompile(Plots.plot, (Array{Any, 1}, Function, Function,))
precompile(Plots.should_add_to_legend, (Plots.Series,))
precompile(Plots.plot, (Array{Any, 1}, DataFrames.DataFrame, Symbol,))
precompile(Plots.plot, (Array{Any, 1}, Array{Plots.OHLC, 1},))
precompile(Plots.convertToAnyVector, (Array{Float64, 2}, Base.Dict{Symbol, Any},))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Array{ASCIIString, 1}, Array{Float64, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Symbol, 1}, Int64,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Int64, 1},))
precompile(Plots.pie, (Array{Any, 1}, Array{ASCIIString, 1},))
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Any, 1}, Int64,))
precompile(Plots.merge_with_base_supported, (Array{Symbol, 1},))
precompile(Plots.histogram2d, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.StepRange{Int64, Int64}, Array{Float64, 2},))
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.font, ())
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
precompile(Plots.plot, (Array{Any, 1}, Array{Function, 1}, Array{Float64, 1},))
precompile(Plots.scatter, (Array{Any, 1}, Base.LinSpace{Float64},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Base.LinSpace{Float64},))
precompile(Plots.plot!, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
precompile(Plots.get_zvalues, (Int64,))
precompile(Plots.plot, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots.histogram, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.hline!, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.layout_args, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.heatmap, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots._replace_linewidth, (Base.Dict{Symbol, Any},))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
precompile(Plots.py_markercolor, (Base.Dict{Symbol, Any},))
precompile(Plots.unzip, (Array{Tuple{Float64, Float64}, 1},))
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 2}, Symbol,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
precompile(Plots.contour, (Array{Any, 1}, Base.FloatRange{Float64},))
precompile(Plots.scatter, (Array{Any, 1}, DataFrames.DataFrame,))
precompile(Plots.scatter!, (Array{Any, 1}, Base.LinSpace{Float64},))
precompile(Plots.scatter!, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.getxy, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.get_xy, (Array{Plots.OHLC, 1}, Base.UnitRange{Int64},))
precompile(Plots.convertToAnyVector, (Array{Function, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Int64, Float64, Plots.PlotText,))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.get_color_palette, (Symbol, ColorTypes.RGB{Float64}, Int64,))
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Plots.PlotText,))
precompile(Plots.py_colormap, (Plots.ColorGradient, Float64,))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Stroke,))
precompile(Plots.call, (Type{Plots.ColorVector}, Array{Symbol, 1},))
precompile(Plots.py_colormap, (Plots.ColorGradient, Void,))
precompile(Plots.py_fillcolor, (Base.Dict{Symbol, Any},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Float64,))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.call, (Type{Plots.Plot},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Array{Int64, 1},))
precompile(Plots.getExtension, (UTF8String,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout},))
precompile(Plots.update!, (Array{Any, 1}, Plots.Axis,))
precompile(Plots.frame, (Plots.Animation, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 1}, Symbol,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1},))
precompile(Plots.fakedata, (Int64,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.py_compute_axis_minval, (Plots.Axis,))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.command_idx, (Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.getindex, (Plots.Axis, Symbol,))
precompile(Plots.__init__, ())
precompile(Plots.isvertical, (Base.Dict{Symbol, Any},))
precompile(Plots.getExtension, (ASCIIString,))
precompile(Plots.py_marker, (Symbol,))
precompile(Plots.py_init_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64},))
precompile(Plots.bucket_index, (Float64, Base.LinSpace{Float64},))
precompile(Plots.default, (Array{Any, 1},))
precompile(Plots.filter_data!, (Base.Dict{Symbol, Any}, Array{Int64, 1},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1}, Base.LinSpace{Float64},))
precompile(Plots.slice_arg, (Array{Symbol, 2}, Int64,))
precompile(Plots.getindex, (Plots.Plot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.plot!, (Array{Any, 1},))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.FloatRange{Float64},))
precompile(Plots.getindex, (Plots.Plot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.handle_dfs, (DataFrames.DataFrame, Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
precompile(Plots.filter_data, (Base.UnitRange{Int64}, Array{Int64, 1},))
precompile(Plots.call, (Type{Plots.ColorWrapper}, ColorTypes.RGBA{Float64},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
precompile(Plots.color_or_nothing!, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Shape,))
precompile(Plots.py_fillcolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.transpose_z, (Base.Dict{Symbol, Any}, Array{Float64, 2}, Bool,))
precompile(Plots.py_linecolor, (Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.OHLC}, Float64, Float64, Float64, Float64,))
precompile(Plots.setxy!, (Plots.Plot{Plots.PyPlotBackend}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64,))
precompile(Plots.push!, (Plots.Segments, Float64, Float64, Float64, Float64,))
precompile(Plots.handle_group, (DataFrames.DataFrame, Base.Dict{Symbol, Any},))
precompile(Plots.lightness_from_background, (ColorTypes.RGB{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.LinSpace{Float64},))
precompile(Plots.py_bbox, (Array{Any, 1},))
precompile(Plots.py_markerstrokecolor, (Base.Dict{Symbol, Any},))
precompile(Plots.arrow, ())
precompile(Plots.convert, (Type{Array{Float64, 1}}, Base.StepRange{Int64, Int64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Float64, 1},))
precompile(Plots.convertLegendValue, (Symbol,))
precompile(Plots.slice_arg, (Array{Measures.Length{:mm, Float64}, 2}, Int64,))
precompile(Plots.calc_num_subplots, (Plots.GridLayout,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.slice_arg, (Array{Plots.ColorWrapper, 2}, Int64,))
precompile(Plots.slice_arg, (Array{ASCIIString, 2}, Int64,))
precompile(Plots.filter_data, (Array{Float64, 1}, Array{Int64, 1},))
precompile(Plots.py_linecolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.discrete_value!, (Plots.Axis, ASCIIString,))
precompile(Plots.allShapes, (ColorTypes.RGBA{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Int64, 1},))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.LinSpace{Float64},))
precompile(Plots.discrete_value!, (Plots.Axis, Symbol,))
precompile(Plots.push!, (Plots.Segments, Float64, Int64, Int64, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.heatmap_edges, (Array{Float64, 1},))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.StepRange{Int64, Int64},))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Shape, Symbol,))
precompile(Plots.py_color, (Plots.ColorWrapper, Float64,))
precompile(Plots.call, (Type{Plots.GridLayout}, Int64, Int64,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64}, Symbol,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Bool, Symbol,))
precompile(Plots.hvline_limits, (Plots.Axis,))
precompile(Plots.current, ())
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Float64, Symbol,))
precompile(Plots.compute_gridsize, (Int64, Int64, Int64,))
precompile(Plots.py_color, (ColorTypes.RGB{Float64}, Void,))
precompile(Plots.interpolate_rgb, (ColorTypes.RGBA{Float64}, ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.UnitRange{Int64},))
precompile(Plots.allShapes, (Float64,))
precompile(Plots.warn_on_deprecated_backend, (Symbol,))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Int64, 1},))
precompile(Plots.setindex!, (Plots.GridLayout, Plots.EmptyLayout, Int64, Int64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Int64, Int64},))
precompile(Plots.allShapes, (Int64,))
precompile(Plots.py_markercolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.interpolate_rgb, (ColorTypes.RGB{Float64}, ColorTypes.RGB{Float64}, Float64,))
precompile(Plots.get_ticks, (Plots.Axis,))
precompile(Plots.backend, ())
precompile(Plots.get_xy, (Plots.OHLC{Float64}, Int64, Float64,))
precompile(Plots.allShapes, (Plots.Stroke,))
precompile(Plots.replaceAliases!, (Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any},))
precompile(Plots._create_backend_figure, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, UTF8String,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.allShapes, (Plots.Shape,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Stroke, Symbol,))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Float64, 1},))
precompile(Plots.rowsize, (Expr,))
precompile(Plots.get_axis, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, ASCIIString,))
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Float64, Float64},))
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Plots.Shape,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Bool,))
precompile(Plots.supported_types, (Plots.PyPlotBackend,))
precompile(Plots.get_axis, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.setindex!, (Plots.GridLayout, Plots.GridLayout, Int64, Int64,))
precompile(Plots.plot, ())
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.FloatRange{Float64},))
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Symbol,))
precompile(Plots.ok, (Float64, Float64, Int64,))
precompile(Plots.allShapes, (Symbol,))
precompile(Plots._initialize_backend, (Plots.PyPlotBackend,))
precompile(Plots.plot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.bar, (Array{Float64, 1},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Base.LinSpace{Float64},))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Int64, Symbol,))
precompile(Plots.nanappend!, (Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.autopick, (Array{ColorTypes.RGBA, 1}, Int64,))
precompile(Plots.compute_xyz, (Void, Array{Int64, 1}, Void,))
precompile(Plots._add_markershape, (Base.Dict{Symbol, Any},))
precompile(Plots._backend_instance, (Symbol,))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.update_child_bboxes!, (Plots.GridLayout,))
precompile(Plots._replace_markershape, (Symbol,))
precompile(Plots.has_black_border_for_default, (Symbol,))
precompile(Plots._filter_input_data!, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64},))
precompile(Plots.text, (ASCIIString, Int64, Symbol,))
precompile(Plots.allShapes, (Array{Symbol, 2},))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.UnitRange{Int64},))
precompile(Plots.replaceAlias!, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{ASCIIString, 1}, Array{Float64, 1}, Void,))
precompile(Plots.layout_args, (Int64,))
precompile(Plots.text, (ASCIIString, Symbol, Int64,))
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Base.FloatRange{Float64}, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.all3D, (Base.Dict{Symbol, Any},))
precompile(Plots.cycle, (Array{Plots.Subplot, 1}, Int64,))
precompile(Plots.compute_xyz, (Base.StepRange{Int64, Int64}, Array{Float64, 1}, Void,))
precompile(Plots.plotarea!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.like_surface, (Symbol,))
precompile(Plots.build_layout, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.py_linestyle, (Symbol, Symbol,))
precompile(Plots.plot!, (Array{Float64, 2},))
precompile(Plots.plot!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1}, Base.LinSpace{Float64},))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Void,))
precompile(Plots.yaxis!, (ASCIIString, Symbol,))
precompile(Plots.compute_xyz, (Base.LinSpace{Float64}, Array{Float64, 1}, Void,))
precompile(Plots.isijulia, ())
precompile(Plots.addExtension, (UTF8String, ASCIIString,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Array{Float64, 1},))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Float64, Float64,))
precompile(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(Plots.layout_args, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Array{Float64, 1}, Void,))
precompile(Plots.addExtension, (ASCIIString, ASCIIString,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
precompile(Plots._initialize_backend, (Plots.PlotlyBackend,))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Int64, Float64, Float64,))
precompile(Plots.bbox!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.vline!, (Array{Int64, 1},))
precompile(Plots.supported_markers, (Plots.PyPlotBackend,))
precompile(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(Plots.stroke, (Int64,))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Void,))
precompile(Plots.right, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.extractGroupArgs, (Symbol, DataFrames.DataFrame, Symbol,))
precompile(Plots.generate_colorgradient, (ColorTypes.RGB{Float64},))
precompile(Plots.expand_extrema!, (Plots.Extrema, Bool,))
precompile(Plots.py_colormap, (Plots.ColorWrapper, Void,))
precompile(Plots.expand_extrema!, (Plots.Extrema, Float64,))
precompile(Plots.contour, (Base.FloatRange{Float64},))
precompile(Plots.bottom, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.text, (ASCIIString, Symbol,))
precompile(Plots.create_grid, (Symbol,))
precompile(Plots.expand_extrema!, (Plots.Axis, Bool,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol,))
precompile(Plots.convertToAnyVector, (Void, Base.Dict{Symbol, Any},))
precompile(Plots.py_dpi_scale, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
precompile(Plots.png, (ASCIIString,))
precompile(Plots.supported_scales, (Plots.PyPlotBackend,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.extendSeriesData, (Array{Float64, 1}, Float64,))
precompile(Plots.compute_xyz, (Void, Array{Float64, 1}, Void,))
precompile(Plots.py_color, (Symbol,))
precompile(Plots.expand_extrema!, (Plots.Extrema, Int64,))
precompile(Plots.supported_styles, (Plots.PyPlotBackend,))
precompile(Plots._initialize_backend, (Plots.UnicodePlotsBackend,))
precompile(Plots._initialize_backend, (Plots.GRBackend,))
precompile(Plots.is3d, (Symbol,))
precompile(Plots.supported_types, (Plots.UnicodePlotsBackend,))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Function, Void,))
precompile(Plots.py_color, (Symbol, Void,))
precompile(Plots.trueOrAllTrue, (Function, Array{Symbol, 2},))
precompile(Plots.typemin, (Measures.Length{:mm, Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Float64,))
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.leftpad, (Plots.GridLayout,))
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.centers, (Base.LinSpace{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Int64,))
precompile(Plots.text, (ASCIIString,))
precompile(Plots.convertColor, (ColorTypes.RGB{Float64},))
precompile(Plots.py_color, (Plots.ColorWrapper, Void,))
precompile(Plots.py_color, (Plots.ColorWrapper,))
precompile(Plots.trueOrAllTrue, (Function, Int64,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64},))
precompile(Plots.extrema, (Plots.Axis,))
precompile(Plots.top, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.convertColor, (Symbol,))
precompile(Plots.size, (Plots.Surface{Array{Float64, 2}},))
precompile(Plots.isdark, (ColorTypes.RGB{Float64},))
precompile(Plots.rowsize, (Symbol,))
precompile(Plots.series_list, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.convertToAnyVector, (Array{Float64, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.update!, (Plots.Axis,))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Float64, Array{Float64, 1},))
precompile(Plots.wraptuple, (Bool,))
precompile(Plots.call, (Type{Plots.Shape}, Array{Tuple{Float64, Float64}, 1},))
precompile(Plots.slice_arg, (Base.StepRange{Int64, Int64}, Int64,))
precompile(Plots.sticks_fillfrom, (Void, Int64,))
precompile(Plots.left, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.gr, ())
precompile(Plots.leftpad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.supported_markers, ())
precompile(Plots.colorscheme, (Symbol,))
precompile(Plots.convertColor, (ColorTypes.RGB{Float64}, Void,))
precompile(Plots.isscalar, (Int64,))
precompile(Plots.wraptuple, (Int64,))
precompile(Plots.call, (Type{Plots.Plot}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.supported_styles, ())
precompile(Plots.frame, (Plots.Animation,))
precompile(Plots.toppad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.link_axes!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.convertLegendValue, (Bool,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Void,))
precompile(Plots.plotly, ())
precompile(Plots.ispositive, (Measures.Length{:mm, Float64},))
precompile(Plots.rightpad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.GroupBy}, Array{ASCIIString, 1}, Array{Array{Int64, 1}, 1},))
precompile(Plots.px2inch, (Int64,))
precompile(Plots.slice_arg, (Tuple{Int64, Int64}, Int64,))
precompile(Plots.call, (Type{Plots.UnicodePlotsBackend},))
precompile(Plots.trueOrAllTrue, (Function, Symbol,))
precompile(Plots.bottompad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.annotate!, (Array{Tuple{Int64, Float64, Plots.PlotText}, 1},))
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.Plot}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.title!, (ASCIIString,))
precompile(Plots.slice_arg, (Bool, Int64,))
precompile(Plots.wraptuple, (Float64,))
precompile(Plots.bottompad, (Plots.GridLayout,))
precompile(Plots.py_stepstyle, (Symbol,))
precompile(Plots.link_axes!, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.call, (Type{Plots.GRBackend},))
precompile(Plots.unicodeplots, ())
precompile(Plots.rightpad, (Plots.GridLayout,))
precompile(Plots.call, (Type{Plots.PlotlyBackend},))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64},))
precompile(Plots.toppad, (Plots.GridLayout,))
precompile(Plots.calc_edges, (Array{Float64, 1}, Int64,))
precompile(Plots.colorscheme, (ColorTypes.RGBA{Float64},))
precompile(Plots.slice_arg, (Int64, Int64,))
precompile(Plots.pyplot, ())
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots._series_added, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots.get_color_palette, (Array{ColorTypes.RGBA, 1}, ColorTypes.RGB{Float64}, Int64,))
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.slice_arg, (Void, Int64,))
precompile(Plots.cycle, (Int64, Int64,))
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.PyPlotBackend},))
precompile(Plots.update_child_bboxes!, (Plots.Subplot{Plots.PyPlotBackend}, Array{Measures.Length{:mm, Float64}, 1},))
precompile(Plots.filter_data, (Void, Array{Int64, 1},))
precompile(Plots.slice_arg, (Symbol, Int64,))
precompile(Plots.slice_arg, (ASCIIString, Int64,))
precompile(Plots.layout_args, (Plots.GridLayout,))
precompile(Plots.wraptuple, (Tuple{},))
precompile(Plots.calc_num_subplots, (Plots.EmptyLayout,))
precompile(Plots.wraptuple, (Tuple{Symbol, Float64, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{ASCIIString, Tuple{Int64, Int64}, Base.StepRange{Int64, Int64}, Symbol},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Float64, Array{Symbol, 2}},))
precompile(Plots.wraptuple, (Tuple{Int64, Array{Symbol, 2}},))
precompile(Plots.wraptuple, (Tuple{ASCIIString, Symbol},))
precompile(Plots._replace_markershape, (Array{Symbol, 2},))
precompile(Plots.wraptuple, (Tuple{Symbol, Int64},))
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Symbol},))
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{Float64, Array{Symbol, 2}, Int64},))
precompile(Plots.py_color, (ColorTypes.RGB{Float64},))
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol},))
precompile(Plots.tovec, (Array{Float64, 1},))
precompile(Plots.get_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.eltype, (Plots.Surface{Array{Float64, 2}},))
precompile(Plots.nobigs, (Array{Float64, 1},))
precompile(Plots.get_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.annotations, (Array{Any, 1},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol},))
precompile(Plots.colorscheme, (Plots.ColorWrapper,))
precompile(Plots.colorscheme, (Plots.ColorGradient,))
precompile(Plots.text, (Plots.PlotText,))
precompile(Plots._replace_markershape, (Plots.Shape,))
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64, Float64, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{Plots.Shape, Int64, ColorTypes.RGBA{Float64}},))
end

View File

@ -1,40 +0,0 @@
#! format: off
should_precompile = true
# Don't edit the following! Instead change the script for `snoop_bot`.
ismultios = false
ismultiversion = true
# 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
@static if v"1.6.0-DEV" <= VERSION <= v"1.6.9"
@static if isfile(joinpath(@__DIR__, "../deps/SnoopCompile/precompile//1.6/precompile_Plots.jl"))
include("../deps/SnoopCompile/precompile//1.6/precompile_Plots.jl")
_precompile_()
end
elseif v"1.7.0-DEV" <= VERSION <= v"1.7.9"
@static if isfile(joinpath(@__DIR__, "../deps/SnoopCompile/precompile//1.7/precompile_Plots.jl"))
include("../deps/SnoopCompile/precompile//1.7/precompile_Plots.jl")
_precompile_()
end
elseif v"1.8.0-DEV" <= VERSION <= v"1.8.9"
@static if isfile(joinpath(@__DIR__, "../deps/SnoopCompile/precompile//1.8/precompile_Plots.jl"))
include("../deps/SnoopCompile/precompile//1.8/precompile_Plots.jl")
_precompile_()
end
elseif v"1.9.0-DEV" <= VERSION <= v"1.9.9"
@static if isfile(joinpath(@__DIR__, "../deps/SnoopCompile/precompile//1.9/precompile_Plots.jl"))
include("../deps/SnoopCompile/precompile//1.9/precompile_Plots.jl")
_precompile_()
end
else
end
end # precompile_enclosure

File diff suppressed because it is too large Load Diff

429
src/series.jl Normal file
View File

@ -0,0 +1,429 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
function convertToAnyVector(args...)
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
end
# --------------------------------------------------------------------
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
nobigs(v::AVec{BigInt}) = map(Int64, v)
nobigs(v) = v
@noinline function compute_xyz(x, y, z)
x = compute_x(x,y,z)
y = compute_y(x,y,z)
z = compute_z(x,y,z)
nobigs(x), nobigs(y), nobigs(z)
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
# we are going to build recipes to do the processing and splitting of the args
# ensure we dispatch to the slicer
immutable SliceIt end
# the catch-all recipes
@recipe function f(::Type{SliceIt}, x, y, z)
# @show "HERE", typeof((x,y,z))
xs, _ = convertToAnyVector(x, d)
ys, _ = convertToAnyVector(y, d)
zs, _ = convertToAnyVector(z, d)
fr = pop!(d, :fillrange, nothing)
fillranges, _ = if typeof(fr) <: Number
([fr],nothing)
else
convertToAnyVector(fr, d)
end
mf = length(fillranges)
# @show zs
mx = length(xs)
my = length(ys)
mz = length(zs)
# ret = Any[]
for i in 1:max(mx, my, mz)
# add a new series
di = copy(d)
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
# @show i, typeof((xi, yi, zi))
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
# @show i, typeof((di[:x], di[:y], di[:z]))
# handle fillrange
fr = fillranges[mod1(i,mf)]
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
# @show i, di[:x], di[:y], di[:z]
push!(series_list, RecipeData(di, ()))
end
nothing # don't add a series for the main block
end
# this is the default "type recipe"... just pass the object through
@recipe f{T<:Any}(::Type{T}, v::T) = v
# this should catch unhandled "series recipes" and error with a nice message
@recipe f{V<:Val}(::Type{V}, x, y, z) = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
did_replace = false
newx = _apply_type_recipe(d, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
y === newy || (did_replace = true)
newz = _apply_type_recipe(d, z)
z === newz || (did_replace = true)
if did_replace
newx, newy, newz
else
SliceIt, x, y, z
end
end
@recipe function f(x, y)
did_replace = false
newx = _apply_type_recipe(d, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
y === newy || (did_replace = true)
if did_replace
newx, newy
else
SliceIt, x, y, nothing
end
end
@recipe function f(y)
newy = _apply_type_recipe(d, y)
if y !== newy
newy
else
SliceIt, nothing, y, nothing
end
end
# if there's more than 3 inputs, it can't be passed directly to SliceIt
# so we'll apply_type_recipe to all of them
@recipe function f(v1, v2, v3, v4, vrest...)
did_replace = false
newargs = map(v -> begin
newv = _apply_type_recipe(d, v)
if newv !== v
did_replace = true
end
newv
end, (v1, v2, v3, v4, vrest...))
if !did_replace
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
end
newargs
end
# # --------------------------------------------------------------------
# # 1 argument
# # --------------------------------------------------------------------
@recipe f(n::Integer) = n, n, n
# return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f{T<:Number}(mat::AMat{T})
if all3D(d)
n,m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
SliceIt, nothing, mat, nothing
end
end
# # images - grays
@recipe function f{T<:Gray}(mat::AMat{T})
if nativeImagesSupported()
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
end
end
# # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T})
if nativeImagesSupported()
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
z, d[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
end
end
#
# # plotting arbitrary shapes/polygons
@recipe function f(shape::Shape)
seriestype --> :shape
shape_coords(shape)
end
@recipe function f(shapes::AVec{Shape})
seriestype --> :shape
shape_coords(shapes)
end
@recipe function f(shapes::AMat{Shape})
seriestype --> :shape
for j in 1:size(shapes,2)
@series shape_coords(vec(shapes[:,j]))
end
end
#
#
# # function without range... use the current range of the x-axis
# @recipe function f(f::FuncOrFuncs)
# plt = d[:plot_object]
# f, xmin(plt), xmax(plt)
# end
#
# # --------------------------------------------------------------------
# # 2 arguments
# # --------------------------------------------------------------------
#
#
# # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in)
@recipe function f(f::FuncOrFuncs, x)
@assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
x, f
end
#
# # --------------------------------------------------------------------
# # 3 arguments
# # --------------------------------------------------------------------
#
#
# # 3d line or scatter
@recipe function f(x::AVec, y::AVec, z::AVec)
# st = get(d, :seriestype, :none)
# if st == :scatter
# d[:seriestype] = :scatter3d
# elseif !is3d(st)
# d[:seriestype] = :path3d
# end
SliceIt, x, y, z
end
@recipe function f(x::AMat, y::AMat, z::AMat)
# st = get(d, :seriestype, :none)
# if size(x) == size(y) == size(z)
# if !is3d(st)
# seriestype := :path3d
# end
# end
SliceIt, x, y, z
end
#
# # surface-like... function
@recipe function f(x::AVec, y::AVec, zf::Function)
# x = X <: Number ? sort(x) : x
# y = Y <: Number ? sort(y) : y
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
end
#
# # surface-like... matrix grid
@recipe function f(x::AVec, y::AVec, z::AMat)
if !like_surface(get(d, :seriestype, :none))
d[:seriestype] = :contour
end
SliceIt, x, y, Surface(z)
end
#
#
# # --------------------------------------------------------------------
# # Parametric functions
# # --------------------------------------------------------------------
#
# # special handling... xmin/xmax with parametric function(s)
@recipe f(f::FuncOrFuncs, xmin::Number, xmax::Number) = linspace(xmin, xmax, 100), f
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
#
# # special handling... 3D parametric function(s)
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec)
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints = 200)
fx, fy, fz, linspace(umin, umax, numPoints)
end
#
#
# # --------------------------------------------------------------------
# # Lists of tuples and FixedSizeArrays
# # --------------------------------------------------------------------
#
# # if we get an unhandled tuple, just splat it in
@recipe f(tup::Tuple) = tup
#
# # (x,y) tuples
@recipe f{R1<:Number,R2<:Number}(xy::AVec{Tuple{R1,R2}}) = unzip(xy)
@recipe f{R1<:Number,R2<:Number}(xy::Tuple{R1,R2}) = [xy[1]], [xy[2]]
#
# # (x,y,z) tuples
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::AVec{Tuple{R1,R2,R3}}) = unzip(xyz)
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
#
# # 2D FixedSizeArrays
@recipe f{T<:Number}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = unzip(xy)
@recipe f{T<:Number}(xy::FixedSizeArrays.Vec{2,T}) = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f{T<:Number}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = unzip(xyz)
@recipe f{T<:Number}(xyz::FixedSizeArrays.Vec{3,T}) = [xyz[1]], [xyz[2]], [xyz[3]]
#
# # --------------------------------------------------------------------
# # handle grouping
# # --------------------------------------------------------------------
# @recipe function f(groupby::GroupBy, args...)
# for (i,glab) in enumerate(groupby.groupLabels)
# # create a new series, with the label of the group, and an idxfilter (to be applied in slice_and_dice)
# # TODO: use @series instead
# @show i, glab, groupby.groupIds[i]
# di = copy(d)
# get!(di, :label, string(glab))
# get!(di, :idxfilter, groupby.groupIds[i])
# push!(series_list, RecipeData(di, args))
# end
# nothing
# end
# split the group into 1 series per group, and set the label and idxfilter for each
@recipe function f(groupby::GroupBy, args...)
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
args
end
end
end

View File

@ -1,504 +0,0 @@
@nospecialize
"""
scatter(x,y)
scatter!(x,y)
Make a scatter plot of y vs x.
# Examples
```julia-repl
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
julia> scatter([(1,4),(2,5),(3,6)])
```
"""
@shorthands scatter
"""
bar(x,y)
bar!(x,y)
Make a bar plot of y vs x.
# Arguments
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Examples
```julia-repl
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
julia> bar([(1,4),(2,5),(3,6)])
```
"""
@shorthands bar
@shorthands barh
"""
histogram(x)
histogram!(x)
Plot a histogram.
# Arguments
- `x`: AbstractVector of values to be binned
- $(_document_argument("bins"))
- `weights`: Vector of weights for the values in `x`, for weighted bin counts
- $(_document_argument("normalize"))
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Example
```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,weights=weights([4,7,3,9,12,2,6]))
```
"""
@shorthands histogram
"""
barhist(x)
barhist!(x)
Make a histogram bar plot. See `histogram`.
"""
@shorthands barhist
"""
stephist(x)
stephist!(x)
Make a histogram step plot (bin counts are represented using horizontal lines
instead of bars). See `histogram`.
"""
@shorthands stephist
"""
scatterhist(x)
scatterhist!(x)
Make a histogram scatter plot (bin counts are represented using points
instead of bars). See `histogram`.
"""
@shorthands scatterhist
"""
histogram2d(x,y)
histogram2d!(x,y)
Plot a two-dimensional histogram.
# Arguments
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
its weight to the height of its bin.
# Example
```julia-repl
julia> histogram2d(randn(10_000),randn(10_000))
```
"""
@shorthands histogram2d
"""
density(x)
density!(x)
Make a line plot of a kernel density estimate of x.
# Arguments
- `x`: AbstractVector of samples for probability density estimation
# Example
```julia-repl
julia> using StatsPlots
julia> density(randn(100_000))
```
"""
@shorthands density
"""
heatmap(x,y,z)
heatmap!(x,y,z)
Plot a heatmap of the rectangular array `z`.
# Example
```julia-repl
julia> heatmap(randn(10,10))
```
"""
@shorthands heatmap
@shorthands plots_heatmap
"""
hexbin(x,y)
hexbin!(x,y)
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
with hexagonal bins)
# Example
```julia-repl
julia> hexbin(randn(10_000), randn(10_000))
```
"""
@shorthands hexbin
"""
sticks(x,y)
sticks!(x,y)
Draw a stick plot of y vs x.
# Example
```julia-repl
julia> sticks(1:10)
```
"""
@shorthands sticks
"""
hline(y)
hline!(y)
Draw horizontal lines at positions specified by the values in
the AbstractVector `y`
# Example
```julia-repl
julia> hline([-1,0,2])
```
"""
@shorthands hline
"""
vline(x)
vline!(x)
Draw vertical lines at positions specified by the values in
the AbstractVector `x`
# Example
```julia-repl
julia> vline([-1,0,2])
```
"""
@shorthands vline
"""
hspan(y)
Draw a rectangle between the horizontal line at position `y[1]`
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
then further rectangles are drawn between `y[3]` and `y[4]`,
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
last entry of `y` is ignored.
# Example
```julia-repl
julia> hspan(1:6)
```
"""
@shorthands hspan
"""
vspan(x)
Draw a rectangle between the vertical line at position `x[1]`
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
then further rectangles are drawn between `x[3]` and `x[4]`,
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
last entry of `x` is ignored.
# Example
```julia-repl
julia> vspan(1:6)
```
"""
@shorthands vspan
"""
ohlc(x,y::Vector{OHLC})
ohlc!(x,y::Vector{OHLC})
Make open-high-low-close plot. Each entry of y is represented by a vertical
segment extending from the low value to the high value, with short horizontal
segments on the left and right indicating the open and close values, respectively.
# Example
```julia-repl
julia> meanprices = cumsum(randn(100))
julia> y = OHLC[(p+rand(),p+1,p-1,p+rand()) for p in meanprices]
julia> ohlc(y)
```
"""
@shorthands ohlc
"""
contour(x,y,z)
contour!(x,y,z)
Draw contour lines of the `Surface` z.
# Arguments
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
# Example
```julia-repl
julia> x = y = range(-20, stop = 20, length = 100)
julia> contour(x, y, (x, y) -> x^2 + y^2)
```
"""
@shorthands contour
"An alias for `contour` with fill = true."
@shorthands contourf
@shorthands contour3d
"""
surface(x,y,z)
surface!(x,y,z)
Draw a 3D surface plot.
# Example
```julia-repl
julia> using LinearAlgebra
julia> x = y = range(-3, stop = 3, length = 100)
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
```
"""
@shorthands surface
"""
wireframe(x,y,z)
wireframe!(x,y,z)
Draw a 3D wireframe plot.
# Example
```julia-repl
julia> wireframe(1:10,1:10,randn(10,10))
```
"""
@shorthands wireframe
"""
path3d(x,y,z)
path3d!(x,y,z)
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
..., to `(x[end],y[end],z[end])`.
# Example
```julia-repl
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@shorthands path3d
"""
scatter3d(x,y,z)
scatter3d!(x,y,z)
Make a 3D scatter plot.
# Example
```julia-repl
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@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)
Make a box and whisker plot.
# Keyword arguments
- `notch`: Bool. Notch the box plot? (false)
- `whisker_range`: Real. Whiskers extend `whisker_range`*IQR below the first quartile
and above the third quartile. Values outside this range are shown as outliers (1.5)
- `outliers`: Bool. Show outliers? (true)
- `whisker_width`: Real or Symbol. Length of whiskers; the options are `:match` to match the box width, `:half`, or a number to indicate the total length. (:half)
# Example
```julia-repl
julia> using StatsPlots
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands boxplot
"""
violin(x,y,z)
violin!(x,y,z)
Make a violin plot.
# Example
```julia-repl
julia> violin(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands violin
"""
quiver(x,y,quiver=(u,v))
quiver!(x,y,quiver=(u,v))
Make a quiver (vector field) plot. The `i`th vector extends
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
# Example
```julia-repl
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
```
"""
@shorthands quiver
"""
curves(x,y)
curves!(x,y)
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
# Example
```julia-repl
julia> curves([1,2,3,4],[1,1,2,4])
```
"""
@shorthands curves
"Plot a pie diagram"
@shorthands pie
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple; kw...) = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple; kw...) = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple; kw...) = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin, xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin, ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin, zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...)
xticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} =
plot!(; xticks = (ticks, labels), kw...)
yticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} =
plot!(; yticks = (ticks, labels), kw...)
"""
annotate!(anns...)
Add annotations to an existing plot.
# Arguments
- `anns`: An `AbstractVector` of tuples of the form `(x,y,text)`. The `text` object
can be a `String`, `PlotText` PlotText (created with `text(args...)`),
or a tuple of arguments to `text` (e.g., `("Label", 8, :red, :top)`).
# Example
```julia-repl
julia> plot(1:10)
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
julia> annotate!([(4, 4, ("More text", 8, 45.0, :bottom, :red))])
```
"""
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::Tuple...; kw...) = plot!(; annotation = collect(anns), kw...)
annotate!(anns::AVec{<:Tuple}; kw...) = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
"Specify y axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
@doc """
abline!([plot,] a, b; kwargs...)
Adds ax+b... straight line over the current plot, without changing the axis limits
""" abline!
@doc """
areaplot([x,] y)
areaplot!([x,] y)
Draw a stacked area plot of the matrix y.
# Examples
```julia-repl
julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], fillalpha = [0.2 0.3 0.4])
```
""" areaplot
@doc """
lens!([plot,] x, y, inset = (sp_index, bbox(x1, x2, y1, y2)))
Magnify a region of a plot given by `x` and `y`.
`sp_index` is the index of the subplot and `x1`, `x2`, `y1` and `y2` should be between `0` and `1`.
""" lens!
@specialize

View File

@ -1,26 +1,22 @@
function Subplot(::T; parent = RootLayout()) where {T<:AbstractBackend}
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
Subplot{T}( Subplot{T}(
parent, parent,
Series[],
(20mm, 5mm, 2mm, 10mm), (20mm, 5mm, 2mm, 10mm),
defaultbox, defaultbox,
defaultbox, defaultbox,
DefaultsDict(KW(), _subplot_defaults), KW(),
nothing,
nothing, nothing,
nothing
) )
end end
"""
plotarea(subplot)
Return the bounding box of a subplot
"""
plotarea(sp::Subplot) = sp.plotarea plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox) plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
Base.size(sp::Subplot) = (1, 1)
Base.size(sp::Subplot) = (1,1)
Base.length(sp::Subplot) = 1 Base.length(sp::Subplot) = 1
Base.getindex(sp::Subplot, r::Int, c::Int) = sp Base.getindex(sp::Subplot, r::Int, c::Int) = sp
@ -32,32 +28,20 @@ bottompad(sp::Subplot) = sp.minpad[4]
get_subplot(plt::Plot, sp::Subplot) = sp get_subplot(plt::Plot, sp::Subplot) = sp
get_subplot(plt::Plot, i::Integer) = plt.subplots[i] get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
get_subplot(plt::Plot, k) = plt.spmap[k] get_subplot(plt::Plot, k) = plt.spmap[k]
get_subplot(series::Series) = series.plotattributes[:subplot] get_subplot(series::Series) = series.d[:subplot]
get_subplot_index(plt::Plot, idx::Integer) = Int(idx) get_subplot_index(plt::Plot, idx::Integer) = Int(idx)
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots) get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattributes[:subplot] === sp, sp.plt.series_list) series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
function should_add_to_legend(series::Series) function should_add_to_legend(series::Series)
series.plotattributes[:primary] && series.d[:primary] && series.d[:label] != "" &&
series.plotattributes[:label] != "" && !(series.d[:seriestype] in (
!( :hexbin,:histogram2d,:hline,:vline,
series.plotattributes[:seriestype] in ( :contour,:contourf,:contour3d,:surface,:wireframe,
:hexbin, :heatmap, :pie, :image
:bins2d, ))
:histogram2d,
:hline,
:vline,
:contour,
:contourf,
:contour3d,
:surface,
:wireframe,
:heatmap,
:image,
)
)
end end
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

View File

@ -1,137 +1,65 @@
"""
theme(s::Symbol)
Specify the colour theme for plots. const _invisible = RGBA(0,0,0,0)
"""
function theme(s::Symbol; kw...) const _themes = KW(
defaults = copy(PlotThemes._themes[s].defaults) :default => KW(
_theme(s, defaults; kw...) :bg => :white,
:bglegend => :match,
:bginside => :match,
:bgoutside => :match,
:fg => :auto,
:fglegend => :match,
:fggrid => :match,
:fgaxis => :match,
:fgtext => :match,
:fgborder => :match,
:fgguide => :match,
)
)
function add_theme(sym::Symbol, theme::KW)
_themes[sym] = theme
end end
function _theme(s::Symbol, defaults::AKW; kw...) # add a new theme, using an existing theme as the base
# Reset to defaults to overwrite active theme function add_theme(sym::Symbol;
reset_defaults() base = :default, # start with this theme
bg = _themes[base][:bg],
# Set the theme's gradient as default bglegend = _themes[base][:bglegend],
if haskey(defaults, :colorgradient) bginside = _themes[base][:bginside],
PlotUtils.default_cgrad(pop!(defaults, :colorgradient)) bgoutside = _themes[base][:bgoutside],
else fg = _themes[base][:fg],
PlotUtils.default_cgrad(:default) fglegend = _themes[base][:fglegend],
end fggrid = _themes[base][:fggrid],
fgaxis = _themes[base][:fgaxis],
# maybe overwrite the theme's gradient fgtext = _themes[base][:fgtext],
kw = KW(kw) fgborder = _themes[base][:fgborder],
if haskey(kw, :colorgradient) fgguide = _themes[base][:fgguide],
PlotUtils.default_cgrad(pop!(kw, :colorgradient)) kw...)
end _themes[sym] = merge(KW(
:bg => bg,
# Set the theme's defaults :bglegend => bglegend,
default(; defaults..., kw...) :bginside => bginside,
return :bgoutside => bgoutside,
:fg => fg,
:fglegend => fglegend,
:fggrid => fggrid,
:fgaxis => fgaxis,
:fgtext => fgtext,
:fgborder => fgborder,
:fgguide => fgguide,
), KW(kw))
end end
@deprecate set_theme(s) theme(s) add_theme(:ggplot2,
bglegend = _invisible,
bginside = :lightgray,
fg = :white,
fglegend = _invisible,
fgtext = :gray,
fgguide = :black
)
@userplot ShowTheme function set_theme(sym::Symbol)
default(; _themes[sym]...)
_color_functions =
KW(:protanopic => protanopic, :deuteranopic => deuteranopic, :tritanopic => tritanopic)
_get_showtheme_args(thm::Symbol) = thm, identity
_get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func, identity)
@recipe function showtheme(st::ShowTheme)
thm, cfunc = _get_showtheme_args(st.args...)
defaults = PlotThemes._themes[thm].defaults
# get the gradient
gradient_colors = color_list(cgrad(get(defaults, :colorgradient, :default)))
colorgradient = cgrad(cfunc.(RGB.(gradient_colors)))
# get the palette
cp = color_list(palette(get(defaults, :palette, :default)))
cp = cfunc.(RGB.(cp))
# apply the theme
for k in keys(defaults)
k in (:colorgradient, :palette) && continue
def = defaults[k]
arg = get(_keyAliases, k, k)
plotattributes[arg] = if typeof(def) <: Colorant
cfunc(RGB(def))
elseif eltype(def) <: Colorant
cfunc.(RGB.(def))
elseif occursin("color", string(arg))
cfunc.(RGB.(plot_color.(def)))
else
def
end
end
Random.seed!(1)
label := ""
colorbar := false
layout := (2, 3)
for j in 1:4
@series begin
subplot := 1
color_palette := cp
seriestype := :path
cumsum(randn(50))
end
@series begin
subplot := 2
seriestype := :scatter
color_palette := cp
marker := (:circle, :diamond, :star5, :square)[j]
randn(10), randn(10)
end
end
@series begin
subplot := 3
seriestype := :histogram
color_palette := cp
randn(1000) .+ (0:2:4)'
end
f(r) = sin(r) / r
_norm(x, y) = norm([x, y])
x = y = range(-3π, stop = 3π, length = 30)
z = f.(_norm.(x, y'))
wi = 2:3:30
@series begin
subplot := 4
seriestype := :heatmap
seriescolor := colorgradient
xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
x, y, z
end
@series begin
subplot := 5
seriestype := :surface
seriescolor := colorgradient
xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
x, y, z
end
n = 100
ts = range(0, stop = 10π, length = n)
x = (0.1ts) .* cos.(ts)
y = (0.1ts) .* sin.(ts)
z = 1:n
@series begin
subplot := 6
seriescolor := colorgradient
linewidth := 3
line_z := z
x, y, z
end
end end

View File

@ -2,57 +2,47 @@
# TODO: I declare lots of types here because of the lacking ability to do forward declarations in current Julia # TODO: I declare lots of types here because of the lacking ability to do forward declarations in current Julia
# I should move these to the relevant files when something like "extern" is implemented # I should move these to the relevant files when something like "extern" is implemented
const AVec = AbstractVector typealias AVec AbstractVector
const AMat = AbstractMatrix typealias AMat AbstractMatrix
const KW = Dict{Symbol,Any} typealias KW Dict{Symbol,Any}
const AKW = AbstractDict{Symbol,Any}
const TicksArgs =
Union{AVec{T},Tuple{AVec{T},AVec{S}},Symbol} where {T<:Real,S<:AbstractString}
struct PlotsDisplay <: AbstractDisplay end immutable PlotsDisplay <: Display end
abstract AbstractBackend
abstract AbstractPlot{T<:AbstractBackend}
abstract AbstractLayout
# ----------------------------------------------------------- # -----------------------------------------------------------
struct InputWrapper{T} immutable InputWrapper{T}
obj::T obj::T
end end
wrap(obj::T) where {T} = InputWrapper{T}(obj) wrap{T}(obj::T) = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
mutable struct Series
plotattributes::DefaultsDict
end
attr(series::Series, k::Symbol) = series.plotattributes[k]
attr!(series::Series, v, k::Symbol) = (series.plotattributes[k] = v)
# ----------------------------------------------------------- # -----------------------------------------------------------
# a single subplot # a single subplot
mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout type Subplot{T<:AbstractBackend} <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
series_list::Vector{Series} # arguments for each series
minpad::Tuple # leftpad, toppad, rightpad, bottompad minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox # the canvas area which is available to this subplot bbox::BoundingBox # the canvas area which is available to this subplot
plotarea::BoundingBox # the part where the data goes plotarea::BoundingBox # the part where the data goes
attr::DefaultsDict # args specific to this subplot attr::KW # args specific to this subplot
o # can store backend-specific data... like a pyplot ax o # can store backend-specific data... like a pyplot ax
plt # the enclosing Plot object (can't give it a type because of no forward declarations) plt # the enclosing Plot object (can't give it a type because of no forward declarations)
end end
Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
# ----------------------------------------------------------- # -----------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place # simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
mutable struct Axis type Axis
sps::Vector{Subplot} sp::Subplot
plotattributes::DefaultsDict d::KW
end end
mutable struct Extrema type Extrema
emin::Float64 emin::Float64
emax::Float64 emax::Float64
end end
@ -60,14 +50,24 @@ Extrema() = Extrema(Inf, -Inf)
# ----------------------------------------------------------- # -----------------------------------------------------------
const SubplotMap = Dict{Any,Subplot} typealias SubplotMap Dict{Any, Subplot}
# ----------------------------------------------------------- # -----------------------------------------------------------
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T} type Series
d::KW
end
attr(series::Series, k::Symbol) = series.d[k]
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
# -----------------------------------------------------------
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type backend::T # the backend type
n::Int # number of series n::Int # number of series
attr::DefaultsDict # arguments for the whole plot attr::KW # arguments for the whole plot
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
series_list::Vector{Series} # arguments for each series series_list::Vector{Series} # arguments for each series
o # the backend's plot object o # the backend's plot object
subplots::Vector{Subplot} subplots::Vector{Subplot}
@ -78,35 +78,18 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
end end
function Plot() function Plot()
Plot( Plot(backend(), 0, KW(), KW(), Series[], nothing,
backend(), Subplot[], SubplotMap(), EmptyLayout(),
0, Subplot[], false)
DefaultsDict(KW(), _plot_defaults),
Series[],
nothing,
Subplot[],
SubplotMap(),
EmptyLayout(),
Subplot[],
false,
)
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i] Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
Base.length(plt::Plot) = length(plt.subplots) Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
Base.lastindex(plt::Plot) = length(plt)
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r, c]
Base.size(plt::Plot) = size(plt.layout)
Base.size(plt::Plot, i::Integer) = size(plt.layout)[i]
Base.ndims(plt::Plot) = 2
# attr(plt::Plot, k::Symbol) = plt.attr[k] # attr(plt::Plot, k::Symbol) = plt.attr[k]
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v) # attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i] Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
Base.lastindex(sp::Subplot) = length(series_list(sp))
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

1
test/.gitignore vendored
View File

@ -1 +0,0 @@
reference_images

18
test/REQUIRE Normal file
View File

@ -0,0 +1,18 @@
julia 0.4
RecipesBase
PlotUtils
StatPlots
Reexport
Measures
Showoff
FactCheck
Images
ImageMagick
@osx QuartzImageIO
GR
DataFrames
RDatasets
VisualRegressionTests
UnicodePlots
Glob

View File

@ -1,71 +1,105 @@
import Plots._current_plots_version
# replace `f(args...)` with `f(rng, args...)` for `f ∈ (rand, randn)` using VisualRegressionTests
function replace_rand!(ex) end # using ExamplePlots
function replace_rand!(ex::Expr)
for arg in ex.args import DataFrames, RDatasets
replace_rand!(arg)
end # don't let pyplot use a gui... it'll crash
if ex.head === :call && ex.args[1] (:rand, :randn, :(Plots.fakedata)) # note: Agg will set gui -> :none in PyPlot
pushfirst!(ex.args, ex.args[1]) ENV["MPLBACKEND"] = "Agg"
ex.args[2] = :rng try
end @eval import PyPlot
end info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
function fix_rand!(ex)
replace_rand!(ex)
end end
function image_comparison_tests(
pkg::Symbol, using Plots
idx::Int; using StatPlots
debug = false, using FactCheck
popup = !is_ci(), using Glob
sigma = [1, 1],
tol = 1e-2, default(size=(500,300))
)
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.8.1"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
Plots._debugMode.on = debug Plots._debugMode.on = debug
example = Plots._examples[idx] example = Plots._examples[idx]
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))
# ensure consistent results
srand(1234)
# reference image directory setup
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
refdir = Pkg.dir("PlotReferenceImages", "Plots", string(pkg))
fn = "ref$idx.png" fn = "ref$idx.png"
reffn = reference_file(pkg, idx, _current_plots_version)
newfn = joinpath(reference_path(pkg, _current_plots_version), fn) # firgure out version info
@debug example.exprs G = glob(joinpath(relpath(refdir), "*"))
# @show refdir fn G
slash = (@windows ? "\\" : "/")
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
versions = reverse(sort(versions))
versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions
newdir = joinpath(refdir, string(_current_plots_version))
newfn = joinpath(newdir, fn)
# figure out which reference file we should compare to, by finding the highest versioned file
reffn = nothing
for v in versions
tmpfn = joinpath(refdir, string(v), fn)
if isfile(tmpfn)
reffn = tmpfn
break
end
end
# now we have the fn (if any)... do the comparison
# @show reffn
if reffn == nothing
reffn = newfn
end
# @show reffn
# return
# test function # test function
func = (fn, idx) -> begin func = (fn, idx) -> begin
eval(:(rng = StableRNG(PLOTS_SEED))) map(eval, example.exprs)
for the_expr in example.exprs
expr = Expr(:block)
push!(expr.args, the_expr)
fix_rand!(expr)
eval(expr)
end
png(fn) png(fn)
end end
# try
# run(`mkdir -p $newdir`)
# catch err
# display(err)
# end
# # reffn = joinpath(refdir, "ref$idx.png")
# 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, eps=eps, newfn = newfn)
end end
function image_comparison_facts( function image_comparison_facts(pkg::Symbol;
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, eps = 1e-2) # acceptable error (percent)
) # acceptable error (percent)
for i in 1:length(Plots._examples) for i in 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) |> @fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
success == true
end end
end end
end end

View File

@ -5,11 +5,9 @@ set -ex
sudo apt-get -qq update sudo apt-get -qq update
# sudo apt-get install -y wkhtmltopdf # sudo apt-get install -y wkhtmltopdf
sudo apt-get install -y xfonts-75dpi xfonts-base sudo apt-get install -y xfonts-75dpi
wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
wkhtmltoimage http://www.google.com test.png wkhtmltoimage http://www.google.com test.png
ls ls

View File

@ -1,60 +0,0 @@
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,483 +1,91 @@
using Plots: guidefont, series_annotations, PLOTS_SEED module PlotsTests
using VisualRegressionTests
using RecipesBase
using StableRNGs
using TestImages
using LibGit2
using Random
using FileIO
using Plots
using Dates
using JSON
using Test
using Gtk
import GeometryBasics
import ImageMagick
@testset "Infrastructure" begin
@test_nowarn JSON.Parser.parse(
String(read(joinpath(dirname(pathof(Plots)), "..", ".zenodo.json"))),
)
end
@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 "Utils" begin
zipped = (
[(1, 2)],
[("a", "b")],
[(1, "a"), (2, "b")],
[(1, 2), (3, 4)],
[(1, 2, 3), (3, 4, 5)],
[(1, 2, 3, 4), (3, 4, 5, 6)],
[(1, 2.0), (missing, missing)],
[(1, missing), (missing, "a")],
[(missing, missing)],
[(missing, missing, missing), ("a", "b", "c")],
)
for z in zipped
@test isequal(collect(zip(Plots.RecipesPipeline.unzip(z)...)), z)
@test isequal(
collect(zip(Plots.RecipesPipeline.unzip(GeometryBasics.Point.(z))...)),
z,
)
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)
@test (==)(
Plots.texmath2unicode(
raw"Equation $y = \alpha \cdot x + \beta$ and eqn $y = \sin(x)^2$",
),
raw"Equation y = α ⋅ x + β and eqn y = sin(x)²",
)
@test Plots.isvector([1, 2])
@test !Plots.isvector(nothing)
@test Plots.ismatrix([1 2; 3 4])
@test !Plots.ismatrix(nothing)
@test Plots.isscalar(1.0)
@test !Plots.isscalar(nothing)
@test Plots.tovec([]) isa AbstractVector
@test Plots.tovec(nothing) isa AbstractVector
@test Plots.anynan(1, 3, (1, NaN, 3))
@test Plots.allnan(1, 2, (NaN, NaN, 1))
@test Plots.makevec([]) isa AbstractVector
@test Plots.makevec(1) isa AbstractVector
@test Plots.maketuple(1) == (1, 1)
@test Plots.maketuple((1, 1)) == (1, 1)
@test Plots.ok(1, 2)
@test !Plots.ok(1, 2, NaN)
@test Plots.ok((1, 2, 3))
@test !Plots.ok((1, 2, NaN))
@test Plots.nansplit([1, 2, NaN, 3, 4]) == [[1.0, 2.0], [3.0, 4.0]]
@test Plots.nanvcat([1, NaN]) |> length == 4
@test Plots.nop() === nothing
@test_throws ErrorException Plots.notimpl()
@test Plots.inch2px(1) isa AbstractFloat
@test Plots.px2inch(1) isa AbstractFloat
@test Plots.inch2mm(1) isa AbstractFloat
@test Plots.mm2inch(1) isa AbstractFloat
@test Plots.px2mm(1) isa AbstractFloat
@test Plots.mm2px(1) isa AbstractFloat
p = plot()
@test xlims() isa Tuple
@test ylims() isa Tuple
@test zlims() isa Tuple
Plots.makekw(foo = 1, bar = 2) isa Dict
@test_throws ErrorException Plots.inline()
@test_throws ErrorException Plots._do_plot_show(plot(), :inline)
@test_throws ErrorException Plots.dumpcallstack()
Plots.debugplots(true)
Plots.debugplots(false)
Plots.debugshow(devnull, nothing)
Plots.debugshow(devnull, [1])
p = plot(1)
push!(p, 1.5)
push!(p, 1, 1.5)
# append!(p, [1., 2.])
append!(p, 1, 2.5, 2.5)
push!(p, (1.5, 2.5))
push!(p, 1, (1.5, 2.5))
append!(p, (1.5, 2.5))
append!(p, 1, (1.5, 2.5))
p = plot([1, 2, 3], [4, 5, 6])
@test Plots.xmin(p) == 1
@test Plots.xmax(p) == 3
@test Plots.ignorenan_extrema(p) == (1, 3)
@test Plots.get_attr_symbol(:x, "lims") == :xlims
@test Plots.get_attr_symbol(:x, :lims) == :xlims
@testset "NaN-separated Segments" begin
segments(args...) = collect(iter_segments(args...))
nan10 = fill(NaN, 10)
@test segments(11:20) == [1:10]
@test segments([NaN]) == []
@test segments(nan10) == []
@test segments([nan10; 1:5]) == [11:15]
@test segments([1:5; nan10]) == [1:5]
@test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30]
@test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10]
@test segments([nan10; 1:15], [1:15; nan10]) == [11:15]
end
end
@testset "Axes" begin
p = plot()
axis = p.subplots[1][:xaxis]
@test typeof(axis) == Plots.Axis
@test Plots.discrete_value!(axis, "HI") == (0.5, 1)
@test Plots.discrete_value!(axis, :yo) == (1.5, 2)
@test Plots.ignorenan_extrema(axis) == (0.5, 1.5)
@test axis[:discrete_map] == Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i in 1:5])
Plots.discrete_value!(axis, ["x$i" for i in 0:2])
@test Plots.ignorenan_extrema(axis) == (0.5, 7.5)
end
@testset "NoFail" begin
# ensure backend with tested display
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
dsp = TextDisplay(IOContext(IOBuffer(), :color => true))
@testset "plot" begin
for plt in [
histogram([1, 0, 0, 0, 0, 0]),
plot([missing]),
plot([missing, missing]),
plot(fill(missing, 10)),
plot([missing; 1:4]),
plot([fill(missing, 10); 1:4]),
plot([1 1; 1 missing]),
plot(["a" "b"; missing "d"], [1 2; 3 4]),
]
display(dsp, plt)
end
@test_nowarn plot(x -> x^2, 0, 2)
end
@testset "bar" begin
p = bar([3, 2, 1], [1, 2, 3])
@test p isa Plots.Plot
@test display(dsp, p) isa Nothing
end
@testset "gui" begin
open(tempname(), "w") do io
redirect_stdout(io) do
gui(plot())
end
end
end
end
@testset "Coverage" begin
@testset "themes" begin
p = showtheme(:dark)
@test p isa Plots.Plot
end
@testset "plotattr" begin
tmp = tempname()
open(tmp, "w") do io
redirect_stdout(io) do
plotattr("seriestype")
plotattr(:Plot)
plotattr()
end
end
str = join(readlines(tmp), "")
@test occursin("seriestype", str)
@test occursin("Plot attributes", str)
end
@testset "legend" begin
@test isa(
Plots.legend_pos_from_angle(20, 0.0, 0.5, 1.0, 0.0, 0.5, 1.0),
NTuple{2,<:AbstractFloat},
)
@test Plots.legend_anchor_index(-1) == 1
@test Plots.legend_anchor_index(+0) == 2
@test Plots.legend_anchor_index(+1) == 3
@test Plots.legend_angle(:foo_bar) == (45, :inner)
@test Plots.legend_angle(20.0) ==
Plots.legend_angle((20.0, :inner)) ==
(20.0, :inner)
@test Plots.legend_angle((20.0, 10.0)) == (20.0, 10.0)
end
end
@testset "Output" begin
@test Plots.defaultOutputFormat(plot()) == "png"
@test Plots.addExtension("foo", "bar") == "foo.bar"
fn = tempname()
gr()
let p = plot()
Plots.png(p, fn)
Plots.png(fn)
savefig(p, "$fn.png")
savefig("$fn.png")
Plots.pdf(p, fn)
Plots.pdf(fn)
savefig(p, "$fn.pdf")
savefig("$fn.pdf")
Plots.ps(p, fn)
Plots.ps(fn)
savefig(p, "$fn.ps")
savefig("$fn.ps")
Plots.svg(p, fn)
Plots.svg(fn)
savefig(p, "$fn.svg")
savefig("$fn.svg")
end
if Sys.islinux()
pgfplotsx()
let p = plot()
Plots.tex(p, fn)
Plots.tex(fn)
savefig(p, "$fn.tex")
savefig("$fn.tex")
end
end
unicodeplots()
let p = plot()
Plots.txt(p, fn)
Plots.txt(fn)
savefig(p, "$fn.txt")
savefig("$fn.txt")
end
plotlyjs()
let p = plot()
Plots.html(p, fn)
Plots.html(fn)
savefig(p, "$fn.html")
savefig("$fn.html")
if Sys.islinux()
Plots.eps(p, fn)
Plots.eps(fn)
savefig(p, "$fn.eps")
savefig("$fn.eps")
end
end
@test_throws ErrorException savefig("$fn.foo")
end
gr() # reset to default backend
for fn in (
"test_args.jl",
"test_defaults.jl",
"test_pipeline.jl",
"test_axes.jl",
"test_layouts.jl",
"test_contours.jl",
"test_axis_letter.jl",
"test_components.jl",
"test_shorthands.jl",
"integration_dates.jl",
"test_recipes.jl",
"test_hdf5plots.jl",
"test_pgfplotsx.jl",
"test_plotly.jl",
"test_animations.jl",
)
@testset "$fn" begin
include(fn)
end
end
reference_dir(args...) =
joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
function reference_file(backend, i, version)
refdir = reference_dir("Plots", string(backend))
fn = "ref$i.png"
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
reffn = joinpath(refdir, string(version), fn)
for v in versions
tmpfn = joinpath(refdir, string(v), fn)
if isfile(tmpfn)
reffn = tmpfn
break
end
end
return reffn
end
reference_path(backend, version) = reference_dir("Plots", string(backend), string(version))
if !isdir(reference_dir())
mkpath(reference_dir())
LibGit2.clone(
"https://github.com/JuliaPlots/PlotReferenceImages.jl.git",
reference_dir(),
)
end
include("imgcomp.jl") include("imgcomp.jl")
Random.seed!(PLOTS_SEED)
default(show = false, reuse = true) # don't actually show the plots # don't actually show the plots
srand(1234)
default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
is_ci() = get(ENV, "CI", "false") == "true" # facts("Gadfly") do
const PLOTS_IMG_TOL = parse( # @fact gadfly() --> Plots.GadflyBackend()
Float64, # @fact backend() --> Plots.GadflyBackend()
get(ENV, "PLOTS_IMG_TOL", is_ci() ? Sys.iswindows() ? "2e-4" : "1e-4" : "1e-5"),
)
## Uncomment the following lines to update reference images for different backends
# @testset "GR" begin
# image_comparison_facts(:gr, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:gr])
# end
# #
# plotly() # @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
# @testset "Plotly" begin # @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
# image_comparison_facts(:plotly, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:plotlyjs]) # @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
# end # @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
# #
# pyplot() # image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# @testset "PyPlot" begin
# image_comparison_facts(:pyplot, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pyplot])
# end
#
# pgfplotsx()
# @testset "PGFPlotsX" begin
# image_comparison_facts(:pgfplotsx, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
# end # end
## facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
@testset "Examples" begin image_comparison_facts(:pyplot, skip=[], eps=img_eps)
if Sys.islinux()
backends = (
:unicodeplots,
:pgfplotsx,
:inspectdr,
:plotlyjs,
:gaston,
# :pyplot, # FIXME: fails with system matplotlib
)
only = setdiff(
1:length(Plots._examples),
(Plots._backend_skips[be] for be in backends)...,
)
for be in backends
@info be
for (i, p) in Plots.test_examples(be, only = only, disp = false)
fn = tempname() * ".png"
png(p, fn)
@test filesize(fn) > 1_000
end
end
end
end end
@testset "Backends" begin facts("GR") do
@testset "UnicodePlots" begin @fact gr() --> Plots.GRBackend()
@test unicodeplots() == Plots.UnicodePlotsBackend() @fact backend() --> Plots.GRBackend()
@test backend() == Plots.UnicodePlotsBackend()
io = IOContext(IOBuffer(), :color => true) # @linux_only image_comparison_facts(:gr, skip=[], eps=img_eps)
end
facts("Plotly") do
@fact plotly() --> Plots.PlotlyBackend()
@fact backend() --> Plots.PlotlyBackend()
# # until png generation is reliable on OSX, just test on linux
# @linux_only image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
end
# facts("Immerse") do
# @fact immerse() --> Plots.ImmerseBackend()
# @fact backend() --> Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
# end
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
# end
facts("UnicodePlots") do
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
@fact backend() --> Plots.UnicodePlotsBackend()
# lets just make sure it runs without error # lets just make sure it runs without error
p = plot(rand(10)) @fact isa(plot(rand(10)), Plot) --> true
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = bar(randn(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([1, 2], [3, 4])
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
hline!(p, [3.1])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot((plot(i) for i in 1:4)..., layout = (2, 2))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
end
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
end
end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test p isa Plots.Plot
@test_broken display(p) isa Nothing
end
end end
facts("Axes") do
p = plot()
axis = p.subplots[1][:xaxis]
@fact typeof(axis) --> Axis
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
@fact extrema(axis) --> (0.5,1.5)
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i=1:5])
Plots.discrete_value!(axis, ["x$i" for i=0:2])
@fact extrema(axis) --> (0.5, 7.5)
end
FactCheck.exitstatus()
end # module

36
test/snoop.jl Normal file
View File

@ -0,0 +1,36 @@
import SnoopCompile
### Log the compiles
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
# include(Pkg.dir("Plots", "test","runtests.jl"))
# end
# ----------------------------------------------------------
### Parse the compiles and generate precompilation scripts
# This can be run repeatedly to tweak the scripts
# IMPORTANT: we must have the module(s) defined for the parcelation
# step, otherwise we will get no precompiles for the Plots module
using Plots
data = SnoopCompile.read("/tmp/plots_compiles.csv")
# The Plots tests are run inside a module PlotsTest, so all
# the precompiles get credited to PlotsTest. Credit them to Plots instead.
subst = Dict("PlotsTests"=>"Plots")
# Blacklist helps fix problems:
# - MIME uses type-parameters with symbols like :image/png, which is
# not parseable
blacklist = ["MIME"]
# Use these two lines if you want to create precompile functions for
# individual packages
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
SnoopCompile.write("/tmp/precompile", pc)
pdir = Pkg.dir("Plots")
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)

View File

@ -1,61 +0,0 @@
@testset "Empty anim" begin
anim = @animate for i in []
end
@test_throws ArgumentError gif(anim)
end
@userplot CirclePlot
@recipe function f(cp::CirclePlot)
x, y, i = cp.args
n = length(x)
inds = circshift(1:n, 1 - i)
linewidth --> range(0, 10, length = n)
seriesalpha --> range(0, 1, length = n)
aspect_ratio --> 1
label --> false
x[inds], y[inds]
end
@testset "Circle plot" begin
n = 10
t = range(0, 2π, length = n)
x = sin.(t)
y = cos.(t)
anim = @animate for i in 1:n
circleplot(x, y, i)
end
@test filesize(gif(anim).filename) > 10_000
@test filesize(mov(anim).filename) > 10_000
@test filesize(mp4(anim).filename) > 10_000
@test filesize(webm(anim).filename) > 10_000
@gif for i in 1:n
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end every 5
end
@testset "html" begin
p = plot([sin, cos], zeros(0), leg = false, xlims = (0, 2π), ylims = (-1, 1))
anim = Animation()
for x in range(0, stop = 2π, length = 10)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
agif = gif(anim)
html = tempname() * ".html"
open(html, "w") do io
show(io, MIME("text/html"), agif)
end
@test filesize(html) > 10_000
@test showable(MIME("image/gif"), agif)
agif = mp4(anim)
html = tempname() * ".html"
open(html, "w") do io
show(io, MIME("text/html"), agif)
end
@test filesize(html) > 10_000
end

View File

@ -1,27 +0,0 @@
using Plots, Test
@testset "Series Attributes" begin
pl = plot([[1, 2, 3], [2, 3, 4]], lw = 5)
@test hline!(deepcopy(pl), [1.75])[1].series_list[3][:label] ==
hline!(deepcopy(pl), [1.75], z_order = :front)[1].series_list[3][:label] ==
"y3"
@test hline!(deepcopy(pl), [1.75], z_order = :back)[1].series_list[1][:label] == "y3"
@test hline!(deepcopy(pl), [1.75], z_order = 2)[1].series_list[2][:label] == "y3"
end
@testset "Axis Attributes" begin
pl = @test_nowarn plot(; tickfont = font(10, "Times"))
for axis in (:xaxis, :yaxis, :zaxis)
@test pl[1][axis][:tickfontsize] == 10
@test pl[1][axis][:tickfontfamily] == "Times"
end
end
@testset "Permute recipes" begin
pl = bar(["a", "b", "c"], [1, 2, 3])
ppl = bar(["a", "b", "c"], [1, 2, 3], permute = (:x, :y))
@test xticks(ppl) == yticks(pl)
@test yticks(ppl) == xticks(pl)
@test filter(isfinite, pl[1][1][:x]) == filter(isfinite, ppl[1][1][:y])
@test filter(isfinite, pl[1][1][:y]) == filter(isfinite, ppl[1][1][:x])
end

View File

@ -1,122 +0,0 @@
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
@testset "axis-aliases" begin
@test haskey(Plots._keyAliases, :xguideposition)
@test haskey(Plots._keyAliases, :x_guide_position)
@test !haskey(Plots._keyAliases, :xguide_position)
p = plot(1:2, xl = "x label")
@test p[1][:xaxis][:guide] === "x label"
p = plot(1:2, xrange = (0, 3))
@test xlims(p) === (0, 3)
p = plot(1:2, xtick = [1.25, 1.5, 1.75])
@test p[1][:xaxis][:ticks] == [1.25, 1.5, 1.75]
p = plot(1:2, xlabelfontsize = 4)
@test p[1][:xaxis][:guidefontsize] == 4
p = plot(1:2, xgα = 0.07)
@test p[1][:xaxis][:gridalpha] 0.07
p = plot(1:2, xgridls = :dashdot)
@test p[1][:xaxis][:gridstyle] === :dashdot
p = plot(1:2, xgridcolor = :red)
@test p[1][:xaxis][:foreground_color_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
p = plot(1:2, xminorgridcolor = :red)
@test p[1][:xaxis][:foreground_color_minor_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
p = plot(1:2, xgrid_lw = 0.01)
@test p[1][:xaxis][:gridlinewidth] 0.01
p = plot(1:2, xminorgrid_lw = 0.01)
@test p[1][:xaxis][:minorgridlinewidth] 0.01
p = plot(1:2, xtickor = :out)
@test p[1][:xaxis][:tick_direction] === :out
end
@testset "aliases" begin
compare(p::Plots.Plot, s::Symbol, val, op) =
op(p[1][:xaxis][s], val) && op(p[1][:yaxis][s], val) && op(p[1][:zaxis][s], val)
p = plot(1:2, guide = "all labels")
@test compare(p, :guide, "all labels", ===)
p = plot(1:2, label = "test")
@test compare(p, :guide, "", ===)
p = plot(1:2, lim = (0, 3))
@test xlims(p) === ylims(p) === zlims(p) === (0, 3)
p = plot(1:2, tick = [1.25, 1.5, 1.75])
@test compare(p, :ticks, [1.25, 1.5, 1.75], ==)
p = plot(1:2, labelfontsize = 4)
@test compare(p, :guidefontsize, 4, ==)
p = plot(1:2, gα = 0.07)
@test compare(p, :gridalpha, 0.07, )
p = plot(1:2, gridls = :dashdot)
@test compare(p, :gridstyle, :dashdot, ===)
p = plot(1:2, gridcolor = :red)
@test compare(p, :foreground_color_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
p = plot(1:2, minorgridcolor = :red)
@test compare(p, :foreground_color_minor_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
p = plot(1:2, grid_lw = 0.01)
@test compare(p, :gridlinewidth, 0.01, )
p = plot(1:2, minorgrid_lw = 0.01)
@test compare(p, :minorgridlinewidth, 0.01, )
p = plot(1:2, tickor = :out)
@test compare(p, :tick_direction, :out, ===)
end

View File

@ -1,28 +0,0 @@
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

View File

@ -1,221 +0,0 @@
using Plots, Test
@testset "Shapes" begin
@testset "Type" begin
square = Shape([(0, 0.0), (1, 0.0), (1, 1.0), (0, 1.0)])
@test Plots.get_xs(square) == [0, 1, 1, 0]
@test Plots.get_ys(square) == [0, 0, 1, 1]
@test Plots.vertices(square) == [(0, 0), (1, 0), (1, 1), (0, 1)]
@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 in 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
@testset "Misc" begin
@test Plots.weave([1, 3], [2, 4]) == collect(1:4)
@test Plots.makeshape(3) isa Plots.Shape
@test Plots.makestar(3) isa Plots.Shape
@test Plots.makecross() isa Plots.Shape
@test Plots.makearrowhead(10.0) isa Plots.Shape
@test Plots.rotate(1.0, 2.0, 5.0, (0, 0)) isa Tuple
star = Plots.makestar(3)
star_scaled = Plots.scale(star, 0.5)
Plots.scale!(star, 0.5)
@test Plots.get_xs(star) == Plots.get_xs(star_scaled)
@test Plots.get_ys(star) == Plots.get_ys(star_scaled)
@test Plots.extrema_plus_buffer([1, 2], 0.1) == (0.9, 2.1)
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 "Text" begin
t = Plots.PlotText("foo")
f = Plots.font()
@test Plots.PlotText(nothing).str == "nothing"
@test length(t) == 3
@test text(t).str == "foo"
@test text(t, f).str == "foo"
@test text("bar", f).str == "bar"
@test text(true).str == "true"
end
@testset "Annotations" begin
ann = Plots.series_annotations(missing)
@test Plots.series_annotations(["1" "2"; "3" "4"]) isa AbstractMatrix
@test Plots.series_annotations(10).strs[1].str == "10"
@test Plots.series_annotations(nothing) === nothing
@test Plots.series_annotations(ann) == ann
@test Plots.annotations(["1" "2"; "3" "4"]) isa AbstractMatrix
@test Plots.annotations(ann) == ann
@test Plots.annotations([ann]) == [ann]
@test Plots.annotations(nothing) == []
t = Plots.text("foo")
sp = plot(1)[1]
@test Plots.locate_annotation(sp, 1, 2, t) == (1, 2, t)
@test Plots.locate_annotation(sp, 1, 2, 3, t) == (1, 2, 3, t)
@test Plots.locate_annotation(sp, (0.1, 0.2), t) isa Tuple
@test Plots.locate_annotation(sp, (0.1, 0.2, 0.3), t) isa Tuple
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, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)])
@test_logs (:warn, "Unused SeriesAnnotations arg: triangle (Symbol)") begin
p = plot(
[1, 2, 3],
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 only(sa.strs).str == "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"]]),
)
for i in 1:5
@test only(spl.series_list[i].plotattributes[:series_annotations].strs).str ==
"1/$i"
end
p = plot([1, 2], annotations = (1.5, 2, text("foo", :left)))
x, y, txt = only(p.subplots[end][:annotations])
@test (x, y) == (1.5, 2)
@test txt.str == "foo"
p = plot([1, 2], annotations = ((0.1, 0.5), :auto))
pos, txt = only(p.subplots[end][:annotations])
@test pos == (0.1, 0.5)
@test txt.str == "(a)"
end
@testset "Bezier" begin
curve = Plots.BezierCurve([Plots.P2(0.0, 0.0), Plots.P2(0.5, 1.0), Plots.P2(1.0, 0.0)])
@test curve(0.75) == Plots.P2(0.75, 0.375)
@test length(coords(curve, 10)) == 10
end

View File

@ -1,68 +0,0 @@
using Plots, Test
import RecipesPipeline
@testset "Contours" begin
@testset "check_contour_levels" begin
@test Plots.check_contour_levels(2) === nothing
@test Plots.check_contour_levels(-1.0:0.2:10.0) === nothing
@test Plots.check_contour_levels([-100, -2, -1, 0, 1, 2, 100]) === nothing
@test_throws ArgumentError Plots.check_contour_levels(1.0)
@test_throws ArgumentError Plots.check_contour_levels((1, 2, 3))
@test_throws ArgumentError Plots.check_contour_levels(-3)
end
@testset "RecipesPipeline.preprocess_attributes!" begin
function equal_after_pipeline(kw)
kw = deepcopy(kw)
RecipesPipeline.preprocess_attributes!(kw)
kw == kw
end
@test equal_after_pipeline(KW(:levels => 1))
@test equal_after_pipeline(KW(:levels => 1:10))
@test equal_after_pipeline(KW(:levels => [1.0, 3.0, 5.0]))
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(
KW(:levels => 1.0),
)
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(
KW(:levels => (1, 2, 3)),
)
@test_throws ArgumentError RecipesPipeline.preprocess_attributes!(KW(:levels => -3))
end
@testset "contour[f]" begin
x = (-2π):0.1:(2π)
y = (-π):0.1:π
z = cos.(y) .* sin.(x')
@testset "Incorrect input" begin
@test_throws ArgumentError contour(x, y, z, levels = 1.0)
@test_throws ArgumentError contour(x, y, z, levels = (1, 2, 3))
@test_throws ArgumentError contour(x, y, z, levels = -3)
end
@testset "Default number" begin
@test contour(x, y, z)[1][1].plotattributes[:levels] ==
Plots._series_defaults[:levels]
end
@testset "Number" begin
@testset "$n contours" for n in (2, 5, 100)
p = contour(x, y, z, levels = n)
attr = p[1][1].plotattributes
@test attr[:seriestype] == :contour
@test attr[:levels] == n
end
end
@testset "Range" begin
levels = -1:0.5:1
@test contour(x, y, z, levels = levels)[1][1].plotattributes[:levels] == levels
end
@testset "Set of levels" begin
levels = [-1, 0.25, 0, 0.25, 1]
@test contour(x, y, z, levels = levels)[1][1].plotattributes[:levels] == levels
end
end
end

View File

@ -1,101 +0,0 @@
using Plots, Test, Plots.Colors
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 Plots.guidefont(pl[1][:xaxis]).family == "palantino"
end
empty!(PLOTS_DEFAULTS)
Plots.__init__()
@testset "default" begin
default(fillrange = 0)
@test Plots._series_defaults[:fillrange] == 0
pl = plot(1:5)
@test pl[1][1][:fillrange] == 0
default()
end
@testset "Legend defaults" begin
p = plot()
@test p[1][:legend_font_family] == "sans-serif"
@test p[1][:legend_font_pointsize] == 8
@test p[1][:legend_font_halign] == :hcenter
@test p[1][:legend_font_valign] == :vcenter
@test p[1][:legend_font_rotation] == 0.0
@test p[1][:legend_font_color] == RGB{Colors.N0f8}(0.0, 0.0, 0.0)
@test p[1][:legend_position] == :best
@test p[1][:legend_title] == nothing
@test p[1][:legend_title_font_family] == "sans-serif"
@test p[1][:legend_title_font_pointsize] == 11
@test p[1][:legend_title_font_halign] == :hcenter
@test p[1][:legend_title_font_valign] == :vcenter
@test p[1][:legend_title_font_rotation] == 0.0
@test p[1][:legend_title_font_color] == RGB{Colors.N0f8}(0.0, 0.0, 0.0)
@test p[1][:legend_background_color] == RGBA{Float64}(1.0, 1.0, 1.0, 1.0)
@test p[1][:legend_foreground_color] == RGB{Colors.N0f8}(0.0, 0.0, 0.0)
end # testset
@testset "Legend API" begin
p = plot(;
legendfontfamily = "serif",
legendfontsize = 12,
legendfonthalign = :left,
legendfontvalign = :top,
legendfontrotation = 1,
legendfontcolor = :red,
legend = :outertopleft,
legendtitle = "The legend",
legendtitlefontfamily = "helvetica",
legendtitlefontsize = 3,
legendtitlefonthalign = :right,
legendtitlefontvalign = :bottom,
legendtitlefontrotation = -5.2,
legendtitlefontcolor = :blue,
background_color_legend = :cyan,
foreground_color_legend = :green,
)
@test p[1][:legend_font_family] == "serif"
@test p[1][:legend_font_pointsize] == 12
@test p[1][:legend_font_halign] == :left
@test p[1][:legend_font_valign] == :top
@test p[1][:legend_font_rotation] == 1.0
@test p[1][:legend_font_color] == :red
@test p[1][:legend_position] == :outertopleft
@test p[1][:legend_title] == "The legend"
@test p[1][:legend_title_font_family] == "helvetica"
@test p[1][:legend_title_font_pointsize] == 3
@test p[1][:legend_title_font_halign] == :right
@test p[1][:legend_title_font_valign] == :bottom
@test p[1][:legend_title_font_rotation] == -5.2
@test p[1][:legend_title_font_color] == :blue
@test p[1][:legend_background_color] == RGBA{Float64}(0.0, 1.0, 1.0, 1.0)
@test p[1][:legend_foreground_color] == RGBA{Float64}(0.0, 0.5019607843137255, 0.0, 1.0)
#remember settings
plot(legend_font_pointsize = 20)
sp = plot!(label = "R")[1]
@test Plots.legendfont(sp).pointsize == 20
#setting whole font
sp = plot(
1:5,
legendfont = font(12),
legend_font_halign = :left,
foreground_color_subplot = :red,
)[1]
@test Plots.legendfont(sp).pointsize == 12
@test Plots.legendfont(sp).halign == :left
# match mechanism
@test sp[:legend_font_color] == sp[:foreground_color_subplot]
@test Plots.legendfont(sp).color == sp[:foreground_color_subplot]
# magic invocation
@test_nowarn sp = plot(; legendfont = 12)[1]
@test sp[:legend_font_pointsize] == 12
@test Plots.legendfont(sp).pointsize == 12
end # testset

View File

@ -1,20 +0,0 @@
using Plots, HDF5
@testset "HDF5_Plots" begin
fname = "tmpplotsave.hdf5"
hdf5()
x = 1:10
psrc = plot(x, x .* x) #Create some plot
Plots.hdf5plot_write(psrc, fname)
#Read back file:
gr() #Choose some fast backend likely to work in test environment.
pread = Plots.hdf5plot_read(fname)
#Make sure data made it through:
@test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x]
@test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y]
#display(pread) #Don't display. Regression env might not support
end #testset

Some files were not shown because too many files have changed in this diff Show More