Compare commits

..

1 Commits

Author SHA1 Message Date
BeastyBlacksmith 43adbdbc79 Update precompile_*.jl file 2020-11-16 09:17:40 +00:00
69 changed files with 4938 additions and 9654 deletions
-12
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
+1 -1
View File
@@ -28,5 +28,5 @@ inspectdr | | |
### Versions
Plots.jl version:
Backend version (`]st -m <backend(s)>`):
Backend version (`]st -m`):
Output of `versioninfo()`:
+7 -9
View File
@@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
version: # NOTE: the versions below should match those in your botconfig
- '1'
- '1.5'
os: # NOTE: should match the os setting of your botconfig
- ubuntu-latest
arch:
@@ -41,10 +41,10 @@ jobs:
# TESTCMD
- name: Default TESTCMD
run: echo "TESTCMD=julia" >> $GITHUB_ENV
run: echo ::set-env name=TESTCMD::"julia"
- name: Ubuntu TESTCMD
if: startsWith(matrix.os,'ubuntu')
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
run: echo ::set-env name=TESTCMD::"xvfb-run --auto-servernum julia"
# Generate precompile files
- name: Generating precompile files
@@ -75,12 +75,10 @@ jobs:
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 }}"
commit-message: Update precompile_*.jl file
title: "[AUTO] Update precompiles"
labels: SnoopCompile
branch: "SnoopCompile_AutoPR"
Skip:
-31
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
# 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 }}
+7 -12
View File
@@ -13,7 +13,6 @@ jobs:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
GKS_ENCODING: "utf8"
GKSwstype: "100"
name: Julia ${{ matrix.version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
@@ -60,10 +59,10 @@ jobs:
# TESTCMD
- name: Default TESTCMD
run: echo "TESTCMD=julia" >> $GITHUB_ENV
run: echo ::set-env name=TESTCMD::"julia"
- name: Ubuntu TESTCMD
if: startsWith(matrix.os,'ubuntu')
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
run: echo ::set-env name=TESTCMD::"xvfb-run --auto-servernum julia"
# Julia Dependencies
- name: Install Julia dependencies
@@ -71,16 +70,12 @@ jobs:
# Run tests
- name: Run Graphical test
run: |
$TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true)'
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots")'
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes")'
run: $TESTCMD --project -e 'using Pkg; Pkg.test(coverage=true);'
# Codecov
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
- name: Codecov
uses: julia-actions/julia-uploadcodecov@latest
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Skip:
if: "contains(github.event.head_commit.message, '[skip ci]')"
-56
View File
@@ -1,56 +0,0 @@
name: docs
on:
push:
branches:
- master
tags: '*'
jobs:
Build_docs:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
repository: JuliaPlots/PlotDocs.jl
- uses: julia-actions/setup-julia@v1
- name: Cache artifacts
uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y qt5-default \
ttf-mscorefonts-installer \
poppler-utils \
pdf2svg \
texlive-latex-base \
texlive-binaries \
texlive-pictures \
texlive-latex-extra \
texlive-luatex \
ghostscript-x \
libgconf2-4 \
gnuplot
sudo fc-cache -vr
- name: build documentation
env:
PYTHON: ""
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
run: |
export JULIA_DEBUG=Documenter
export PLOTDOCS_ANSICOLOR=true
export GKSwstype=nul # Plots.jl/issues/3664
xvfb-run julia --color=yes --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.add(PackageSpec(name="Plots", rev=split(ENV["GITHUB_REF"], "/", limit=3)[3])); Pkg.instantiate()'
# xvfb-run julia --color=yes --project=docs/ -e 'using Pkg; pkg"add Documenter#master"'
xvfb-run julia --color=yes --project=docs/ -e 'using Pkg; pkg"st -m"'
xvfb-run julia --color=yes --project=docs/ -e 'withenv("GITHUB_REPOSITORY" => "JuliaPlots/PlotDocs.jl") do; include("docs/make.jl"); end'
-22
View File
@@ -1,22 +0,0 @@
name: format
on:
pull_request:
jobs:
JuliaFormatter:
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
# Check format
- name: Install JuliaFormatter and format
run: |
git diff --name-only --exit-code
julia -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"'
julia -e 'using JuliaFormatter; [format(["src", "test"]) for _ in 1:2]'
git diff --exit-code
-35
View File
@@ -1,35 +0,0 @@
name: format-pr
on:
schedule:
- cron: '0 0 * * SUN'
jobs:
build:
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 JuliaFormatter CSTParser#master"'
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 }}"
-3
View File
@@ -10,6 +10,3 @@ deps/deps.jl
Manifest.toml
dev/
test/tmpplotsave.hdf5
/.benchmarkci
/benchmark/*.json
.vscode/
-698
View File
@@ -1,698 +0,0 @@
{
"title": "Plots.jl",
"license": "MIT",
"creators": [
{
"affiliation": "Elemental Cognition",
"name": "Tom Breloff"
}
],
"contributors":[
{
"affiliation": "TU Wien",
"name": "Daniel Schwabeneder",
"orcid": "0000-0002-0412-0777",
"type": "ProjectLeader"
},
{
"affiliation": "GLOBE Institute, 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",
"type": "Other"
},
{
"name": "david-macmahon",
"type": "Other"
},
{
"name": "Fredrik Ekre",
"type": "Other"
},
{
"name": "Maaz Bin Tahir Saeed",
"type": "Other"
},
{
"name": "Kristoffer Carlsson",
"type": "Other"
},
{
"name": "Will Kearney",
"type": "Other"
},
{
"name": "Niklas Korsbo",
"type": "Other"
},
{
"name": "Miles Lucas",
"type": "Other"
},
{
"name": "@Godisemo",
"type": "Other"
},
{
"name": "Florian Oswald",
"type": "Other"
},
{
"name": "Diego Javier Zea",
"type": "Other"
},
{
"name": "@WillRam",
"type": "Other"
},
{
"name": "Fedor Bezrukov",
"type": "Other"
},
{
"name": "Spencer Lyon",
"type": "Other"
},
{
"name": "Darwin Darakananda",
"type": "Other"
},
{
"name": "Lukas Hauertmann",
"type": "Other"
},
{
"name": "Huckleberry Febbo",
"type": "Other"
},
{
"name": "@H-M-H",
"type": "Other"
},
{
"name": "Josh Day",
"type": "Other"
},
{
"name": "@wfgra",
"type": "Other"
},
{
"name": "Sheehan Olver",
"type": "Other"
},
{
"name": "Jerry Ling",
"type": "Other"
},
{
"name": "Jks Liu",
"type": "Other"
},
{
"name": "Seth Axen",
"type": "Other"
},
{
"name": "@o01eg",
"type": "Other"
},
{
"name": "Sebastian Micluța-Câmpeanu",
"type": "Other"
},
{
"name": "Tim Holy",
"type": "Other"
},
{
"name": "Tony Kelman",
"type": "Other"
},
{
"name": "Antoine Levitt",
"type": "Other"
},
{
"name": "Iblis Lin",
"type": "Other"
},
{
"name": "Harry Scholes",
"type": "Other"
},
{
"name": "@djsegal",
"type": "Other"
},
{
"name": "Goran Nakerst",
"type": "Other"
},
{
"name": "Felix Hagemann",
"type": "Other"
},
{
"name": "Matthieu Gomez",
"type": "Other"
},
{
"name": "@biggsbiggsby",
"type": "Other"
},
{
"name": "Jonathan Anderson",
"type": "Other"
},
{
"name": "Michael Kraus",
"type": "Other"
},
{
"name": "Carlo Lucibello",
"type": "Other"
},
{
"name": "Robin Deits",
"type": "Other"
},
{
"name": "Misha Mkhasenko",
"type": "Other"
},
{
"name": "Benoît Legat",
"type": "Other"
},
{
"name": "Steven G. Johnson",
"type": "Other"
},
{
"name": "John Verzani",
"type": "Other"
},
{
"name": "Mattias Fält",
"type": "Other"
},
{
"name": "Rashika Karki",
"type": "Other"
},
{
"name": "Morten Piibeleht",
"type": "Other"
},
{
"name": "Filippo Vicentini",
"type": "Other"
},
{
"name": "David Anthoff",
"type": "Other"
},
{
"name": "Leon Wabeke",
"type": "Other"
},
{
"name": "Yusuke Kominami",
"type": "Other"
},
{
"name": "Oscar Dowson",
"type": "Other"
},
{
"name": "Max G",
"type": "Other"
},
{
"name": "Fabian Greimel",
"type": "Other"
},
{
"name": "Jérémy",
"type": "Other"
},
{
"name": "Pearl Li",
"type": "Other"
},
{
"name": "David P. Sanders",
"type": "Other"
},
{
"name": "Asbjørn Nilsen Riseth",
"type": "Other"
},
{
"name": "Jan Weidner",
"type": "Other"
},
{
"name": "@jakkor2",
"type": "Other"
},
{
"name": "Pablo Zubieta",
"type": "Other"
},
{
"name": "Hamza Yusuf Çakır",
"type": "Other"
},
{
"name": "John Rinehart",
"type": "Other"
},
{
"name": "Martin Biel",
"type": "Other"
},
{
"name": "Moritz Schauer",
"type": "Other"
},
{
"name": "Moesè Giodano",
"type": "Other"
},
{
"name": "@olegshtch",
"type": "Other"
},
{
"name": "Leon Shen",
"type": "Other"
},
{
"name": "Jeff Fessler",
"type": "Other"
},
{
"name": "@hustf",
"type": "Other"
},
{
"name": "Asim H Dar",
"type": "Other"
},
{
"name": "@8uurg",
"type": "Other"
},
{
"name": "Abel Siqueira",
"type": "Other"
},
{
"name": "Adrian Dawid",
"type": "Other"
},
{
"name": "Alberto Lusiani",
"type": "Other"
},
{
"name": "Balázs Mezei",
"type": "Other"
},
{
"name": "Ben Ide",
"type": "Other"
},
{
"name": "Benjamin Lungwitz",
"type": "Other"
},
{
"affiliation": "University of Graz",
"name": "Bernd Riederer",
"type": "Other",
"orcid": "0000-0001-8390-0087"
},
{
"name": "Christina Lee",
"type": "Other"
},
{
"name": "Christof Stocker",
"type": "Other"
},
{
"name": "Christoph Finkensiep",
"type": "Other"
},
{
"name": "@Cornelius-G",
"type": "Other"
},
{
"name": "Daniel Høegh",
"type": "Other"
},
{
"name": "Denny Biasiolli",
"type": "Other"
},
{
"name": "Dieter Castel",
"type": "Other"
},
{
"name": "Elliot Saba",
"type": "Other"
},
{
"name": "Fengyang Wang",
"type": "Other"
},
{
"name": "Fons van der Plas",
"type": "Other"
},
{
"name": "Fredrik Bagge Carlson",
"type": "Other"
},
{
"name": "Graham Smith",
"type": "Other"
},
{
"name": "Hayato Ikoma",
"type": "Other"
},
{
"name": "Hessam Mehr",
"type": "Other"
},
{
"name": "@InfiniteChai",
"type": "Other"
},
{
"name": "Jack Dunn",
"type": "Other"
},
{
"name": "Jeff Bezanson",
"type": "Other"
},
{
"name": "Jeff Eldredge",
"type": "Other"
},
{
"name": "Jinay Jain",
"type": "Other"
},
{
"name": "Johan Blåbäck",
"type": "Other"
},
{
"name": "@jmert",
"type": "Other"
},
{
"name": "Lakshya Khatri",
"type": "Other"
},
{
"name": "Lia Siegelmann",
"type": "Other"
},
{
"name": "@marekkukan-tw",
"type": "Other"
},
{
"affiliation": "ETH Zurich",
"name": "Mauro Werder",
"type": "Other",
"orcid": "0000-0003-0137-9377"
},
{
"name": "Maxim Grechkin",
"type": "Other"
},
{
"name": "Michael Cawte",
"type": "Other"
},
{
"name": "@milesfrain",
"type": "Other"
},
{
"name": "Nicholas Bauer",
"type": "Other"
},
{
"name": "Nicolau Leal Werneck",
"type": "Other"
},
{
"name": "@nilshg",
"type": "Other"
},
{
"name": "Oliver Evans",
"type": "Other"
},
{
"name": "Peter Gagarinov",
"type": "Other"
},
{
"name": "Páll Haraldsson",
"type": "Other"
},
{
"name": "Rik Huijzer",
"type": "Other"
},
{
"name": "Romain Franconville",
"type": "Other"
},
{
"name": "Ronan Pigott",
"type": "Other"
},
{
"name": "Roshan Shariff",
"type": "Other"
},
{
"name": "Scott Thomas",
"type": "Other"
},
{
"name": "Sebastian Rollén",
"type": "Other"
},
{
"name": "Seth Bromberger",
"type": "Other"
},
{
"name": "Siva Swaminathan",
"type": "Other"
},
{
"name": "Tim DuBois",
"type": "Other"
},
{
"name": "Travis DePrato",
"type": "Other"
},
{
"name": "Will Thompson",
"type": "Other"
},
{
"name": "Yakir Luc Gagnon",
"type": "Other"
},
{
"name": "Benjamin Chislett",
"type": "Other"
},
{
"name": "@hhaensel",
"type": "Other"
},
{
"name": "@improbable22",
"type": "Other"
},
{
"name": "Johannes Fleck",
"type": "Other"
},
{
"name": "Peter Czaban",
"type": "Other"
},
{
"name": "@innerlee",
"type": "Other"
},
{
"name": "Mats Cronqvist",
"type": "Other"
},
{
"name": "Shi Pengcheng",
"type": "Other"
},
{
"name": "@wg030",
"type": "Other"
},
{
"affiliation": "University of Cambridge",
"name": "Will Tebbutt",
"type": "Other"
},
{
"name": "@t-bltg",
"type": "Other"
},
{
"name": "Fred Callaway",
"type": "Other"
}
],
"upload_type": "software"
}
+8 -11
View File
@@ -1,13 +1,12 @@
name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"]
version = "1.21.3"
version = "1.9.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"
@@ -37,22 +36,21 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
Contour = "0.5"
FFMPEG = "0.2, 0.3, 0.4"
FixedPointNumbers = "0.6, 0.7, 0.8"
GR = "0.53, 0.54, 0.55, 0.57, 0.58, 0.59"
GeometryBasics = "0.2, 0.3.1, 0.4"
GR = "0.46, 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53"
GeometryBasics = "0.2, 0.3.1"
JSON = "0.21, 1"
Latexify = "0.14, 0.15"
Latexify = "0.14"
Measures = "0.3"
NaNMath = "0.3"
PlotThemes = "2"
PlotUtils = "1"
RecipesBase = "1"
RecipesPipeline = "0.3.5, 0.4"
Reexport = "0.2, 1.0"
RecipesPipeline = "0.2"
Reexport = "0.2"
Requires = "1"
Scratch = "1"
Showoff = "0.3.1, 1.0"
Showoff = "0.3.1"
StatsBase = "0.32, 0.33"
UnicodePlots = "2.2"
julia = "1.5"
[extras]
@@ -65,7 +63,6 @@ Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a"
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
@@ -76,4 +73,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
[targets]
test = ["Distributions", "FileIO", "Gtk", "ImageMagick", "Images", "LibGit2", "OffsetArrays", "PGFPlotsX", "PlotlyJS", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]
test = ["Distributions", "FileIO", "Gtk", "ImageMagick", "Images", "LibGit2", "OffsetArrays", "PGFPlotsX", "HDF5", "RDatasets", "StableRNGs", "StaticArrays", "StatsPlots", "Test", "TestImages", "UnicodePlots", "VisualRegressionTests"]
-4
View File
@@ -18,10 +18,6 @@
[![][docs-img]][docs-url]
[![Codecov](https://codecov.io/gh/JuliaPlots/Plots.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaPlots/Plots.jl)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4725317.svg)](https://doi.org/10.5281/zenodo.4725317)
This is the DOI for all Versions, please follow the link to get the DOI for a specific version.
#### Created by Tom Breloff (@tbreloff)
#### Maintained by the [JuliaPlots members](https://github.com/orgs/JuliaPlots/people)
-5
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"
-10
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
-3
View File
@@ -1,6 +1,3 @@
github_checks:
annotations: false
ignore:
- "src/backends/inspectdr.jl"
- "src/backends/orca.jl"
@@ -0,0 +1,390 @@
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(Plots.Type)),NamedTuple{(:label, :blank),Tuple{Symbol,Bool}},Type{Plots.EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.Type)),NamedTuple{(:label, :width, :height),Tuple{Symbol,Symbol,Measures.Length{:pct,Float64}}},Type{Plots.EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.Type)),NamedTuple{(:parent,),Tuple{Plots.GridLayout}},Type{Plots.Subplot},Plots.GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.Type)),NamedTuple{(:parent,),Tuple{Plots.GridLayout}},Type{Plots.Subplot},Plots.PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.Type)),NamedTuple{(:parent,),Tuple{Plots.Subplot{Plots.GRBackend}}},Type{Plots.Subplot},Plots.GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.Type)),NamedTuple{(:parent,),Tuple{Plots.Subplot{Plots.PlotlyBackend}}},Type{Plots.Subplot},Plots.PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Plots._make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Array{Int64,1}}},typeof(Plots._make_hist),Tuple{Array{Float64,1}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(Plots._make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Nothing}},typeof(Plots._make_hist),Tuple{Array{Float64,1},Array{Float64,1}},Int64})
Base.precompile(Tuple{Core.kwftype(typeof(Plots._make_hist)),NamedTuple{(:normed, :weights),Tuple{Bool,Nothing}},typeof(Plots._make_hist),Tuple{Array{Float64,1}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:flip,),Tuple{Bool}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:formatter,),Tuple{typeof(RecipesPipeline.datetimeformatter)}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:grid, :lims),Tuple{Bool,Tuple{Int64,Int64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:grid, :lims, :flip),Tuple{Bool,Tuple{Int64,Int64},Bool}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:grid,),Tuple{Bool}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:gridlinewidth, :grid, :gridalpha, :gridstyle, :foreground_color_grid),Tuple{Int64,Bool,Float64,Symbol,RGBA{Float64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:guide,),Tuple{String}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:lims, :flip, :ticks, :guide),Tuple{Tuple{Int64,Int64},Bool,StepRange{Int64,Int64},String}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:lims,),Tuple{Tuple{Float64,Float64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:lims,),Tuple{Tuple{Int64,Float64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:lims,),Tuple{Tuple{Int64,Int64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:rotation,),Tuple{Int64}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:scale, :guide),Tuple{Symbol,String}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.attr!)),NamedTuple{(:ticks,),Tuple{UnitRange{Int64}}},typeof(attr!),Plots.Axis})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.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(Plots.gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(Plots.gr_polyline),Array{Int64,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(Plots.gr_polyline),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(Plots.gr_polyline),StepRange{Int64,Int64},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(Plots.gr_polyline),UnitRange{Int64},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.gr_polyline)),NamedTuple{(:arrowside, :arrowstyle),Tuple{Symbol,Symbol}},typeof(Plots.gr_polyline),UnitRange{Int64},UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.heatmap)),Any,typeof(heatmap),Any,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.histogram)),Any,typeof(histogram),Any})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.hline!)),Any,typeof(hline!),Any})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.lens!)),Any,typeof(lens!),Any,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:alpha, :seriestype),Tuple{Float64,Symbol}},typeof(plot!),Array{GeometryBasics.Point{2,Float64},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:annotation,),Tuple{Array{Tuple{Int64,Float64,Plots.PlotText},1}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:line, :seriestype),Tuple{Tuple{Int64,Symbol,Float64,Array{Symbol,2}},Symbol}},typeof(plot!),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:lw, :color),Tuple{Int64,Symbol}},typeof(plot!),Function,Float64,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:lw, :color),Tuple{Int64,Symbol}},typeof(plot!),Plots.Plot{Plots.GRBackend},Function,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),Plots.Plot{Plots.GRBackend},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),Plots.Plot{Plots.PlotlyBackend},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:marker, :series_annotations, :seriestype),Tuple{Tuple{Int64,Float64,Symbol},Array{Any,1},Symbol}},typeof(plot!),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:markersize, :c, :seriestype),Tuple{Int64,Symbol,Symbol}},typeof(plot!),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,Measures.BoundingBox{Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}},Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}}}}}},typeof(plot!),Array{Int64,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,Measures.BoundingBox{Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}},Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}}}}}},typeof(plot!),Plots.Plot{Plots.GRBackend},Array{Int64,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:seriestype, :inset),Tuple{Symbol,Tuple{Int64,Measures.BoundingBox{Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}},Tuple{Measures.Length{:w,Float64},Measures.Length{:h,Float64}}}}}},typeof(plot!),Plots.Plot{Plots.PlotlyBackend},Array{Int64,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot!),Array{Int64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:title,),Tuple{String}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:w,),Tuple{Int64}},typeof(plot!),Plots.Plot{Plots.GRBackend},Array{Float64,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:xgrid,),Tuple{Tuple{Symbol,Symbol,Int64,Symbol,Float64}}},typeof(plot!),Plots.Plot{Plots.GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:yaxis,),Tuple{Tuple{String,Symbol}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Plots.Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Plots.Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Plots.Plot{Plots.GRBackend},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot!)),NamedTuple{(:zcolor, :m, :ms, :lab, :seriestype),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Plots.Stroke},Array{Float64,1},String,Symbol}},typeof(plot!),Plots.Plot{Plots.PlotlyBackend},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:annotations, :leg),Tuple{Tuple{Int64,Float64,Plots.PlotText},Bool}},typeof(plot),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:aspect_ratio, :seriestype),Tuple{Int64,Symbol}},typeof(plot),Array{String,1},Array{String,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:bins, :weights, :seriestype),Tuple{Symbol,Array{Int64,1},Symbol}},typeof(plot),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:color, :line, :marker),Tuple{Array{Symbol,2},Tuple{Symbol,Int64},Tuple{Array{Symbol,2},Int64,Float64,Plots.Stroke}}},typeof(plot),Array{Array{T,1} where T,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:connections, :seriestype),Tuple{Tuple{Array{Int64,1},Array{Int64,1},Array{Int64,1}},Symbol}},typeof(plot),Array{Int64,1},Array{Int64,1},Vararg{Array{Int64,1},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:fill, :seriestype),Tuple{Bool,Symbol}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks, :seriestype),Tuple{Array{Symbol,2},Array{String,2},Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}},Int64,String,Int64,UnitRange{Int64},Symbol}},typeof(plot),Array{Array{Float64,1},1},Array{Array{Float64,1},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:grid, :title),Tuple{Tuple{Symbol,Symbol,Symbol,Int64,Float64},String}},typeof(plot),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:lab, :w, :palette, :fill, :α),Tuple{String,Int64,PlotUtils.ContinuousColorGradient,Int64,Float64}},typeof(plot),StepRange{Int64,Int64},Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend),Tuple{Array{String,2},String,String,Int64,Symbol}},typeof(plot),Array{Function,1},Float64,Vararg{Float64,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:label,),Tuple{Array{String,2}}},typeof(plot),Array{AbstractArray{Float64,1},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :group, :linetype, :linecolor),Tuple{Plots.GridLayout,Array{String,1},Array{Symbol,2},Symbol}},typeof(plot),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha),Tuple{Tuple{Int64,Int64},String,Int64,Float64}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend},Vararg{Plots.Plot{Plots.GRBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha),Tuple{Tuple{Int64,Int64},String,Int64,Float64}},typeof(plot),Plots.Plot{Plots.PlotlyBackend},Plots.Plot{Plots.PlotlyBackend},Vararg{Plots.Plot{Plots.PlotlyBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :link),Tuple{Int64,Symbol}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :link),Tuple{Int64,Symbol}},typeof(plot),Plots.Plot{Plots.PlotlyBackend},Plots.Plot{Plots.PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :palette, :bg_inside),Tuple{Int64,Array{PlotUtils.ContinuousColorGradient,2},Array{Symbol,2}}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :t, :leg, :ticks, :border),Tuple{Plots.GridLayout,Array{Symbol,2},Bool,Nothing,Symbol}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :title, :titlelocation, :left_margin, :bottom_margin, :xrotation),Tuple{Plots.GridLayout,Array{String,2},Symbol,Array{Measures.Length{:mm,Float64},2},Measures.Length{:mm,Float64},Int64}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:layout, :xlims),Tuple{Plots.GridLayout,Tuple{Int64,Float64}}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend},Vararg{Plots.Plot{Plots.GRBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:legend,),Tuple{Bool}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend},Vararg{Plots.Plot{Plots.GRBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:legend,),Tuple{Bool}},typeof(plot),Plots.Plot{Plots.PlotlyBackend},Plots.Plot{Plots.PlotlyBackend},Vararg{Plots.Plot{Plots.PlotlyBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Array{Tuple{Int64,Real},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend},Vararg{Plots.Plot{Plots.GRBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:legend,),Tuple{Symbol}},typeof(plot),Plots.Plot{Plots.PlotlyBackend},Plots.Plot{Plots.PlotlyBackend},Vararg{Plots.Plot{Plots.PlotlyBackend},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:line, :lab, :ms),Tuple{Tuple{Array{Symbol,2},Int64},Array{String,2},Int64}},typeof(plot),Array{Array{T,1} where T,1},Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:line, :label, :legendtitle),Tuple{Tuple{Int64,Array{Symbol,2}},Array{String,2},String}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:line, :leg, :fill),Tuple{Int64,Bool,Tuple{Int64,Symbol}}},typeof(plot),Function,Function,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:line, :marker, :bg, :fg, :xlim, :ylim, :leg),Tuple{Tuple{Int64,Symbol,Symbol},Tuple{Shape,Int64,RGBA{Float64}},Symbol,Symbol,Tuple{Int64,Int64},Tuple{Int64,Int64},Bool}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:line_z, :linewidth, :legend),Tuple{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Int64,Bool}},typeof(plot),Array{Float64,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:m, :lab, :bg, :xlim, :ylim, :seriestype),Tuple{Tuple{Int64,Symbol},Array{String,2},Symbol,Tuple{Int64,Int64},Tuple{Int64,Int64},Symbol}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:marker,),Tuple{Bool}},typeof(plot),Array{Union{Missing, Int64},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:marker_z, :color, :legend, :seriestype),Tuple{typeof(+),Symbol,Bool,Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:nbins, :seriestype),Tuple{Int64,Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:nbins, :show_empty_bins, :normed, :aspect_ratio, :seriestype),Tuple{Tuple{Int64,Int64},Bool,Bool,Int64,Symbol}},typeof(plot),Array{Complex{Float64},1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:proj, :m),Tuple{Symbol,Int64}},typeof(plot),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:projection, :seriestype),Tuple{Symbol,Symbol}},typeof(plot),Array{Int64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:quiver, :seriestype),Tuple{Tuple{Array{Float64,1},Array{Float64,1},Array{Float64,1}},Symbol}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Array{Float64,1},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:reg, :fill),Tuple{Bool,Tuple{Int64,Symbol}}},typeof(plot),Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:ribbon,),Tuple{Tuple{LinRange{Float64},LinRange{Float64}}}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:ribbon,),Tuple{typeof(sqrt)}},typeof(plot),UnitRange{Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:seriestype, :markershape, :markersize, :color),Tuple{Array{Symbol,2},Array{Symbol,1},Int64,Array{Symbol,1}}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot),Array{Dates.DateTime,1},UnitRange{Int64},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:seriestype,),Tuple{Symbol}},typeof(plot),Array{OHLC,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:st, :xlabel, :ylabel, :zlabel),Tuple{Symbol,String,String,String}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Array{Float64,1},N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:title, :l, :seriestype),Tuple{String,Float64,Symbol}},typeof(plot),Array{String,1},Array{Float64,1}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:title,),Tuple{Array{String,2}}},typeof(plot),Plots.Plot{Plots.GRBackend},Plots.Plot{Plots.GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:title,),Tuple{Array{String,2}}},typeof(plot),Plots.Plot{Plots.PlotlyBackend},Plots.Plot{Plots.PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:title,),Tuple{String}},typeof(plot),Plots.Plot{Plots.GRBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:title,),Tuple{String}},typeof(plot),Plots.Plot{Plots.PlotlyBackend}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:w,),Tuple{Int64}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:xaxis, :background_color, :leg),Tuple{Tuple{String,Tuple{Int64,Int64},StepRange{Int64,Int64},Symbol},RGB{Float64},Bool}},typeof(plot),Array{Float64,2}})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:yflip, :aspect_ratio),Tuple{Bool,Symbol}},typeof(plot),Array{Float64,1},Array{Int64,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.plot)),NamedTuple{(:zcolor, :m, :leg, :cbar, :w),Tuple{StepRange{Int64,Int64},Tuple{Int64,Float64,Symbol,Plots.Stroke},Bool,Bool,Int64}},typeof(plot),Array{Float64,1},Array{Float64,1},Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.portfoliocomposition)),Any,typeof(portfoliocomposition),Any,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.scatter!)),Any,typeof(scatter!),Any,Vararg{Any,N} where N})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.scatter!)),Any,typeof(scatter!),Any})
Base.precompile(Tuple{Core.kwftype(typeof(Plots.test_examples)),NamedTuple{(:skip,),Tuple{Array{Int64,1}}},typeof(test_examples),Symbol})
Base.precompile(Tuple{Type{Plots.GridLayout},Int64,Vararg{Int64,N} where N})
Base.precompile(Tuple{Type{Shape},Array{Tuple{Float64,Float64},1}})
Base.precompile(Tuple{typeof(Base.Broadcast.copyto_nonleaf!),Array{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},1},Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(Plots.contour_levels),Tuple{Base.Broadcast.Extruded{Array{Any,1},Tuple{Bool},Tuple{Int64}},Base.RefValue{Tuple{Float64,Float64}}}},Base.OneTo{Int64},Int64,Int64})
Base.precompile(Tuple{typeof(Base.Broadcast.materialize),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(Plots.contour_levels),Tuple{Array{Any,1},Base.RefValue{Tuple{Float64,Float64}}}}})
Base.precompile(Tuple{typeof(Base.Broadcast.materialize),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(Plots.get_linecolor),Tuple{Array{Any,1},Base.RefValue{Tuple{Float64,Float64}}}}})
Base.precompile(Tuple{typeof(Base.collect_similar),Array{AbstractLayout,1},Base.Generator{Array{AbstractLayout,1},typeof(Plots.leftpad)}})
Base.precompile(Tuple{typeof(Base.collect_similar),Array{AbstractLayout,2},Base.Generator{Array{AbstractLayout,2},typeof(Plots._update_min_padding!)}})
Base.precompile(Tuple{typeof(Base.vect),Tuple{Int64,Float64,Plots.PlotText},Vararg{Tuple{Int64,Float64,Plots.PlotText},N} where N})
Base.precompile(Tuple{typeof(Plots._bin_centers),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}})
Base.precompile(Tuple{typeof(Plots._cbar_unique),Array{Int64,1},String})
Base.precompile(Tuple{typeof(Plots._cbar_unique),Array{Nothing,1},String})
Base.precompile(Tuple{typeof(Plots._cbar_unique),Array{PlotUtils.ContinuousColorGradient,1},String})
Base.precompile(Tuple{typeof(Plots._cbar_unique),Array{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},1},String})
Base.precompile(Tuple{typeof(Plots._cbar_unique),Array{Symbol,1},String})
Base.precompile(Tuple{typeof(Plots._cycle),Array{Float64,1},Array{Int64,1}})
Base.precompile(Tuple{typeof(Plots._cycle),Array{Float64,1},StepRange{Int64,Int64}})
Base.precompile(Tuple{typeof(Plots._cycle),Array{Float64,1},UnitRange{Int64}})
Base.precompile(Tuple{typeof(Plots._cycle),Base.OneTo{Int64},Array{Int64,1}})
Base.precompile(Tuple{typeof(Plots._cycle),StepRange{Int64,Int64},Array{Int64,1}})
Base.precompile(Tuple{typeof(Plots._do_plot_show),Plots.Plot{Plots.GRBackend},Bool})
Base.precompile(Tuple{typeof(Plots._do_plot_show),Plots.Plot{Plots.PlotlyBackend},Bool})
Base.precompile(Tuple{typeof(Plots._heatmap_edges),Array{Float64,1},Bool})
Base.precompile(Tuple{typeof(Plots._plot!),Plots.Plot,Any,Any})
Base.precompile(Tuple{typeof(Plots._preprocess_barlike),RecipesPipeline.DefaultsDict,Base.OneTo{Int64},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots._preprocess_binlike),RecipesPipeline.DefaultsDict,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots._replace_markershape),Array{Symbol,1}})
Base.precompile(Tuple{typeof(Plots._update_min_padding!),Plots.GridLayout})
Base.precompile(Tuple{typeof(Plots._update_subplot_args),Plots.Plot{Plots.GRBackend},Plots.Subplot{Plots.GRBackend},Dict{Symbol,Any},Int64,Bool})
Base.precompile(Tuple{typeof(Plots._update_subplot_args),Plots.Plot{Plots.PlotlyBackend},Plots.Subplot{Plots.PlotlyBackend},Dict{Symbol,Any},Int64,Bool})
Base.precompile(Tuple{typeof(Plots._update_subplot_periphery),Plots.Subplot{Plots.GRBackend},Array{Any,1}})
Base.precompile(Tuple{typeof(Plots.build_layout),Plots.GridLayout,Int64})
Base.precompile(Tuple{typeof(Plots.convert_to_polar),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1},Tuple{Int64,Float64}})
Base.precompile(Tuple{typeof(Plots.create_grid),Expr})
Base.precompile(Tuple{typeof(Plots.error_coords),Array{Float64,1},Array{Float64,1},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots.error_zipit),Tuple{Array{Float64,1},Array{Float64,1},Array{Float64,1}}})
Base.precompile(Tuple{typeof(Plots.fakedata),Int64,Vararg{Int64,N} where N})
Base.precompile(Tuple{typeof(Plots.get_clims),Plots.Subplot{Plots.GRBackend},Plots.Series,Function})
Base.precompile(Tuple{typeof(Plots.get_minor_ticks),Plots.Subplot{Plots.GRBackend},Plots.Axis,Tuple{Array{Float64,1},Array{String,1}}})
Base.precompile(Tuple{typeof(Plots.get_minor_ticks),Plots.Subplot{Plots.GRBackend},Plots.Axis,Tuple{Array{Int64,1},Array{String,1}}})
Base.precompile(Tuple{typeof(Plots.get_series_color),Array{Symbol,1},Plots.Subplot{Plots.GRBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(Plots.get_series_color),Array{Symbol,1},Plots.Subplot{Plots.PlotlyBackend},Int64,Symbol})
Base.precompile(Tuple{typeof(Plots.get_xy),Array{OHLC,1}})
Base.precompile(Tuple{typeof(Plots.gr_add_legend),Plots.Subplot{Plots.GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor),NTuple{9,Float64}},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots.gr_add_legend),Plots.Subplot{Plots.GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor),Tuple{Int64,Float64,Float64,Float64,Int64,Float64,Float64,Float64,Float64}},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots.gr_display),Plots.Subplot{Plots.GRBackend},Measures.Length{:mm,Float64},Measures.Length{:mm,Float64},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots.gr_draw_colorbar),Plots.GRColorbar,Plots.Subplot{Plots.GRBackend},Tuple{Float64,Float64},Array{Float64,1}})
Base.precompile(Tuple{typeof(Plots.gr_draw_contour),Plots.Series,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,2},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_grid),Plots.Subplot{Plots.GRBackend},Plots.Axis,Segments{Tuple{Float64,Float64}}})
Base.precompile(Tuple{typeof(Plots.gr_draw_heatmap),Plots.Series,Array{Float64,1},Array{Float64,1},Array{Float64,2},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_heatmap),Plots.Series,Base.OneTo{Int64},Base.OneTo{Int64},Array{Float64,2},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_markers),Plots.Series,Array{Int64,1},Array{Float64,1},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_markers),Plots.Series,Base.OneTo{Int64},Array{Float64,1},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_markers),Plots.Series,StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Array{Float64,1},Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_segments),Plots.Series,Array{Float64,1},Array{Float64,1},Int64,Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_segments),Plots.Series,Base.OneTo{Int64},Array{Float64,1},Nothing,Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_draw_segments),Plots.Series,StepRange{Int64,Int64},Array{Float64,1},Int64,Tuple{Float64,Float64}})
Base.precompile(Tuple{typeof(Plots.gr_get_ticks_size),Tuple{Array{Float64,1},Array{Any,1}},Int64})
Base.precompile(Tuple{typeof(Plots.gr_get_ticks_size),Tuple{Array{Float64,1},Array{String,1}},Int64})
Base.precompile(Tuple{typeof(Plots.gr_get_ticks_size),Tuple{Array{Int64,1},Array{String,1}},Int64})
Base.precompile(Tuple{typeof(Plots.gr_label_ticks),Plots.Subplot{Plots.GRBackend},Symbol,Tuple{Array{Float64,1},Array{String,1}}})
Base.precompile(Tuple{typeof(Plots.gr_label_ticks_3d),Plots.Subplot{Plots.GRBackend},Symbol,Tuple{Array{Float64,1},Array{String,1}}})
Base.precompile(Tuple{typeof(Plots.gr_polaraxes),Int64,Float64,Plots.Subplot{Plots.GRBackend}})
Base.precompile(Tuple{typeof(Plots.gr_set_gradient),PlotUtils.ContinuousColorGradient})
Base.precompile(Tuple{typeof(Plots.heatmap_edges),Array{Float64,1},Symbol})
Base.precompile(Tuple{typeof(Plots.heatmap_edges),Base.OneTo{Int64},Symbol})
Base.precompile(Tuple{typeof(Plots.heatmap_edges),StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}},Symbol})
Base.precompile(Tuple{typeof(Plots.heatmap_edges),UnitRange{Int64},Symbol})
Base.precompile(Tuple{typeof(Plots.ignorenan_extrema),StepRange{Int64,Int64}})
Base.precompile(Tuple{typeof(Plots.ignorenan_minimum),Array{Int64,1}})
Base.precompile(Tuple{typeof(Plots.is_marker_supported),Plots.PlotlyBackend,Array{Symbol,1}})
Base.precompile(Tuple{typeof(Plots.layout_args),Int64})
Base.precompile(Tuple{typeof(Plots.make_fillrange_side),UnitRange{Int64},LinRange{Float64}})
Base.precompile(Tuple{typeof(Plots.optimal_ticks_and_labels),Plots.Subplot{Plots.GRBackend},Plots.Axis,StepRange{Int64,Int64}})
Base.precompile(Tuple{typeof(Plots.optimal_ticks_and_labels),Plots.Subplot{Plots.GRBackend},Plots.Axis,UnitRange{Int64}})
Base.precompile(Tuple{typeof(Plots.processFontArg!),Dict{Symbol,Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(Plots.processGridArg!),Dict{Symbol,Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(Plots.processGridArg!),RecipesPipeline.DefaultsDict,Bool,Symbol})
Base.precompile(Tuple{typeof(Plots.processLineArg),Dict{Symbol,Any},Array{Symbol,2}})
Base.precompile(Tuple{typeof(Plots.processLineArg),Dict{Symbol,Any},Symbol})
Base.precompile(Tuple{typeof(Plots.processMarkerArg),Dict{Symbol,Any},Array{Symbol,2}})
Base.precompile(Tuple{typeof(Plots.processMarkerArg),Dict{Symbol,Any},Plots.Stroke})
Base.precompile(Tuple{typeof(Plots.processMarkerArg),Dict{Symbol,Any},RGBA{Float64}})
Base.precompile(Tuple{typeof(Plots.processMarkerArg),Dict{Symbol,Any},Shape})
Base.precompile(Tuple{typeof(Plots.processMarkerArg),Dict{Symbol,Any},Symbol})
Base.precompile(Tuple{typeof(Plots.process_annotation),Plots.Subplot{Plots.GRBackend},Int64,Float64,Plots.PlotText})
Base.precompile(Tuple{typeof(Plots.process_annotation),Plots.Subplot{Plots.PlotlyBackend},Int64,Float64,Plots.PlotText})
Base.precompile(Tuple{typeof(Plots.process_axis_arg!),Dict{Symbol,Any},StepRange{Int64,Int64},Symbol})
Base.precompile(Tuple{typeof(Plots.process_axis_arg!),Dict{Symbol,Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(Plots.process_axis_arg!),Dict{Symbol,Any},Tuple{Int64,Int64},Symbol})
Base.precompile(Tuple{typeof(Plots.quiver_using_arrows),RecipesPipeline.DefaultsDict})
Base.precompile(Tuple{typeof(Plots.quiver_using_hack),RecipesPipeline.DefaultsDict})
Base.precompile(Tuple{typeof(Plots.reset_axis_defaults_byletter!)})
Base.precompile(Tuple{typeof(Plots.slice_arg),Array{Measures.Length{:mm,Float64},2},Int64})
Base.precompile(Tuple{typeof(Plots.slice_arg),Array{PlotUtils.ContinuousColorGradient,2},Int64})
Base.precompile(Tuple{typeof(Plots.slice_arg),Array{RGBA{Float64},2},Int64})
Base.precompile(Tuple{typeof(Plots.slice_arg),Array{String,2},Int64})
Base.precompile(Tuple{typeof(Plots.slice_arg),Array{Symbol,2},Int64})
Base.precompile(Tuple{typeof(Plots.slice_arg),Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}},Int64})
Base.precompile(Tuple{typeof(Plots.straightline_data),Tuple{Float64,Float64},Tuple{Float64,Float64},Array{Float64,1},Array{Float64,1},Int64})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},AbstractArray{OHLC,1}})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Array{Complex{Float64},1}})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Plots.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{: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{: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{:sticks}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol,Any},Type{Val{:xerror}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesPipeline._finish_userrecipe!),Plots.Plot{Plots.GRBackend},Array{Dict{Symbol,Any},1},RecipeData})
Base.precompile(Tuple{typeof(RecipesPipeline._finish_userrecipe!),Plots.Plot{Plots.PlotlyBackend},Array{Dict{Symbol,Any},1},RecipeData})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plots.Plot{Plots.GRBackend},RecipesPipeline.DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plots.Plot{Plots.PlotlyBackend},RecipesPipeline.DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plots.Plot{Plots.GRBackend},Dict{Symbol,Any},Array{Dict{Symbol,Any},1}})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plots.Plot{Plots.PlotlyBackend},Dict{Symbol,Any},Array{Dict{Symbol,Any},1}})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plots.Plot{Plots.GRBackend},RecipesPipeline.DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plots.Plot{Plots.GRBackend},Array{Dict{Symbol,Any},1},Dict{Symbol,Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plots.Plot{Plots.PlotlyBackend},Array{Dict{Symbol,Any},1},Dict{Symbol,Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.unzip),Array{GeometryBasics.Point{2,Float64},1}})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.GRBackend},Array{RecipeData,1},Symbol,String})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.GRBackend},Dict{Symbol,Any},Symbol,String})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.GRBackend},RecipesPipeline.DefaultsDict,Symbol,String})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.PlotlyBackend},Array{RecipeData,1},Symbol,String})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.PlotlyBackend},Dict{Symbol,Any},Symbol,String})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plots.Plot{Plots.PlotlyBackend},RecipesPipeline.DefaultsDict,Symbol,String})
Base.precompile(Tuple{typeof(backend),Plots.PlotlyBackend})
Base.precompile(Tuple{typeof(bbox),Float64,Float64,Float64,Float64})
Base.precompile(Tuple{typeof(bbox),Measures.Length{:mm,Float64},Measures.Length{:mm,Float64},Measures.Length{:mm,Float64},Measures.Length{:mm,Float64}})
Base.precompile(Tuple{typeof(contour),Any,Vararg{Any,N} where N})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(Plots.get_colorgradient),Tuple{Array{Any,1}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(Plots.get_linealpha),Tuple{Array{Any,1}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(Plots.get_linestyle),Tuple{Array{Any,1}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(Plots.get_linewidth),Tuple{Array{Any,1}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2},Tuple{Base.OneTo{Int64},Base.OneTo{Int64}},typeof(Plots.gr_color),Tuple{Array{RGBA{Float64},2}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(string),Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(typeof),Tuple{Tuple{Plots.PortfolioComposition}}}}}})
Base.precompile(Tuple{typeof(copy),Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(string),Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(typeof),Tuple{Tuple{Plots.Spy}}}}}})
Base.precompile(Tuple{typeof(deepcopy),Plots.Plot{Plots.PlotlyBackend}})
Base.precompile(Tuple{typeof(font),String,Vararg{Any,N} where N})
Base.precompile(Tuple{typeof(iter_segments),Array{Float64,1},Array{Float64,1},UnitRange{Int64}})
Base.precompile(Tuple{typeof(iter_segments),Base.OneTo{Int64},Array{Float64,1}})
Base.precompile(Tuple{typeof(merge),NamedTuple{(:annotation,),Tuple{Array{Tuple{Int64,Float64,Plots.PlotText},1}}},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}})
Base.precompile(Tuple{typeof(merge),NamedTuple{(:zcolor, :m, :ms, :lab),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Plots.Stroke},Array{Float64,1},String}},NamedTuple{(:seriestype,),Tuple{Symbol}}})
Base.precompile(Tuple{typeof(pairs),NamedTuple{(:zcolor, :m, :ms, :lab),Tuple{Array{Float64,1},Tuple{Symbol,Float64,Plots.Stroke},Array{Float64,1},String}}})
Base.precompile(Tuple{typeof(plot!),Any})
Base.precompile(Tuple{typeof(plot),Any,Any})
Base.precompile(Tuple{typeof(plot),Any})
Base.precompile(Tuple{typeof(push!),Plots.Plot{Plots.GRBackend},Float64,Array{Float64,1}})
Base.precompile(Tuple{typeof(spy),Any})
Base.precompile(Tuple{typeof(stroke),Int64,Vararg{Any,N} where N})
Base.precompile(Tuple{typeof(text),String,Int64,Symbol,Vararg{Symbol,N} where N})
Base.precompile(Tuple{typeof(text),String,Symbol,Int64,Vararg{Any,N} where N})
Base.precompile(Tuple{typeof(text),String,Symbol})
Base.precompile(Tuple{typeof(title!),AbstractString})
Base.precompile(Tuple{typeof(vcat),Array{Any,1},Array{Tuple{Int64,Float64,Plots.PlotText},1}})
Base.precompile(Tuple{typeof(vcat),Array{Any,1},Tuple{Int64,Float64,Plots.PlotText}})
Base.precompile(Tuple{typeof(vline!),Any})
Base.precompile(Tuple{typeof(xgrid!),Plots.Plot{Plots.GRBackend},Symbol,Vararg{Any,N} where N})
Base.precompile(Tuple{typeof(yaxis!),Any,Any})
let fbody = try __lookup_kwbody__(which(Plots.text, (String,Int64,Vararg{Any,N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(text),String,Int64,Vararg{Any,N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(Plots.text, (String,Symbol,Vararg{Any,N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(text),String,Symbol,Vararg{Any,N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(Plots.title!, (AbstractString,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(title!),AbstractString,))
end
end
let fbody = try __lookup_kwbody__(which(Plots.vline!, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(vline!),Any,))
end
end
let fbody = try __lookup_kwbody__(which(Plots.yaxis!, (Any,Vararg{Any,N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(yaxis!),Any,Vararg{Any,N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.plot!, ())) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.plot!, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Any,))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.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(RecipesBase.plot, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Any,))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.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(RecipesBase.plot, (Plots.Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Plots.Plot,))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.plot, (Plots.Plot,Plots.Plot,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Plots.Plot,Plots.Plot,))
end
end
let fbody = try __lookup_kwbody__(which(RecipesBase.plot, (Plots.Plot,Plots.Plot,Vararg{Plots.Plot,N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Plots.Plot,Plots.Plot,Vararg{Plots.Plot,N} where N,))
end
end
end
-418
View File
@@ -1,418 +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{(:label, :blank), Tuple{Symbol, Bool}},Type{EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:label, :width, :height), Tuple{Symbol, Symbol, Length{:pct, Float64}}},Type{EmptyLayout}})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{GridLayout}},Type{Subplot},GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{GridLayout}},Type{Subplot},PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{Subplot{GRBackend}}},Type{Subplot},GRBackend})
Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:parent,), Tuple{Subplot{PlotlyBackend}}},Type{Subplot},PlotlyBackend})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Int64})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}, Vector{Float64}},Tuple{Int64, Int64}})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Nothing}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(_make_hist)),NamedTuple{(:normed, :weights), Tuple{Bool, Vector{Int64}}},typeof(_make_hist),Tuple{Vector{Float64}},Symbol})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:flip,), Tuple{Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{Symbol}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:formatter,), Tuple{typeof(datetimeformatter)}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :flip, :minorgrid, :guide), Tuple{Bool, Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims), Tuple{Bool, Tuple{Float64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :lims, :flip), Tuple{Bool, Tuple{Float64, Float64}, Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :minorgrid, :guide), Tuple{Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid, :minorgrid, :mirror, :guide), Tuple{Bool, Bool, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:grid,), Tuple{Bool}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:gridlinewidth, :grid, :gridalpha, :gridstyle, :foreground_color_grid), Tuple{Int64, Bool, Float64, Symbol, RGBA{Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guide,), Tuple{String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guide_position, :guidefontvalign, :mirror, :guide), Tuple{Symbol, Symbol, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:guidefonthalign, :guide_position, :mirror, :guide), Tuple{Symbol, Symbol, Bool, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims, :flip, :ticks, :guide), Tuple{Tuple{Int64, Int64}, Bool, StepRange{Int64, Int64}, String}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Float64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Float64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(:lims,), Tuple{Tuple{Int64, Int64}}},typeof(attr!),Axis})
Base.precompile(Tuple{Core.kwftype(typeof(attr!)),NamedTuple{(: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}},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(hline!)),Any,typeof(hline!),Any})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{GRBackend},Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Plot{PlotlyBackend},Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:alpha, :seriestype), Tuple{Float64, Symbol}},typeof(plot!),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:annotation,), Tuple{Vector{Tuple{Int64, Float64, Tuple{String, Any, Any, Any}}}}},typeof(plot!)})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:layout, :margin), Tuple{GridLayout, 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{(: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{(: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{(:framestyle, :title, :color, :layout, :label, :markerstrokewidth, :ticks, :seriestype), Tuple{Matrix{Symbol}, Matrix{String}, Base.ReshapedArray{Int64, 2, UnitRange{Int64}, Tuple{}}, Int64, String, Int64, UnitRange{Int64}, Symbol}},typeof(plot),Vector{Vector{Float64}},Vector{Vector{Float64}}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:grid, :title), Tuple{Tuple{Symbol, Symbol, Symbol, Int64, Float64}, String}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:lab, :w, :palette, :fill, :α), Tuple{String, Int64, PlotUtils.ContinuousColorGradient, Int64, Float64}},typeof(plot),StepRange{Int64, Int64},Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:label, :title, :xlabel, :linewidth, :legend), Tuple{Matrix{String}, String, String, Int64, Symbol}},typeof(plot),Vector{Function},Float64,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{GridLayout, Vector{String}, Matrix{Symbol}, Symbol}},typeof(plot),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :label, :fillrange, :fillalpha), Tuple{Tuple{Int64, Int64}, String, Int64, Float64}},typeof(plot),Plot{GRBackend},Plot{GRBackend},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{GridLayout, 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{GridLayout, Matrix{Symbol}, Bool, Nothing, Symbol}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :title, :titlelocation, :left_margin, :bottom_margin, :xrotation), Tuple{GridLayout, Matrix{String}, Symbol, Matrix{AbsoluteLength}, AbsoluteLength, Int64}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xguide, :yguide, :xguidefonthalign, :yguidefontvalign, :xguideposition, :yguideposition, :ymirror, :xmirror, :legend, :seriestype), Tuple{Int64, String, String, Matrix{Symbol}, Matrix{Symbol}, Symbol, Matrix{Symbol}, Matrix{Bool}, Matrix{Bool}, Bool, Matrix{Symbol}}},typeof(plot),Matrix{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot)),NamedTuple{(:layout, :xlims), Tuple{GridLayout, Tuple{Int64, Float64}}},typeof(plot),Plot{GRBackend},Plot{GRBackend},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{(: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{: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{:xerror}},Any,Any,Any})
Base.precompile(Tuple{typeof(RecipesBase.apply_recipe),AbstractDict{Symbol, Any},Vector{ComplexF64}})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{GRBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.add_series!),Plot{PlotlyBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{GRBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{GRBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.process_userrecipe!),Plot{PlotlyBackend},Vector{Dict{Symbol, Any}},Dict{Symbol, Any}})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},DefaultsDict,Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{GRBackend},Dict{Symbol, Any},Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},DefaultsDict,Symbol,Any})
Base.precompile(Tuple{typeof(RecipesPipeline.warn_on_recipe_aliases!),Plot{PlotlyBackend},Dict{Symbol, Any},Symbol,Any})
Base.precompile(Tuple{typeof(_bin_centers),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Int64},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Nothing},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Symbol},String})
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),StepRange{Int64, Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},UnitRange{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},Vector{Int64}})
Base.precompile(Tuple{typeof(_do_plot_show),Plot{GRBackend},Bool})
Base.precompile(Tuple{typeof(_do_plot_show),Plot{PlotlyBackend},Bool})
Base.precompile(Tuple{typeof(_heatmap_edges),Vector{Float64},Bool,Bool})
Base.precompile(Tuple{typeof(_plot!),Plot,Any,Any})
Base.precompile(Tuple{typeof(_preprocess_barlike),DefaultsDict,Base.OneTo{Int64},Vector{Float64}})
Base.precompile(Tuple{typeof(_preprocess_binlike),DefaultsDict,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Vector{Float64}})
Base.precompile(Tuple{typeof(_update_min_padding!),GridLayout})
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{GRBackend},Subplot{GRBackend},Dict{Symbol, Any},Int64,Bool})
Base.precompile(Tuple{typeof(_update_subplot_args),Plot{PlotlyBackend},Subplot{PlotlyBackend},Dict{Symbol, Any},Int64,Bool})
Base.precompile(Tuple{typeof(_update_subplot_periphery),Subplot{GRBackend},Vector{Any}})
Base.precompile(Tuple{typeof(_update_subplot_periphery),Subplot{PlotlyBackend},Vector{Any}})
Base.precompile(Tuple{typeof(axis_limits),Subplot{GRBackend},Symbol,Bool,Bool})
Base.precompile(Tuple{typeof(axis_limits),Subplot{PlotlyBackend},Symbol,Bool,Bool})
Base.precompile(Tuple{typeof(backend),PlotlyBackend})
Base.precompile(Tuple{typeof(bbox),AbsoluteLength,AbsoluteLength,AbsoluteLength,AbsoluteLength})
Base.precompile(Tuple{typeof(bbox),Float64,Float64,Float64,Float64})
Base.precompile(Tuple{typeof(build_layout),GridLayout,Int64,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(create_grid),Expr})
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),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_colorbar),GRColorbar,Subplot{GRBackend},Tuple{Float64, Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(gr_draw_contour),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_heatmap),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Float64,Float64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Float64,Float64,Tuple{Float64, Float64},Int64,Int64,Int64,Shape{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Float64,Tuple{Float64, Float64},Int64,Float64,Int64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_marker),Series,Int64,Int64,Tuple{Float64, Float64},Int64,Int64,Int64,Symbol})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,Base.OneTo{Int64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_markers),Series,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},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_markers),Series,Vector{Int64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},UnitRange{Int64},Tuple{Vector{Float64}, Vector{Float64}},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Base.OneTo{Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,StepRange{Int64, Int64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_segments),Series,Vector{Float64},Vector{Float64},Int64,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_shapes),Series,Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Matrix{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_draw_surface),Series,Vector{Float64},Vector{Float64},Vector{Float64},Tuple{Float64, Float64}})
Base.precompile(Tuple{typeof(gr_fill_viewport),Vector{Float64},RGBA{Float64}})
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Float64}, Vector{String}},Int64})
Base.precompile(Tuple{typeof(gr_get_ticks_size),Tuple{Vector{Int64}, Vector{String}},Int64})
Base.precompile(Tuple{typeof(gr_label_ticks),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(gr_label_ticks_3d),Subplot{GRBackend},Symbol,Tuple{Vector{Float64}, Vector{String}}})
Base.precompile(Tuple{typeof(gr_polaraxes),Int64,Float64,Subplot{GRBackend}})
Base.precompile(Tuple{typeof(gr_polyline),Vector{Float64},Vector{Float64},Function})
Base.precompile(Tuple{typeof(gr_set_gradient),PlotUtils.ContinuousColorGradient})
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), NTuple{9, Float64}}})
Base.precompile(Tuple{typeof(gr_update_viewport_legend!),Vector{Float64},Subplot{GRBackend},NamedTuple{(:w, :h, :dy, :leftw, :textw, :rightw, :xoffset, :yoffset, :width_factor), Tuple{Int64, 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),Base.OneTo{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol,StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),UnitRange{Int64},Symbol})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol,UnitRange{Int64},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol,Vector{Float64},Symbol,Tuple{Int64, Int64},Bool})
Base.precompile(Tuple{typeof(heatmap_edges),Vector{Float64},Symbol})
Base.precompile(Tuple{typeof(ignorenan_minimum),Vector{Int64}})
Base.precompile(Tuple{typeof(make_fillrange_side),UnitRange{Int64},LinRange{Float64}})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Float64, Float64},Symbol,Function})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Float64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),Nothing,Tuple{Int64, Int64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),StepRange{Int64, Int64},Tuple{Int64, Int64},Symbol,Symbol})
Base.precompile(Tuple{typeof(optimal_ticks_and_labels),UnitRange{Int64},Tuple{Float64, Float64},Symbol,Symbol})
Base.precompile(Tuple{typeof(partialcircle),Int64,Float64,Int64})
Base.precompile(Tuple{typeof(plot),Any,Any})
Base.precompile(Tuple{typeof(plot),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{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},Stroke})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(processMinorGridArg!),Dict{Symbol, Any},Bool,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{Float64, Float64, Float64},Tuple{Float64, Float64, Float64}})
Base.precompile(Tuple{typeof(push!),Segments{Tuple{Float64, Float64, Float64}},Tuple{Int64, Float64, Int64},Tuple{Int64, Float64, 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),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, N} where N})
Base.precompile(Tuple{typeof(title!),AbstractString})
Base.precompile(Tuple{typeof(unzip),Vector{GeometryBasics.Point2{Float64}}})
Base.precompile(Tuple{typeof(vline!),Any})
Base.precompile(Tuple{typeof(xgrid!),Plot{GRBackend},Symbol,Vararg{Any, N} where N})
Base.precompile(Tuple{typeof(xlims),Subplot{PlotlyBackend}})
isdefined(Plots, Symbol("#add_major_or_minor_segments#120")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#120")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#121")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#121")),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(plot!, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Any,))
end
end
let fbody = try __lookup_kwbody__(which(plot!, (Any,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot!),Any,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Any,))
end
end
let fbody = try __lookup_kwbody__(which(plot, (Any,Vararg{Any, N} where N,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(plot),Any,Vararg{Any, N} where N,))
end
end
let fbody = try __lookup_kwbody__(which(title!, (AbstractString,))) catch missing end
if !ismissing(fbody)
precompile(fbody, (Any,typeof(title!),AbstractString,))
end
end
end
+3
View File
@@ -3,6 +3,9 @@ using CompileBot
snoop_bench(
BotConfig(
"Plots",
yml_path= "SnoopCompile.yml",
else_os = "linux",
else_version = "1.5",
),
joinpath(@__DIR__, "precompile_script.jl"),
)
+3
View File
@@ -3,6 +3,9 @@ using CompileBot
snoop_bot(
BotConfig(
"Plots",
yml_path= "SnoopCompile.yml",
else_os = "linux",
else_version = "1.5",
),
joinpath(@__DIR__, "precompile_script.jl"),
)
+32 -48
View File
@@ -4,17 +4,7 @@ if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optle
@eval Base.Experimental.@optlevel 1
end
const _current_plots_version = VersionNumber(
split(
first(
filter(
line -> occursin("version", line),
readlines(normpath(@__DIR__, "..", "Project.toml")),
),
),
"\"",
)[2],
)
const _current_plots_version = VersionNumber(split(first(filter(line -> occursin("version", line), readlines(normpath(@__DIR__, "..", "Project.toml")))), "\"")[2])
using Reexport
@@ -31,12 +21,10 @@ using Base.Meta
@reexport using PlotThemes
import Showoff
import StatsBase
import Downloads
import JSON
using Requires
#! format: off
export
grid,
bbox,
@@ -129,7 +117,8 @@ export
scalefontsize,
scalefontsizes,
resetfontsizes
#! format: on
# ---------------------------------------------------------
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
@@ -148,6 +137,7 @@ ignorenan_extrema(x) = Base.extrema(x)
# This makes it impossible to create row vectors of String and Symbol with the transpose operator.
# This solves this issue, internally in Plots at least.
# commented out on the insistence of the METADATA maintainers
#Base.transpose(x::Symbol) = x
@@ -158,13 +148,12 @@ ignorenan_extrema(x) = Base.extrema(x)
import Measures
module PlotMeasures
import Measures
import Measures:
Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct,Float64}(1.0)
const pct = Length{:pct, Float64}(1.0)
Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
@@ -179,8 +168,7 @@ import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
# ---------------------------------------------------------
import RecipesPipeline
import RecipesPipeline:
SliceIt,
import RecipesPipeline: SliceIt,
DefaultsDict,
Formatted,
AbstractSurface,
@@ -199,13 +187,8 @@ import RecipesPipeline:
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-1.57.1.min.js"
include("types.jl")
include("utils.jl")
include("colorbars.jl")
include("axes.jl")
include("args.jl")
include("components.jl")
@@ -224,7 +207,6 @@ include("output.jl")
include("ijulia.jl")
include("fileio.jl")
include("init.jl")
include("legend.jl")
include("backends/plotly.jl")
include("backends/gr.jl")
@@ -232,34 +214,36 @@ include("backends/web.jl")
include("shorthands.jl")
let PlotOrSubplot = Union{Plot,Subplot}
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin, xmax), kw...)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin, ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin, zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks, labels), kw...)
global yticks!(plt::PlotOrSubplot, ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks, labels), kw...)
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
let PlotOrSubplot = Union{Plot, Subplot}
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
global yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
end
# ---------------------------------------------------------
const CURRENT_BACKEND = CurrentBackend(:none)
const PLOTS_SEED = 1234
include("precompile_includer.jl")
+70 -85
View File
@@ -14,24 +14,24 @@ end
Add a plot (the current plot if not specified) to an existing animation
"""
function frame(anim::Animation, plt::P = current()) where {P<:AbstractPlot}
function frame(anim::Animation, plt::P=current()) where P<:AbstractPlot
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename)
end
giffn() = (isijulia() ? "tmp.gif" : tempname() * ".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname() * ".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname() * ".mp4")
webmfn() = (isijulia() ? "tmp.webm" : tempname() * ".webm")
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
webmfn() = (isijulia() ? "tmp.webm" : tempname()*".webm")
mutable struct FrameIterator
itr
every::Int
kw
end
FrameIterator(itr; every = 1, kw...) = FrameIterator(itr, every, kw)
FrameIterator(itr; every=1, kw...) = FrameIterator(itr, every, kw)
"""
Animate from an iterator which returns the plot args each iteration.
@@ -48,8 +48,8 @@ function animate(fitr::FrameIterator, fn = giffn(); kw...)
end
# most things will implement this
function animate(obj, fn = giffn(); every = 1, fps = 20, loop = 0, kw...)
animate(FrameIterator(obj, every, kw), fn; fps = fps, loop = loop)
function animate(obj, fn = giffn(); every=1, fps=20, loop=0, kw...)
animate(FrameIterator(obj, every, kw), fn; fps=fps, loop=loop)
end
# -----------------------------------------------
@@ -69,16 +69,12 @@ webm(anim::Animation, fn = webmfn(); kw...) = buildanimation(anim, fn, false; kw
ffmpeg_framerate(fps) = "$fps"
ffmpeg_framerate(fps::Rational) = "$(fps.num)/$(fps.den)"
function buildanimation(
anim::Animation,
fn::AbstractString,
is_animated_gif::Bool = true;
fps::Real = 20,
loop::Integer = 0,
variable_palette::Bool = false,
verbose = false,
show_msg::Bool = true,
)
function buildanimation(anim::Animation, fn::AbstractString,
is_animated_gif::Bool=true;
fps::Real = 20, loop::Integer = 0,
variable_palette::Bool=false,
verbose=false,
show_msg::Bool=true)
if length(anim.frames) == 0
throw(ArgumentError("Cannot build empty animations"))
end
@@ -86,49 +82,41 @@ function buildanimation(
fn = abspath(expanduser(fn))
animdir = anim.dir
framerate = ffmpeg_framerate(fps)
verbose_level = (verbose isa Int ? verbose : verbose ? 32 : 16) # "error"
verbose_level = (verbose isa Int ? verbose :
verbose ? 32 # "info"
: 16) # "error"
if is_animated_gif
if variable_palette
# generate a colorpalette for each frame for highest quality, but larger filesize
palette = "palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`,
)
palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -lavfi "$palette" -loop $loop -y $fn`)
else
# generate a colorpalette first so ffmpeg does not have to guess it
ffmpeg_exe(
`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`,
)
ffmpeg_exe(`-v $verbose_level -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
# then apply the palette to get better results
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`,
)
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -loop $loop -y $fn`)
end
else
ffmpeg_exe(
`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -vf format=yuv420p -loop $loop -y $fn`,
)
ffmpeg_exe(`-v $verbose_level -framerate $framerate -i $(animdir)/%06d.png -loop $loop -y $fn`)
end
show_msg && @info("Saved animation to ", fn)
AnimatedGif(fn)
end
# write out html to view the gif
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
ext = file_extension(agif.filename)
if ext == "gif"
html =
"<img src=\"data:image/gif;base64," *
base64encode(read(agif.filename)) *
"\" />"
elseif ext in ("mov", "mp4", "webm")
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>"
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
@@ -137,67 +125,64 @@ function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
return nothing
end
# Only gifs can be shown via image/gif
Base.showable(::MIME"image/gif", agif::AnimatedGif) = file_extension(agif.filename) == "gif"
function Base.show(io::IO, ::MIME"image/gif", agif::AnimatedGif)
open(fio -> write(io, fio), agif.filename)
open(fio-> write(io, fio), agif.filename)
end
# -----------------------------------------------
function _animate(forloop::Expr, args...; callgif = false)
if forloop.head (:for, :while)
error("@animate macro expects a for- or while-block. got: $(forloop.head)")
end
if forloop.head != :for
error("@animate macro expects a for-block. got: $(forloop.head)")
end
# add the call to frame to the end of each iteration
animsym = gensym("anim")
countersym = gensym("counter")
freqassert = :()
block = forloop.args[2]
# add the call to frame to the end of each iteration
animsym = gensym("anim")
countersym = gensym("counter")
freqassert = :()
block = forloop.args[2]
# create filter
n = length(args)
filterexpr = if n == 0
# no filter... every iteration gets a frame
true
# create filter
n = length(args)
filterexpr = if n == 0
# no filter... every iteration gets a frame
true
elseif args[1] == :every
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
:(mod1($countersym, $freq) == 1)
elseif args[1] == :every
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
:(mod1($countersym, $freq) == 1)
elseif args[1] == :when
# filter on custom expression
@assert n == 2
args[2]
elseif args[1] == :when
# filter on custom expression
@assert n == 2
args[2]
else
error("Unsupported animate filter: $args")
end
else
error("Unsupported animate filter: $args")
end
push!(block.args, :(
if $filterexpr
Plots.frame($animsym)
end
))
push!(block.args, :($countersym += 1))
push!(block.args, :(if $filterexpr; Plots.frame($animsym); end))
push!(block.args, :(global $countersym += 1))
# add a final call to `gif(anim)`?
retval = callgif ? :(Plots.gif($animsym)) : animsym
# add a final call to `gif(anim)`?
retval = callgif ? :(Plots.gif($animsym)) : animsym
# full expression:
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Plots.Animation() # init animation object
let $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
end
$retval # return the animation object, or the gif
end)
# full expression:
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Plots.Animation() # init animation object
global $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
$retval # return the animation object, or the gif
end)
end
"""
+158 -181
View File
@@ -1,188 +1,165 @@
const _arg_desc = KW(
# series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
:linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
: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`.",
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers",
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
:markerstrokewidth => "Number. Width of the marker stroke (border) in pixels",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`",
:x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer (number of contours) or AbstractVector (contour values). Determines contour levels for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default)",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
# series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
:linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default).",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots)",
:plot_titlevspan => "Number in [0,1]. Vertical span of the whole plot title (fraction of the plot height)",
:background_color => "Color Type. Base color for all backgrounds.",
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
:foreground_color => "Color Type. Base color for all foregrounds.",
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
:window_title => "String. Title of the standalone gui-window.",
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
:background_color => "Color Type. Base color for all backgrounds.",
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
:foreground_color => "Color Type. Base color for all foregrounds.",
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
:window_title => "String. Title of the standalone gui-window.",
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes",
# subplot args
:title => "String. Subplot title.",
:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.",
:legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries",
:legendtitle => "String. Legend title.",
:legendtitlefontfamily => "String or Symbol. Font family of the legend title.",
:legendtitlefontsize => "Integer. Font pointsize the legend title.",
:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center",
:legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center",
:legendtitlefontrotation => "Real. Font rotation of the legend title",
:legendtitlefontcolor => "Color Type. Font color of the legend title",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.",
:colorbar_fontfamily => "String or Symbol. Font family of colobar entries.",
:colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.",
:colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.",
:colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries",
:colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`",
:colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:legendfont => "Font. Font of legend items.",
:legendtitlefont => "Font. Font of the legend title.",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String, PlotText (created with `text(args...)`), or a tuple of arguments to `text` (e.g., `(\"Label\", 8, :red, :top)`). Add one-off text annotations at the x,y coordinates.",
:annotationfontfamily => "String or Symbol. Font family of annotations.",
:annotationfontsize => "Integer. Font pointsize of annotations.",
:annotationhalign => "Symbol. horizontal alignment of annotations, :hcenter, :left, :right or :center.",
:annotationvalign => "Symbol. Vertical alignment of annotations, :vcenter, :top, :bottom or :center.",
:annotationrotation => "Float. Rotation of annotations in degrees.",
:annotationcolor => "Colorant or :match. Color of annotations.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# subplot args
:title => "String. Subplot title.",
:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position). 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)",
:legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries",
:legendtitle => "String. Legend title.",
:legendtitlefontfamily => "String or Symbol. Font family of the legend title.",
:legendtitlefontsize => "Integer. Font pointsize the legend title.",
:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center",
:legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center",
:legendtitlefontrotation => "Real. Font rotation of the legend title",
:legendtitlefontcolor => "Color Type. Font color of the legend title",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.",
:legendtitlefont => "Font. Font of the legend title.",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
:guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => """
NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).
`:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]
`:symmetric` sets the limits to be symmetric around zero.
Set widen=true to widen the specified limits (as occurs when lims are not specified).
""",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in`, `:out` or `:none`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => """
Bool or :auto. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders.
Defaults to `:auto`, which widens unless limits were manually set.
""",
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
# axis args
:guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
: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` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
:draw_arrow => "Bool. Draw arrow at the end of the axis.",
)
+530 -1004
View File
File diff suppressed because it is too large Load Diff
+227 -379
View File
@@ -1,4 +1,5 @@
# xaxis(args...; kw...) = Axis(:x, args...; kw...)
# yaxis(args...; kw...) = Axis(:y, args...; kw...)
# zaxis(args...; kw...) = Axis(:z, args...; kw...)
@@ -23,7 +24,7 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
end
function get_axis(sp::Subplot, letter::Symbol)
axissym = get_attr_symbol(letter, :axis)
axissym = Symbol(letter, :axis)
if haskey(sp.attr, axissym)
sp.attr[axissym]
else
@@ -35,45 +36,42 @@ function process_axis_arg!(plotattributes::AKW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
plotattributes[get_attr_symbol(letter, :tickfont)] = arg
plotattributes[get_attr_symbol(letter, :guidefont)] = arg
plotattributes[Symbol(letter,:tickfont)] = arg
plotattributes[Symbol(letter,:guidefont)] = arg
elseif arg in _allScales
plotattributes[get_attr_symbol(letter, :scale)] = arg
plotattributes[Symbol(letter,:scale)] = arg
elseif arg in (:flip, :invert, :inverted)
plotattributes[get_attr_symbol(letter, :flip)] = true
plotattributes[Symbol(letter,:flip)] = true
elseif T <: AbstractString
plotattributes[get_attr_symbol(letter, :guide)] = arg
plotattributes[Symbol(letter,:guide)] = arg
# xlims/ylims
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
plotattributes[get_attr_symbol(letter, sym)] = arg
plotattributes[Symbol(letter,sym)] = arg
# xticks/yticks
# xticks/yticks
elseif T <: AVec
plotattributes[get_attr_symbol(letter, :ticks)] = arg
plotattributes[Symbol(letter,:ticks)] = arg
elseif arg === nothing
plotattributes[get_attr_symbol(letter, :ticks)] = []
plotattributes[Symbol(letter,:ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
plotattributes[get_attr_symbol(letter, :showaxis)] = showaxis(arg, letter)
plotattributes[Symbol(letter,:showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number
plotattributes[get_attr_symbol(letter, :rotation)] = arg
plotattributes[Symbol(letter,:rotation)] = arg
elseif typeof(arg) <: Function
plotattributes[get_attr_symbol(letter, :formatter)] = arg
plotattributes[Symbol(letter,:formatter)] = arg
elseif !handleColors!(
plotattributes,
arg,
get_attr_symbol(letter, :foreground_color_axis),
)
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
@warn("Skipped $(letter)axis arg $arg")
end
end
@@ -89,19 +87,13 @@ function attr!(axis::Axis, args...; kw...)
RecipesPipeline.preprocess_attributes!(KW(kw))
# then override for any keywords... only those keywords that already exists in plotattributes
for (k, v) in kw
for (k,v) in kw
if haskey(plotattributes, k)
if k == :discrete_values
# add these discrete values to the axis
for vi in v
discrete_value!(axis, vi)
end
#could perhaps use TimeType here, as Date and DateTime are both subtypes of TimeType
# or could perhaps check if dateformatter or datetimeformatter is in use
elseif k == :lims && isa(v, Tuple{Date,Date})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
elseif k == :lims && isa(v, Tuple{DateTime,DateTime})
plotattributes[k] = (v[1].instant.periods.value, v[2].instant.periods.value)
else
plotattributes[k] = v
end
@@ -124,8 +116,11 @@ Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v,
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
const _label_func =
Dict{Symbol,Function}(:log10 => x -> "10^$x", :log2 => x -> "2^$x", :ln => x -> "e^$x")
const _label_func = Dict{Symbol,Function}(
:log10 => x -> "10^$x",
:log2 => x -> "2^$x",
:ln => x -> "e^$x",
)
labelfunc(scale::Symbol, backend::AbstractBackend) = get(_label_func, scale, string)
const _label_func_tex = Dict{Symbol,Function}(
@@ -135,10 +130,12 @@ const _label_func_tex = Dict{Symbol,Function}(
)
labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode)
function optimal_ticks_and_labels(ticks, alims, scale, formatter)
amin, amax = alims
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
amin, amax = axis_limits(sp, axis[:letter])
# scale the limits
scale = axis[:scale]
sf = RecipesPipeline.scale_func(scale)
# If the axis input was a Date or DateTime use a special logic to find
@@ -149,18 +146,18 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
# rather than on the input format
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
if ticks === nothing && scale == :identity
if formatter == RecipesPipeline.dateformatter
if axis[:formatter] == RecipesPipeline.dateformatter
# optimize_datetime_ticks returns ticks and labels(!) based on
# integers/floats corresponding to the DateTime type. Thus, the axes
# limits, which resulted from converting the Date type to integers,
# are converted to 'DateTime integers' (actually floats) before
# being passed to optimize_datetime_ticks.
# (convert(Int, convert(DateTime, convert(Date, i))) == 87600000*i)
ticks, labels =
optimize_datetime_ticks(864e5 * amin, 864e5 * amax; k_min = 2, k_max = 4)
ticks, labels = optimize_datetime_ticks(864e5 * amin, 864e5 * amax;
k_min = 2, k_max = 4)
# Now the ticks are converted back to floats corresponding to Dates.
return ticks / 864e5, labels
elseif formatter == RecipesPipeline.datetimeformatter
elseif axis[:formatter] == RecipesPipeline.datetimeformatter
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
end
end
@@ -170,9 +167,8 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
scaled_ticks = optimize_ticks(
sf(amin),
sf(amax);
k_min = scale _logScales ? 2 : 4, # minimum number of ticks
k_min = 4, # minimum number of ticks
k_max = 8, # maximum number of ticks
scale = scale,
)[1]
elseif typeof(ticks) <: Int
scaled_ticks, viewmin, viewmax = optimize_ticks(
@@ -184,22 +180,19 @@ function optimal_ticks_and_labels(ticks, alims, scale, formatter)
# `strict_span = false` rewards cases where the span of the
# chosen ticks is not too much bigger than amin - amax:
strict_span = false,
scale = scale,
)
# axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax))
axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax))
else
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end
unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks)
labels = if any(isfinite, unscaled_ticks)
formatter = axis[:formatter]
if formatter in (:auto, :plain, :scientific, :engineering)
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter))
elseif formatter == :latex
map(
x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"),
Showoff.showoff(unscaled_ticks, :auto),
)
map(x -> string("\$", replace(convert_sci_unicode(x), '×' => "\\times"), "\$"), Showoff.showoff(unscaled_ticks, :auto))
else
# there was an override for the formatter... use that on the unscaled ticks
map(formatter, unscaled_ticks)
@@ -222,172 +215,81 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(sp::Subplot, axis::Axis; update = true)
if update || !haskey(axis.plotattributes, :optimized_ticks)
dvals = axis[:discrete_values]
ticks = _transform_ticks(axis[:ticks])
axis.plotattributes[:optimized_ticks] =
if (
ticks isa Symbol &&
ticks !== :none &&
ispolar(sp) &&
axis[:letter] === :x &&
!isempty(dvals)
)
collect(0:(pi / 4):(7pi / 4)), string.(0:45:315)
else
cvals = axis[:continuous_values]
alims = axis_limits(sp, axis[:letter])
scale = axis[:scale]
formatter = axis[:formatter]
get_ticks(ticks, cvals, dvals, alims, scale, formatter)
end
end
return axis.plotattributes[:optimized_ticks]
end
# Ticks getter functions
for l in (:x, :y, :z)
axis = string(l, "-axis") # "x-axis"
ticks = string(l, "ticks") # "xticks"
f = Symbol(ticks) # :xticks
@eval begin
"""
$($f)(p::Plot)
returns a vector of the $($axis) ticks of the subplots of `p`.
Example use:
```jldoctest
julia> p = plot(1:5, $($ticks)=[1,2])
julia> $($f)(p)
1-element Vector{Tuple{Vector{Float64}, Vector{String}}}:
([1.0, 2.0], ["1", "2"])
```
If `p` consists of a single subplot, you might want to grab
only the first element, via
```jldoctest
julia> $($f)(p)[1]
([1.0, 2.0], ["1", "2"])
```
or you can call $($f) on the first (only) subplot of `p` via
```jldoctest
julia> $($f)(p[1])
([1.0, 2.0], ["1", "2"])
```
"""
$f(p::Plot) = get_ticks(p, $(Meta.quot(l)))
"""
$($f)(sp::Subplot)
returns the $($axis) ticks of the subplot `sp`.
Note that the ticks are returned as tuples of values and labels:
```jldoctest
julia> sp = plot(1:5, $($ticks)=[1,2]).subplots[1]
Subplot{1}
julia> $($f)(sp)
([1.0, 2.0], ["1", "2"])
```
"""
$f(sp::Subplot) = get_ticks(sp, $(Meta.quot(l)))
export $f
end
end
# get_ticks from axis symbol :x, :y, or :z
get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[get_attr_symbol(s, :axis)])
get_ticks(p::Plot, s::Symbol) = [get_ticks(sp, s) for sp in p.subplots]
function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where {T}
if ticks === :none
return T[], String[]
elseif !isempty(dvals)
n = length(dvals)
if ticks === :all || n < 16
return cvals, string.(dvals)
if ticks in (:none, nothing, false)
axis.plotattributes[:optimized_ticks] = nothing
else
Δ = ceil(Int, n / 10)
rng = Δ:Δ:n
return cvals[rng], string.(dvals[rng])
# treat :native ticks as :auto
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values]
cv, dv = if typeof(ticks) <: Symbol
if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto && n > 15
Δ = ceil(Int, n / 10)
Δ:Δ:n
else # if ticks == :all
1:n
end
axis[:continuous_values][rng], dvals[rng]
elseif ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
# compute optimal ticks and labels
optimal_ticks_and_labels(sp, axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(sp, axis, ticks)
end
elseif typeof(ticks) <: NTuple{2, Any}
# assuming we're passed (ticks, labels)
ticks
else
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
end
axis.plotattributes[:optimized_ticks] = (cv, dv)
end
else
return optimal_ticks_and_labels(nothing, args...)
end
axis.plotattributes[:optimized_ticks]
end
get_ticks(ticks::AVec, cvals, dvals, args...) = optimal_ticks_and_labels(ticks, args...)
function get_ticks(ticks::Int, dvals, cvals, args...)
if !isempty(dvals)
rng = round.(Int, range(1, stop = length(dvals), length = ticks))
cvals[rng], string.(dvals[rng])
else
optimal_ticks_and_labels(ticks, args...)
end
end
get_ticks(ticks::NTuple{2,Any}, args...) = ticks
get_ticks(::Nothing, cvals::T, args...) where {T} = T[], String[]
get_ticks(ticks::Bool, args...) =
ticks ? get_ticks(:auto, args...) : get_ticks(nothing, args...)
get_ticks(::T, args...) where {T} = error("Unknown ticks type in get_ticks: $T")
_transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where {T<:Dates.TimeType} = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2,Any}) = (_transform_ticks(ticks[1]), ticks[2])
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
function get_minor_ticks(sp, axis, ticks)
axis[:minorticks] (:none, nothing, false) && !axis[:minorgrid] && return nothing
axis[:minorticks] in (:none, nothing, false) && !axis[:minorgrid] && return nothing
ticks = ticks[1]
length(ticks) < 2 && return nothing
amin, amax = axis_limits(sp, axis[:letter])
scale = axis[:scale]
log_scaled = scale _logScales
base = get(_logScaleBases, scale, nothing)
# add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
if log_scaled
sub = round(Int, log(base, ticks[2] / ticks[1]))
ticks = [ticks[1] / base; ticks; ticks[end] * base]
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
if length(ticks) > 2
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
elseif axis[:scale] in (:none, :identity)
ratio = 1
else
sub = 1 # unused
ratio = length(ticks) > 2 ? (ticks[3] - ticks[2]) / (ticks[2] - ticks[1]) : 1
first_step = ticks[2] - ticks[1]
last_step = ticks[end] - ticks[end - 1]
ticks = [ticks[1] - first_step / ratio; ticks; ticks[end] + last_step * ratio]
return nothing
end
first_step = ticks[2] - ticks[1]
last_step = ticks[end] - ticks[end-1]
ticks = [ticks[1] - first_step/ratio; ticks; ticks[end] + last_step*ratio]
# default to 9 intervals between major ticks for log10 scale and 5 intervals otherwise
n_default = (scale == :log10) ? 9 : 5
n =
typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] :
n_default
#Default to 5 intervals between major ticks
n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : 5
minorticks = typeof(ticks[1])[]
for (i, hi) in enumerate(ticks[2:end])
for (i,hi) in enumerate(ticks[2:end])
lo = ticks[i]
if isfinite(lo) && isfinite(hi) && hi > lo
if log_scaled
for e in 1:sub
lo_ = lo * base^(e - 1)
hi_ = lo_ * base
step = (hi_ - lo_) / n
append!(
minorticks,
collect(
(lo_ + (e > 1 ? 0 : step)):step:(hi_ - (e < sub ? 0 :
step / 2)),
),
)
end
else
step = (hi - lo) / n
append!(minorticks, collect((lo + step):step:(hi - step / 2)))
end
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
end
end
minorticks[amin .<= minorticks .<= amax]
@@ -395,15 +297,17 @@ end
# -------------------------------------------------------------------------
function reset_extrema!(sp::Subplot)
for asym in (:x, :y, :z)
sp[get_attr_symbol(asym, :axis)][:extrema] = Extrema()
for asym in (:x,:y,:z)
sp[Symbol(asym,:axis)][:extrema] = Extrema()
end
for series in sp.series_list
expand_extrema!(sp, series.plotattributes)
end
end
function expand_extrema!(ex::Extrema, v::Number)
ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin
ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax
@@ -418,13 +322,14 @@ end
expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
ex = axis[:extrema]
ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin
ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax
ex
end
function expand_extrema!(axis::Axis, v::AVec{N}) where {N<:Number}
function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
ex = axis[:extrema]
for vi in v
expand_extrema!(ex, vi)
@@ -432,6 +337,7 @@ function expand_extrema!(axis::Axis, v::AVec{N}) where {N<:Number}
ex
end
function expand_extrema!(sp::Subplot, plotattributes::AKW)
vert = isvertical(plotattributes)
@@ -442,22 +348,16 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
else
letter == :x ? :y : letter == :y ? :x : :z
end]
if (
letter != :z &&
plotattributes[:seriestype] == :straightline &&
any(series[:seriestype] != :straightline for series in series_list(sp)) &&
data[1] != data[2]
)
if letter != :z && plotattributes[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
data = [NaN]
end
axis = sp[get_attr_symbol(letter, :axis)]
axis = sp[Symbol(letter, "axis")]
if isa(data, Volume)
expand_extrema!(sp[:xaxis], data.x_extents)
expand_extrema!(sp[:yaxis], data.y_extents)
expand_extrema!(sp[:zaxis], data.z_extents)
elseif eltype(data) <: Number ||
(isa(data, Surface) && all(di -> isa(di, Number), data.surf))
elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
if !(eltype(data) <: Number)
# huh... must have been a mis-typed surface? lets swap it out
data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf))
@@ -467,9 +367,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
plotattributes[letter],
plotattributes[get_attr_symbol(letter, :(_discrete_indices))] =
discrete_value!(axis, data)
plotattributes[letter], plotattributes[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
expand_extrema!(axis, plotattributes[letter])
end
end
@@ -503,11 +401,9 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
bw = plotattributes[:bar_width]
if bw === nothing
bw =
plotattributes[:bar_width] =
_bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(data))))
bw = plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
end
axis = sp.attr[get_attr_symbol(dsym, :axis)]
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end
@@ -516,8 +412,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
if plotattributes[:seriestype] == :heatmap
for letter in (:x, :y)
data = plotattributes[letter]
axis = sp[get_attr_symbol(letter, :axis)]
scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity)
axis = sp[Symbol(letter, "axis")]
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
@@ -536,85 +432,49 @@ function widen(lmin, lmax, scale = :identity)
span = f(lmax) - f(lmin)
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
eps = NaNMath.max(1e-16, 0.03span)
invf(f(lmin) - eps), invf(f(lmax) + eps)
invf(f(lmin)-eps), invf(f(lmax)+eps)
end
# figure out if widening is a good idea.
const _widen_seriestypes = (
:line,
:path,
:steppre,
:stepmid,
:steppost,
:sticks,
:scatter,
:barbins,
:barhist,
:histogram,
:scatterbins,
:scatterhist,
:stepbins,
:stephist,
:bins2d,
:histogram2d,
:bar,
:shape,
:path3d,
:scatter3d,
)
const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
function default_should_widen(axis::Axis)
if axis[:widen] isa Bool
return axis[:widen]
end
# automatic behavior: widen if limits aren't specified and series type is appropriate
(is_2tuple(axis[:lims]) || axis[:lims] == :round) && return false
for sp in axis.sps
for series in series_list(sp)
if series.plotattributes[:seriestype] in _widen_seriestypes
return true
should_widen = false
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round)
for sp in axis.sps
for series in series_list(sp)
if series.plotattributes[:seriestype] in _widen_seriestypes
should_widen = true
end
end
end
end
false
should_widen
end
function round_limits(amin, amax, scale)
base = get(_logScaleBases, scale, 10.0)
factor = base^(1 - round(log(base, amax - amin)))
amin = floor(amin * factor) / factor
amax = ceil(amax * factor) / factor
function round_limits(amin,amax)
scale = 10^(1-round(log10(amax - amin)))
amin = floor(amin*scale)/scale
amax = ceil(amax*scale)/scale
amin, amax
end
# using the axis extrema and limit overrides, return the min/max value for this axis
function axis_limits(
sp,
letter,
should_widen = default_should_widen(sp[get_attr_symbol(letter, :axis)]),
consider_aspect = true,
)
axis = sp[get_attr_symbol(letter, :axis)]
function axis_limits(sp, letter, should_widen = default_should_widen(sp[Symbol(letter, :axis)]), consider_aspect = true)
axis = sp[Symbol(letter, :axis)]
ex = axis[:extrema]
amin, amax = ex.emin, ex.emax
lims = axis[:lims]
has_user_lims = (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
if has_user_lims
lmin, lmax = lims
if lmin == :auto
elseif isfinite(lmin)
if lmin != :auto && isfinite(lmin)
amin = lmin
end
if lmax == :auto
elseif isfinite(lmax)
if lmax != :auto && isfinite(lmax)
amax = lmax
end
end
if lims == :symmetric
aval = max(abs(amin), abs(amax))
amin = -aval
amax = aval
end
if amax <= amin && isfinite(amin)
amax = amin + 1.0
end
@@ -625,25 +485,20 @@ function axis_limits(
if axis[:letter] == :x
amin, amax = 0, 2pi
elseif lims == :auto
# widen max radius so ticks dont overlap with theta axis
#widen max radius so ticks dont overlap with theta axis
0, amax + 0.1 * abs(amax - amin)
else
amin, amax
end
elseif should_widen
elseif should_widen && axis[:widen]
widen(amin, amax, axis[:scale])
elseif lims == :round
round_limits(amin, amax, axis[:scale])
round_limits(amin,amax)
else
amin, amax
end
if (
!has_user_lims &&
consider_aspect &&
letter in (:x, :y) &&
!(sp[:aspect_ratio] in (:none, :auto) || RecipesPipeline.is3d(:sp))
)
if !has_user_lims && consider_aspect && letter in (:x, :y) && !(sp[:aspect_ratio] in (:none, :auto) || RecipesPipeline.is3d(:sp))
aspect_ratio = isa(sp[:aspect_ratio], Number) ? sp[:aspect_ratio] : 1
plot_ratio = height(plotarea(sp)) / width(plotarea(sp))
dist = amax - amin
@@ -711,11 +566,11 @@ end
# add the discrete value for each item. return the continuous values and the indices
function discrete_value!(axis::Axis, v::AMat)
n, m = axes(v)
n,m = axes(v)
cmat = zeros(axes(v))
discrete_indices = similar(Array{Int}, axes(v))
for i in n, j in m
cmat[i, j], discrete_indices[i, j] = discrete_value!(axis, v[i, j])
cmat[i,j], discrete_indices[i,j] = discrete_value!(axis, v[i,j])
end
cmat, discrete_indices
end
@@ -729,10 +584,10 @@ end
# compute the line segments which should be drawn for this axis
function axis_drawing_info(sp, letter)
# find out which axis we are dealing with
asym = get_attr_symbol(letter, :axis)
asym = Symbol(letter, :axis)
isy = letter === :y
oletter = isy ? :x : :y
oasym = get_attr_symbol(oletter, :axis)
oasym = Symbol(oletter, :axis)
# get axis objects, ticks and minor ticks
ax, oax = sp[asym], sp[oasym]
@@ -758,11 +613,7 @@ function axis_drawing_info(sp, letter)
if sp[:framestyle] != :grid
push!(segments, reverse_if((amin, oa1), isy), reverse_if((amax, oa1), isy))
# don't show the 0 tick label for the origin framestyle
if (
sp[:framestyle] == :origin &&
!(ticks in (:none, nothing, false)) &&
length(ticks) > 1
)
if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
i = findfirst(==(0), ticks[1])
if i !== nothing
deleteat!(ticks[1], i)
@@ -778,62 +629,60 @@ function axis_drawing_info(sp, letter)
)
end
end
if ax[:ticks] (:none, nothing, false)
if !(ax[:ticks] in (:none, nothing, false))
f = RecipesPipeline.scale_func(oax[:scale])
invf = RecipesPipeline.inverse_scale_func(oax[:scale])
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(oamax) - f(oamin)))
(-t, t)
else
ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(oa1) + 0.012 * (f(oa2) - f(oa1)) * ticks_in)
(oa1, t)
end
add_major_or_minor_segments(ticks, grid, segments, factor, cond) = begin
ticks === nothing && return
if cond
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + factor * (f(oamax) - f(oamin)))
(-t, t)
else
ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(oa1) + factor * (f(oa2) - f(oa1)) * ticks_in)
(oa1, t)
end
for tick in ticks[1]
if ax[:showaxis]
push!(
tick_segments,
reverse_if((tick, tick_start), isy),
reverse_if((tick, tick_stop), isy),
)
end
if ax[:grid]
push!(
grid_segments,
reverse_if((tick, oamin), isy),
reverse_if((tick, oamax), isy),
)
end
end
for tick in ticks
if ax[:showaxis] && cond
if !(ax[:minorticks] in (:none, nothing, false)) || ax[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(oamax) - f(oamin)))
(-t, t)
else
t = invf(f(oa1) + 0.006 * (f(oa2) - f(oa1)) * ticks_in)
(oa1, t)
end
for tick in minor_ticks
if ax[:showaxis]
push!(
tick_segments,
reverse_if((tick, tick_start), isy),
reverse_if((tick, tick_stop), isy),
)
end
if grid
if ax[:minorgrid]
push!(
segments,
minorgrid_segments,
reverse_if((tick, oamin), isy),
reverse_if((tick, oamax), isy),
)
end
end
end
ax_length = letter === :x ? height(sp.plotarea).value : width(sp.plotarea).value
# add major grid segments
add_major_or_minor_segments(
ticks[1],
ax[:grid],
grid_segments,
1.2 / ax_length,
ax[:tick_direction] !== :none,
)
# add minor grid segments
if ax[:minorticks] (:none, nothing, false) || ax[:minorgrid]
add_major_or_minor_segments(
minor_ticks,
ax[:minorgrid],
minorgrid_segments,
0.6 / ax_length,
true,
)
end
end
end
@@ -843,7 +692,7 @@ function axis_drawing_info(sp, letter)
tick_segments = tick_segments,
grid_segments = grid_segments,
minorgrid_segments = minorgrid_segments,
border_segments = border_segments,
border_segments = border_segments
)
end
@@ -861,9 +710,9 @@ function axis_drawing_info_3d(sp, letter)
near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x
ax = sp[get_attr_symbol(letter, :axis)]
nax = sp[get_attr_symbol(near_letter, :axis)]
fax = sp[get_attr_symbol(far_letter, :axis)]
ax = sp[Symbol(letter, :axis)]
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
@@ -879,7 +728,8 @@ function axis_drawing_info_3d(sp, letter)
minorgrid_segments = Segments(3)
border_segments = Segments(3)
if sp[:framestyle] != :none # && letter === :x
if sp[:framestyle] != :none# && letter === :x
na0, na1 = if sp[:framestyle] in (:origin, :zerolines)
0, 0
else
@@ -899,13 +749,9 @@ function axis_drawing_info_3d(sp, letter)
sort_3d_axes(amax, na0, fa0, letter),
)
# don't show the 0 tick label for the origin framestyle
if (
sp[:framestyle] == :origin &&
!(ticks in (:none, nothing, false)) &&
length(ticks) > 1
)
if sp[:framestyle] == :origin && !(ticks in (:none, nothing, false)) && length(ticks) > 1
i0 = findfirst(==(0), ticks[1])
if i0 !== nothing
if ind !== nothing
deleteat!(ticks[1], i0)
deleteat!(ticks[2], i0)
end
@@ -919,70 +765,72 @@ function axis_drawing_info_3d(sp, letter)
)
end
end
if ax[:ticks] (:none, nothing, false)
# TODO this can be simplified, we do almost the same thing twice for grid and minorgrid
if !(ax[:ticks] in (:none, nothing, false))
f = RecipesPipeline.scale_func(nax[:scale])
invf = RecipesPipeline.inverse_scale_func(nax[:scale])
ga0, ga1 =
sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1)
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(namax) - f(namin)))
(-t, t)
else
ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(na0) + 0.012 * (f(na1) - f(na0)) * ticks_in)
(na0, t)
end
add_major_or_minor_segments(ticks, grid, segments, factor, cond) = begin
ticks === nothing && return
if cond
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + factor * (f(namax) - f(namin)))
(-t, t)
else
ticks_in = ax[:tick_direction] == :out ? -1 : 1
t = invf(f(na0) + factor * (f(na1) - f(na0)) * ticks_in)
(na0, t)
end
ga0, ga1 = sp[:framestyle] in (:origin, :zerolines) ? (namin, namax) : (na0, na1)
for tick in ticks[1]
if ax[:showaxis]
push!(
tick_segments,
sort_3d_axes(tick, tick_start, fa0, letter),
sort_3d_axes(tick, tick_stop, fa0, letter),
)
end
if ax[:grid]
push!(
grid_segments,
sort_3d_axes(tick, ga0, fa0, letter),
sort_3d_axes(tick, ga1, fa0, letter),
)
push!(
grid_segments,
sort_3d_axes(tick, ga1, fa0, letter),
sort_3d_axes(tick, ga1, fa1, letter),
)
end
end
for tick in ticks
if ax[:showaxis] && cond
if !(ax[:minorticks] in (:none, nothing, false)) || ax[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(namax) - f(namin)))
(-t, t)
else
t = invf(f(na0) + 0.006 * (f(na1) - f(na0)) * ticks_in)
(na0, t)
end
for tick in minorticks
if ax[:showaxis]
push!(
tick_segments,
sort_3d_axes(tick, tick_start, fa0, letter),
sort_3d_axes(tick, tick_stop, fa0, letter),
)
end
if grid
fa0_, fa1_ = reverse_if((fa0, fa1), ax[:mirror])
ga0_, ga1_ = reverse_if((ga0, ga1), ax[:mirror])
if ax[:minorgrid]
push!(
segments,
sort_3d_axes(tick, ga0_, fa0_, letter),
sort_3d_axes(tick, ga1_, fa0_, letter),
minorgrid_segments,
sort_3d_axes(tick, ga0, fa0, letter),
sort_3d_axes(tick, ga1, fa0, letter),
)
push!(
segments,
sort_3d_axes(tick, ga1_, fa0_, letter),
sort_3d_axes(tick, ga1_, fa1_, letter),
minorgrid_segments,
sort_3d_axes(tick, ga1, fa0, letter),
sort_3d_axes(tick, ga1, fa1, letter),
)
end
end
end
# add major grid segments
add_major_or_minor_segments(
ticks[1],
ax[:grid],
grid_segments,
0.012,
ax[:tick_direction] !== :none,
)
# add minor grid segments
if ax[:minorticks] (:none, nothing, false) || ax[:minorgrid]
add_major_or_minor_segments(
minor_ticks,
ax[:minorgrid],
minorgrid_segments,
0.006,
true,
)
end
end
end
@@ -992,11 +840,11 @@ function axis_drawing_info_3d(sp, letter)
tick_segments = tick_segments,
grid_segments = grid_segments,
minorgrid_segments = minorgrid_segments,
border_segments = border_segments,
border_segments = border_segments
)
end
reverse_if(x, cond) = cond ? reverse(x) : x
axis_tuple(x, y, letter) = reverse_if((x, y), letter === :y)
axes_shift(t, i) = i % 3 == 0 ? t : i % 3 == 1 ? (t[3], t[1], t[2]) : (t[2], t[3], t[1])
axes_shift(t, i) = i % 3 == 0 ? t : i % 3 == 1 ? (t[3], t[1], t[2]) : (t[2], t[3], t[1])
+178 -605
View File
File diff suppressed because it is too large Load Diff
+65 -207
View File
@@ -27,7 +27,7 @@ const _pgfplots_markers = KW(
:diamond => "diamond*",
:pentagon => "pentagon*",
:hline => "-",
:vline => "|",
:vline => "|"
)
const _pgfplots_legend_pos = KW(
@@ -38,6 +38,7 @@ const _pgfplots_legend_pos = KW(
:outertopright => "outer north east",
)
const _pgf_series_extrastyle = KW(
:steppre => "const plot mark right",
:stepmid => "const plot mark mid",
@@ -49,7 +50,11 @@ const _pgf_series_extrastyle = KW(
# PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor
const _pgf_annotation_halign = KW(:center => "", :left => "right", :right => "left")
const _pgf_annotation_halign = KW(
:center => "",
:left => "right",
:right => "left"
)
const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
const _pgf_framestyle_defaults = Dict(:semi => :box)
@@ -58,9 +63,7 @@ function pgf_framestyle(style::Symbol)
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
@warn(
"Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead."
)
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
default_style
end
end
@@ -75,15 +78,15 @@ end
function pgf_color(grad::ColorGradient)
# Can't handle ColorGradient here, fallback to defaults.
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316, 0.97868012)
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316,0.97868012)
cstr, 1
end
# Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c), blue(c))
end, ", ")
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ")
end
pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
@@ -91,7 +94,7 @@ pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
function pgf_fillstyle(plotattributes, i = 1)
cstr, a = pgf_color(get_fillcolor(plotattributes, i))
cstr,a = pgf_color(get_fillcolor(plotattributes, i))
fa = get_fillalpha(plotattributes, i)
if fa !== nothing
a = fa
@@ -123,15 +126,8 @@ end
function pgf_marker(plotattributes, i = 1)
shape = _cycle(plotattributes[:markershape], i)
cstr, a = pgf_color(
plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)),
)
cstr_stroke, a_stroke = pgf_color(
plot_color(
get_markerstrokecolor(plotattributes, i),
get_markerstrokealpha(plotattributes, i),
),
)
cstr, a = pgf_color(plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)))
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)))
return string(
"mark = $(get(_pgfplots_markers, shape, "*")),\n",
"mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),\n",
@@ -142,28 +138,22 @@ function pgf_marker(plotattributes, i = 1)
line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid"))
}",
)
}"
)
end
function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1)
# Construct the style string.
# Currently supports color and orientation
cstr, a = pgf_color(val.font.color)
push!(
o,
PGFPlots.Plots.Node(
val.str, # Annotation Text
x,
y,
style = """
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation),
font=$(pgf_font(val.font.pointsize, thickness_scaling))
""",
),
)
cstr,a = pgf_color(val.font.color)
push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text
x, y,
style="""
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation),
font=$(pgf_font(val.font.pointsize, thickness_scaling))
"""))
end
# --------------------------------------------------------------------------------------
@@ -251,15 +241,7 @@ function pgf_series(sp::Subplot, series::Series)
# add fillrange
if series[:fillrange] !== nothing && st != :shape
push!(
series_collection,
pgf_fillrange_series(
series,
i,
_cycle(series[:fillrange], rng),
seg_args...,
),
)
push!(series_collection, pgf_fillrange_series(series, i, _cycle(series[:fillrange], rng), seg_args...))
end
# build/return the series object
@@ -331,7 +313,7 @@ end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
axis = sp[get_attr_symbol(letter, :axis)]
axis = sp[Symbol(letter,:axis)]
style = []
kw = KW()
@@ -342,7 +324,7 @@ function pgf_axis(sp::Subplot, letter)
framestyle = pgf_framestyle(sp[:framestyle])
# axis guide
kw[get_attr_symbol(letter, :label)] = axis[:guide]
kw[Symbol(letter,:label)] = axis[:guide]
# axis label position
labelpos = ""
@@ -354,23 +336,7 @@ function pgf_axis(sp::Subplot, letter)
# Add label font
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
push!(
style,
string(
letter,
"label style = {",
labelpos,
"font = ",
pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
axis[:guidefontrotation],
"}",
),
)
push!(style, string(letter, "label style = {", labelpos ,"font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
@@ -378,7 +344,7 @@ function pgf_axis(sp::Subplot, letter)
# scale
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
kw[get_attr_symbol(letter, :mode)] = "log"
kw[Symbol(letter,:mode)] = "log"
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
end
@@ -397,20 +363,16 @@ function pgf_axis(sp::Subplot, letter)
# limits
# TODO: support zlims
if letter != :z
lims =
ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
axis_limits(sp, letter)
kw[get_attr_symbol(letter, :min)] = lims[1]
kw[get_attr_symbol(letter, :max)] = lims[2]
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
ticks = get_ticks(sp, axis)
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
tick_values =
ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] :
ticks[1]
push!(style, string(letter, "tick = {", join(tick_values, ","), "}"))
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = Vector{String}(undef, length(ticks[2]))
@@ -419,59 +381,21 @@ function pgf_axis(sp::Subplot, letter)
power = string("{", power, "}")
tick_labels[i] = string(base, "^", power)
end
push!(
style,
string(letter, "ticklabels = {\$", join(tick_labels, "\$,\$"), "\$}"),
)
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels =
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
if axis[:formatter] in (:scientific, :auto)
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
end
push!(style, string(letter, "ticklabels = {", join(tick_labels, ","), "}"))
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
end
push!(
style,
string(
letter,
"tick align = ",
(axis[:tick_direction] == :out ? "outside" : "inside"),
),
)
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
cstr, α = pgf_color(plot_color(axis[:tickfontcolor]))
push!(
style,
string(
letter,
"ticklabel style = {font = ",
pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
axis[:tickfontrotation],
"}",
),
)
push!(
style,
string(
letter,
" grid style = {",
pgf_linestyle(
pgf_thickness_scaling(sp) * axis[:gridlinewidth],
axis[:foreground_color_grid],
axis[:gridalpha],
axis[:gridstyle],
),
"}",
),
)
push!(style, string(letter, "ticklabel style = {font = ", pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:tickfontrotation], "}"))
push!(style, string(letter, " grid style = {", pgf_linestyle(pgf_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]), "}"))
end
# framestyle
@@ -488,20 +412,7 @@ function pgf_axis(sp::Subplot, letter)
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(
style,
string(
"extra ",
letter,
" tick style = {grid = major, major grid style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
axis[:foreground_color_border],
1.0,
),
"}}",
),
)
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
end
if !axis[:showaxis]
@@ -510,19 +421,7 @@ function pgf_axis(sp::Subplot, letter)
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
else
push!(
style,
string(
letter,
" axis line style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
axis[:foreground_color_border],
1.0,
),
"}",
),
)
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
end
# return the style list and KW args
@@ -531,6 +430,7 @@ end
# ----------------------------------------------------------------
function _update_plot_object(plt::Plot{PGFPlotsBackend})
plt.o = PGFPlots.Axis[]
# Obtain the total height of the plot by extracting the maximal bottom
@@ -538,7 +438,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
total_height = bottom(bbox(plt.layout))
for sp in plt.subplots
# first build the PGFPlots.Axis object
# first build the PGFPlots.Axis object
style = ["unbounded coords=jump"]
kw = KW()
@@ -556,34 +456,18 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# A round on 2 decimal places should be enough precision for 300 dpi
# plots.
bb = bbox(sp)
push!(
style,
"""
xshift = $(left(bb).value)mm,
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""",
)
push!(style, """
xshift = $(left(bb).value)mm,
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""")
kw[:width] = "$(width(bb).value)mm"
kw[:height] = "$(height(bb).value)mm"
if sp[:title] != ""
kw[:title] = "$(sp[:title])"
cstr, α = pgf_color(plot_color(sp[:titlefontcolor]))
push!(
style,
string(
"title style = {font = ",
pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)),
", color = ",
cstr,
", draw opacity = ",
α,
", rotate = ",
sp[:titlefontrotation],
"}",
),
)
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
end
if get_aspect_ratio(sp) in (1, :equal)
@@ -597,25 +481,15 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
cstr, bg_alpha = pgf_color(plot_color(sp[:background_color_legend]))
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
push!(
style,
string(
"legend style = {",
pgf_linestyle(
pgf_thickness_scaling(sp),
sp[:foreground_color_legend],
fg_alpha,
"solid",
),
",",
push!(style, string(
"legend style = {",
pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid", ), ",",
"fill = $cstr,",
"fill opacity = $bg_alpha,",
"text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),",
"font = ",
pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)),
"}",
),
)
"font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)),
"}",
))
if any(s[:seriestype] == :contour for s in series_list(sp))
kw[:view] = "{0}{90}"
@@ -646,10 +520,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
for series in series_list(sp)
for col in (:markercolor, :fillcolor, :linecolor)
if typeof(series.plotattributes[col]) == ColorGradient
push!(
style,
"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}",
)
push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}")
if sp[:colorbar] == :none
kw[:colorbar] = "false"
@@ -672,26 +543,17 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# add series annotations
anns = series[:series_annotations]
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
pgf_add_annotation!(
o,
xi,
yi,
PlotText(str, fnt),
pgf_thickness_scaling(series),
)
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt), pgf_thickness_scaling(series))
end
end
# add the annotations
for ann in sp[:annotations]
pgf_add_annotation!(
o,
locate_annotation(sp, ann...)...,
pgf_thickness_scaling(sp),
)
pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp))
end
# add the PGFPlots.Axis to the list
push!(plt.o, o)
end
@@ -706,7 +568,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
pgfplt = PGFPlots.plot(plt.o)
# save a pdf
fn = tempname() * ".pdf"
fn = tempname()*".pdf"
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
@@ -717,12 +579,8 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
end
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
fn = tempname() * ".tex"
PGFPlots.save(
fn,
backend_object(plt),
include_preamble = plt.attr[:tex_output_standalone],
)
fn = tempname()*".tex"
PGFPlots.save(fn, backend_object(plt), include_preamble=plt.attr[:tex_output_standalone])
write(io, read(open(fn), String))
end
-607
View File
@@ -1,607 +0,0 @@
# https://github.com/mbaz/Gaston.
# --------------------------------------------
# These functions are called by Plots
# --------------------------------------------
# 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
elseif st == :heatmap
length(x) == size(z, 2) + 1 && (x = @view x[1:(end - 1)])
length(y) == size(z, 1) + 1 && (y = @view y[1:(end - 1)])
end
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]
if sp[:legend] (: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[:legendtitle] !== nothing
# NOTE: cannot use legendtitlefont(sp) as it will override legendfont
push!(axesconf, "set key title '$(sp[:legendtitle])'")
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
+283 -520
View File
File diff suppressed because it is too large Load Diff
+122 -120
View File
@@ -13,6 +13,7 @@ Read from .hdf5 file using:
display(pread)
==#
#==TODO
===============================================================================
1. Support more features.
@@ -45,7 +46,7 @@ import Dates
#Plots.jl imports HDF5 to main:
import ..HDF5
import ..HDF5: Group, Dataset
import ..HDF5: HDF5Group, HDF5Dataset
import ..Colors, ..Colorant
import ..PlotUtils.ColorSchemes.ColorScheme
@@ -55,8 +56,7 @@ import ..HDF5PLOT_MAP_STR2TELEM, ..HDF5PLOT_MAP_TELEM2STR
import ..HDF5Plot_PlotRef, ..HDF5PLOT_PLOTREF
import ..BoundingBox, ..Extrema, ..Length
import ..RecipesPipeline.datetimeformatter
import ..PlotUtils.ColorPalette,
..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient
import ..PlotUtils.ColorPalette, ..PlotUtils.CategoricalColorGradient, ..PlotUtils.ContinuousColorGradient
import ..Surface, ..Shape, ..Arrow
import ..GridLayout, ..RootLayout
import ..Font, ..PlotText, ..SeriesAnnotations
@@ -66,13 +66,14 @@ import .._axis_defaults
import ..plot, ..plot!
#Types that already have built-in HDF5 support (just write out natively):
const HDF5_SupportedTypes = Union{Number,String}
const HDF5_SupportedTypes = Union{Number, String}
#TODO: Types_HDF5Support
#Dispatch types:
struct CplxTuple end #Identifies a "complex" tuple structure (not merely numbers)
struct CplxTuple; end #Identifies a "complex" tuple structure (not merely numbers)
#HDF5 reader will auto-detect type correctly:
struct HDF5_AutoDetect end #See HDF5_SupportedTypes
struct HDF5_AutoDetect; end #See HDF5_SupportedTypes
#==
===============================================================================#
@@ -81,12 +82,13 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
#(Used to add type information as an HDF5 string attribute)
#(Also used to dispatch appropriate read function through _read_typed())
_telem2str = Dict{String,Type}(
_telem2str = Dict{String, Type}(
"NOTHING" => Nothing,
"SYMBOL" => Symbol,
"RGBA" => Colorant, #Write out any Colorant to an #RRGGBBAA string
"TUPLE" => Tuple,
"CTUPLE" => CplxTuple,
"CTUPLE" => CplxTuple, #Tuple of complex structures
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Array{Any} (because Array{T<:Union{Number, String}} natively supported by HDF5)
@@ -113,12 +115,10 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1
"SUBPLOT" => Subplot,
)
merge!(HDF5PLOT_MAP_STR2TELEM, _telem2str) #Faster to create than push!()??
merge!(
HDF5PLOT_MAP_TELEM2STR,
Dict{Type,String}(v => k for (k, v) in HDF5PLOT_MAP_STR2TELEM),
)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
#==Helper functions
===============================================================================#
@@ -151,47 +151,48 @@ function _hdf5_merge!(dest::AKW, src::AKW)
end
#_type_for_map returns the type to use with HDF5PLOT_MAP_TELEM2STR[], in case it is not concrete:
_type_for_map(::Type{T}) where {T} = T #Catch-all
_type_for_map(::Type{T}) where {T<:BoundingBox} = BoundingBox
_type_for_map(::Type{T}) where {T<:ColorScheme} = ColorScheme
_type_for_map(::Type{T}) where {T<:Surface} = Surface
_type_for_map(::Type{T}) where T = T #Catch-all
_type_for_map(::Type{T}) where T<:BoundingBox = BoundingBox
_type_for_map(::Type{T}) where T<:ColorScheme = ColorScheme
_type_for_map(::Type{T}) where T<:Surface = Surface
#==Read/write things like type name in attributes
===============================================================================#
function _write_datatype_attr(ds::Union{Group,Dataset}, ::Type{T}) where {T}
function _write_datatype_attr(ds::Union{HDF5Group, HDF5Dataset}, ::Type{T}) where T
typestr = HDF5PLOT_MAP_TELEM2STR[T]
HDF5.attributes(ds)["TYPE"] = typestr
HDF5.attrs(ds)["TYPE"] = typestr
end
function _read_datatype_attr(ds::Union{Group,Dataset})
if !Base.haskey(HDF5.attributes(ds), "TYPE")
function _read_datatype_attr(ds::Union{HDF5Group, HDF5Dataset})
if !HDF5.exists(HDF5.attrs(ds), "TYPE")
return HDF5_AutoDetect
end
typestr = HDF5.read(HDF5.attributes(ds)["TYPE"])
typestr = HDF5.read(HDF5.attrs(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
function _write_typeparam_attr(ds::HDF5Dataset, v::Length{T}) where T
HDF5.attrs(ds)["TYPEPARAM"] = string(T) #Need to add units for Length
end
_read_typeparam_attr(ds::Dataset) = HDF5.read(HDF5.attributes(ds)["TYPEPARAM"])
_read_typeparam_attr(ds::HDF5Dataset) = HDF5.read(HDF5.attrs(ds)["TYPEPARAM"])
function _write_length_attr(grp::Group, v::Vector) #of a vector
HDF5.attributes(grp)["LENGTH"] = length(v)
function _write_length_attr(grp::HDF5Group, v::Vector) #of a vector
HDF5.attrs(grp)["LENGTH"] = length(v)
end
_read_length_attr(::Type{Vector}, grp::Group) = HDF5.read(HDF5.attributes(grp)["LENGTH"])
_read_length_attr(::Type{Vector}, grp::HDF5Group) = HDF5.read(HDF5.attrs(grp)["LENGTH"])
function _write_size_attr(grp::Group, v::Array) #of an array
HDF5.attributes(grp)["SIZE"] = [size(v)...]
function _write_size_attr(grp::HDF5Group, v::Array) #of an array
HDF5.attrs(grp)["SIZE"] = [size(v)...]
end
_read_size_attr(::Type{Array}, grp::Group) =
tuple(HDF5.read(HDF5.attributes(grp)["SIZE"])...)
_read_size_attr(::Type{Array}, grp::HDF5Group) = tuple(HDF5.read(HDF5.attrs(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
function _write_typed(grp::HDF5Group, name::String, v::T) where T
tstr = string(T)
path = HDF5.name(grp) * "/" * name
@info("Type not supported: $tstr\npath: $path")
@@ -199,50 +200,52 @@ function _write_typed(grp::Group, name::String, v::T) where T
end
=#
#Default behaviour: Assumes value is supported by HDF5 format
function _write_typed(grp::Group, name::String, v::HDF5_SupportedTypes)
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, name::String, v::Symbol)
grp[name] = String(v)
_write_datatype_attr(grp[name], Symbol)
end
function _write_typed(grp::Group, name::String, v::Colorant)
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, 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))
function _write_typed(grp::HDF5Group, name::String, v::typeof(datetimeformatter))
grp[name] = string(v) #Just write something that helps reader
_write_datatype_attr(grp[name], typeof(datetimeformatter))
_write_datatype_attr(grp[name], typeof(datetimeformatter))
end
function _write_typed(grp::Group, name::String, v::Array{T}) where {T<:Number} #Default for arrays
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, 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)
function _write_harray(grp::HDF5Group, name::String, v::Array)
sgrp = HDF5.g_create(grp, name)
sz = size(v)
lidx = LinearIndices(sz)
@@ -257,8 +260,8 @@ function _write_harray(grp::Group, name::String, v::Array)
end
#Write Dict without tagging with type:
function _write(grp::Group, name::String, d::AbstractDict)
sgrp = HDF5.create_group(grp, name)
function _write(grp::HDF5Group, name::String, d::AbstractDict)
sgrp = HDF5.g_create(grp, name)
for (k, v) in d
kstr = string(k)
_write_typed(sgrp, kstr, v)
@@ -267,19 +270,20 @@ function _write(grp::Group, name::String, d::AbstractDict)
end
#Write out arbitrary `struct`s:
function _writestructgeneric(grp::Group, obj::T) where {T}
function _writestructgeneric(grp::HDF5Group, obj::T) where T
for fname in fieldnames(T)
v = getfield(obj, fname)
_write_typed(grp, String(fname), v)
v = getfield(obj, fname)
_write_typed(grp, String(fname), v)
end
return
end
#==_write_typed(): More complex structures. (Labels with type name.)
===============================================================================#
#Catch-all (default behaviour for `struct`s):
function _write_typed(grp::Group, name::String, v::T) where {T}
function _write_typed(grp::HDF5Group, 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
@@ -290,67 +294,68 @@ function _write_typed(grp::Group, name::String, v::T) where {T}
end
#If attribute is supported and no writer is defined, then this should work:
objgrp = HDF5.create_group(grp, name)
objgrp = HDF5.g_create(grp, name)
_write_datatype_attr(objgrp, MT)
_writestructgeneric(objgrp, v)
end
function _write_typed(grp::Group, name::String, v::Array{T}) where {T}
function _write_typed(grp::HDF5Group, name::String, v::Array{T}) where T
_write_harray(grp, name, v)
_write_datatype_attr(grp[name], Array) #{Any}
end
function _write_typed(grp::Group, name::String, v::Tuple, ::Type{ELT}) where {ELT<:Number} #Basic Tuple
function _write_typed(grp::HDF5Group, 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
function _write_typed(grp::HDF5Group, 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))
_write_typed(grp::HDF5Group, 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
=#
function _write_typed(grp::HDF5Group, 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
function _write_typed(grp::HDF5Group, 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)
function _write_typed(grp::HDF5Group, name::String, v::Axis)
sgrp = HDF5.g_create(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)
function _write_typed(grp::HDF5Group, name::String, v::Subplot)
#Not for use in main "Plot.subplots[]" hierarchy. Just establishes reference with subplot_index.
sgrp = HDF5.create_group(grp, name)
sgrp = HDF5.g_create(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)
function _write_typed(grp::HDF5Group, 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})
function _write(grp::HDF5Group, sp::Subplot{HDF5Backend})
_write_typed(grp, "attr", sp.attr)
listgrp = HDF5.create_group(grp, "series_list")
listgrp = HDF5.g_create(grp, "series_list")
_write_length_attr(listgrp, sp.series_list)
for (i, series) in enumerate(sp.series_list)
#Just write .plotattributes part:
@@ -360,73 +365,71 @@ function _write(grp::Group, sp::Subplot{HDF5Backend})
return
end
function _write(grp::Group, plt::Plot{HDF5Backend})
function _write(grp::HDF5Group, plt::Plot{HDF5Backend})
_write_typed(grp, "attr", plt.attr)
listgrp = HDF5.create_group(grp, "subplots")
listgrp = HDF5.g_create(grp, "subplots")
_write_length_attr(listgrp, plt.subplots)
for (i, sp) in enumerate(plt.subplots)
sgrp = HDF5.create_group(listgrp, "$i")
sgrp = HDF5.g_create(listgrp, "$i")
_write(sgrp, sp)
end
return
end
function hdf5plot_write(
plt::Plot{HDF5Backend},
path::AbstractString;
name::String = "_unnamed",
)
function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString; name::String="_unnamed")
HDF5.h5open(path, "w") do file
HDF5.write_dataset(file, "VERSION_INFO", _get_Plots_versionstr())
grp = HDF5.create_group(file, h5plotpath(name))
HDF5.d_write(file, "VERSION_INFO", _get_Plots_versionstr())
grp = HDF5.g_create(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)
_read(::Type{HDF5_AutoDetect}, ds::HDF5Dataset) = HDF5.read(ds)
function _read(::Type{Nothing}, ds::Dataset)
function _read(::Type{Nothing}, ds::HDF5Dataset)
nstr = "nothing"
v = HDF5.read(ds)
if nstr != v
path = HDF5.name(ds)
throw(Meta.ParseError("_read(::Nothing, ::Group): Read $v != $nstr:\n$path"))
throw(Meta.ParseError("_read(::Nothing, ::HDF5Group): 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)
_read(::Type{Symbol}, ds::HDF5Dataset) = Symbol(HDF5.read(ds))
_read(::Type{Colorant}, ds::HDF5Dataset) = parse(Colorant, HDF5.read(ds))
_read(::Type{Tuple}, ds::HDF5Dataset) = tuple(HDF5.read(ds)...)
function _read(::Type{Extrema}, ds::HDF5Dataset)
v = HDF5.read(ds)
return Extrema(v[1], v[2])
end
function _read(::Type{Length}, ds::Dataset)
function _read(::Type{Length}, ds::HDF5Dataset)
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
_read(::Type{typeof(datetimeformatter)}, ds::HDF5Dataset) = 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)
function _read_typed(grp::HDF5Group, 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}
function _readstructgeneric(::Type{T}, grp::HDF5Group) where T
vlist = Array{Any}(nothing, fieldcount(T))
for (i, fname) in enumerate(fieldnames(T))
vlist[i] = _read_typed(grp, String(fname))
@@ -435,10 +438,10 @@ function _readstructgeneric(::Type{T}, grp::Group) where {T}
end
#Read KW from group:
function _read(::Type{KW}, grp::Group)
function _read(::Type{KW}, grp::HDF5Group)
d = KW()
gkeys = keys(grp)
for k in gkeys
gnames = names(grp)
for k in gnames
try
v = _read_typed(grp, k)
d[Symbol(k)] = v
@@ -451,17 +454,16 @@ function _read(::Type{KW}, grp::Group)
return d
end
#== _read(): More complex structures.
===============================================================================#
#Catch-all (default behaviour for `struct`s):
_read(T::Type, grp::Group) = _readstructgeneric(T, grp)
_read(T::Type, grp::HDF5Group) = _readstructgeneric(T, grp)
function _read(::Type{Array}, grp::Group) #Array{Any}
function _read(::Type{Array}, grp::HDF5Group) #Array{Any}
sz = _read_size_attr(Array, grp)
if tuple(0) == sz
return []
end
if tuple(0) == sz; return []; end
result = Array{Any}(undef, sz)
lidx = LinearIndices(sz)
@@ -477,9 +479,9 @@ function _read(::Type{Array}, grp::Group) #Array{Any}
return reshape(result, sz)
end
_read(::Type{CplxTuple}, grp::Group) = tuple(_read(Array, grp)...)
_read(::Type{CplxTuple}, grp::HDF5Group) = tuple(_read(Array, grp)...)
function _read(::Type{GridLayout}, grp::Group)
function _read(::Type{GridLayout}, grp::HDF5Group)
#parent = _read_typed(grp, "parent") #Can't use generic reader
parent = RootLayout() #TODO: support parent???
minpad = _read_typed(grp, "minpad")
@@ -492,33 +494,32 @@ function _read(::Type{GridLayout}, grp::Group)
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)
function _read(::Type{DefaultsDict}, grp::HDF5Group)
#User should set DefaultsDict.defaults to one of:
# _plot_defaults, _subplot_defaults, _axis_defaults, _series_defaults
path = HDF5.name(ds)
@warn(
"Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot."
)
@warn("Cannot yet read DefaultsDict using _read_typed():\n $path\nCannot fully reconstruct plot.")
end
function _read(::Type{Axis}, grp::Group)
function _read(::Type{Axis}, grp::HDF5Group)
#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)
function _read(::Type{Subplot}, grp::HDF5Group)
#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")
function _read(grp::HDF5Group, sp::Subplot)
listgrp = HDF5.g_open(grp, "series_list")
nseries = _read_length_attr(Vector, listgrp)
for i in 1:nseries
sgrp = HDF5.open_group(listgrp, "$i")
sgrp = HDF5.g_open(listgrp, "$i")
seriesinfo = _read(KW, sgrp)
plot!(sp, seriesinfo[:x], seriesinfo[:y]) #Add data & create data structures
@@ -526,40 +527,42 @@ function _read(grp::Group, sp::Subplot)
end
#Perform after adding series... otherwise values get overwritten:
agrp = HDF5.open_group(grp, "attr")
agrp = HDF5.g_open(grp, "attr")
_hdf5_merge!(sp.attr, _read(KW, agrp))
return sp
end
function _read_plot(grp::Group)
listgrp = HDF5.open_group(grp, "subplots")
function _read_plot(grp::HDF5Group)
listgrp = HDF5.g_open(grp, "subplots")
n = _read_length_attr(Vector, listgrp)
#Construct new plot, +allocate subplots:
plt = plot(layout = n)
plt = plot(layout=n)
HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout"
agrp = HDF5.open_group(grp, "attr")
agrp = HDF5.g_open(grp, "attr")
_hdf5_merge!(plt.attr, _read(KW, agrp))
for (i, sp) in enumerate(plt.subplots)
sgrp = HDF5.open_group(listgrp, "$i")
sgrp = HDF5.g_open(listgrp, "$i")
_read(sgrp, sp)
end
return plt
end
function hdf5plot_read(path::AbstractString; name::String = "_unnamed")
function hdf5plot_read(path::AbstractString; name::String="_unnamed")
HDF5.h5open(path, "r") do file
grp = HDF5.open_group(file, h5plotpath("_unnamed"))
grp = HDF5.g_open(file, h5plotpath("_unnamed"))
return _read_plot(grp)
end
end
end #module _hdf5_implementation
#==Implement Plots.jl backend interface for HDF5Backend
===============================================================================#
@@ -637,8 +640,7 @@ end
#==Interface actually required to use HDF5Backend
===============================================================================#
hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) =
_hdf5_implementation.hdf5plot_write(plt, path)
hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString) = _hdf5_implementation.hdf5plot_write(plt, path)
hdf5plot_write(path::AbstractString) = _hdf5_implementation.hdf5plot_write(current(), path)
hdf5plot_read(path::AbstractString) = _hdf5_implementation.hdf5plot_read(path)
+104 -209
View File
@@ -17,6 +17,9 @@ Add in functionality to Plots.jl:
is_marker_supported(::InspectDRBackend, shape::Shape) = true
_inspectdr_to_pixels(bb::BoundingBox) =
InspectDR.BoundingBox(to_pixels(left(bb)), to_pixels(right(bb)), to_pixels(top(bb)), to_pixels(bottom(bb)))
#Do we avoid Map to avoid possible pre-comile issues?
function _inspectdr_mapglyph(s::Symbol)
s == :rect && return :square
@@ -44,16 +47,16 @@ _inspectdr_mapcolor(v::Colorant) = v
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
@warn("Color gradients are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(g.colors[div(1 + end, 2)])
_inspectdr_mapcolor(g.colors[div(1+end,2)])
end
function _inspectdr_mapcolor(v::AVec)
@warn("Vectors of colors are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(v[div(1 + end, 2)])
_inspectdr_mapcolor(v[div(1+end,2)])
end
#Hack: suggested point size does not seem adequate relative to plot size, for some reason.
_inspectdr_mapptsize(v) = 1.5 * v
_inspectdr_mapptsize(v) = 1.5*v
function _inspectdr_add_annotations(plot, x, y, val)
#What kind of annotation is this?
@@ -61,21 +64,14 @@ end
#plot::InspectDR.Plot2D
function _inspectdr_add_annotations(plot, x, y, val::PlotText)
vmap = Dict{Symbol,Symbol}(:top => :t, :bottom => :b) #:vcenter
hmap = Dict{Symbol,Symbol}(:left => :l, :right => :r) #:hcenter
vmap = Dict{Symbol, Symbol}(:top=>:t, :bottom=>:b) #:vcenter
hmap = Dict{Symbol, Symbol}(:left=>:l, :right=>:r) #:hcenter
align = Symbol(get(vmap, val.font.valign, :c), get(hmap, val.font.halign, :c))
fnt = InspectDR.Font(
val.font.family,
val.font.pointsize,
color = _inspectdr_mapcolor(val.font.color),
fnt = InspectDR.Font(val.font.family, val.font.pointsize,
color =_inspectdr_mapcolor(val.font.color)
)
ann = InspectDR.atext(
val.str,
x = x,
y = y,
font = fnt,
angle = val.font.rotation,
align = align,
ann = InspectDR.atext(val.str, x=x, y=y,
font=fnt, angle=val.font.rotation, align=align
)
InspectDR.add(plot, ann)
return
@@ -83,63 +79,9 @@ 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
#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
@@ -154,12 +96,13 @@ end
# ---------------------------------------------------------------------------
#Glyph used when plotting "Shape"s:
INSPECTDR_GLYPH_SHAPE =
InspectDR.GlyphPolyline(2 * InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y)
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
mutable struct InspecDRPlotRef
mplot::Union{Nothing,InspectDR.Multiplot}
gui::Union{Nothing,InspectDR.GtkPlot}
mplot::Union{Nothing, InspectDR.Multiplot}
gui::Union{Nothing, InspectDR.GtkPlot}
end
_inspectdr_getmplot(::Any) = nothing
@@ -208,9 +151,7 @@ end
function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend})
plot = sp.o
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot
return
end
if nothing == plot; return; end
plot.data = []
plot.userannot = [] #Clear old markers/text annotation/polyline "annotation"
return plot
@@ -226,12 +167,9 @@ 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
if nothing == plot; return; end
_vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x, y = if st == :straightline
@@ -242,33 +180,30 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
Θ = x
r = y
x = r .* cos.(Θ)
y = r .* sin.(Θ)
Θ = x; r = y
x = r.*cos.(Θ); y = r.*sin.(Θ)
end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
nx = length(x)
ny = length(y)
nx = length(x); ny = length(y)
if nx < ny
series[:x] = Float64[x[mod1(i, nx)] for i in 1:ny]
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
elseif ny > nx
series[:y] = Float64[y[mod1(i, ny)] for i in 1:nx]
series[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
end
#= TODO: Eventually support
series[:fillcolor] #I think this is fill under line
zorder = series[:series_plotindex]
#= TODO: Eventually support
series[:fillcolor] #I think this is fill under line
zorder = series[:series_plotindex]
For st in :shape:
zorder = series[:series_plotindex],
=#
For st in :shape:
zorder = series[:series_plotindex],
=#
if st in (:shape,)
x, y = shape_data(series)
nmax = 0
for (i, rng) in enumerate(iter_segments(x, y))
for (i,rng) in enumerate(iter_segments(x, y))
nmax = i
if length(rng) > 1
linewidth = series[:linewidth]
@@ -276,12 +211,11 @@ function _series_added(plt::Plot{InspectDRBackend}, series::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)
line = InspectDR.line(
style=:solid, width=linewidth, color=linecolor
)
apline = InspectDR.PolylineAnnotation(
x[rng],
y[rng],
line = line,
fillcolor = fillcolor,
x[rng], y[rng], line=line, fillcolor=fillcolor
)
InspectDR.add(plot, apline)
end
@@ -294,24 +228,21 @@ function _series_added(plt::Plot{InspectDRBackend}, series::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 = InspectDR.add(plot, Float64[], Float64[], id=series[:label])
wfrm.line = InspectDR.line(
style = :none,
width = linewidth, #linewidth affects glyph
style=:none, width=linewidth, #linewidth affects glyph
)
wfrm.glyph = InspectDR.glyph(
shape = INSPECTDR_GLYPH_SHAPE,
size = 8,
color = linecolor,
fillcolor = fillcolor,
shape = INSPECTDR_GLYPH_SHAPE, size = 8,
color = linecolor, fillcolor = fillcolor
)
end
elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost)
elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost)
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth:
_style = (0 == linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id = series[:label])
_style = (0==linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id=series[:label])
wfrm.line = InspectDR.line(
style = _style,
width = series[:linewidth],
@@ -325,18 +256,14 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
wfrm.glyph = InspectDR.glyph(
shape = _inspectdr_mapglyph(series[:markershape]),
size = _inspectdr_mapglyphsize(series[:markersize]),
color = _inspectdr_mapcolor(
plot_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
),
fillcolor = _inspectdr_mapcolor(
plot_color(get_markercolor(series, clims), get_markeralpha(series)),
),
color = _inspectdr_mapcolor(plot_color(series[:markerstrokecolor], series[:markerstrokealpha])),
fillcolor = _inspectdr_mapcolor(plot_color(series[:markercolor], series[:markeralpha])),
)
end
# this is all we need to add the series_annotations text
anns = series[:series_annotations]
for (xi, yi, str, fnt) in EachAnn(anns, x, y)
for (xi,yi,str,fnt) in EachAnn(anns, x, y)
_inspectdr_add_annotations(plot, xi, yi, PlotText(str, fnt))
end
return
@@ -356,91 +283,72 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
plot = sp.o
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
ygrid_show = yaxis[:grid]
strip.grid = InspectDR.GridRect(
vmajor = xgrid_show, # vminor=xgrid_show,
hmajor = ygrid_show, # hminor=ygrid_show,
vmajor=xgrid_show, # vminor=xgrid_show,
hmajor=ygrid_show, # hminor=ygrid_show,
)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
if ispolar(sp)
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
rmax = NaNMath.max(abs(ymin), abs(ymax))
xmin, xmax = -rmax, rmax
ymin, ymax = -rmax, rmax
end
plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
#Set current extents = full extents (needed for _eval(strip.grid,...))
plot.xext = plot.xext_full
strip.yext = strip.yext_full
_inspectdr_setticks(sp, plot, strip, xaxis, yaxis)
plot.xscale = _inspectdr_getscale(xaxis[:scale], false)
strip.yscale = _inspectdr_getscale(yaxis[:scale], true)
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
if ispolar(sp)
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
rmax = NaNMath.max(abs(ymin), abs(ymax))
xmin, xmax = -rmax, rmax
ymin, ymax = -rmax, rmax
end
plot.xext = InspectDR.PExtents1D() #reset
strip.yext = InspectDR.PExtents1D() #reset
plot.xext_full = InspectDR.PExtents1D(xmin, xmax)
strip.yext_full = InspectDR.PExtents1D(ymin, ymax)
a = plot.annotation
a.title = sp[:title]
a.xlabel = xaxis[:guide]
a.ylabels = [yaxis[:guide]]
a.title = sp[:title]
a.xlabel = xaxis[:guide]; a.ylabels = [yaxis[:guide]]
#Modify base layout of new object:
l = plot.layout.defaults = deepcopy(InspectDR.defaults.plotlayout)
#IMPORTANT: Must deepcopy to ensure we don't change layouts of other plots.
#Works because plot uses defaults (not user-overwritten `layout.values`)
l.frame_canvas.fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l.frame_data.fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l.frame_data.line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l.font_title = InspectDR.Font(
sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor]),
)
#Cannot independently control fonts of axes with InspectDR:
l.font_axislabel = InspectDR.Font(
xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor]),
)
l.font_ticklabel = InspectDR.Font(
xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor]),
)
l.enable_legend = (sp[:legend] != :none)
#l.halloc_legend = 150 #TODO: compute???
l.font_legend = InspectDR.Font(
sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:legendfontcolor]),
)
l.frame_legend.fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
#_round!() ensures values use integer spacings (looks better on screen):
InspectDR._round!(InspectDR.autofit2font!(l, legend_width = 10.0)) #10 "em"s wide
return
l = plot.layout
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l[:font_title] = InspectDR.Font(sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:titlefontcolor])
)
#Cannot independently control fonts of axes with InspectDR:
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
)
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:tickfontcolor])
)
l[:enable_legend] = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:legendfontcolor])
)
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
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
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)
@@ -484,19 +392,17 @@ end
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{InspectDRBackend})
plot = sp.o
if !isa(plot, InspectDR.Plot2D)
return sp.minpad
end
if !isa(plot, InspectDR.Plot2D); return sp.minpad; end
#Computing plotbounds with 0-BoundingBox returns required padding:
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0, 0, 0, 0))
bb = InspectDR.plotbounds(plot.layout.values, InspectDR.BoundingBox(0,0,0,0))
#NOTE: plotbounds always pads for titles, legends, etc. even if not in use.
#TODO: possibly zero-out items not in use??
# add in the user-specified margin to InspectDR padding:
leftpad = abs(bb.xmin) * px + sp[:left_margin]
toppad = abs(bb.ymin) * px + sp[:top_margin]
rightpad = abs(bb.xmax) * px + sp[:right_margin]
bottompad = abs(bb.ymax) * px + sp[:bottom_margin]
leftpad = abs(bb.xmin)*px + sp[:left_margin]
toppad = abs(bb.ymin)*px + sp[:top_margin]
rightpad = abs(bb.xmax)*px + sp[:right_margin]
bottompad = abs(bb.ymax)*px + sp[:bottom_margin]
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
@@ -505,25 +411,16 @@ 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[]
if nothing == mplot; return; end
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)
graphbb = _inspectdr_to_pixels(plotarea(sp))
plot = mplot.subplots[i]
plot.plotbb = InspectDR.plotbounds(plot.layout.values, graphbb)
end
gplot = _inspectdr_getgui(plt.o)
if nothing == gplot
return
end
if nothing == gplot; return; end
gplot.src = mplot #Ensure still references current plot
InspectDR.refresh(gplot)
@@ -559,9 +456,7 @@ end
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot
return
end
if nothing == mplot; return; end
gplot = _inspectdr_getgui(plt.o)
if nothing == gplot
+262 -348
View File
@@ -8,11 +8,23 @@ Base.@kwdef mutable struct PGFPlotsXPlot
function PGFPlotsXPlot(is_created, was_shown, the_plot)
pgfx_plot = new(is_created, was_shown, the_plot)
# tikz libraries
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{arrows.meta}")
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usetikzlibrary{backgrounds}")
PGFPlotsX.push_preamble!(
pgfx_plot.the_plot,
"\\usetikzlibrary{arrows.meta}",
)
PGFPlotsX.push_preamble!(
pgfx_plot.the_plot,
"\\usetikzlibrary{backgrounds}",
)
# pgfplots libraries
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{patchplots}")
PGFPlotsX.push_preamble!(pgfx_plot.the_plot, "\\usepgfplotslibrary{fillbetween}")
PGFPlotsX.push_preamble!(
pgfx_plot.the_plot,
"\\usepgfplotslibrary{patchplots}",
)
PGFPlotsX.push_preamble!(
pgfx_plot.the_plot,
"\\usepgfplotslibrary{fillbetween}",
)
# compatibility fixes
# add background layer to standard layers
PGFPlotsX.push_preamble!(
@@ -70,14 +82,13 @@ function surface_to_vecs(x::AVec, y::AVec, s::Union{AMat,Surface})
end
return xn, yn, zn
end
surface_to_vecs(x::AVec, y::AVec, z::AVec) = x, y, z
function Base.push!(pgfx_plot::PGFPlotsXPlot, item)
push!(pgfx_plot.the_plot, item)
end
function pgfx_split_extra_opts(extra)
return (get(extra, :add, nothing), filter(x -> first(x) != :add, extra))
return (get(extra, :add, nothing), filter( x-> first(x) != :add, extra))
end
function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
if !pgfx_plot.is_created || pgfx_plot.was_shown
@@ -89,9 +100,8 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
extra_plot = wraptuple(extra_plot)
push!(the_plot, extra_plot...)
end
bgc =
plt.attr[:background_color_outside] == :match ? plt.attr[:background_color] :
plt.attr[:background_color_outside]
bgc = plt.attr[:background_color_outside] == :match ?
plt.attr[:background_color] : plt.attr[:background_color_outside]
if bgc isa Colors.Colorant
cstr = plot_color(bgc)
a = alpha(cstr)
@@ -107,27 +117,11 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
end
for sp in plt.subplots
bb1 = sp.plotarea
bb2 = bbox(sp)
sp_width = width(bb2)
sp_height = height(bb2)
dx, dy = bb2.x0
sp_width = width(bb2)
sp_height = height(bb2)
if sp[:subplot_index] == plt[:plot_titleindex]
x = dx + sp_width / 2 - 10mm # FIXME: get rid of magic constant
y = dy + sp_height / 2
pgfx_add_annotation!(
the_plot,
x,
y,
PlotText(plt[:plot_title], plottitlefont(plt)),
pgfx_thickness_scaling(plt);
cs = "",
options = PGFPlotsX.Options("anchor" => "center"),
)
continue
end
sp_width = width(bb2)
sp_height = height(bb2)
lpad = leftpad(sp) + sp[:left_margin]
rpad = rightpad(sp) + sp[:right_margin]
tpad = toppad(sp) + sp[:top_margin]
@@ -136,6 +130,10 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
dy += tpad
axis_height = sp_height - (tpad + bpad)
axis_width = sp_width - (rpad + lpad)
cstr = plot_color(sp[:background_color_legend])
a = alpha(cstr)
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
title_cstr = plot_color(sp[:titlefontcolor])
title_a = alpha(title_cstr)
title_loc = sp[:titlelocation]
@@ -144,24 +142,48 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
axis_opt = PGFPlotsX.Options(
"point meta max" => get_clims(sp)[2],
"point meta min" => get_clims(sp)[1],
"legend cell align" => "left",
"title" => sp[:title],
"title style" => PGFPlotsX.Options(
pgfx_get_title_pos(title_loc)...,
"font" => pgfx_font(sp[:titlefontsize], pgfx_thickness_scaling(sp)),
pgfx_get_title_pos(title_loc)...,
"font" => pgfx_font(
sp[:titlefontsize],
pgfx_thickness_scaling(sp),
),
"color" => title_cstr,
"draw opacity" => title_a,
"rotate" => sp[:titlefontrotation],
),
"legend style" => pgfx_get_legend_style(sp),
"axis background/.style" =>
PGFPlotsX.Options("fill" => bgc_inside, "opacity" => bgc_inside_a),
"legend style" => PGFPlotsX.Options(
pgfx_linestyle(
pgfx_thickness_scaling(sp),
sp[:foreground_color_legend],
fg_alpha,
"solid",
) => nothing,
"fill" => cstr,
"fill opacity" => a,
"text opacity" => alpha(plot_color(sp[:legendfontcolor])),
"font" => pgfx_font(
sp[:legendfontsize],
pgfx_thickness_scaling(sp),
),
),
"axis background/.style" => PGFPlotsX.Options(
"fill" => bgc_inside,
"opacity" => bgc_inside_a,
),
# These are for layouting
"anchor" => "north west",
"xshift" => string(dx),
"yshift" => string(-dy),
)
sp_width > 0 * mm ? push!(axis_opt, "width" => string(axis_width)) : nothing
sp_height > 0 * mm ? push!(axis_opt, "height" => string(axis_height)) : nothing
sp_width > 0 * mm ? push!(axis_opt, "width" => string(axis_width)) :
nothing
sp_height > 0 * mm ? push!(axis_opt, "height" => string(axis_height)) :
nothing
# legend position
push!(axis_opt["legend style"], pgfx_get_legend_pos(sp[:legend])...)
for letter in (:x, :y, :z)
if letter != :z || RecipesPipeline.is3d(sp)
pgfx_axis!(axis_opt, sp, letter)
@@ -202,22 +224,16 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
@label colorbar_end
if hascolorbar(sp)
cticks = get_colorbar_ticks(sp)[2]
colorbar_style = PGFPlotsX.Options("title" => sp[:colorbar_title])
colorbar_style = PGFPlotsX.Options(
"title" => sp[:colorbar_title],
"xticklabel style" => pgfx_get_ticklabel_style(sp, sp[:xaxis]),
"yticklabel style" => pgfx_get_ticklabel_style(sp, sp[:yaxis]),
)
if sp[:colorbar] === :top
push!(
colorbar_style,
push!(colorbar_style,
"at" => string((0.5, 1.05)),
"anchor" => "south",
"xtick" => string("{", join(cticks, ","), "}"),
"xticklabel pos" => "upper",
"xticklabel style" => pgfx_get_colorbar_ticklabel_style(sp),
)
else
push!(
colorbar_style,
"ytick" => string("{", join(cticks, ","), "}"),
"yticklabel style" => pgfx_get_colorbar_ticklabel_style(sp),
)
end
push!(
@@ -225,8 +241,6 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
string("colorbar", pgfx_get_colorbar_pos(sp[:colorbar])) => nothing,
"colorbar style" => colorbar_style,
)
else
push!(axis_opt, "colorbar" => "false")
end
if RecipesPipeline.is3d(sp)
azim, elev = sp[:camera]
@@ -266,19 +280,15 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
"color" => single_color(opt[:linecolor]),
"name path" => string(series_id),
)
extra_series, extra_series_opt =
pgfx_split_extra_opts(series[:extra_kwargs])
extra_series, extra_series_opt = pgfx_split_extra_opts(series[:extra_kwargs])
series_opt = merge(series_opt, PGFPlotsX.Options(extra_series_opt...))
if (
RecipesPipeline.is3d(series) ||
st in (:heatmap, :contour) ||
(st == :quiver && opt[:z] !== nothing)
)
if RecipesPipeline.is3d(series) || st in (:heatmap, :contour) || (st == :quiver && opt[:z] !== nothing)
series_func = PGFPlotsX.Plot3
else
series_func = PGFPlotsX.Plot
end
if sf !== nothing && !isfilledcontour(series) && series[:ribbon] === nothing
if sf !== nothing &&
!isfilledcontour(series) && series[:ribbon] === nothing
push!(series_opt, "area legend" => nothing)
end
pgfx_add_series!(Val(st), axis, series_opt, series, series_func, opt)
@@ -328,10 +338,9 @@ end
function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, opt)
# treat segments
segments = collect(series_segments(series, series[:seriestype]; check = true))
segments = iter_segments(series, series[:seriestype])
sf = opt[:fillrange]
for (k, segment) in enumerate(segments)
i, rng = segment.attr_index, segment.range
for (i, rng) in enumerate(segments)
segment_opt = PGFPlotsX.Options()
segment_opt = merge(segment_opt, pgfx_linestyle(opt, i))
if opt[:markershape] != :none
@@ -342,7 +351,10 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o
scale_factor = 0.00125
mark_size = opt[:markersize] * scale_factor
path = join(
["($(x[i] * mark_size), $(y[i] * mark_size))" for i in eachindex(x)],
[
"($(x[i] * mark_size), $(y[i] * mark_size))"
for i in eachindex(x)
],
" -- ",
)
c = get_markercolor(series, i)
@@ -360,26 +372,31 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o
segment_opt = merge(segment_opt, pgfx_marker(opt, i))
end
# add fillrange
if sf !== nothing && !isfilledcontour(series)
if sf isa Number || sf isa AVec
pgfx_fillrange_series!(axis, series, series_func, i, _cycle(sf, rng), rng)
if sf !== nothing &&
!isfilledcontour(series)
if sf isa Number || sf isa AVec
pgfx_fillrange_series!(
axis,
series,
series_func,
i,
_cycle(sf, rng),
rng,
)
elseif sf isa Tuple && series[:ribbon] !== nothing
for sfi in sf
pgfx_fillrange_series!(
axis,
series,
series_func,
i,
_cycle(sfi, rng),
rng,
)
pgfx_fillrange_series!(
axis,
series,
series_func,
i,
_cycle(sfi, rng),
rng,
)
end
end
if (
k == 1 &&
series[:subplot][:legend] != :none &&
pgfx_should_add_to_legend(series)
)
if i == 1 &&
series[:subplot][:legend] != :none && pgfx_should_add_to_legend(series)
pgfx_filllegend!(series_opt, opt)
end
end
@@ -388,44 +405,46 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o
if arrow isa Arrow
arrow_opt = merge(
segment_opt,
PGFPlotsX.Options(
"quiver" => PGFPlotsX.Options(
"u" => "\\thisrow{u}",
"v" => "\\thisrow{v}",
pgfx_arrow(arrow, :head) => nothing,
),
),
PGFPlotsX.Options("quiver" => PGFPlotsX.Options(
"u" => "\\thisrow{u}",
"v" => "\\thisrow{v}",
pgfx_arrow(arrow, :head) => nothing,
)
)
)
if arrow.side == :head
x_arrow = opt[:x][rng][(end - 1):end]
y_arrow = opt[:y][rng][(end - 1):end]
x_path = opt[:x][rng][1:(end - 1)]
y_path = opt[:y][rng][1:(end - 1)]
x_arrow = opt[:x][rng][end-1:end]
y_arrow = opt[:y][rng][end-1:end]
x_path = opt[:x][rng][1:end-1]
y_path = opt[:y][rng][1:end-1]
elseif arrow.side == :tail
x_arrow = opt[:x][rng][2:-1:1]
y_arrow = opt[:y][rng][2:-1:1]
x_path = opt[:x][rng][2:end]
y_path = opt[:y][rng][2:end]
elseif arrow.side == :both
x_arrow = opt[:x][rng][[2, 1, end - 1, end]]
y_arrow = opt[:y][rng][[2, 1, end - 1, end]]
x_path = opt[:x][rng][2:(end - 1)]
y_path = opt[:y][rng][2:(end - 1)]
x_arrow = opt[:x][rng][[2,1,end-1,end]]
y_arrow = opt[:y][rng][[2,1,end-1,end]]
x_path = opt[:x][rng][2:end-1]
y_path = opt[:y][rng][2:end-1]
end
coordinates = PGFPlotsX.Table([
:x => x_arrow[1:2:(end - 1)],
:y => y_arrow[1:2:(end - 1)],
:u => [x_arrow[i] - x_arrow[i - 1] for i in 2:2:lastindex(x_arrow)],
:v => [y_arrow[i] - y_arrow[i - 1] for i in 2:2:lastindex(y_arrow)],
])
arrow_plot = series_func(merge(series_opt, arrow_opt), coordinates)
:x => x_arrow[1:2:end-1],
:y => y_arrow[1:2:end-1],
:u => [x_arrow[i] - x_arrow[i-1] for i in 2:2:lastindex(x_arrow)],
:v => [y_arrow[i] - y_arrow[i-1] for i in 2:2:lastindex(y_arrow)],
])
arrow_plot =
series_func(merge(series_opt, arrow_opt), coordinates)
push!(axis, arrow_plot)
coordinates = PGFPlotsX.Table(x_path, y_path)
segment_plot = series_func(merge(series_opt, segment_opt), coordinates)
segment_plot =
series_func(merge(series_opt, segment_opt), coordinates)
push!(axis, segment_plot)
else
coordinates = PGFPlotsX.Table(pgfx_series_arguments(series, opt, rng)...)
segment_plot = series_func(merge(series_opt, segment_opt), coordinates)
segment_plot =
series_func(merge(series_opt, segment_opt), coordinates)
push!(axis, segment_plot)
end
# fill between functions
@@ -443,14 +462,11 @@ function pgfx_add_series!(::Val{:path}, axis, series_opt, series, series_func, o
),
)
end
pgfx_add_legend!(axis, series, opt, k)
pgfx_add_legend!(axis, series, opt, i)
end # for segments
# get that last marker
if !isnothing(opt[:y]) && !any(isnan, opt[:y]) && opt[:markershape] isa AVec
additional_plot = PGFPlotsX.PlotInc(
pgfx_marker(opt, length(segments) + 1),
PGFPlotsX.Coordinates(tuple((last(opt[:x]), last(opt[:y])))),
)
additional_plot = PGFPlotsX.PlotInc(pgfx_marker(opt, length(segments) + 1), PGFPlotsX.Coordinates(tuple((last(opt[:x]), last(opt[:y])))))
push!(axis, additional_plot)
end
end
@@ -474,20 +490,20 @@ function pgfx_add_series!(::Val{:scatter3d}, axis, series_opt, series, series_fu
end
function pgfx_add_series!(::Val{:surface}, axis, series_opt, series, series_func, opt)
alpha = get_fillalpha(series)
push!(
series_opt,
"surf" => nothing,
"mesh/rows" => length(unique(opt[:x])), # unique if its all vectors
"mesh/cols" => length(unique(opt[:y])),
"mesh/rows" => length(opt[:x]),
"mesh/cols" => length(opt[:y]),
"z buffer" => "sort",
"opacity" => alpha === nothing ? 1.0 : alpha,
)
pgfx_add_series!(axis, series_opt, series, series_func, opt)
end
function pgfx_add_series!(::Val{:wireframe}, axis, series_opt, series, series_func, opt)
push!(series_opt, "mesh" => nothing, "mesh/rows" => length(opt[:x]))
push!(series_opt, "mesh" => nothing,
"mesh/rows" => length(opt[:x])
)
pgfx_add_series!(axis, series_opt, series, series_func, opt)
end
@@ -512,15 +528,12 @@ function pgfx_add_series!(::Val{:heatmap}, axis, series_opt, series, series_func
end
function pgfx_add_series!(::Val{:mesh3d}, axis, series_opt, series, series_func, opt)
ptable = join(
[string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...)],
"\n ",
)
ptable = join([ string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...) ], "\n ")
push!(
series_opt,
"patch" => nothing,
"table/row sep" => "\\\\",
"patch table" => ptable,
"patch table" => ptable
)
pgfx_add_series!(axis, series_opt, series, series_func, opt)
end
@@ -555,10 +568,9 @@ function pgfx_add_series!(::Val{:contour3d}, axis, series_opt, series, series_fu
series_opt,
"contour prepared" => PGFPlotsX.Options("labels" => opt[:contour_labels]),
)
series_opt = merge(series_opt, pgfx_linestyle(opt))
series_opt = merge( series_opt, pgfx_linestyle(opt) )
args = pgfx_series_arguments(series, opt)
series_plot =
series_func(series_opt, PGFPlotsX.Table(Contour.contours(args..., opt[:levels])))
series_plot = series_func(series_opt, PGFPlotsX.Table(Contour.contours(args..., opt[:levels])))
push!(axis, series_plot)
pgfx_add_legend!(axis, series, opt)
end
@@ -656,8 +668,7 @@ function pgfx_add_legend!(axis, series, opt, i = 1)
return nothing
end
pgfx_series_arguments(series, opt, range) =
(arg[range] for arg in pgfx_series_arguments(series, opt))
pgfx_series_arguments(series, opt, range) = (arg[range] for arg in pgfx_series_arguments(series, opt))
function pgfx_series_arguments(series, opt)
st = series[:seriestype]
return if st in (:contour, :contour3d)
@@ -695,7 +706,7 @@ pgfx_get_marker(k) = get(
none = "none",
cross = "+",
xcross = "x",
(+) = "+",
+ = "+",
x = "x",
utriangle = "triangle*",
dtriangle = "triangle*",
@@ -721,7 +732,7 @@ pgfx_get_xguide_pos(k) = get(
left = "at={(ticklabel* cs:-0.02)}, anchor=east,",
),
k,
"at={(ticklabel cs:0.5)}, anchor=near ticklabel",
"at={(ticklabel cs:0.5)}, anchor=near ticklabel"
)
pgfx_get_yguide_pos(k) = get(
@@ -731,7 +742,7 @@ pgfx_get_yguide_pos(k) = get(
bottom = "at={(ticklabel* cs:-0.02)}, anchor=north,",
),
k,
"at={(ticklabel cs:0.5)}, anchor=near ticklabel",
"at={(ticklabel cs:0.5)}, anchor=near ticklabel"
)
pgfx_get_legend_pos(k) = get(
@@ -756,93 +767,36 @@ pgfx_get_legend_pos(k) = get(
Symbol(k),
("at" => string((1.02, 1)), "anchor" => "north west"),
)
pgfx_get_legend_pos(t::Tuple{S,T}) where {S<:Real,T<:Real} =
("at" => "{$(string(t))}", "anchor" => "north west")
pgfx_get_legend_pos(nt::NamedTuple) =
("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor))
pgfx_get_legend_pos(theta::Real) = pgfx_get_legend_pos((theta, :inner))
function pgfx_get_legend_pos(v::Tuple{S,Symbol}) where {S<:Real}
(s, c) = sincosd(v[1])
anchors = [
"south west" "south" "south east"
"west" "center" "east"
"north west" "north" "north east"
]
if v[2] === :inner
rect = (0.07, 0.5, 1.0, 0.07, 0.52, 1.0)
anchor = anchors[legend_anchor_index(s), legend_anchor_index(c)]
else
rect = (-0.15, 0.5, 1.05, -0.15, 0.52, 1.1)
anchor = anchors[4 - legend_anchor_index(s), 4 - legend_anchor_index(c)]
end
return ("at" => "$(string(legend_pos_from_angle(v[1],rect...)))", "anchor" => anchor)
end
function pgfx_get_legend_style(sp)
cstr = plot_color(sp[:background_color_legend])
a = alpha(cstr)
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
legfont = legendfont(sp)
PGFPlotsX.Options(
pgfx_linestyle(
pgfx_thickness_scaling(sp),
sp[:foreground_color_legend],
fg_alpha,
"solid",
) => nothing,
"fill" => cstr,
"fill opacity" => a,
"text opacity" => alpha(plot_color(sp[:legendfontcolor])),
"font" => pgfx_font(sp[:legendfontsize], pgfx_thickness_scaling(sp)),
"text" => plot_color(sp[:legendfontcolor]),
"cells" => PGFPlotsX.Options(
"anchor" => get(
(left = "west", right = "east", hcenter = "center"),
legfont.halign,
"west",
),
),
pgfx_get_legend_pos(sp[:legend])...,
)
end
pgfx_get_legend_pos(t::Tuple) = ("at" => "{$(string(t))}", "anchor" => "north west")
pgfx_get_legend_pos(nt::NamedTuple) = ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor))
pgfx_get_colorbar_pos(s) =
get((left = " left", bottom = " horizontal", top = " horizontal"), s, "")
pgfx_get_colorbar_pos(b::Bool) = ""
pgfx_get_title_pos(s) = get(
(
pgfx_get_title_pos(s) =
get((
left = ("at" => "{(0,1)}", "anchor" => "south west"),
right = ("at" => "{(1,1)}", "anchor" => "south east"),
),
s,
("at" => "{(0.5,1)}", "anchor" => "south"),
)
), s,
("at" => "{(0.5,1)}", "anchor" => "south"))
pgfx_get_title_pos(t::Tuple) = ("at" => "{$(string(t))}", "anchor" => "south")
pgfx_get_title_pos(nt::NamedTuple) =
("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor))
pgfx_get_title_pos(nt::NamedTuple) = ("at" => "{$(string(nt.at))}", "anchor" => string(nt.anchor))
function pgfx_get_ticklabel_style(sp, axis)
cstr = plot_color(axis[:tickfontcolor])
return PGFPlotsX.Options(
"font" => pgfx_font(axis[:tickfontsize], pgfx_thickness_scaling(sp)),
"font" => pgfx_font(
axis[:tickfontsize], pgfx_thickness_scaling(sp)
),
"color" => cstr,
"draw opacity" => alpha(cstr),
"rotate" => axis[:tickfontrotation],
)
end
function pgfx_get_colorbar_ticklabel_style(sp)
cstr = plot_color(sp[:colorbar_tickfontcolor])
return PGFPlotsX.Options(
"font" => pgfx_font(sp[:colorbar_tickfontsize], pgfx_thickness_scaling(sp)),
"color" => cstr,
"draw opacity" => alpha(cstr),
"rotate" => sp[:colorbar_tickfontrotation],
)
end
## --------------------------------------------------------------------------------------
# Generates a colormap for pgfplots based on a ColorGradient
pgfx_arrow(::Nothing) = "every arrow/.append style={-}"
function pgfx_arrow(arr::Arrow, side = arr.side)
components = String[]
@@ -873,7 +827,6 @@ function pgfx_filllegend!(series_opt, opt)
}""")
end
# Generates a colormap for pgfplots based on a ColorGradient
pgfx_colormap(cl::PlotUtils.AbstractColorList) = pgfx_colormap(color_list(cl))
function pgfx_colormap(v::Vector{<:Colorant})
join(map(v) do c
@@ -881,26 +834,18 @@ function pgfx_colormap(v::Vector{<:Colorant})
end, "\n")
end
function pgfx_colormap(cg::ColorGradient)
join(
map(1:length(cg)) do i
@sprintf(
"rgb(%.8f)=(%.8f,%.8f,%.8f)",
cg.values[i],
red(cg.colors[i]),
green(cg.colors[i]),
blue(cg.colors[i])
)
end,
"\n",
)
join(map(1:length(cg)) do i
@sprintf("rgb(%.8fcm)=(%.8f,%.8f,%.8f)", cg.values[i], red(cg.colors[i]), green(cg.colors[i]), blue(cg.colors[i]))
end, "\n")
end
function pgfx_framestyle(style::Symbol)
if style in (:box, :axes, :origin, :zerolines, :grid, :none)
return style
else
default_style = get((semi = :box,), style, :axes)
@warn "Framestyle :$style is not (yet) supported by the PGFPlotsX backend. :$default_style was chosen instead."
@warn( "Framestyle :$style is not (yet) supported by the PGFPlotsX backend. :$default_style was cosen instead.",)
default_style
end
end
@@ -951,20 +896,20 @@ end
function pgfx_should_add_to_legend(series::Series)
series.plotattributes[:primary] &&
!(
series.plotattributes[:seriestype] in (
:hexbin,
:bins2d,
:histogram2d,
:hline,
:vline,
:contour,
:contourf,
:contour3d,
:heatmap,
:image,
)
!(
series.plotattributes[:seriestype] in (
:hexbin,
:bins2d,
:histogram2d,
:hline,
:vline,
:contour,
:contourf,
:contour3d,
:heatmap,
:image,
)
)
end
function pgfx_marker(plotattributes, i = 1)
@@ -981,9 +926,8 @@ function pgfx_marker(plotattributes, i = 1)
pgfx_thickness_scaling(plotattributes) *
0.75 *
_cycle(plotattributes[:markersize], i)
mark_freq =
!any(isnan, plotattributes[:y]) && plotattributes[:markershape] isa AVec ?
length(plotattributes[:markershape]) : 1
mark_freq = !any(isnan, plotattributes[:y]) && plotattributes[:markershape] isa AVec ?
length(plotattributes[:markershape]) : 1
return PGFPlotsX.Options(
"mark" => shape isa Shape ? "PlotsShape$i" : pgfx_get_marker(shape),
"mark size" => "$mark_size pt",
@@ -1006,47 +950,29 @@ function pgfx_marker(plotattributes, i = 1)
else
0
end,
pgfx_get_linestyle(_cycle(plotattributes[:markerstrokestyle], i)) =>
nothing,
pgfx_get_linestyle(_cycle(plotattributes[:markerstrokestyle], i)) => nothing,
),
)
end
function pgfx_add_annotation!(
o,
x,
y,
val,
thickness_scaling = 1;
cs = "axis cs:",
options = PGFPlotsX.Options(),
)
function pgfx_add_annotation!(o, x, y, val, thickness_scaling = 1)
# Construct the style string.
cstr = val.font.color
a = alpha(cstr)
push!(
o,
join([
[
"\\node",
sprint(
PGFPlotsX.print_tex,
merge(
PGFPlotsX.Options(
get(
(hcenter = "", left = "right", right = "left"),
val.font.halign,
"",
) => nothing,
"color" => cstr,
"draw opacity" => convert(Float16, a),
"rotate" => val.font.rotation,
"font" => pgfx_font(val.font.pointsize, thickness_scaling),
),
options,
),
PGFPlotsX.Options(
get((center = "", left = "right", right = "left"), val.font.halign, "") =>
nothing,
"color" => cstr,
"draw opacity" => convert(Float16, a),
"rotate" => val.font.rotation,
"font" => pgfx_font(val.font.pointsize, thickness_scaling),
),
string(" at (", cs, x, ",", y, ") {", val.str, "};"),
]),
" at (axis cs:$x, $y) {$(val.str)};",
],
)
end
@@ -1111,13 +1037,15 @@ end
function pgfx_fillrange_series!(axis, series, series_func, i, fillrange, rng)
fillrange_opt = PGFPlotsX.Options("line width" => "0", "draw opacity" => "0")
fillrange_opt = merge(fillrange_opt, pgfx_fillstyle(series, i))
push!(fillrange_opt, "mark" => "none") # no markers on fillranges
fillrange_opt = merge(fillrange_opt, pgfx_marker(series, i))
push!(fillrange_opt, "forget plot" => nothing)
opt = series.plotattributes
args =
RecipesPipeline.is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) :
args = RecipesPipeline.is3d(series) ? (opt[:x][rng], opt[:y][rng], opt[:z][rng]) :
(opt[:x][rng], opt[:y][rng])
push!(axis, PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)))
push!(
axis,
PGFPlotsX.PlotInc(fillrange_opt, pgfx_fillrange_args(fillrange, args...)),
)
return axis
end
@@ -1147,8 +1075,8 @@ function pgfx_sanitize_string(s::AbstractString)
s = replace(s, r"\\?\{" => "\\{")
s = replace(s, r"\\?\}" => "\\}")
s = map(split(s, "")) do s
isascii(s) ? s : latexify(s)
end |> join
isascii(s) ? s : latexify(s)
end |> join
end
@require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin
using .LaTeXStrings
@@ -1159,64 +1087,60 @@ end
end
end
function pgfx_sanitize_plot!(plt)
for (key, value) in plt.attr
if value isa Union{AbstractString,AbstractVector{<:AbstractString}}
plt.attr[key] = pgfx_sanitize_string.(value)
for (key, value) in plt.attr
if value isa Union{AbstractString, AbstractVector{<:AbstractString}}
plt.attr[key] = pgfx_sanitize_string.(value)
end
end
end
for subplot in plt.subplots
for (key, value) in subplot.attr
if key == :annotations && subplot.attr[:annotations] !== nothing
old_ann = subplot.attr[key]
for i in eachindex(old_ann)
subplot.attr[key][i] =
(old_ann[i][1], old_ann[i][2], pgfx_sanitize_string(old_ann[i][3]))
end
elseif value isa Union{AbstractString,AbstractVector{<:AbstractString}}
subplot.attr[key] = pgfx_sanitize_string.(value)
elseif value isa Axis
for (k, v) in value.plotattributes
if v isa Union{AbstractString,AbstractVector{<:AbstractString}}
value.plotattributes[k] = pgfx_sanitize_string.(v)
for subplot in plt.subplots
for (key, value) in subplot.attr
if key == :annotations && subplot.attr[:annotations] !== nothing
old_ann = subplot.attr[key]
for i in eachindex(old_ann)
subplot.attr[key][i] = (old_ann[i][1], old_ann[i][2], pgfx_sanitize_string(old_ann[i][3]))
end
elseif value isa Union{AbstractString, AbstractVector{<:AbstractString}}
subplot.attr[key] = pgfx_sanitize_string.(value)
end
end
end
end
for series in plt.series_list
for (key, value) in series.plotattributes
if key == :series_annotations &&
series.plotattributes[:series_annotations] !== nothing
old_ann = series.plotattributes[key].strs
for i in eachindex(old_ann)
series.plotattributes[key].strs[i] = pgfx_sanitize_string(old_ann[i])
for series in plt.series_list
for (key, value) in series.plotattributes
if key == :series_annotations && series.plotattributes[:series_annotations] !== nothing
old_ann = series.plotattributes[key].strs
for i in eachindex(old_ann)
series.plotattributes[key].strs[i] = pgfx_sanitize_string(old_ann[i])
end
elseif value isa Union{AbstractString, AbstractVector{<:AbstractString}}
series.plotattributes[key] = pgfx_sanitize_string.(value)
end
elseif value isa Union{AbstractString,AbstractVector{<:AbstractString}}
series.plotattributes[key] = pgfx_sanitize_string.(value)
end
end
end
##
##
end
# --------------------------------------------------------------------------------------
function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
axis = sp[get_attr_symbol(letter, :axis)]
axis = sp[Symbol(letter, :axis)]
# turn off scaled ticks
push!(opt, "scaled $(letter) ticks" => "false", string(letter, :label) => axis[:guide])
tick_color = plot_color(axis[:foreground_color_axis])
push!(
opt,
"$(letter) tick style" =>
PGFPlotsX.Options("color" => color(tick_color), "opacity" => alpha(tick_color)),
"scaled $(letter) ticks" => "false",
string(letter, :label) => axis[:guide],
)
tick_color = plot_color(axis[:foreground_color_axis])
push!(opt,
"$(letter) tick style" => PGFPlotsX.Options(
"color" => color(tick_color),
"opacity" => alpha(tick_color),
),
)
tick_label_color = plot_color(axis[:tickfontcolor])
push!(
opt,
push!(opt,
"$(letter) tick label style" => PGFPlotsX.Options(
"color" => color(tick_color),
"opacity" => alpha(tick_color),
"rotate" => axis[:rotation],
"rotate" => axis[:rotation]
),
)
@@ -1238,13 +1162,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
opt,
string(letter, "label style") => PGFPlotsX.Options(
labelpos => nothing,
"at" => string(
"{(ticklabel cs:",
get((left = 0, right = 1), axis[:guidefonthalign], 0.5),
")}",
),
"anchor" => "near ticklabel",
"font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
"font" => pgfx_font(axis[:guidefontsize], pgfx_thickness_scaling(sp)),
"color" => cstr,
"draw opacity" => α,
"rotate" => axis[:guidefontrotation],
@@ -1258,7 +1176,8 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
push!(opt, string(letter, :mode) => "log")
scale == :ln || push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)")
scale == :ln ||
push!(opt, "log basis $letter" => "$(scale == :log2 ? 2 : 10)")
end
# ticks on or off
@@ -1276,8 +1195,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
end
# limits
lims =
ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) :
axis_limits(sp, letter)
push!(opt, string(letter, :min) => lims[1], string(letter, :max) => lims[2])
@@ -1288,48 +1206,48 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
tick_values =
ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] :
ticks[1]
push!(opt, string(letter, "tick") => string("{", join(tick_values, ","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
push!(
opt,
string(letter, "tick") => string("{", join(tick_values, ","), "}"),
)
if axis[:showaxis] &&
axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = similar(ticks[2])
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
if tick_labels isa Vector{String}
push!(
opt,
string(letter, "ticklabels") =>
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
)
elseif tick_labels isa Vector{LaTeXString}
push!(opt, string(letter, "ticklabels") => join(tick_labels))
end
push!(
opt,
string(letter, "ticklabels") =>
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
)
elseif axis[:showaxis]
tick_labels =
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
if axis[:formatter] in (:scientific, :auto) && tick_labels isa Vector{String}
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] :
ticks[2]
if axis[:formatter] in (:scientific, :auto)
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
end
push!(
opt,
string(letter, "ticklabels") => string("{", join(tick_labels, ","), "}"),
string(letter, "ticklabels") =>
string("{", join(tick_labels, ","), "}"),
)
else
push!(opt, string(letter, "ticklabels") => "{}")
end
if axis[:tick_direction] === :none
push!(opt, string(letter, "tick style") => "draw=none")
else
push!(
opt,
string(letter, "tick align") =>
(axis[:tick_direction] == :out ? "outside" : "inside"),
)
end
push!(opt, string(letter, "ticklabel style") => pgfx_get_ticklabel_style(sp, axis))
push!(
opt,
string(letter, "tick align") =>
(axis[:tick_direction] == :out ? "outside" : "inside"),
)
push!(
opt, string(letter, "ticklabel style") => pgfx_get_ticklabel_style(sp, axis)
)
push!(
opt,
string(letter, " grid style") => pgfx_linestyle(
@@ -1353,8 +1271,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
minor_ticks
push!(
opt,
string("extra ", letter, " ticks") =>
string("{", join(minor_ticks, ","), "}"),
string("extra ", letter, " ticks") => string("{", join(minor_ticks, ","), "}"),
)
push!(opt, string("extra ", letter, " tick labels") => "")
push!(
@@ -1367,9 +1284,7 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
axis[:minorgridalpha],
axis[:minorgridstyle],
),
"major tick length" =>
typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ||
axis[:minorticks] ? "0.1cm" : "0",
"major tick length" => typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 || axis[:minorticks] ? "0.1cm" : "0"
),
)
end
@@ -1426,8 +1341,7 @@ end
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{PGFPlotsXBackend})
leg = sp[:legend]
if leg in (:best, :outertopright, :outerright, :outerbottomright) ||
(leg isa Tuple && leg[1] >= 1)
if leg in (:best, :outertopright, :outerright, :outerbottomright) || (leg isa Tuple && leg[1] >= 1)
sp.minpad = (0mm, 0mm, 5mm, 0mm)
else
sp.minpad = (0mm, 0mm, 0mm, 0mm)
@@ -1446,22 +1360,22 @@ function _update_plot_object(plt::Plot{PGFPlotsXBackend})
plt.o(plt)
end
for mime in ("application/pdf", "image/svg+xml")
@eval function _show(io::IO, mime::MIME{Symbol($mime)}, plt::Plot{PGFPlotsXBackend})
for mime in ("application/pdf", "image/png", "image/svg+xml")
@eval function _show(
io::IO,
mime::MIME{Symbol($mime)},
plt::Plot{PGFPlotsXBackend},
)
plt.o.was_shown = true
show(io, mime, plt.o.the_plot)
end
end
function _show(io::IO, mime::MIME{Symbol("image/png")}, plt::Plot{PGFPlotsXBackend})
plt.o.was_shown = true
plt_file = tempname() * ".png"
PGFPlotsX.pgfsave(plt_file, plt.o.the_plot; dpi = plt[:dpi])
write(io, read(plt_file))
rm(plt_file; force = true)
end
function _show(io::IO, mime::MIME{Symbol("application/x-tex")}, plt::Plot{PGFPlotsXBackend})
function _show(
io::IO,
mime::MIME{Symbol("application/x-tex")},
plt::Plot{PGFPlotsXBackend},
)
plt.o.was_shown = true
PGFPlotsX.print_tex(
io,
+185 -348
View File
@@ -7,13 +7,12 @@ function _plotly_framestyle(style::Symbol)
return style
else
default_style = get((semi = :box, origin = :zerolines), style, :axes)
@warn(
"Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was chosen instead."
)
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
default_style
end
end
# --------------------------------------------------------------------------------------
using UUIDs
@@ -24,7 +23,7 @@ function labelfunc(scale::Symbol, backend::PlotlyBackend)
texfunc = labelfunc_tex(scale)
function (x)
tex_x = texfunc(x)
sup_x = replace(tex_x, r"\^{(.*)}" => s"<sup>\1</sup>")
sup_x = replace( tex_x, r"\^{(.*)}"=>s"<sup>\1</sup>" )
# replace dash with \minus (U+2212)
replace(sup_x, "-" => "")
end
@@ -33,25 +32,30 @@ end
function plotly_font(font::Font, color = font.color)
KW(
:family => font.family,
:size => round(Int, font.pointsize * 1.4),
:size => round(Int, font.pointsize*1.4),
:color => rgba_string(color),
)
end
function plotly_annotation_dict(x, y, val; xref = "paper", yref = "paper")
KW(:text => val, :xref => xref, :x => x, :yref => yref, :y => y, :showarrow => false)
function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
KW(
:text => val,
:xref => xref,
:x => x,
:yref => yref,
:y => y,
:showarrow => false,
)
end
function plotly_annotation_dict(x, y, ptxt::PlotText; xref = "paper", yref = "paper")
merge(
plotly_annotation_dict(x, y, ptxt.str; xref = xref, yref = yref),
KW(
:font => plotly_font(ptxt.font),
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
:rotation => -ptxt.font.rotation,
),
)
function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper")
merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW(
:font => plotly_font(ptxt.font),
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
:rotation => -ptxt.font.rotation,
))
end
# function get_annotation_dict_for_arrow(plotattributes::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
@@ -96,9 +100,9 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
if aspect_ratio == :equal
aspect_ratio = 1.0
end
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
want_ratio = ((xmax - xmin) / (ymax - ymin)) / aspect_ratio
xmin,xmax = axis_limits(sp, :x)
ymin,ymax = axis_limits(sp, :y)
want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio
parea_ratio = width(plotarea) / height(plotarea)
if want_ratio > parea_ratio
# need to shrink y
@@ -114,34 +118,33 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts)
pcts
end
# this method gets the start/end in percentage of the canvas for this axis direction
function plotly_domain(sp::Subplot)
figw, figh = sp.plt[:size]
pcts = bbox_to_pcts(sp.plotarea, figw * px, figh * px)
pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px)
pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts)
x_domain = [pcts[1], pcts[1] + pcts[3]]
y_domain = [pcts[2], pcts[2] + pcts[4]]
return x_domain, y_domain
end
function plotly_axis(axis, sp, anchor = nothing, domain = nothing)
letter = axis[:letter]
framestyle = sp[:framestyle]
ax = KW(
:visible => framestyle != :none,
:title => axis[:guide],
:showgrid => axis[:grid],
:gridcolor =>
rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => framestyle == :zerolines,
:visible => framestyle != :none,
:title => axis[:guide],
:showgrid => axis[:grid],
:gridcolor => rgba_string(plot_color(axis[:foreground_color_grid], axis[:gridalpha])),
:gridwidth => axis[:gridlinewidth],
:zeroline => framestyle == :zerolines,
:zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks =>
axis[:tick_direction] === :out ? "outside" :
axis[:tick_direction] === :in ? "inside" : "",
:mirror => framestyle == :box,
:showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside",
:mirror => framestyle == :box,
:showticklabels => axis[:showaxis],
)
if anchor !== nothing
@@ -162,9 +165,7 @@ function plotly_axis(axis, sp, anchor = nothing, domain = nothing)
if !(axis[:ticks] in (nothing, :none, false))
ax[:titlefont] = plotly_font(guidefont(axis))
ax[:tickfont] = plotly_font(tickfont(axis))
ax[:tickcolor] =
framestyle in (:zerolines, :grid) || !axis[:showaxis] ?
rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# ticks
@@ -193,7 +194,10 @@ function plotly_axis(axis, sp, anchor = nothing, domain = nothing)
end
function plotly_polaraxis(sp::Subplot, axis::Axis)
ax = KW(:visible => axis[:showaxis], :showline => axis[:grid])
ax = KW(
:visible => axis[:showaxis],
:showline => axis[:grid],
)
if axis[:letter] == :x
ax[:range] = rad2deg.(axis_limits(sp, :x))
@@ -211,7 +215,7 @@ function plotly_layout(plt::Plot)
w, h = plt[:size]
plotattributes_out[:width], plotattributes_out[:height] = w, h
plotattributes_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
plotattributes_out[:margin] = KW(:l => 0, :b => 20, :r => 0, :t => 20)
plotattributes_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
plotattributes_out[:annotations] = KW[]
@@ -232,12 +236,9 @@ function plotly_layout(plt::Plot)
else
0.5 * (left(bb) + right(bb))
end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w * px, h * px)
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
title_font = font(titlefont(sp), :top)
push!(
plotattributes_out[:annotations],
plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)),
)
push!(plotattributes_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
end
plotattributes_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
@@ -246,10 +247,8 @@ function plotly_layout(plt::Plot)
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
if ispolar(sp)
plotattributes_out[Symbol("angularaxis$(spidx)")] =
plotly_polaraxis(sp, sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] =
plotly_polaraxis(sp, sp[:yaxis])
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp, sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp, sp[:yaxis])
else
x_domain, y_domain = plotly_domain(sp)
if RecipesPipeline.is3d(sp)
@@ -264,15 +263,15 @@ function plotly_layout(plt::Plot)
#2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW(
:eye => KW(
:x => cosd(azim) * sind(theta) * 2.6,
:y => sind(azim) * sind(theta) * 2.6,
:z => cosd(theta) * 2.6,
:x => cosd(azim)*sind(theta)*2.6,
:y => sind(azim)*sind(theta)*2.6,
:z => cosd(theta)*2.6,
),
),
)
else
plotattributes_out[Symbol("xaxis$(x_idx)")] =
plotly_axis(sp[:xaxis], sp, string("y", y_idx), x_domain)
plotly_axis(sp[:xaxis], sp, string("y", y_idx) , x_domain)
# don't allow yaxis to be reupdated/reanchored in a linked subplot
if spidx == y_idx
plotattributes_out[Symbol("yaxis$(y_idx)")] =
@@ -286,28 +285,16 @@ function plotly_layout(plt::Plot)
# annotations
for ann in sp[:annotations]
append!(
plotattributes_out[:annotations],
KW[plotly_annotation_dict(
locate_annotation(sp, ann...)...;
xref = "x$(x_idx)",
yref = "y$(y_idx)",
)],
)
append!(plotattributes_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
end
# series_annotations
for series in series_list(sp)
anns = series[:series_annotations]
for (xi, yi, str, fnt) in EachAnn(anns, series[:x], series[:y])
push!(
plotattributes_out[:annotations],
plotly_annotation_dict(
xi,
yi,
PlotText(str, fnt);
xref = "x$(x_idx)",
yref = "y$(y_idx)",
),
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
push!(plotattributes_out[:annotations], plotly_annotation_dict(
xi,
yi,
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
)
end
end
@@ -330,25 +317,26 @@ function plotly_layout(plt::Plot)
end
# turn off hover if nothing's using it
if all(series -> series.plotattributes[:hover] in (false, :none), plt.series_list)
if all(series -> series.plotattributes[:hover] in (false,:none), plt.series_list)
plotattributes_out[:hovermode] = "none"
end
plotattributes_out = recursive_merge(plotattributes_out, plt.attr[:extra_plot_kwargs])
end
function plotly_add_legend!(plotattributes_out::KW, sp::Subplot)
plotattributes_out[:showlegend] = sp[:legend] != :none
legend_position = plotly_legend_pos(sp[:legend])
if sp[:legend] != :none
plotattributes_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:borderwidth => 1,
:traceorder => "normal",
:xanchor => legend_position.xanchor,
:yanchor => legend_position.yanchor,
:font => plotly_font(legendfont(sp)),
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => legend_position.coords[1],
:y => legend_position.coords[2],
@@ -372,71 +360,36 @@ function plotly_legend_pos(pos::Symbol)
xouterright = 1.05
xouterleft = -0.15
plotly_legend_position_mapping = (
right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"),
left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"),
top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"),
bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"),
bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"),
right = (coords = [1.0, ycenter], xanchor = "right", yanchor = "middle"),
left = (coords = [xleft, ycenter], xanchor = "left", yanchor = "middle"),
top = (coords = [xcenter, ytop], xanchor = "center", yanchor = "top"),
bottom = (coords = [xcenter, ybot], xanchor = "center", yanchor = "bottom"),
bottomleft = (coords = [xleft, ybot], xanchor = "left", yanchor = "bottom"),
bottomright = (coords = [1.0, ybot], xanchor = "right", yanchor = "bottom"),
topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"),
topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"),
outertop = (coords = [center, youtertop], xanchor = "upper", yanchor = "middle"),
outerbottom = (coords = [center, youterbot], xanchor = "lower", yanchor = "middle"),
outerleft = (coords = [xouterleft, center], xanchor = "left", yanchor = "top"),
outerright = (coords = [xouterright, center], xanchor = "right", yanchor = "top"),
outertopleft = (coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"),
outertopright = (
coords = [xouterright, ytop],
xanchor = "upper",
yanchor = "right",
),
outerbottomleft = (
coords = [xouterleft, ybot],
xanchor = "lower",
yanchor = "left",
),
outerbottomright = (
coords = [xouterright, ybot],
xanchor = "lower",
yanchor = "right",
),
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto"),
topright = (coords = [1.0, 1.0], xanchor = "right", yanchor = "top"),
topleft = (coords = [xleft, 1.0], xanchor = "left", yanchor = "top"),
outertop =(coords = [center, youtertop ], xanchor = "upper", yanchor = "middle"),
outerbottom =(coords = [center, youterbot], xanchor = "lower", yanchor = "middle"),
outerleft =(coords = [xouterleft, center], xanchor = "left", yanchor = "top"),
outerright =(coords = [xouterright, center], xanchor = "right", yanchor = "top"),
outertopleft =(coords = [xouterleft, ytop], xanchor = "upper", yanchor = "left"),
outertopright = (coords = [xouterright, ytop], xanchor = "upper", yanchor = "right"),
outerbottomleft =(coords = [xouterleft, ybot], xanchor = "lower", yanchor = "left"),
outerbottomright =(coords = [xouterright, ybot], xanchor = "lower", yanchor = "right"),
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto")
)
legend_position =
get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default)
legend_position = get(plotly_legend_position_mapping, pos, plotly_legend_position_mapping.default)
end
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real,T<:Real} =
(coords = v, xanchor = "left", yanchor = "top")
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = (coords=v, xanchor="left", yanchor="top")
plotly_legend_pos(theta::Real) = plotly_legend_pos((theta, :inner))
function plotly_legend_pos(v::Tuple{S,Symbol}) where {S<:Real}
(s, c) = sincosd(v[1])
xanchors = ["left", "center", "right"]
yanchors = ["bottom", "middle", "top"]
if v[2] === :inner
rect = (0.07, 0.5, 1.0, 0.07, 0.52, 1.0)
xanchor = xanchors[legend_anchor_index(c)]
yanchor = yanchors[legend_anchor_index(s)]
else
rect = (-0.15, 0.5, 1.05, -0.15, 0.52, 1.1)
xanchor = xanchors[4 - legend_anchor_index(c)]
yanchor = yanchors[4 - legend_anchor_index(s)]
end
return (
coords = legend_pos_from_angle(v[1], rect...),
xanchor = xanchor,
yanchor = yanchor,
)
end
function plotly_layout_json(plt::Plot)
JSON.json(plotly_layout(plt), 4)
end
plotly_colorscale(cg::ColorGradient, α = nothing) =
[[v, rgba_string(plot_color(cg.colors[v], α))] for v in cg.values]
function plotly_colorscale(c::AbstractVector{<:Colorant}, α = nothing)
@@ -455,12 +408,13 @@ function plotly_colorscale(cg::PlotUtils.CategoricalColorGradient, α = nothing)
cinds = repeat(1:n, inner = 2)
vinds = vcat((i:(i + 1) for i in 1:n)...)
return [
[cg.values[vinds[i]], rgba_string(plot_color(color_list(cg)[cinds[i]], α))] for
i in eachindex(cinds)
[cg.values[vinds[i]], rgba_string(plot_color(color_list(cg)[cinds[i]], α))]
for i in eachindex(cinds)
]
end
plotly_colorscale(c, α = nothing) = plotly_colorscale(_as_gradient(c), α)
get_plotly_marker(k, def) = get(
(
rect = "square",
@@ -487,11 +441,12 @@ function plotly_link_indicies(plt::Plot, sp::Subplot)
x_idx, y_idx
end
# the Shape contructor will automatically close the shape. since we need it closed,
# we split by NaNs and then construct/destruct the shapes to get the closed coords
function plotly_close_shapes(x, y)
xs, ys = nansplit(x), nansplit(y)
for i in eachindex(xs)
for i=eachindex(xs)
shape = Shape(xs[i], ys[i])
xs[i], ys[i] = coords(shape)
end
@@ -499,12 +454,12 @@ function plotly_close_shapes(x, y)
end
function plotly_data(series::Series, letter::Symbol, data)
axis = series[:subplot][get_attr_symbol(letter, :axis)]
axis = series[:subplot][Symbol(letter, :axis)]
data = if axis[:ticks] == :native && data !== nothing
plotly_native_data(axis, data)
else
data
data
end
if series[:seriestype] in (:heatmap, :contour, :surface, :wireframe, :mesh3d)
@@ -537,9 +492,7 @@ function plotly_convert_to_datetime(x::AbstractArray, formatter::Function)
elseif formatter == timeformatter
map(xi -> string(Dates.Date(Dates.now()), " ", formatter(xi)), x)
else
error(
"Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter",
)
error("Invalid DateTime formatter. Expected Plots.datetime/date/time formatter but got $formatter")
end
end
#ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z)
@@ -577,12 +530,11 @@ function plotly_series(plt::Plot, series::Series)
x, y = straightline_data(series, 100)
z = series[:z]
else
x, y, z = series[:x], series[:y], series[:z]
x, y, z = series[:x], series[:y], series[:z]
end
x, y, z = (
plotly_data(series, letter, data) for
(letter, data) in zip((:x, :y, :z), (x, y, z))
x, y, z = (plotly_data(series, letter, data)
for (letter, data) in zip((:x, :y, :z), (x, y, z))
)
plotattributes_out[:name] = series[:label]
@@ -590,8 +542,7 @@ function plotly_series(plt::Plot, series::Series)
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d, :straightline)
hasfillrange =
st in (:path, :scatter, :scattergl, :straightline) &&
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
plotattributes_out[:colorbar] = KW(:title => sp[:colorbar_title])
@@ -609,63 +560,32 @@ function plotly_series(plt::Plot, series::Series)
y = heatmap_edges(y, sp[:yaxis][:scale])
plotattributes_out[:type] = "heatmap"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
plotattributes_out[:colorscale] =
plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:showscale] = hascolorbar(sp)
elseif st == :contour
filled = isfilledcontour(series)
plotattributes_out[:type] = "contour"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
plotattributes_out[:contours] = KW(
:coloring => filled ? "fill" : "lines",
:showlabels => series[:contour_labels] == true,
)
# Plotly does not support arbitrary sets of contours
# (https://github.com/plotly/plotly.js/issues/4503)
# so we distinguish AbstractRanges and AbstractVectors
let levels = series[:levels]
if levels isa AbstractRange
plotattributes_out[:contours][:start] = first(levels)
plotattributes_out[:contours][:end] = last(levels)
plotattributes_out[:contours][:size] = step(levels)
elseif levels isa AVec
levels_range =
range(first(levels), stop = last(levels), length = length(levels))
plotattributes_out[:contours][:start] = first(levels_range)
plotattributes_out[:contours][:end] = last(levels_range)
plotattributes_out[:contours][:size] = step(levels_range)
@warn(
"setting arbitrary contour levels with Plotly backend is not supported; " *
"use a range to set equally-spaced contours or an integer to set the " *
"approximate number of contours with the keyword `levels`. " *
"Setting levels to $(levels_range)"
)
elseif levels isa Integer
plotattributes_out[:ncontours] = levels + 2
end
end
plotattributes_out[:colorscale] =
plotly_colorscale(series[:linecolor], series[:linealpha])
plotattributes_out[:ncontours] = series[:levels] + 2
plotattributes_out[:contours] = KW(:coloring => filled ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
plotattributes_out[:showscale] = hascolorbar(sp) && hascolorbar(series)
elseif st in (:surface, :wireframe)
plotattributes_out[:type] = "surface"
plotattributes_out[:type] = "surface"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if st == :wireframe
plotattributes_out[:hidesurface] = true
wirelines = KW(
:show => true,
:color =>
rgba_string(plot_color(series[:linecolor], series[:linealpha])),
:color => rgba_string(plot_color(series[:linecolor], series[:linealpha])),
:highlightwidth => series[:linewidth],
)
plotattributes_out[:contours] =
KW(:x => wirelines, :y => wirelines, :z => wirelines)
plotattributes_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
plotattributes_out[:showscale] = false
else
plotattributes_out[:colorscale] =
plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:opacity] = series[:fillalpha]
if series[:fill_z] !== nothing
plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
@@ -673,34 +593,24 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out[:showscale] = hascolorbar(sp)
end
elseif st == :mesh3d
plotattributes_out[:type] = "mesh3d"
plotattributes_out[:type] = "mesh3d"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if series[:connections] !== nothing
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
i, j, k = series[:connections]
if !(length(i) == length(j) == length(k))
throw(
ArgumentError(
"Argument connections must consist of equally sized arrays.",
),
)
end
plotattributes_out[:i] = i
plotattributes_out[:j] = j
plotattributes_out[:k] = k
else
throw(
ArgumentError(
"Argument connections has to be a tuple of three arrays.",
),
)
end
end
plotattributes_out[:colorscale] =
plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:color] =
rgba_string(plot_color(series[:fillcolor], series[:fillalpha]))
if series[:connections] !== nothing
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
i,j,k = series[:connections]
if !(length(i) == length(j) == length(k))
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
end
plotattributes_out[:i] = i
plotattributes_out[:j] = j
plotattributes_out[:k] = k
else
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
end
end
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:color] = rgba_string(plot_color(series[:fillcolor], series[:fillalpha]))
plotattributes_out[:opacity] = series[:fillalpha]
if series[:fill_z] !== nothing
plotattributes_out[:surfacecolor] = handle_surface(series[:fill_z])
@@ -715,25 +625,12 @@ function plotly_series(plt::Plot, series::Series)
if hasmarker
inds = eachindex(x)
plotattributes_out[:marker] = KW(
:symbol =>
get_plotly_marker(series[:markershape], string(series[:markershape])),
:symbol => get_plotly_marker(series[:markershape], string(series[:markershape])),
# :opacity => series[:markeralpha],
:size => 2 * _cycle(series[:markersize], inds),
:color =>
rgba_string.(
plot_color.(
get_markercolor.(series, inds),
get_markeralpha.(series, inds),
),
),
:color => rgba_string.(plot_color.(get_markercolor.(series, inds), get_markeralpha.(series, inds))),
:line => KW(
:color =>
rgba_string.(
plot_color.(
get_markerstrokecolor.(series, inds),
get_markerstrokealpha.(series, inds),
),
),
:color => rgba_string.(plot_color.(get_markerstrokecolor.(series, inds), get_markerstrokealpha.(series, inds))),
:width => _cycle(series[:markerstrokewidth], inds),
),
)
@@ -746,7 +643,7 @@ function plotly_series(plt::Plot, series::Series)
end
function plotly_series_shapes(plt::Plot, series::Series, clims)
segments = series_segments(series; check = true)
segments = iter_segments(series)
plotattributes_outs = Vector{KW}(undef, length(segments))
# TODO: create a plotattributes_out for each polygon
@@ -761,52 +658,40 @@ function plotly_series_shapes(plt::Plot, series::Series, clims)
:legendgroup => series[:label],
)
x, y = (
plotly_data(series, letter, data) for
(letter, data) in zip((:x, :y), shape_data(series, 100))
x, y = (plotly_data(series, letter, data)
for (letter, data) in zip((:x, :y), shape_data(series, 100))
)
for (k, segment) in enumerate(segments)
i, rng = segment.attr_index, segment.range
for (i,rng) in enumerate(segments)
length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill
plotattributes_out = merge(
plotattributes_base,
KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(
plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
),
),
)
plotattributes_out = merge(plotattributes_base, KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))),
))
if series[:markerstrokewidth] > 0
plotattributes_out[:line] = KW(
:color => rgba_string(
plot_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
),
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:dash => string(get_linestyle(series, i)),
)
end
plotattributes_out[:showlegend] = k == 1 ? should_add_to_legend(series) : false
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(plotattributes_out, series)
plotly_hover!(plotattributes_out, _cycle(series[:hover], i))
plotattributes_outs[k] = plotattributes_out
plotattributes_outs[i] = plotattributes_out
end
if series[:fill_z] !== nothing
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
elseif series[:line_z] !== nothing
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
elseif series[:marker_z] !== nothing
push!(
plotattributes_outs,
plotly_colorbar_hack(series, plotattributes_base, :marker),
)
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
end
plotattributes_outs
end
@@ -817,46 +702,35 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d, :straightline)
hasfillrange =
st in (:path, :scatter, :scattergl, :straightline) &&
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
segments = collect(series_segments(series, st))
plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1) * length(segments))
segments = iter_segments(series, st)
plotattributes_outs = fill(KW(), (hasfillrange ? 2 : 1 ) * length(segments))
needs_scatter_fix = !isscatter && hasmarker && !any(isnan, y) && length(segments) > 1
for (k, segment) in enumerate(segments)
i, rng = segment.attr_index, segment.range
needs_scatter_fix = !isscatter && hasmarker && !any(isnan,y) && length(segments) > 1
for (i,rng) in enumerate(segments)
plotattributes_out = deepcopy(plotattributes_base)
plotattributes_out[:showlegend] = k == 1 ? should_add_to_legend(series) : false
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotattributes_out[:legendgroup] = series[:label]
# set the type
if st in (:path, :scatter, :scattergl, :straightline)
plotattributes_out[:type] = st == :scattergl ? "scattergl" : "scatter"
plotattributes_out[:type] = st==:scattergl ? "scattergl" : "scatter"
plotattributes_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if series[:fillrange] == true ||
series[:fillrange] == 0 ||
isa(series[:fillrange], Tuple)
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
plotattributes_out[:fill] = "tozeroy"
plotattributes_out[:fillcolor] = rgba_string(
plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
)
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real},Real}
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
plotattributes_out[:fill] = "tonexty"
plotattributes_out[:fillcolor] = rgba_string(
plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
)
plotattributes_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
elseif !(series[:fillrange] in (false, nothing))
@warn(
"fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])"
)
@warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
end
plotattributes_out[:x], plotattributes_out[:y] = x[rng], y[rng]
@@ -867,32 +741,20 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
else
hasline ? "lines" : "none"
end
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] =
x[rng], y[rng], z[rng]
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x[rng], y[rng], z[rng]
end
# add "marker"
if hasmarker
mcolor = rgba_string(
plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i)),
)
lcolor = rgba_string(
plot_color(
get_markerstrokecolor(series, i),
get_markerstrokealpha(series, i),
),
)
mcolor = rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i)))
lcolor = rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i)))
plotattributes_out[:marker] = KW(
:symbol => get_plotly_marker(
_cycle(series[:markershape], i),
string(_cycle(series[:markershape], i)),
),
:symbol => get_plotly_marker(_cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => needs_scatter_fix ? [1, 0] : 1,
:size => 2 * _cycle(series[:markersize], i),
:color => needs_scatter_fix ? [mcolor, "rgba(0, 0, 0, 0.000)"] : mcolor,
:line => KW(
:color =>
needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor,
:color => needs_scatter_fix ? [lcolor, "rgba(0, 0, 0, 0.000)"] : lcolor,
:width => _cycle(series[:markerstrokewidth], i),
),
)
@@ -901,14 +763,10 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
# add "line"
if hasline
plotattributes_out[:line] = KW(
:color => rgba_string(
plot_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
),
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:shape => if st == :steppre
"vh"
elseif st == :stepmid
"hvh"
elseif st == :steppost
"hv"
else
@@ -930,12 +788,8 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
if typeof(series[:fillrange]) <: Real
series[:fillrange] = fill(series[:fillrange], length(rng))
elseif typeof(series[:fillrange]) <: Tuple
f1 =
typeof(series[:fillrange][1]) <: Real ?
fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng]
f2 =
typeof(series[:fillrange][2]) <: Real ?
fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng]
f1 = typeof(series[:fillrange][1]) <: Real ? fill(series[:fillrange][1], length(rng)) : series[:fillrange][1][rng]
f2 = typeof(series[:fillrange][2]) <: Real ? fill(series[:fillrange][2], length(rng)) : series[:fillrange][2][rng]
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
@@ -945,17 +799,15 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
else
# if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange
# is the series that will do the filling
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] =
concatenate_fillrange(x[rng], series[:fillrange])
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], series[:fillrange])
plotattributes_out_fillrange[:line][:width] = 0
delete!(plotattributes_out, :fill)
delete!(plotattributes_out, :fillcolor)
end
plotattributes_outs[(2k - 1):(2k)] =
[plotattributes_out_fillrange, plotattributes_out]
plotattributes_outs[(2 * i - 1):(2 * i)] = [plotattributes_out_fillrange, plotattributes_out]
else
plotattributes_outs[k] = plotattributes_out
plotattributes_outs[i] = plotattributes_out
end
end
@@ -964,10 +816,7 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
elseif series[:fill_z] !== nothing
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
elseif series[:marker_z] !== nothing
push!(
plotattributes_outs,
plotly_colorbar_hack(series, plotattributes_base, :marker),
)
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
end
plotattributes_outs
@@ -997,6 +846,7 @@ function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symb
return plotattributes_out
end
function plotly_polar!(plotattributes_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
@@ -1033,23 +883,30 @@ plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt), 4)
html_head(plt::Plot{PlotlyBackend}) = plotly_html_head(plt)
html_body(plt::Plot{PlotlyBackend}) = plotly_html_body(plt)
const ijulia_initialized = Ref(false)
function plotly_html_head(plt::Plot)
plotly =
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) :
"https://cdn.plot.ly/$(_plotly_min_js_filename)"
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) : "https://cdn.plot.ly/plotly-1.57.1.min.js"
include_mathjax = get(plt[:extra_plot_kwargs], :include_mathjax, "")
mathjax_file =
include_mathjax != "cdn" ? ("file://" * include_mathjax) :
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"
mathjax_head =
include_mathjax == "" ? "" : "<script src=\"$mathjax_file\"></script>\n\t\t"
mathjax_file = include_mathjax != "cdn" ? ("file://" * include_mathjax) : "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"
mathjax_head = include_mathjax == "" ? "" : "<script src=\"$mathjax_file\"></script>\n\t\t"
if isijulia()
mathjax_head
else
"$mathjax_head<script src=$(repr(plotly))></script>"
if isijulia() && !ijulia_initialized[]
# using requirejs seems to be key to load a js depency in IJulia!
# https://requirejs.org/docs/start.html
# https://github.com/JuliaLang/IJulia.jl/issues/345
display("text/html", """
<script type="text/javascript">
requirejs([$(repr(plotly))], function(p) {
window.Plotly = p
});
</script>
""")
ijulia_initialized[] = true
end
return "$mathjax_head<script src=$(repr(plotly))></script>"
end
function plotly_html_body(plt, style = nothing)
@@ -1057,34 +914,12 @@ function plotly_html_body(plt, style = nothing)
w, h = plt[:size]
style = "width:$(w)px;height:$(h)px;"
end
requirejs_prefix = ""
requirejs_suffix = ""
if isijulia()
# require.js adds .js automatically
plotly_no_ext =
use_local_dependencies[] ? ("file:///" * plotly_local_file_path[]) :
"https://cdn.plot.ly/$(_plotly_min_js_filename)"
plotly_no_ext = plotly_no_ext[1:(end - 3)]
requirejs_prefix = """
requirejs.config({
paths: {
Plotly: '$(plotly_no_ext)'
}
});
require(['Plotly'], function (Plotly) {
"""
requirejs_suffix = "});"
end
uuid = UUIDs.uuid4()
html = """
<div id=\"$(uuid)\" style=\"$(style)\"></div>
<script>
$(requirejs_prefix)
$(js_body(plt, uuid))
$(requirejs_suffix)
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
</script>
"""
html
@@ -1092,7 +927,7 @@ end
function js_body(plt::Plot, uuid)
js = """
var PLOT = document.getElementById('$(uuid)');
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
"""
end
@@ -1114,10 +949,12 @@ function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{Plotly
plotly_show_js(io, plot)
end
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, embeddable_html(plt))
write(io, standalone_html(plt))
end
function _display(plt::Plot{PlotlyBackend})
standalone_html_window(plt)
end
+5 -7
View File
@@ -25,24 +25,22 @@ for (mime, fmt) in (
"image/svg+xml" => "svg",
"image/eps" => "eps",
)
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) =
PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt)
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plotlyjs_syncplot(plt), format = $fmt)
end
# Use the Plotly implementation for json and html:
_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) =
plotly_show_js(io, plt)
_show(io::IO, mime::MIME"application/vnd.plotly.v1+json", plt::Plot{PlotlyJSBackend}) = plotly_show_js(io, plt)
html_head(plt::Plot{PlotlyJSBackend}) = plotly_html_head(plt)
html_body(plt::Plot{PlotlyJSBackend}) = plotly_html_body(plt)
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) =
write(io, embeddable_html(plt))
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = write(io, standalone_html(plt))
_display(plt::Plot{PlotlyJSBackend}) = display(plotlyjs_syncplot(plt))
function PlotlyJS.WebIO.render(plt::Plot{PlotlyJSBackend})
return PlotlyJS.WebIO.render(plotlyjs_syncplot(plt))
plt_html = sprint(show, MIME("text/html"), plt)
return PlotlyJS.WebIO.render(PlotlyJS.WebIO.dom"div"(innerHTML=plt_html))
end
function closeall(::PlotlyJSBackend)
+297 -577
View File
File diff suppressed because it is too large Load Diff
+101 -142
View File
@@ -1,30 +1,32 @@
# https://github.com/JuliaPlots/UnicodePlots.jl
# https://github.com/Evizero/UnicodePlots.jl
# don't warn on unsupported... there's just too many warnings!!
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
# --------------------------------------------------------------------------------------
_canvas_map() = (
ascii = UnicodePlots.AsciiCanvas,
block = UnicodePlots.BlockCanvas,
braille = UnicodePlots.BrailleCanvas,
density = UnicodePlots.DensityCanvas,
dot = UnicodePlots.DotCanvas,
heatmap = UnicodePlots.HeatmapCanvas,
lookup = UnicodePlots.LookupCanvas,
)
function _canvas_map()
(
braille = UnicodePlots.BrailleCanvas,
ascii = UnicodePlots.AsciiCanvas,
block = UnicodePlots.BlockCanvas,
dot = UnicodePlots.DotCanvas,
density = UnicodePlots.DensityCanvas,
)
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 unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
plt.o = UnicodePlots.Plot[]
canvas_map = _canvas_map()
function rebuildUnicodePlot!(plt::Plot, width, height)
plt.o = []
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xlim = axis_limits(sp, :x)
ylim = axis_limits(sp, :y)
xlim = axis_limits(sp, :x)
ylim = axis_limits(sp, :y)
# make vectors
xlim = [xlim[1], xlim[2]]
@@ -36,106 +38,108 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
canvas_type = if (ct = _canvas_type[]) == :auto
isijulia() ? :ascii : :braille
ct = _canvas_type[]
canvas_type = if ct == :auto
isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
else
ct
_canvas_map()[ct]
end
o = UnicodePlots.Plot(
x,
y,
canvas_map[canvas_type];
# special handling for spy
if length(sp.series_list) == 1
series = sp.series_list[1]
if series[:seriestype] == :spy
push!(plt.o, UnicodePlots.spy(
series[:z].surf,
width = width,
height = height,
title = sp[:title],
canvas = canvas_type
))
continue
end
end
# # make it a bar canvas if plotting bar
# if any(series -> series[:seriestype] == :bar, series_list(sp))
# canvas_type = UnicodePlots.BarplotGraphics
# end
o = UnicodePlots.Plot(x, y, canvas_type;
width = width,
height = height,
title = sp[:title],
xlim = xlim,
ylim = ylim,
xlabel = xaxis[:guide],
ylabel = yaxis[:guide],
border = isijulia() ? :ascii : :solid,
border = isijulia() ? :ascii : :solid
)
# set the axis labels
UnicodePlots.xlabel!(o, xaxis[:guide])
UnicodePlots.ylabel!(o, yaxis[:guide])
# now use the ! functions to add to the plot
for series in series_list(sp)
o = addUnicodeSeries!(sp, o, series, sp[:legend] != :none, xlim, ylim)
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
end
push!(plt.o, o) # save the object
# save the object
push!(plt.o, o)
end
end
# add a single series
function addUnicodeSeries!(
sp::Subplot{UnicodePlotsBackend},
up::UnicodePlots.Plot,
series,
addlegend::Bool,
xlim,
ylim,
)
st = series[:seriestype]
function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = plotattributes[:seriestype]
if st == :histogram2d
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
return
end
if st in (:path, :straightline)
func = UnicodePlots.lineplot!
elseif st == :scatter || plotattributes[:markershape] != :none
func = UnicodePlots.scatterplot!
# elseif st == :bar
# func = UnicodePlots.barplot!
elseif st == :shape
func = UnicodePlots.lineplot!
else
error("Linestyle $st not supported by UnicodePlots")
end
# get the series data and label
x, y = if st == :straightline
straightline_data(series)
straightline_data(plotattributes)
elseif st == :shape
shape_data(series)
shape_data(plotattributes)
else
float(series[:x]), float(series[:y])
[collect(float(plotattributes[s])) for s in (:x, :y)]
end
label = addlegend ? plotattributes[:label] : ""
# special handling (src/interface)
if st == :histogram2d
return UnicodePlots.densityplot(x, y)
elseif st == :heatmap
rng = range(0, 1, length = length(UnicodePlots.COLOR_MAP_DATA[:viridis]))
cmap = [(red(c), green(c), blue(c)) for c in get(get_colorgradient(series), rng)]
return UnicodePlots.heatmap(
series[:z].surf;
title = sp[:title],
zlabel = sp[:colorbar_title],
colormap = cmap,
)
elseif st == :spy
return UnicodePlots.spy(series[:z].surf; title = sp[:title])
end
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto
# now use the ! functions to add to the plot
if st in (:path, :straightline, :shape)
func = UnicodePlots.lineplot!
elseif st == :scatter || series[:markershape] != :none
func = UnicodePlots.scatterplot!
else
error("Series type $st not supported by UnicodePlots")
end
label = addlegend ? series[:label] : ""
for (n, segment) in enumerate(series_segments(series, st; check = true))
i, rng = segment.attr_index, segment.range
lc = get_linecolor(series, i)
if typeof(lc) <: UnicodePlots.UserColorType
color = lc
elseif typeof(lc) <: RGBA
lc = convert(ARGB32, lc)
color = map(Int, (red(lc).i, green(lc).i, blue(lc).i))
else
color = :auto
end
up = func(up, x[rng], y[rng]; color = color, name = n == 1 ? label : "")
end
return up
# add the series
x, y = RecipesPipeline.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
func(o, x, y; color = color, name = label)
end
# -------------------------------
# since this is such a hack, it's only callable using `png`... should error during normal `show`
function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
fn = addExtension(fn, "png")
@static if Sys.isapple()
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# @osx_only begin
@static if Sys.isapple()
# BEGIN HACK
# wait while the plot gets drawn
@@ -147,75 +151,30 @@ function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
# END HACK (phew)
return
elseif Sys.islinux()
run(`clear`)
gui(plt)
run(`import -window $(ENV["WINDOWID"]) $fn`)
return
end
error(
"Can only savepng on MacOS or Linux with UnicodePlots (though even then I wouldn't do it)",
)
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end
# -------------------------------
Base.show(plt::Plot{UnicodePlotsBackend}) = _show(stdout, MIME("text/plain"), plt)
# 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 _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
nr, nc = size(plt.layout)
lines_colored = Array{Union{Nothing,Vector{String}}}(undef, nr, nc)
lines_uncolored = copy(lines_colored)
l_max = zeros(Int, nr)
buf = IOBuffer()
cbuf = IOContext(buf, :color => true)
sps = wmax = 0
for r in 1:nr
lmax = 0
for c in 1:nc
l = plt.layout[r, c]
if l isa GridLayout && size(l) != (1, 1)
@error "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(cbuf, sp)
colored = String(take!(buf))
uncolored = replace(colored, r"\x1B\[[0-9;]*[a-zA-Z]" => "")
lines_colored[r, c] = lc = split(colored, "\n")
lines_uncolored[r, c] = lu = split(uncolored, "\n")
lmax = max(length(lc), lmax)
wmax = max(maximum(length.(lu)), wmax)
end
end
end
l_max[r] = lmax
end
empty = ' '^wmax
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)
else
lu = lines_uncolored[r, c]
print(io, pre, lc[n], ' '^(wmax - length(lu[n])))
end
end
println(io)
end
r < nr && println(io)
end
foreach(x -> show(io, x), plt.o)
nothing
end
function _display(plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
map(display, plt.o)
map(show, plt.o)
nothing
end
+3 -13
View File
@@ -3,10 +3,7 @@
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
function standalone_html(
plt::AbstractPlot;
title::AbstractString = get(plt.attr, :window_title, "Plots.jl"),
)
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
"""
<!DOCTYPE html>
<html>
@@ -22,10 +19,6 @@ function standalone_html(
"""
end
function embeddable_html(plt::AbstractPlot)
html_head(plt) * html_body(plt)
end
function open_browser_window(filename::AbstractString)
@static if Sys.isapple()
return run(`open $(filename)`)
@@ -52,8 +45,7 @@ function standalone_html_window(plt::AbstractPlot)
old = use_local_dependencies[] # save state to restore afterwards
# if we open a browser ourself, we can host local files, so
# when we have a local plotly downloaded this is the way to go!
use_local_dependencies[] =
plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
use_local_dependencies[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
filename = write_temp_html(plt)
open_browser_window(filename)
# restore for other backends
@@ -62,9 +54,7 @@ end
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
function html_to_png(html_fn, png_fn, w, h)
run(
`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`,
)
run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`)
end
function show_png_from_html(io::IO, plt::AbstractPlot)
-97
View File
@@ -1,97 +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
function get_clims(sp::Subplot, op = process_clims(sp[:clims]))
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series, op = process_clims(sp[:clims]))
zmin, zmax = if series[:colorbar_entry]
get_clims(sp, op)
else
get_clims(series, op)
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
"""
function get_clims(series::Series, op = ignorenan_extrema)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
for vals in (
series[:seriestype] in z_colored_series ? series[:z] : nothing,
series[:line_z],
series[:marker_z],
series[:fill_z],
)
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing,Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...)
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing,Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap, :surface) ||
any(series[z] !== nothing for z 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
end
+323 -337
View File
@@ -1,20 +1,17 @@
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))
nanappend!(a::AVec{P2}, b) = (push!(a, P2(NaN, NaN)); append!(a, b))
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))
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 = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
# -------------------------------------------------------------
struct Shape{X<:Number,Y<:Number}
x::Vector{X}
y::Vector{Y}
struct Shape
x::Vector{Float64}
y::Vector{Float64}
# function Shape(x::AVec, y::AVec)
# # if x[1] != x[end] || y[1] != y[end]
# # new(vcat(x, x[1]), vcat(y, y[1]))
@@ -41,113 +38,115 @@ vertices(shape::Shape) = collect(zip(shape.x, shape.y))
@deprecate shape_coords coords
"return the vertex points from a Shape or Segments object"
coords(shape::Shape) = shape.x, shape.y
function coords(shape::Shape)
shape.x, shape.y
end
#coords(shapes::AVec{Shape}) = unzip(map(coords, shapes))
function coords(shapes::AVec{<:Shape})
c = map(coords, shapes)
x = [q[1] for q in c]
y = [q[2] for q in c]
function 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, 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`"
partialcircle(start_θ, end_θ, n = 20, r = 1) =
[(r * cos(u), r * sin(u)) for u in range(start_θ, stop = end_θ, length = n)]
function partialcircle(start_θ, end_θ, n = 20, r=1)
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
function weave(x, y; ordering = Vector[x, y])
ret = eltype(x)[]
done = false
while !done
for o in ordering
try
push!(ret, popfirst!(o))
catch
end
end
done = isempty(x) && isempty(y)
function weave(x,y; ordering = Vector[x,y])
ret = eltype(x)[]
done = false
while !done
for o in ordering
try
push!(ret, popfirst!(o))
catch
end
end
ret
done = isempty(x) && isempty(y)
end
ret
end
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
function makestar(n; offset = -0.5, radius = 1.0)
z1 = offset * π
z2 = z1 + π / (n)
outercircle = partialcircle(z1, z1 + 2π, n + 1, radius)
innercircle = partialcircle(z2, z2 + 2π, n + 1, 0.4radius)
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
Shape(weave(outercircle, innercircle))
end
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
makeshape(n; offset = -0.5, radius = 1.0) =
Shape(partialcircle(offset * π, offset * π + 2π, n + 1, radius))
function makeshape(n; offset = -0.5, radius = 1.0)
z = offset * π
Shape(partialcircle(z, z + 2π, n+1, radius))
end
function makecross(; offset = -0.5, radius = 1.0)
z2 = offset * π
z1 = z2 - π / 8
z1 = z2 - π/8
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
Shape(
weave(
outercircle,
innercircle,
ordering = Vector[outercircle, innercircle, outercircle],
),
)
Shape(weave(outercircle, innercircle,
ordering=Vector[outercircle,innercircle,outercircle]))
end
from_polar(angle, dist) = P2(dist * cos(angle), dist * sin(angle))
from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
makearrowhead(angle; h = 2.0, w = 0.4, tip = from_polar(angle, h)) = Shape(
P2[
(0, 0),
from_polar(angle - 0.5π, w) - tip,
from_polar(angle + 0.5π, w) - tip,
(0, 0),
],
)
function makearrowhead(angle; h = 2.0, w = 0.4)
tip = from_polar(angle, h)
Shape(P2[(0,0), from_polar(angle - 0.5π, w) - tip,
from_polar(angle + 0.5π, w) - tip, (0,0)])
end
const _shapes = KW(
:circle => makeshape(20),
:rect => makeshape(4, offset = -0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3, offset = 0.5),
:dtriangle => makeshape(3, offset = -0.5),
:rtriangle => makeshape(3, offset = 0.0),
:ltriangle => makeshape(3, offset = 1.0),
:pentagon => makeshape(5),
:hexagon => makeshape(6),
:heptagon => makeshape(7),
:octagon => makeshape(8),
:cross => makecross(offset = -0.25),
:xcross => makecross(),
:vline => Shape([(0, 1), (0, -1)]),
:hline => Shape([(1, 0), (-1, 0)]),
)
:rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3, offset=0.5),
:dtriangle => makeshape(3, offset=-0.5),
:rtriangle => makeshape(3, offset=0.0),
:ltriangle => makeshape(3, offset=1.0),
:pentagon => makeshape(5),
:hexagon => makeshape(6),
:heptagon => makeshape(7),
:octagon => makeshape(8),
:cross => makecross(offset=-0.25),
:xcross => makecross(),
:vline => Shape([(0,1),(0,-1)]),
:hline => Shape([(1,0),(-1,0)]),
)
for n in 4:8
_shapes[Symbol("star$n")] = makestar(n)
for n in [4,5,6,7,8]
_shapes[Symbol("star$n")] = makestar(n)
end
Shape(k::Symbol) = deepcopy(_shapes[k])
# -----------------------------------------------------------------------
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
"return the centroid of a Shape"
function center(shape::Shape)
x, y = coords(shape)
n = length(x)
A, Cx, Cy = 0, 0, 0
for i in 1:n
ip1 = i == n ? 1 : i + 1
A, Cx, Cy = 0.0, 0.0, 0.0
for i=1:n
ip1 = i==n ? 1 : i+1
A += x[i] * y[ip1] - x[ip1] * y[i]
end
A *= 0.5
for i in 1:n
ip1 = i == n ? 1 : i + 1
for i=1:n
ip1 = i==n ? 1 : i+1
m = (x[i] * y[ip1] - x[ip1] * y[i])
Cx += (x[i] + x[ip1]) * m
Cy += (y[i] + y[ip1]) * m
@@ -158,64 +157,73 @@ end
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
sx, sy = coords(shape)
cx, cy = c
for i in eachindex(sx)
for i=eachindex(sx)
sx[i] = (sx[i] - cx) * x + cx
sy[i] = (sy[i] - cy) * y + cy
end
shape
end
scale(shape::Shape, x::Real, y::Real = x, c = center(shape)) =
scale!(deepcopy(shape), x, y, c)
function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
shapecopy = deepcopy(shape)
scale!(shapecopy, x, y, c)
end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape)
for i in eachindex(sx)
for i=eachindex(sx)
sx[i] += x
sy[i] += y
end
shape
end
translate(shape::Shape, x::Real, y::Real = x) = translate!(deepcopy(shape), x, y)
function translate(shape::Shape, x::Real, y::Real = x)
shapecopy = deepcopy(shape)
translate!(shapecopy, x, y)
end
rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) =
((x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx)
function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
(x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx
end
rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real) =
((y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery)
function rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
(y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery
end
rotate(x::Real, y::Real, θ::Real, c = center(shape)) =
(rotate_x(x, y, Θ, c...), rotate_y(x, y, Θ, c...))
function rotate(x::Real, y::Real, θ::Real, c = center(shape))
cx, cy = c
rotate_x(x, y, Θ, cx, cy), rotate_y(x, y, Θ, cx, cy)
end
function rotate!(shape::Shape, Θ::Real, c = center(shape))
x, y = coords(shape)
for i in eachindex(x)
xi = rotate_x(x[i], y[i], Θ, c...)
yi = rotate_y(x[i], y[i], Θ, c...)
cx, cy = c
for i=eachindex(x)
xi = rotate_x(x[i], y[i], Θ, cx, cy)
yi = rotate_y(x[i], y[i], Θ, cx, cy)
x[i], y[i] = xi, yi
end
shape
end
"rotate an object in space"
function rotate(shape::Shape, θ::Real, c = center(shape))
x, y = coords(shape)
x_new = rotate_x.(x, y, θ, c...)
y_new = rotate_y.(x, y, θ, c...)
Shape(x_new, y_new)
function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c)
end
# -----------------------------------------------------------------------
mutable struct Font
family::AbstractString
pointsize::Int
halign::Symbol
valign::Symbol
rotation::Float64
color::Colorant
family::AbstractString
pointsize::Int
halign::Symbol
valign::Symbol
rotation::Float64
color::Colorant
end
"""
@@ -232,75 +240,80 @@ arguments (which are distinguished by type/value) or as keyword arguments.
# Examples
```julia-repl
julia> font(8)
julia> font(family="serif", halign=:center, rotation=45.0)
julia> font(family="serif",halign=:center,rotation=45.0)
```
"""
function font(args...; kw...)
# defaults
family = "sans-serif"
pointsize = 14
halign = :hcenter
valign = :vcenter
rotation = 0
color = colorant"black"
function font(args...;kw...)
for arg in args
T = typeof(arg)
# defaults
family = "sans-serif"
pointsize = 14
halign = :hcenter
valign = :vcenter
rotation = 0.0
color = colorant"black"
if T == Font
family = arg.family
pointsize = arg.pointsize
halign = arg.halign
valign = arg.valign
rotation = arg.rotation
color = arg.color
elseif arg == :center
halign = :hcenter
valign = :vcenter
elseif arg _haligns
halign = arg
elseif arg _valigns
valign = arg
elseif T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
family = string(arg)
end
elseif typeof(arg) <: Integer
pointsize = arg
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
@warn "Unused font arg: $arg ($(typeof(arg)))"
end
for arg in args
T = typeof(arg)
if T == Font
family = arg.family
pointsize = arg.pointsize
halign = arg.halign
valign = arg.valign
rotation = arg.rotation
color = arg.color
elseif arg == :center
halign = :hcenter
valign = :vcenter
elseif arg in (:hcenter, :left, :right)
halign = arg
elseif arg in (:vcenter, :top, :bottom)
valign = arg
elseif T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
family = string(arg)
end
elseif typeof(arg) <: Integer
pointsize = arg
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
@warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
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
for symbol in keys(kw)
if symbol == :family
family = kw[:family]
elseif symbol == :pointsize
pointsize = kw[:pointsize]
elseif symbol == :halign
halign = kw[:halign]
if halign == :center
halign = :hcenter
end
@assert halign in (:hcenter, :left, :right)
elseif symbol == :valign
valign = kw[:valign]
if valign == :center
valign = :vcenter
end
@assert valign in (:vcenter, :top, :bottom)
elseif symbol == :rotation
rotation = kw[:rotation]
elseif symbol == :color
color = parse(Colorant, kw[:color])
else
@warn("Unused font kwarg: $symbol")
end
end
Font(family, pointsize, halign, valign, rotation, color)
Font(family, pointsize, halign, valign, rotation, color)
end
function scalefontsize(k::Symbol, factor::Number)
@@ -315,13 +328,13 @@ end
Scales all **current** font sizes by `factor`. For example `scalefontsizes(1.1)` increases all current font sizes by 10%. To reset to initial sizes, use `scalefontsizes()`
"""
function scalefontsizes(factor::Number)
for k in keys(merge(_initial_plt_fontsizes, _initial_sp_fontsizes))
for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
scalefontsize(k, factor)
end
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
scalefontsize(get_attr_symbol(letter, k), factor)
for letter in (:x,:y,:z)
for k in (:guidefontsize, :tickfontsize)
scalefontsize(Symbol(letter, k), factor)
end
end
end
@@ -332,20 +345,20 @@ end
Resets font sizes to initial default values.
"""
function scalefontsizes()
for k in keys(merge(_initial_plt_fontsizes, _initial_sp_fontsizes))
for k in (:titlefontsize, :legendfontsize, :legendtitlefontsize)
f = default(k)
if k in keys(_initial_fontsizes)
factor = f / _initial_fontsizes[k]
scalefontsize(k, 1.0 / factor)
scalefontsize(k, 1.0/factor)
end
end
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
for letter in (:x,:y,:z)
for k in (:guidefontsize, :tickfontsize)
if k in keys(_initial_fontsizes)
f = default(get_attr_symbol(letter, k))
f = default(Symbol(letter, k))
factor = f / _initial_fontsizes[k]
scalefontsize(get_attr_symbol(letter, k), 1.0 / factor)
scalefontsize(Symbol(letter, k), 1.0/factor)
end
end
end
@@ -355,8 +368,8 @@ resetfontsizes() = scalefontsizes()
"Wrap a string with font info"
struct PlotText
str::AbstractString
font::Font
str::AbstractString
font::Font
end
PlotText(str) = PlotText(string(str), font())
@@ -369,17 +382,21 @@ Create a PlotText object wrapping a string with font info, for plot annotations.
text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f)
text(str, args...; kw...) = PlotText(string(str), font(args...; kw...))
function text(str, args...;kw...)
PlotText(string(str), font(args...;kw...))
end
Base.length(t::PlotText) = length(t.str)
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
struct Stroke
width
color
alpha
style
width
color
alpha
style
end
"""
@@ -388,141 +405,132 @@ end
Define the properties of the stroke used in plotting lines
"""
function stroke(args...; alpha = nothing)
width = 1
color = :black
style = :solid
width = 1
color = :black
style = :solid
for arg in args
T = typeof(arg)
for arg in args
T = typeof(arg)
# if arg in _allStyles
if allStyles(arg)
style = arg
elseif T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
width = arg
else
@warn "Unused stroke arg: $arg ($(typeof(arg)))"
end
# if arg in _allStyles
if allStyles(arg)
style = arg
elseif T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
width = arg
else
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
end
end
Stroke(width, color, alpha, style)
Stroke(width, color, alpha, style)
end
struct Brush
size # fillrange, markersize, or any other sizey attribute
color
alpha
size # fillrange, markersize, or any other sizey attribute
color
alpha
end
function brush(args...; alpha = nothing)
size = 1
color = :black
size = 1
color = :black
for arg in args
T = typeof(arg)
for arg in args
T = typeof(arg)
if T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
size = arg
else
@warn "Unused brush arg: $arg ($(typeof(arg)))"
end
if T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
size = arg
else
@warn("Unused brush arg: $arg ($(typeof(arg)))")
end
end
Brush(size, color, alpha)
Brush(size, color, alpha)
end
# -----------------------------------------------------------------------
mutable struct SeriesAnnotations
strs::AVec # the labels/names
strs::AbstractVector # the labels/names
font::Font
baseshape::Union{Shape,AVec{Shape},Nothing}
baseshape::Union{Shape, AbstractVector{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...)
function series_annotations(strs::AbstractVector, args...)
fnt = font()
shp = nothing
scalefactor = 1, 1
scalefactor = (1,1)
for arg in args
if isa(arg, Shape) || (isa(arg, AVec) && eltype(arg) == Shape)
if isa(arg, Shape) || (isa(arg, AbstractVector) && 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
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)))"
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
end
end
# if scalefactor != 1
# for s in get(shp)
# scale!(s, scalefactor, scalefactor, (0, 0))
# scale!(s, scalefactor, scalefactor, (0,0))
# end
# end
SeriesAnnotations([_text_label(s, fnt) for s in strs], fnt, shp, scalefactor)
SeriesAnnotations(strs, fnt, shp, scalefactor)
end
series_annotations(anns::SeriesAnnotations) = anns
series_annotations(::Nothing) = nothing
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
# msw, msh = anns.scalefactor
# msw,msh = anns.scalefactor
# ms = series[:markersize]
# msw, msh = if isa(ms, AVec)
# 1, 1
# msw,msh = if isa(ms, AbstractVector)
# 1,1
# elseif is_2tuple(ms)
# ms
# else
# ms, ms
# 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
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Vector{Shape}(undef, length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs, i)
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],
# 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
@@ -533,8 +541,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(anns.baseshape, i)
shapes[i] =
scale(baseshape, msw * xscale / maxscale, msh * yscale / maxscale, (0, 0))
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end
series[:markershape] = shapes
series[:markersize] = msize
@@ -550,120 +557,89 @@ end
function Base.iterate(ea::EachAnn, i = 1)
if ea.anns === nothing || isempty(ea.anns.strs) || i > length(ea.y)
return
return nothing
end
tmp = _cycle(ea.anns.strs, i)
str, fnt = if isa(tmp, PlotText)
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)
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
end
# -----------------------------------------------------------------------
annotations(anns::AMat) = map(annotations, anns)
annotations(sa::SeriesAnnotations) = sa
annotations(::Nothing) = []
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
annotations(::Nothing) = []
annotations(sa::SeriesAnnotations) = sa
_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
# Expand arrays of coordinates, positions and labels into induvidual annotations
# and make sure labels are of type PlotText
function process_annotation(sp::Subplot, xs, ys, labs, font = _annotationfont(sp))
function process_annotation(sp::Subplot, xs, ys, labs, font = font())
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, 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))
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
end
function process_annotation(
sp::Subplot,
positions::Union{AVec{Symbol},Symbol,Tuple},
labs,
font = _annotationfont(sp),
)
function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol}, labs, font = font())
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)))
pos = get(_positionAliases, pos, pos)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
end
_relative_position(xmin, xmax, pos::Length{:pct}) = xmin + pos.value * (xmax - xmin)
function process_any_label(lab, font=Font())
lab isa Tuple ? text(lab...) : text( lab, font )
end
# 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,
function locate_annotation(sp::Subplot, pos::Symbol, lab::PlotText)
position_multiplier = Dict{Symbol, Tuple{Float64,Float64}}(
:topleft => (0.1, 0.9),
:topcenter => (0.5, 0.9),
:topright => (0.9, 0.9),
:bottomleft => (0.1, 0.1),
:bottomcenter => (0.5, 0.1),
:bottomright => (0.9, 0.1),
)
xmin, xmax = ignorenan_extrema(sp[:xaxis])
ymin, ymax = ignorenan_extrema(sp[:yaxis])
x, y = (xmin, ymin).+ position_multiplier[pos].* (xmax - xmin, ymax - ymin)
(x, y, lab)
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)"
struct ZValues
values::Vector{Float64}
zrange::Tuple{Float64,Float64}
values::Vector{Float64}
zrange::Tuple{Float64,Float64}
end
function zvalues(
values::AVec{T},
zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values)),
) where {T<:Real}
ZValues(collect(float(values)), map(Float64, zrange))
function zvalues(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values))) where T<:Real
ZValues(collect(float(values)), map(Float64, zrange))
end
# -----------------------------------------------------------------------
@@ -681,10 +657,13 @@ struct SurfaceFunction <: AbstractSurface
f::Function
end
# -----------------------------------------------------------------------
# # I don't want to clash with ValidatedNumerics, but this would be nice:
# ..(a::T, b::T) = (a, b)
# ..(a::T, b::T) = (a,b)
# -----------------------------------------------------------------------
@@ -705,7 +684,8 @@ Define arrowheads to apply to lines - args are `style` (`:open` or `:closed`),
function arrow(args...)
style = :simple
side = :head
headlength = headwidth = 0.3
headlength = 0.3
headwidth = 0.3
setlength = false
for arg in args
T = typeof(arg)
@@ -725,20 +705,21 @@ function arrow(args...)
elseif T <: Tuple && length(arg) == 2
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
else
@warn "Skipped arrow arg $arg"
@warn("Skipped arrow arg $arg")
end
end
Arrow(style, side, headlength, headwidth)
end
# allow for do-block notation which gets called on every valid start/end pair which
# we need to draw an arrow
function add_arrows(func::Function, x::AVec, y::AVec)
for i in 2:length(x)
xyprev = (x[i - 1], y[i - 1])
for i=2:length(x)
xyprev = (x[i-1], y[i-1])
xy = (x[i], y[i])
if ok(xyprev) && ok(xy)
if i == length(x) || !ok(x[i + 1], y[i + 1])
if i==length(x) || !ok(x[i+1], y[i+1])
# add the arrow from xyprev to xy
func(xyprev, xy)
end
@@ -748,27 +729,32 @@ end
# -----------------------------------------------------------------------
"create a BezierCurve for plotting"
mutable struct BezierCurve{T<:GeometryBasics.Point}
mutable struct BezierCurve{T <: GeometryBasics.Point}
control_points::Vector{T}
end
function (bc::BezierCurve)(t::Real)
p = zero(P2)
n = length(bc.control_points) - 1
n = length(bc.control_points)-1
for i in 0:n
p += bc.control_points[i + 1] * binomial(n, i) * (1 - t)^(n - i) * t^i
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
end
p
end
@deprecate curve_points coords
coords(curve::BezierCurve, n::Integer = 30; range = [0, 1]) =
map(curve, Base.range(first(range), stop = last(range), length = n))
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, Base.range(first(range), stop=last(range), length=n))
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
# may create a loop if necessary. Assumes the view is [0,1]
function directed_curve(args...; kw...)
error("directed_curve has been moved to PlotRecipes")
end
function extrema_plus_buffer(v, buffmult = 0.2)
vmin, vmax = ignorenan_extrema(v)
vdiff = vmax - vmin
vmin,vmax = ignorenan_extrema(v)
vdiff = vmax-vmin
buffer = vdiff * buffmult
vmin - buffer, vmax + buffer
end
+258 -413
View File
@@ -7,7 +7,7 @@ mutable struct PlotExample
exprs::Vector{Expr}
end
# the _examples we'll run for each backend
# the _examples we'll run for each
const _examples = PlotExample[
PlotExample( # 1
"Lines",
@@ -28,33 +28,35 @@ const _examples = PlotExample[
to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the
animation.
""",
[
:(
begin
p = plot(
[sin, cos],
zeros(0),
leg = false,
xlims = (0, 2π),
ylims = (-1, 1),
)
anim = Animation()
for x in range(0, stop = 2π, length = 20)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
[:(
begin
p = plot([sin, cos], zeros(0), leg = false, xlims = (0, 2π), ylims = (-1, 1))
anim = Animation()
for x in range(0, stop = 2π, length = 20)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
),
],
end
)],
),
PlotExample( # 3
"Parametric plots",
"Plot function pair (x(u), y(u)).",
[:(
[
:(
begin
plot(sin, x -> sin(2x), 0, 2π, line = 4, leg = false, fill = (0, :orange))
plot(
sin,
x -> sin(2x),
0,
2π,
line = 4,
leg = false,
fill = (0, :orange),
)
end
)],
),
],
),
PlotExample( # 4
"Colors",
@@ -113,11 +115,12 @@ const _examples = PlotExample[
)
vline!([5, 10])
title!("TITLE")
yaxis!("YLABEL", :log10, minorgrid = true)
yaxis!("YLABEL", :log10)
end
),
],
),
PlotExample( # 6
"Images",
"Plot an image. y-axis is set to flipped",
@@ -125,10 +128,8 @@ const _examples = PlotExample[
:(
begin
import FileIO
import Downloads
path = Downloads.download(
"http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png",
)
path =
download("http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png")
img = FileIO.load(path)
plot(img)
end
@@ -189,11 +190,12 @@ const _examples = PlotExample[
PlotExample( # 11
"Line types",
"",
[:(
[
:(
begin
linetypes = [:path :steppre :steppost :sticks :scatter]
n = length(linetypes)
x = Vector[sort(rand(20)) for i in 1:n]
x = Vector[sort(rand(20)) for i = 1:n]
y = rand(20, n)
plot(
x,
@@ -203,7 +205,8 @@ const _examples = PlotExample[
ms = 15,
)
end
)],
),
],
),
PlotExample( # 12
"Line styles",
@@ -234,17 +237,18 @@ const _examples = PlotExample[
[
:(
begin
markers =
filter(m -> m in Plots.supported_markers(), Plots._shape_keys)
markers = permutedims(markers)
markers = filter(
m -> m in Plots.supported_markers(),
Plots._shape_keys,
)
markers = reshape(markers, 1, length(markers))
n = length(markers)
x = range(0, stop = 10, length = n + 2)[2:(end - 1)]
y = repeat(reshape(reverse(x), 1, :), n, 1)
scatter(
x,
y,
m = markers,
markersize = 8,
m = (8, :auto),
lab = map(string, markers),
bg = :linen,
xlim = (0, 10),
@@ -266,11 +270,17 @@ const _examples = PlotExample[
PlotExample( # 15
"Histogram",
"",
[:(
[
:(
begin
histogram(randn(1000), bins = :scott, weights = repeat(1:5, outer = 200))
histogram(
randn(1000),
bins = :scott,
weights = repeat(1:5, outer = 200),
)
end
)],
),
],
),
PlotExample( # 16
"Subplots",
@@ -316,13 +326,15 @@ const _examples = PlotExample[
PlotExample( # 18
"",
"",
[:(
begin
using Random
Random.seed!(111)
plot!(Plots.fakedata(100, 10))
end
)],
[
:(
begin
using Random
Random.seed!(111)
plot!(Plots.fakedata(100, 10))
end
)
]
),
PlotExample( # 19
"Open/High/Low/Close",
@@ -345,7 +357,8 @@ const _examples = PlotExample[
bot[i] + hgt[i],
bot[i],
closepct[i] * hgt[i] + bot[i],
) for i in 1:n
)
for i = 1:n
]
ohlc(y)
end
@@ -356,21 +369,10 @@ const _examples = PlotExample[
"Annotations",
"""
The `annotations` keyword is used for text annotations in data-coordinates. Pass in a
tuple `(x, y, text)`, a vector of annotations, each of which is a tuple of `x`, `y`
and `text`. You can position annotations using relative coordinates with the syntax
`((px, py), text)`, where for example `px=.25` positions the annotation at `25%` of
the subplot's axis width.
`text` may be a simple `String`, or a `PlotText` object, which can be built with the
method `text(string, attrs...)`.
This wraps font and color attributes and allows you to set text styling.
`text` may also be a tuple `(string, attrs...)` of arguments which are passed
to `Plots.text`.
`annotate!(ann)` is shorthand for `plot!(; annotation=ann)`.
Series annotations are used for annotating individual data points.
They require only the annotation; x/y values are computed. Series annotations
require either plain `String`s or `PlotText` objects.
tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(;
annotation=ann)`. Series annotations are used for annotating individual data points.
They require only the annotation... x/y values are computed. A `PlotText` object can be
build with the method `text(string, attr...)`, which wraps font and color attributes.
""",
[
:(
@@ -382,8 +384,12 @@ const _examples = PlotExample[
leg = false,
)
annotate!([
(5, y[5], ("this is #5", 16, :red, :center)),
(10, y[10], ("this is #10", :right, 20, "courier")),
(5, y[5], Plots.text("this is #5", 16, :red, :center)),
(
10,
y[10],
Plots.text("this is #10", :right, 20, "courier"),
),
])
scatter!(
range(2, stop = 8, length = 6),
@@ -562,8 +568,8 @@ const _examples = PlotExample[
"",
[:(
begin
xs = [string("x", i) for i in 1:10]
ys = [string("y", i) for i in 1:4]
xs = [string("x", i) for i = 1:10]
ys = [string("y", i) for i = 1:4]
z = float((1:4) * reshape(1:10, 1, :))
heatmap(xs, ys, z, aspect_ratio = 1)
end
@@ -598,7 +604,12 @@ const _examples = PlotExample[
begin
import RDatasets
singers = RDatasets.dataset("lattice", "singer")
@df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue))
@df singers violin(
:VoicePart,
:Height,
line = 0,
fill = (0.2, :blue),
)
@df singers boxplot!(
:VoicePart,
:Height,
@@ -626,7 +637,11 @@ const _examples = PlotExample[
anim = Animation()
for x in range(1, stop = 2π, length = 20)
plot(push!(p, x, Float64[sin(x), cos(x), atan(x), cos(x), log(x)]))
plot(push!(
p,
x,
Float64[sin(x), cos(x), atan(x), cos(x), log(x)],
))
frame(anim)
end
end
@@ -651,8 +666,18 @@ const _examples = PlotExample[
10 => ones(40),
-10 => ones(40),
)
b = spdiagm(0 => 1:50, 1 => 1:49, -1 => 1:49, 10 => 1:40, -10 => 1:40)
plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
b = spdiagm(
0 => 1:50,
1 => 1:49,
-1 => 1:49,
10 => 1:40,
-10 => 1:40,
)
plot(
spy(a),
spy(b),
title = ["Unique nonzeros" "Different nonzeros"],
)
end
),
],
@@ -717,37 +742,51 @@ const _examples = PlotExample[
You can use the `line_z` and `marker_z` properties to associate a color with
each line segment or marker in the plot.
""",
[:(
begin
t = range(0, stop = 1, length = 100)
θ = 6π .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z = t, linewidth = 3, legend = false)
p2 = scatter(x, y, marker_z = +, color = :bluesreds, legend = false)
plot(p1, p2)
end
)],
[
:(
begin
t = range(0, stop = 1, length = 100)
θ = 6π .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z = t, linewidth = 3, legend = false)
p2 = scatter(
x,
y,
marker_z = +,
color = :bluesreds,
legend = false,
)
plot(p1, p2)
end
),
],
),
PlotExample( # 36
"Portfolio Composition maps",
"""
see: http://stackoverflow.com/a/37732384/5075246
""",
[:(
begin
using Random
Random.seed!(111)
tickers = ["IBM", "Google", "Apple", "Intel"]
N = 10
D = length(tickers)
weights = rand(N, D)
weights ./= sum(weights, dims = 2)
returns = sort!((1:N) + D * randn(N))
[
:(
begin
using Random
Random.seed!(111)
tickers = ["IBM", "Google", "Apple", "Intel"]
N = 10
D = length(tickers)
weights = rand(N, D)
weights ./= sum(weights, dims = 2)
returns = sort!((1:N) + D * randn(N))
portfoliocomposition(weights, returns, labels = permutedims(tickers))
end
)],
portfoliocomposition(
weights,
returns,
labels = permutedims(tickers),
)
end
),
],
),
PlotExample( # 37
"Ribbons",
@@ -760,7 +799,10 @@ const _examples = PlotExample[
:(
begin
plot(
plot(0:10; ribbon = (LinRange(0, 2, 11), LinRange(0, 1, 11))),
plot(
0:10;
ribbon = (LinRange(0, 2, 11), LinRange(0, 1, 11)),
),
plot(0:10; ribbon = 0:0.5:5),
plot(0:10; ribbon = sqrt),
plot(0:10; ribbon = 1),
@@ -825,7 +867,11 @@ const _examples = PlotExample[
plot!([(0, 0), (0, 0.9), (2, 0.9), (3, 1), (4, 0.9), (80, 0)])
plot!([(0, 0), (0, 0.9), (3, 0.9), (4, 1), (5, 0.9), (80, 0)])
plot!([(0, 0), (0, 0.9), (4, 0.9), (5, 1), (6, 0.9), (80, 0)])
lens!([1, 6], [0.9, 1.1], inset = (1, bbox(0.5, 0.0, 0.4, 0.4)))
lens!(
[1, 6],
[0.9, 1.1],
inset = (1, bbox(0.5, 0.0, 0.4, 0.4)),
)
end
end,
],
@@ -833,15 +879,17 @@ const _examples = PlotExample[
PlotExample( # 41
"Array Types",
"Plots supports different `Array` types that follow the `AbstractArray` interface, like `StaticArrays` and `OffsetArrays.`",
[quote
begin
using StaticArrays, OffsetArrays
sv = SVector{10}(rand(10))
ov = OffsetVector(rand(10), -2)
plot([sv, ov], label = ["StaticArray" "OffsetArray"])
plot!(3ov, ribbon = ov, label = "OffsetArray ribbon")
end
end],
[
quote
begin
using StaticArrays, OffsetArrays
sv = SVector{10}(rand(10))
ov = OffsetVector(rand(10), -2)
plot([sv, ov], label = ["StaticArray" "OffsetArray"])
plot!(3ov, ribbon=ov, label="OffsetArray ribbon")
end
end,
],
),
PlotExample( # 42
"Setting defaults and font arguments",
@@ -857,7 +905,7 @@ const _examples = PlotExample[
tickfont = (12, :orange),
guide = "x",
framestyle = :zerolines,
yminorgrid = true,
yminorgrid = true
)
plot(
[sin, cos],
@@ -876,25 +924,29 @@ const _examples = PlotExample[
PlotExample( # 43
"Heatmap with DateTime axis",
"",
[quote
begin
using Dates
z = rand(5, 5)
x = DateTime.(2016:2020)
y = 1:5
heatmap(x, y, z)
end
end],
[
quote
begin
using Dates
z = rand(5, 5)
x = DateTime.(2016:2020)
y = 1:5
heatmap(x, y, z)
end
end,
],
),
PlotExample( # 44
"Linked axes",
"",
[quote
begin
x = -5:0.1:5
plot(plot(x, x -> x^2), plot(x, x -> sin(x)), layout = 2, link = :y)
end
end],
[
quote
begin
x = -5:0.1:5
plot(plot(x, x->x^2), plot(x, x->sin(x)), layout = 2, link = :y)
end
end,
],
),
PlotExample( # 45
"Error bars and array type recipes",
@@ -909,21 +961,8 @@ const _examples = PlotExample[
value(m::Measurement) = m.val
uncertainty(m::Measurement) = m.err
@recipe function f(
::Type{T},
m::T,
) where {T<:AbstractArray{<:Measurement}}
if !(
get(plotattributes, :seriestype, :path) in [
:contour,
:contourf,
:contour3d,
:heatmap,
:surface,
:wireframe,
:image,
]
)
@recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:Measurement}
if !(get(plotattributes, :seriestype, :path) in [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image])
error_sym = Symbol(plotattributes[:letter], :error)
plotattributes[error_sym] = uncertainty.(m)
end
@@ -933,14 +972,14 @@ const _examples = PlotExample[
x = Measurement.(10sort(rand(10)), rand(10))
y = Measurement.(10sort(rand(10)), rand(10))
z = Measurement.(10sort(rand(10)), rand(10))
surf = Measurement.((1:10) .* (1:10)', rand(10, 10))
surf = Measurement.((1:10) .* (1:10)', rand(10,10))
plot(
scatter(x, [x y]),
scatter(x, y, z),
heatmap(x, y, surf),
wireframe(x, y, surf),
legend = :topleft,
legend = :topleft
)
end
end,
@@ -953,147 +992,104 @@ const _examples = PlotExample[
using GeometryBasics
using Distributions
d = MvNormal([1.0 0.75; 0.75 2.0])
plot([(1, 2), (3, 2), (2, 1), (2, 3)])
scatter!(Point2.(eachcol(rand(d, 1000))), alpha = 0.25)
end],
plot([(1,2),(3,2),(2,1),(2,3)])
scatter!(Point2.(eachcol(rand(d,1000))), alpha=0.25)
end]
),
PlotExample( # 47
"Mesh3d",
"""
Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically.
You can also specify the connections using the connections keyword.
The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle,
such that elements at the same position of these vectors form a triangle.
""",
[
:(
begin
# specify the vertices
x = [0, 1, 2, 0]
y = [0, 0, 1, 2]
z = [0, 2, 0, 1]
"Mesh3d",
"""
Allows to plot arbitrary 3d meshes. If only x,y,z are given the mesh is generated automatically.
You can also specify the connections using the connections keyword.
The connections are specified using a tuple of vectors. Each vector contains the 0-based indices of one point of a triangle,
such that elements at the same position of these vectors form a triangle.
""",
[
:(
begin
# specify the vertices
x=[0, 1, 2, 0]
y=[0, 0, 1, 2]
z=[0, 2, 0, 1]
# specify the triangles
# every column is one triangle,
# where the values denote the indices of the vertices of the triangle
i = [0, 0, 0, 1]
j = [1, 2, 3, 2]
k = [2, 3, 1, 3]
# specify the triangles
# every column is one triangle,
# where the values denote the indices of the vertices of the triangle
i=[0, 0, 0, 1]
j=[1, 2, 3, 2]
k=[2, 3, 1, 3]
# the four triangles gives above give a tetrahedron
mesh3d(
x,
y,
z;
connections = (i, j, k),
title = "triangles",
xlabel = "x",
ylabel = "y",
zlabel = "z",
legend = :none,
margin = 2Plots.mm,
)
end
),
],
# the four triangles gives above give a tetrahedron
mesh3d(x,y,z;connections=(i,j,k))
end
),
],
),
PlotExample( # 48
"Vectors of markershapes and segments",
"",
[
quote
using Base.Iterators: cycle, take
yv = ones(9)
ys = [1; 1; NaN; ones(6)]
y = 5 .- [yv 2ys 3yv 4ys]
plt_color_rows = plot(
y,
seriestype = [:path :path :scatter :scatter],
markershape = collect(take(cycle((:utriangle, :rect)), 9)),
markersize = 8,
color = collect(take(cycle((:red, :black)), 9)),
)
plt_z_cols = plot(
y,
markershape = [:utriangle :x :circle :square],
markersize = [5 10 10 5],
marker_z = [5 4 3 2],
line_z = [1 3 3 1],
linewidth = [1 10 5 1],
)
plot(plt_color_rows, plt_z_cols)
end,
],
[quote
yv = ones(9)
ys = [1; 1; NaN; ones(6)]
plot(
5 .- [yv 2ys 3yv 4ys],
seriestype = [:path :path :scatter :scatter],
markershape = [:utriangle, :rect],
markersize = 8,
color = [:red, :black],
)
end]
),
PlotExample( # 49
"Polar heatmaps",
"",
[quote
x = range(0, 2π, length = 9)
y = 0:4
z = (1:4) .+ (1:8)'
heatmap(x, y, z, projection = :polar)
end],
heatmap(z, projection = :polar)
end]
),
PlotExample( # 50
"3D surface with axis guides",
"",
[
quote
f(x, a) = 1 / x + a * x^2
xs = collect(0.1:0.05:2.0)
as = collect(0.2:0.1:2.0)
[quote
f(x,a) = 1/x + a*x^2
xs = collect(0.1:0.05:2.0);
as = collect(0.2:0.1:2.0);
x_grid = [x for x in xs for y in as]
a_grid = [y for x in xs for y in as]
x_grid = [x for x in xs for y in as];
a_grid = [y for x in xs for y in as];
plot(
x_grid,
a_grid,
f.(x_grid, a_grid),
st = :surface,
xlabel = "longer xlabel",
ylabel = "longer ylabel",
zlabel = "longer zlabel",
)
end,
],
plot(x_grid, a_grid, f.(x_grid,a_grid),
st = :surface,
xlabel = "longer xlabel",
ylabel = "longer ylabel",
zlabel = "longer zlabel",
)
end]
),
PlotExample( # 51
"Images with custom axes",
"",
[
quote
using Plots
using TestImages
img = testimage("lighthouse")
[quote
using Plots
using TestImages
img = testimage("lighthouse")
# plot the image reversing the first dimension and setting yflip = false
plot(
[-π, π],
[-1, 1],
reverse(img, dims = 1),
yflip = false,
aspect_ratio = :none,
)
# plot other data
plot!(sin, -π, π, lw = 3, color = :red)
end,
],
# plot the image reversing the first dimension and setting yflip = false
plot([-π, π], [-1, 1], reverse(img, dims=1), yflip=false, aspect_ratio=:none)
# plot other data
plot!(sin, -π, π, lw=3, color=:red)
end]
),
PlotExample( # 52
PlotExample(
"3d quiver",
"",
[quote
using Plots
ϕs = range(-π, π, length = 50)
θs = range(0, π, length = 25)
θqs = range(1, π - 1, length = 25)
ϕs = range(-π, π, length=50)
θs = range(0, π, length=25)
θqs = range(1, π-1, length=25)
x = vec([sin(θ) * cos(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)])
y = vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θs)])
@@ -1103,183 +1099,32 @@ const _examples = PlotExample[
v = 0.1 * vec([sin(θ) * sin(ϕ) for (ϕ, θ) in Iterators.product(ϕs, θqs)])
w = 0.1 * vec([cos(θ) for (ϕ, θ) in Iterators.product(ϕs, θqs)])
quiver(x, y, z, quiver = (u, v, w))
end],
),
PlotExample( # 53
"Step Types",
"A comparison of the various step-like `seriestype`s",
[
:(
begin
x = 1:5
y = [1, 2, 3, 2, 1]
default(shape = :circle)
plot(
plot(
x,
y,
markershape = :circle,
seriestype = :steppre,
label = "steppre",
),
plot(
x,
y,
markershape = :circle,
seriestype = :stepmid,
label = "stepmid",
),
plot(
x,
y,
markershape = :circle,
seriestype = :steppost,
label = "steppost",
),
layout = (3, 1),
)
end
),
],
),
PlotExample( # 54
"Guide positions and alignment",
"",
[
:(
begin
plot(
rand(10, 4),
layout = 4,
xguide = "x guide",
yguide = "y guide",
xguidefonthalign = [:left :right :right :left],
yguidefontvalign = [:top :bottom :bottom :top],
xguideposition = :top,
yguideposition = [:right :left :right :left],
ymirror = [false true true false],
xmirror = [false false true true],
legend = false,
seriestype = [:bar :scatter :path :stepmid],
)
end
),
],
),
PlotExample( # 55
"3D axis flip / mirror",
"",
[
:(
begin
using LinearAlgebra
scalefontsizes(0.4)
x, y = collect(-6:0.5:10), collect(-8:0.5:8)
args = x, y, (x, y) -> sinc(norm([x, y]) / π)
kwargs = Dict(
:xlabel => "x",
:ylabel => "y",
:zlabel => "z",
:grid => true,
:minorgrid => true,
)
plots = [wireframe(args..., title = "wire"; kwargs...)]
for ax in (:x, :y, :z)
push!(
plots,
wireframe(
args...,
title = "wire-flip-$ax",
xflip = ax == :x,
yflip = ax == :y,
zflip = ax == :z;
kwargs...,
),
)
end
for ax in (:x, :y, :z)
push!(
plots,
wireframe(
args...,
title = "wire-mirror-$ax",
xmirror = ax == :x,
ymirror = ax == :y,
zmirror = ax == :z;
kwargs...,
),
)
end
plt = plot(
plots...,
layout = (@layout [_ ° _; ° ° °; ° ° °]),
margin = 0Plots.px,
)
resetfontsizes()
plt
end
),
],
quiver(x,y,z, quiver=(u,v,w))
end]
),
]
# Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 31]
_backend_skips = Dict(
:gr => [25, 30],
:pyplot => [2, 25, 30, 31, 47, 49, 55],
:plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51, 55],
:plotly => [2, 21, 24, 25, 30, 31, 49, 50, 51, 55],
:gr => [25, 30, 47],
:pyplot => [2, 25, 30, 31, 47, 49],
:plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51],
:plotly => [2, 21, 24, 25, 30, 31, 49, 51],
:pgfplotsx => [
2, # animation
6, # images
16, # pgfplots thinks the upper panel is too small
30, # @df
31, # animation
32, # spy
49, # polar heatmap
51, # image with custom axes
],
:inspectdr => [4, 6, 10, 22, 24, 28, 30, 38, 43, 45, 47, 48, 49, 50, 51, 55],
:unicodeplots => [
6, # embedded images unsupported
13, # markers unsupported
16, # nested layout unsupported
20, # annotations unsupported
21, # custom markers unsupported
22, # contours unsupported
24, # 3D unsupported
26, # nested layout unsupported
29, # nested layout unsupported
33, # grid lines unsupported
34, # framestyle unsupported
37, # ribbons / filled unsupported
43, # heatmap with DateTime
45, # error bars
47, # mesh3D unsupported
48, # markershapes unsupported
49, # polar heatmap
50, # 3D surface unsupported
51, # embedded images unsupported
52, # 3D quiver unsupported
55, # 3D unsupported
],
:gaston => [
2, # animations
31, # animations
49, # TODO: support polar
50, # TODO: 1D data not supported for pm3d
2, # animation
6, # images
16, # pgfplots thinks the upper panel is too small
30, # @df
31, # animation
32, # spy
49, # polar heatmap
51, # image with custom axes
],
)
# ---------------------------------------------------------------------------------
# make and display one plot
+3 -6
View File
@@ -1,10 +1,8 @@
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
_fileio_load(@nospecialize(filename::AbstractString)) =
FileIO.load(filename::AbstractString)
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) =
FileIO.save(filename::AbstractString, x)
_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString)
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x)
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
@@ -23,5 +21,4 @@ function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
write(io, read(open(pngfn), String))
end
const PDFBackends =
Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
+13 -7
View File
@@ -1,14 +1,15 @@
const use_local_dependencies = Ref(false)
const use_local_plotlyjs = Ref(false)
function _init_ijulia_plotting()
# IJulia is more stable with local file
use_local_plotlyjs[] =
plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
use_local_plotlyjs[] = plotly_local_file_path[] === nothing ? false : isfile(plotly_local_file_path[])
ENV["MPLBACKEND"] = "Agg"
end
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
@@ -19,17 +20,22 @@ frontends like jupyterlab and nteract.
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] =
Dict(:data => plotly_series(plt), :layout => plotly_layout(plt))
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] =
Dict(:data => plotly_series(plt), :layout => plotly_layout(plt))
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function _ijulia_display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
@@ -48,9 +54,9 @@ function _ijulia_display_dict(plt::Plot)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
_ijulia__extra_mime_info!(plt, out)
else
error("Unsupported output type $output_type")
end
_ijulia__extra_mime_info!(plt, out)
out
end
+14 -34
View File
@@ -1,7 +1,8 @@
using REPL
using Scratch
const plotly_local_file_path = Ref{Union{Nothing,String}}(nothing)
const plotly_local_file_path = Ref{Union{Nothing, String}}(nothing)
function _plots_defaults()
if isdefined(Main, :PLOTS_DEFAULTS)
@@ -11,6 +12,7 @@ function _plots_defaults()
end
end
function __init__()
user_defaults = _plots_defaults()
if haskey(user_defaults, :theme)
@@ -19,27 +21,14 @@ function __init__()
default(; user_defaults...)
end
insert!(
Base.Multimedia.displays,
findlast(
x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay,
Base.Multimedia.displays,
) + 1,
PlotsDisplay(),
)
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
atreplinit(
i -> begin
while PlotsDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
insert!(
Base.Multimedia.displays,
findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1,
PlotsDisplay(),
)
end,
)
atreplinit(i -> begin
while PlotsDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
end)
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" begin
fn = joinpath(@__DIR__, "backends", "hdf5.jl")
@@ -81,11 +70,6 @@ function __init__()
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()
@@ -95,13 +79,9 @@ function __init__()
end
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global plotly_local_file_path[] =
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
global plotly_local_file_path[] = joinpath(@get_scratch!("plotly"), "plotly-1.54.2.min.js")
if !isfile(plotly_local_file_path[])
Downloads.download(
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
plotly_local_file_path[],
)
download("https://cdn.plot.ly/plotly-1.57.1.min.js", plotly_local_file_path[])
end
use_local_plotlyjs[] = true
@@ -109,8 +89,8 @@ function __init__()
use_local_dependencies[] = use_local_plotlyjs[]
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) =
_show_pdfbackends(io, mime, plt)
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt)
end
end
+158 -169
View File
@@ -18,16 +18,16 @@ ispositive(m::Measure) = m.value > 0
# union together bounding boxes
function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
# empty boxes don't change the union
ispositive(width(bb1)) || return bb2
ispositive(width(bb1)) || return bb2
ispositive(height(bb1)) || return bb2
ispositive(width(bb2)) || return bb1
ispositive(width(bb2)) || return bb1
ispositive(height(bb2)) || return bb1
l = min(left(bb1), left(bb2))
t = min(top(bb1), top(bb2))
r = max(right(bb1), right(bb2))
b = max(bottom(bb1), bottom(bb2))
BoundingBox(l, t, r - l, b - t)
BoundingBox(l, t, r-l, b-t)
end
# this creates a bounding box in the parent's scope, where the child bounding box
@@ -53,7 +53,7 @@ end
# convert a bounding box from absolute coords to percentages...
# returns an array of percentages of figure size: [left, bottom, width, height]
function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
mms = Float64[f(bb).value for f in (left, bottom, width, height)]
mms = Float64[f(bb).value for f in (left,bottom,width,height)]
if flipy
mms[2] = figh.value - mms[2] # flip y when origin in bottom-left
end
@@ -61,10 +61,7 @@ function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
end
function Base.show(io::IO, bbox::BoundingBox)
print(
io,
"BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}",
)
print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
end
# -----------------------------------------------------------
@@ -86,11 +83,12 @@ function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
end
if pct != 0
amin, amax = axis_limits(sp, letter)
xy += pct * (amax - amin)
xy += pct * (amax-amin)
end
xy
end
# -----------------------------------------------------------
# AbstractLayout
@@ -162,8 +160,7 @@ parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
update_position!(layout::AbstractLayout) = nothing
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm, 0mm, 0mm, 0mm]) =
nothing
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
left(layout::AbstractLayout) = left(bbox(layout))
top(layout::AbstractLayout) = top(bbox(layout))
@@ -209,7 +206,7 @@ mutable struct EmptyLayout <: AbstractLayout
end
EmptyLayout(parent = RootLayout(); kw...) = EmptyLayout(parent, defaultbox, KW(kw))
Base.size(layout::EmptyLayout) = (0, 0)
Base.size(layout::EmptyLayout) = (0,0)
Base.length(layout::EmptyLayout) = 0
Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing
@@ -238,25 +235,22 @@ columns of different width.
"""
grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(
dims...;
parent = RootLayout(),
widths = zeros(dims[2]),
heights = zeros(dims[1]),
kw...,
)
function GridLayout(dims...;
parent = RootLayout(),
widths = zeros(dims[2]),
heights = zeros(dims[1]),
kw...)
grid = Matrix{AbstractLayout}(undef, dims...)
layout = GridLayout(
parent,
(20mm, 5mm, 2mm, 10mm),
defaultbox,
grid,
Measure[w * pct for w in widths],
Measure[h * pct for h in heights],
Measure[w*pct for w in widths],
Measure[h*pct for h in heights],
# convert(Vector{Float64}, widths),
# convert(Vector{Float64}, heights),
KW(kw),
)
KW(kw))
for i in eachindex(grid)
grid[i] = EmptyLayout(layout)
end
@@ -265,9 +259,9 @@ end
Base.size(layout::GridLayout) = size(layout.grid)
Base.length(layout::GridLayout) = length(layout.grid)
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r, c]
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c]
function Base.setindex!(layout::GridLayout, v, r::Int, c::Int)
layout.grid[r, c] = v
layout.grid[r,c] = v
end
leftpad(layout::GridLayout) = layout.minpad[1]
@@ -275,6 +269,7 @@ toppad(layout::GridLayout) = layout.minpad[2]
rightpad(layout::GridLayout) = layout.minpad[3]
bottompad(layout::GridLayout) = layout.minpad[4]
# here's how this works... first we recursively "update the minimum padding" (which
# means to calculate the minimum size needed from the edge of the subplot to plot area)
# for the whole layout tree. then we can compute the "padding borders" of this
@@ -286,13 +281,14 @@ bottompad(layout::GridLayout) = layout.minpad[4]
function _update_min_padding!(layout::GridLayout)
map(_update_min_padding!, layout.grid)
layout.minpad = (
maximum(map(leftpad, layout.grid[:, 1])),
maximum(map(toppad, layout.grid[1, :])),
maximum(map(rightpad, layout.grid[:, end])),
maximum(map(bottompad, layout.grid[end, :])),
maximum(map(leftpad, layout.grid[:,1])),
maximum(map(toppad, layout.grid[1,:])),
maximum(map(rightpad, layout.grid[:,end])),
maximum(map(bottompad, layout.grid[end,:]))
)
end
function update_position!(layout::GridLayout)
map(update_position!, layout.grid)
end
@@ -311,9 +307,7 @@ function recompute_lengths(v)
end
leftover = 1.0pct - tot
if cnt > 1 && leftover.value <= 0
error(
"Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover",
)
error("Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover")
end
# now fill in the blanks
@@ -321,21 +315,21 @@ function recompute_lengths(v)
end
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm, 0mm, 0mm])
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
nr, nc = size(layout)
# # create a matrix for each minimum padding direction
# _update_min_padding!(layout)
minpad_left = map(leftpad, layout.grid)
minpad_top = map(toppad, layout.grid)
minpad_right = map(rightpad, layout.grid)
minpad_left = map(leftpad, layout.grid)
minpad_top = map(toppad, layout.grid)
minpad_right = map(rightpad, layout.grid)
minpad_bottom = map(bottompad, layout.grid)
# get the max horizontal (left and right) padding over columns,
# and max vertical (bottom and top) padding over rows
# TODO: add extra padding here
pad_left = maximum(minpad_left, dims = 1)
pad_top = maximum(minpad_top, dims = 2)
pad_right = maximum(minpad_right, dims = 1)
pad_left = maximum(minpad_left, dims = 1)
pad_top = maximum(minpad_top, dims = 2)
pad_right = maximum(minpad_right, dims = 1)
pad_bottom = maximum(minpad_bottom, dims = 2)
# make sure the perimeter match the parent
@@ -349,7 +343,7 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm,
total_pad_vertical = sum(pad_top + pad_bottom)
# now we can compute the total plot area in each direction
total_plotarea_horizontal = width(layout) - total_pad_horizontal
total_plotarea_horizontal = width(layout) - total_pad_horizontal
total_plotarea_vertical = height(layout) - total_pad_vertical
# recompute widths/heights
@@ -361,22 +355,19 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm, 0mm,
# denom_h = sum(layout.heights)
# 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
child = layout[r, c]
for r=1:nr, c=1:nc
child = layout[r,c]
# get the top-left corner of this child... the first one is top-left of the parent (i.e. layout)
child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c - 1].bbox))
child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r - 1, c].bbox))
child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox))
child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox))
# compute plot area
plotarea_left = child_left + pad_left[c]
plotarea_top = child_top + pad_top[r]
plotarea_width = total_plotarea_horizontal * layout.widths[c]
plotarea_height = total_plotarea_vertical * layout.heights[r]
plotarea!(
child,
BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height),
)
plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height))
# compute child bbox
child_width = pad_left[c] + plotarea_width + pad_right[c]
@@ -386,10 +377,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
# all children on this border have the same value
min_child_perimeter = [
c == 1 ? layout.minpad[1] : pad_left[c],
r == 1 ? layout.minpad[2] : pad_top[r],
c == 1 ? layout.minpad[1] : pad_left[c],
r == 1 ? layout.minpad[2] : pad_top[r],
c == nc ? layout.minpad[3] : pad_right[c],
r == nr ? layout.minpad[4] : pad_bottom[r],
r == nr ? layout.minpad[4] : pad_bottom[r]
]
# recursively update the child's children
@@ -404,21 +395,18 @@ function update_inset_bboxes!(plt::Plot)
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
plotarea!(sp, p_area)
bbox!(
sp,
bbox(
left(p_area) - leftpad(sp),
top(p_area) - toppad(sp),
width(p_area) + leftpad(sp) + rightpad(sp),
height(p_area) + toppad(sp) + bottompad(sp),
),
)
bbox!(sp, bbox(
left(p_area) - leftpad(sp),
top(p_area) - toppad(sp),
width(p_area) + leftpad(sp) + rightpad(sp),
height(p_area) + toppad(sp) + bottompad(sp)
))
end
end
# ----------------------------------------------------------------------
calc_num_subplots(layout::AbstractLayout) = get(layout.attr, :blank, false) ? 0 : 1
calc_num_subplots(layout::AbstractLayout) = 1
function calc_num_subplots(layout::GridLayout)
tot = 0
for l in layout.grid
@@ -453,9 +441,7 @@ end
function layout_args(plotattributes::AKW, n_override::Integer)
layout, n = layout_args(n_override, get(plotattributes, :layout, n_override))
if n != n_override
error(
"When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.",
)
error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.")
end
layout, n
end
@@ -465,27 +451,27 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n
end
function layout_args(sztup::NTuple{2,Integer})
function layout_args(sztup::NTuple{2, Integer})
nr, nc = sztup
GridLayout(nr, nc), nr * nc
GridLayout(nr, nc), nr*nc
end
layout_args(n_override::Integer, n::Integer) = layout_args(n)
layout_args(n, sztup::NTuple{2,Integer}) = layout_args(sztup)
layout_args(n, sztup::NTuple{2, Integer}) = layout_args(sztup)
function layout_args(n, sztup::Tuple{Colon,Integer})
function layout_args(n, sztup::Tuple{Colon, Integer})
nc = sztup[2]
nr = ceil(Int, n / nc)
GridLayout(nr, nc), n
end
function layout_args(n, sztup::Tuple{Integer,Colon})
function layout_args(n, sztup::Tuple{Integer, Colon})
nr = sztup[1]
nc = ceil(Int, n / nr)
GridLayout(nr, nc), n
end
function layout_args(sztup::NTuple{3,Integer})
function layout_args(sztup::NTuple{3, Integer})
n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n
@@ -502,58 +488,53 @@ layout_args(n_override::Integer, layout::GridLayout) = layout_args(layout)
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
# ----------------------------------------------------------------------
function build_layout(args...)
layout, n = layout_args(args...)
build_layout(layout, n, Array{Plot}(undef, 0))
build_layout(layout, n)
end
# n is the number of subplots...
function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot})
# # just a single subplot
# 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)
subplots = Subplot[]
spmap = SubplotMap()
empty = isempty(plts)
i = 0
for r in 1:nr, c in 1:nc
l = layout[r, c]
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
if empty
# initialize the inner subplots recursively
sp = Subplot(backend(), parent = layout)
layout[r, c] = sp
push!(subplots, 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
sp = Subplot(backend(), parent=layout)
layout[r,c] = sp
push!(subplots, sp)
spmap[attr(l,:label,gensym())] = sp
if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l, :width)
layout.widths[c] = attr(l,:width)
end
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l, :height)
layout.heights[r] = attr(l,:height)
end
i += inc
i += 1
elseif isa(l, GridLayout)
# sub-grid
if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l, :width)
layout.widths[c] = attr(l,:width)
end
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l, :height)
layout.heights[r] = attr(l,:height)
end
l, sps, m = build_layout(l, n - i, plts)
l, sps, m = build_layout(l, n-i)
append!(subplots, sps)
merge!(spmap, m)
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.")
end
i >= n && break # only add n subplots
@@ -562,6 +543,46 @@ function build_layout(layout::GridLayout, n::Integer, plts::AVec{Plot})
layout, subplots, spmap
end
# build a layout from a list of existing Plot objects
# TODO... much of the logic overlaps with the method above... can we merge?
function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
nr, nc = size(layout)
subplots = Subplot[]
spmap = SubplotMap()
i = 0
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
plt = popfirst!(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
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l,:height)
end
i += length(plt.subplots)
elseif isa(l, GridLayout)
# sub-grid
if get(l.attr, :width, :auto) != :auto
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, 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
@@ -573,9 +594,9 @@ function add_layout_pct!(kw::AKW, v::Expr, idx::Integer, nidx::Integer)
if length(v.args) == 3 && isa(num, Number)
units = v.args[3]
if units == :h
return kw[:h] = num * pct
return kw[:h] = num*pct
elseif units == :w
return kw[:w] = num * pct
return kw[:w] = num*pct
elseif units in (:pct, :px, :mm, :cm, :inch)
idx == 1 && (kw[:w] = v)
(idx == 2 || nidx == 1) && (kw[:h] = v)
@@ -588,29 +609,23 @@ end
function add_layout_pct!(kw::AKW, v::Number, idx::Integer)
# kw[idx == 1 ? :w : :h] = v*pct
idx == 1 && (kw[:w] = v * pct)
(idx == 2 || nidx == 1) && (kw[:h] = v * pct)
idx == 1 && (kw[:w] = v*pct)
(idx == 2 || nidx == 1) && (kw[:h] = v*pct)
end
isrow(v) = isa(v, Expr) && v.head in (:hcat, :row)
isrow(v) = isa(v, Expr) && v.head in (:hcat,:row)
iscol(v) = isa(v, Expr) && v.head == :vcat
rowsize(v) = isrow(v) ? length(v.args) : 1
function create_grid(expr::Expr)
if iscol(expr)
create_grid_vcat(expr)
elseif isrow(expr)
:(
let cell = GridLayout(1, $(length(expr.args)))
$(
[
:(cell[1, $i] = $(create_grid(v))) for
(i, v) in enumerate(expr.args)
]...
)
cell
end
)
:(let cell = GridLayout(1, $(length(expr.args)))
$([:(cell[1,$i] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
elseif expr.head == :curly
create_grid_curly(expr)
@@ -629,58 +644,39 @@ function create_grid_vcat(expr::Expr)
nr = length(expr.args)
nc = rmin
body = Expr(:block)
for r in 1:nr
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))))
for (c,item) in enumerate(arg.args)
push!(body.args, :(cell[$r,$c] = $(create_grid(item))))
end
else
push!(body.args, :(cell[$r, 1] = $(create_grid(arg))))
push!(body.args, :(cell[$r,1] = $(create_grid(arg))))
end
end
:(
let cell = GridLayout($nr, $nc)
$body
cell
end
)
:(let cell = GridLayout($nr, $nc)
$body
cell
end)
else
# otherwise just build one row at a time
:(
let cell = GridLayout($(length(expr.args)), 1)
$(
[
:(cell[$i, 1] = $(create_grid(v))) for
(i, v) in enumerate(expr.args)
]...
)
cell
end
)
:(let cell = GridLayout($(length(expr.args)), 1)
$([:(cell[$i,1] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
end
end
function create_grid_curly(expr::Expr)
kw = KW()
for (i, arg) in enumerate(expr.args[2:end])
add_layout_pct!(kw, arg, i, length(expr.args) - 1)
for (i,arg) in enumerate(expr.args[2:end])
add_layout_pct!(kw, arg, i, length(expr.args)-1)
end
s = expr.args[1]
if isa(s, Expr) && s.head == :call && s.args[1] == :grid
create_grid(
:(grid(
$(s.args[2:end]...),
width = $(get(kw, :w, QuoteNode(:auto))),
height = $(get(kw, :h, QuoteNode(:auto))),
)),
)
create_grid(:(grid($(s.args[2:end]...), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto))))))
elseif isa(s, Symbol)
:(EmptyLayout(
label = $(QuoteNode(s)),
width = $(get(kw, :w, QuoteNode(:auto))),
height = $(get(kw, :h, QuoteNode(:auto))),
))
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
else
error("Unknown use of curly brackets: $expr")
end
@@ -694,13 +690,14 @@ macro layout(mat::Expr)
create_grid(mat)
end
# -------------------------------------------------------------------------
# make all reference the same axis extrema/values.
# merge subplot lists.
function link_axes!(axes::Axis...)
a1 = axes[1]
for i in 2:length(axes)
for i=2:length(axes)
a2 = axes[i]
expand_extrema!(a1, ignorenan_extrema(a2))
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
@@ -722,8 +719,8 @@ function link_subplots(a::AbstractArray{AbstractLayout}, axissym::Symbol)
for l in a
if isa(l, Subplot)
push!(subplots, l)
elseif isa(l, GridLayout) && size(l) == (1, 1)
push!(subplots, l[1, 1])
elseif isa(l, GridLayout) && size(l) == (1,1)
push!(subplots, l[1,1])
end
end
subplots
@@ -739,19 +736,20 @@ function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
end
# don't do anything for most layout types
function link_axes!(l::AbstractLayout, link::Symbol) end
function link_axes!(l::AbstractLayout, link::Symbol)
end
# process a GridLayout, recursively linking axes according to the link symbol
function link_axes!(layout::GridLayout, link::Symbol)
nr, nc = size(layout)
if link in (:x, :both)
for c in 1:nc
link_axes!(layout.grid[:, c], :xaxis)
for c=1:nc
link_axes!(layout.grid[:,c], :xaxis)
end
end
if link in (:y, :both)
for r in 1:nr
link_axes!(layout.grid[r, :], :yaxis)
for r=1:nr
link_axes!(layout.grid[r,:], :yaxis)
end
end
if link == :square
@@ -777,20 +775,11 @@ 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],
)
sp[:right_margin] = max(sp[:right_margin], 30px)
plot!(sp.plt, inset = (sp[:subplot_index], bbox(0,0,1,1)))
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)
twinsp[:background_color_inside] = RGBA{Float64}(0,0,0,0)
link_axes!(sp[:xaxis], twinsp[:xaxis])
twinsp
end
-58
View File
@@ -1,58 +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),
)
+6 -2
View File
@@ -73,6 +73,7 @@ function txt(plt::Plot, fn::AbstractString)
end
txt(fn::AbstractString) = txt(current(), fn)
# ----------------------------------------------------------------
const _savemap = Dict(
@@ -127,6 +128,7 @@ function savefig(plt::Plot, fn::AbstractString)
end
savefig(fn::AbstractString) = savefig(current(), fn)
# ---------------------------------------------------------
"""
@@ -184,8 +186,8 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
end
# delegate showable to _show instead
function Base.showable(m::M, plt::P) where {M<:MIME,P<:Plot}
return hasmethod(_show, Tuple{IO,M,P})
function Base.showable(m::M, plt::P) where {M <: MIME, P <: Plot}
return hasmethod(_show, Tuple{IO, M, P})
end
function _display(plt::Plot)
@@ -222,6 +224,7 @@ Base.show(io::IO, m::MIME"application/prs.juno.plotpane+html", plt::Plot) =
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
@@ -238,6 +241,7 @@ closeall() = closeall(backend())
#
# html_output_format("svg")
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
+27 -79
View File
@@ -5,24 +5,13 @@
function RecipesPipeline.warn_on_recipe_aliases!(
plt::Plot,
plotattributes::AKW,
recipe_type::Symbol,
@nospecialize(args)
recipe_type,
signature_string
)
for k in keys(plotattributes)
if !is_default_attribute(k)
dk = get(_keyAliases, k, k)
if k !== dk
if recipe_type == :user
signature_string = RecipesPipeline.userrecipe_signature_string(args)
elseif recipe_type == :type
signature_string = RecipesPipeline.typerecipe_signature_string(args)
elseif recipe_type == :plot
signature_string = RecipesPipeline.plotrecipe_signature_string(args)
elseif recipe_type == :series
signature_string = RecipesPipeline.seriesrecipe_signature_string(args)
else
throw(ArgumentError("Invalid recipe type `$recipe_type`"))
end
@warn "Attribute alias `$k` detected in the $recipe_type recipe defined for the signature $signature_string. To ensure expected behavior it is recommended to use the default attribute `$dk`."
end
plotattributes[dk] = RecipesPipeline.pop_kw!(plotattributes, k)
@@ -30,6 +19,7 @@ function RecipesPipeline.warn_on_recipe_aliases!(
end
end
## Grouping
RecipesPipeline.splittable_attribute(plt::Plot, key, val::SeriesAnnotations, len) =
@@ -40,6 +30,7 @@ function RecipesPipeline.split_attribute(plt::Plot, key, val::SeriesAnnotations,
return SeriesAnnotations(split_strs, val.font, val.baseshape, val.scalefactor)
end
## Preprocessing attributes
function RecipesPipeline.preprocess_axis_args!(plt::Plot, plotattributes, letter)
# Fix letter for seriestypes that are x only but data gets passed as y
@@ -60,6 +51,7 @@ RecipesPipeline.is_axis_attribute(plt::Plot, attr) = is_axis_attr_noletter(attr)
RecipesPipeline.is_subplot_attribute(plt::Plot, attr) = is_subplot_attr(attr) # in src/args.jl
## User recipes
function RecipesPipeline.process_userrecipe!(plt::Plot, kw_list, kw)
@@ -81,15 +73,13 @@ function _preprocess_userrecipe(kw::AKW)
# map marker_z if it's a Function
if isa(get(kw, :marker_z, nothing), Function)
# TODO: should this take y and/or z as arguments?
kw[:marker_z] =
isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) :
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) :
map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
end
# map line_z if it's a Function
if isa(get(kw, :line_z, nothing), Function)
kw[:line_z] =
isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) :
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) :
map(kw[:line_z], kw[:x], kw[:y], kw[:z])
end
@@ -139,12 +129,15 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW)
end
end
RecipesPipeline.get_axis_limits(plt::Plot, letter) = axis_limits(plt[1], letter, false)
RecipesPipeline.get_axis_limits(plt::Plot, f, letter) = axis_limits(plt[1], letter)
## Plot recipes
RecipesPipeline.type_alias(plt::Plot) = get(_typeAliases, st, st)
## Plot setup
function RecipesPipeline.plot_setup!(plt::Plot, plotattributes, kw_list)
@@ -155,18 +148,18 @@ end
function RecipesPipeline.process_sliced_series_attributes!(plt::Plots.Plot, kw_list)
# swap errors
err_inds =
findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list)
err_inds = findall(kw -> get(kw, :seriestype, :path) in (:xerror, :yerror, :zerror), kw_list)
for ind in err_inds
if get(kw_list[ind - 1], :seriestype, :path) == :scatter
if get(kw_list[ind-1],:seriestype,:path) == :scatter
tmp = copy(kw_list[ind])
kw_list[ind] = copy(kw_list[ind - 1])
kw_list[ind - 1] = tmp
kw_list[ind] = copy(kw_list[ind-1])
kw_list[ind-1] = tmp
end
end
return nothing
end
# TODO: Should some of this logic be moved to RecipesPipeline?
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# merge in anything meant for the Plot
@@ -189,6 +182,7 @@ function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
plt.init = true
end
# handle inset subplots
insets = plt[:inset_subplots]
if insets !== nothing
@@ -221,7 +215,7 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# Subplot/Axis attributes set by a user/series recipe apply only to the
# Subplot object which they belong to.
# TODO: allow matrices to still apply to all subplots
sp_attrs = Dict{Subplot,Any}()
sp_attrs = Dict{Subplot, Any}()
for kw in kw_list
# get the Subplot object to which the series belongs.
sps = get(kw, :subplot, :auto)
@@ -238,24 +232,17 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
attr = KW()
for (k, v) in collect(kw)
if is_subplot_attr(k) || is_axis_attr(k)
v = pop!(kw, k)
if sps isa AbstractArray && v isa AbstractArray && length(v) == length(sps)
v = v[series_idx(kw_list, kw)]
end
attr[k] = v
attr[k] = pop!(kw, k)
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
attr[Symbol(letter, k)] = v
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)
lk = Symbol(letter, k)
if haskey(attr, lk)
kw[lk] = attr[lk]
end
@@ -264,7 +251,6 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
sp_attrs[sp] = attr
end
_add_plot_title!(plt)
# override subplot/axis args. `sp_attrs` take precendence
for (idx, sp) in enumerate(plt.subplots)
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
@@ -277,37 +263,12 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# do we need to link any axes together?
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]
if plot_title != ""
the_layout = plt.layout
vspan = plt[:plot_titlevspan]
plt.layout = grid(2, 1, heights = (vspan, 1 - vspan))
plt.layout.grid[1, 1] = subplot = Subplot(plt.backend, parent = plt.layout[1, 1])
plt.layout.grid[2, 1] = the_layout
subplot.plt = plt
# propagate arguments plt[:plot_titleXXX] --> subplot[:titleXXX]
for sym in filter(x -> startswith(string(x), "plot_title"), keys(_plot_defaults))
subplot[Symbol(string(sym)[(length("plot_") + 1):end])] = plt[sym]
end
top = plt.backend isa PyPlotBackend ? nothing : 0mm
bot = 0mm
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
return nothing
end
## Series recipes
@@ -341,10 +302,7 @@ function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where {T}
st = _override_seriestype_check(plotattributes, st)
# change to a 3d projection for this subplot?
if (
RecipesPipeline.needs_3d_axes(st) ||
(st == :quiver && plotattributes[:z] !== nothing)
)
if RecipesPipeline.needs_3d_axes(st)
sp.attr[:projection] = "3d"
end
@@ -360,10 +318,8 @@ function _override_seriestype_check(plotattributes::AKW, st::Symbol)
# do we want to override the series type?
if !RecipesPipeline.is3d(st) && !(st in (:contour, :contour3d, :quiver))
z = plotattributes[:z]
if (
z !== nothing &&
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
)
if !isa(z, Nothing) &&
(size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d)
plotattributes[:seriestype] = st
end
@@ -371,14 +327,6 @@ function _override_seriestype_check(plotattributes::AKW, st::Symbol)
st
end
function needs_any_3d_axes(sp::Subplot)
any(
RecipesPipeline.needs_3d_axes(
_override_seriestype_check(s.plotattributes, s.plotattributes[:seriestype]),
) for s in series_list(sp)
)
end
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
# adjust extrema and discrete info
if st == :image
@@ -399,9 +347,9 @@ end
function _add_the_series(plt, sp, plotattributes)
extra_kwargs = warn_on_unsupported_args(plt.backend, plotattributes)
if (kw = plt[:extra_kwargs]) isa AbstractDict
plt[:extra_plot_kwargs] = get(kw, :plot, KW())
sp[:extra_kwargs] = get(kw, :subplot, KW())
plotattributes[:extra_kwargs] = get(kw, :series, KW())
plt[:extra_plot_kwargs] = get(kw,:plot,KW())
sp[:extra_kwargs] = get(kw,:subplot, KW())
plotattributes[:extra_kwargs] = get(kw,:series,KW())
elseif plt[:extra_kwargs] == :plot
plt[:extra_plot_kwargs] = extra_kwargs
elseif plt[:extra_kwargs] == :subplot
+20 -66
View File
@@ -1,6 +1,6 @@
mutable struct CurrentPlot
nullableplot::Union{AbstractPlot,Nothing}
nullableplot::Union{AbstractPlot, Nothing}
end
const CURRENT_PLOT = CurrentPlot(nothing)
@@ -20,44 +20,10 @@ current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
# ---------------------------------------------------------
Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
Base.print(io::IO, plt::Plot) = print(io, string(plt))
function Base.show(io::IO, plt::Plot)
print(io, string(plt))
sp_ekwargs = getindex.(plt.subplots, :extra_kwargs)
s_ekwargs = getindex.(plt.series_list, :extra_kwargs)
if (
isempty(plt[:extra_plot_kwargs]) &&
all(isempty, sp_ekwargs) &&
all(isempty, s_ekwargs)
)
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
Base.show(io::IO, plt::Plot) = print(io, string(plt))
getplot(plt::Plot) = plt
getattr(plt::Plot, idx::Int = 1) = plt.attr
@@ -65,6 +31,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:
@@ -75,9 +42,9 @@ 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.
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr(attr)`
function, where `attr` is the symbol `:Series`, `:Subplot`, `:Plot`, or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring, e.g., `plotattr("seriestype")`.
When you pass in matrices, it splits by columns. To see the list of available attributes, use the `plotattr([attr])`
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring; e.g. `plotattr("seriestype")`.
"""
function plot(args...; kw...)
@nospecialize
@@ -92,21 +59,18 @@ function plot(args...; kw...)
end
# build a new plot from existing plots
# note: we split into plt1, plt2 and plts_tail so we can dispatch correctly
plot(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...) =
plot!(deepcopy(plt1), deepcopy(plt2), deepcopy.(plts_tail)...; kw...)
function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
# note: we split into plt1 and plts_tail so we can dispatch correctly
function plot(plt1::Plot, plts_tail::Plot...; kw...)
@nospecialize
plotattributes = KW(kw)
RecipesPipeline.preprocess_attributes!(plotattributes)
# build our plot vector from the args
n = length(plts_tail) + 2
n = length(plts_tail) + 1
plts = Array{Plot}(undef, n)
plts[1] = plt1
plts[2] = plt2
for (i, plt) in enumerate(plts_tail)
plts[i + 2] = plt
for (i,plt) in enumerate(plts_tail)
plts[i+1] = plt
end
# compute the layout
@@ -133,9 +97,9 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
plt.init = true
series_attr = KW()
for (k, v) in plotattributes
for (k,v) in plotattributes
if is_series_attr(k)
series_attr[k] = pop!(plotattributes, k)
series_attr[k] = pop!(plotattributes,k)
end
end
@@ -163,10 +127,9 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
cmdidx += 1
end
end
_add_plot_title!(plt)
# first apply any args for the subplots
for (idx, sp) in enumerate(plt.subplots)
for (idx,sp) in enumerate(plt.subplots)
_update_subplot_args(plt, sp, plotattributes, idx, false)
end
@@ -176,6 +139,8 @@ function plot!(plt1::Plot, plt2::Plot, plts_tail::Plot...; kw...)
plt
end
# this adds to the current plot, or creates a new plot if none are current
function plot!(args...; kw...)
@nospecialize
@@ -189,7 +154,6 @@ function plot!(args...; kw...)
end
# 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...)
@nospecialize
plotattributes = KW(kw)
@@ -211,13 +175,14 @@ function _plot!(plt::Plot, plotattributes, args)
return plt
end
# we're getting ready to display/output. prep for layout calcs, then update
# the plot object after
function prepare_output(plt::Plot)
_before_layout_calcs(plt)
w, h = plt.attr[:size]
plt.layout.bbox = BoundingBox(0mm, 0mm, w * px, h * px)
plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
# One pass down and back up the tree to compute the minimum padding
# of the children on the perimeter. This is an backend callback.
@@ -226,17 +191,6 @@ function prepare_output(plt::Plot)
_update_min_padding!(sp)
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
update_child_bboxes!(plt.layout)
@@ -264,4 +218,4 @@ function plot!(sp::Subplot, args...; kw...)
@nospecialize
plt = sp.plt
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end
end
+14 -23
View File
@@ -1,10 +1,8 @@
const _attribute_defaults = Dict(
:Series => _series_defaults,
:Subplot => _subplot_defaults,
:Plot => _plot_defaults,
:Axis => _axis_defaults,
)
const _attribute_defaults = Dict(:Series => _series_defaults,
:Subplot => _subplot_defaults,
:Plot => _plot_defaults,
:Axis => _axis_defaults)
attrtypes() = join(keys(_attribute_defaults), ", ")
attributes(attrtype::Symbol) = sort(collect(keys(_attribute_defaults[attrtype])))
@@ -23,9 +21,7 @@ Look up the properties of a Plots attribute, or specify an attribute type. Call
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
"""
function plotattr()
println(
"Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())",
)
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
end
function plotattr(attrtype::Symbol)
@@ -48,32 +44,27 @@ printnothing(x) = x
printnothing(x::Nothing) = "nothing"
function plotattr(attrtype::Symbol, attribute::AbstractString)
in(attrtype, keys(_attribute_defaults)) ||
ArgumentError("`attrtype` must match one of $(attrtypes())")
in(attrtype, keys(_attribute_defaults)) || ArgumentError("`attrtype` must match one of $(attrtypes())")
attribute = Symbol(lookup_aliases(attrtype, attribute))
desc = get(_arg_desc, attribute, "")
first_period_idx = findfirst(isequal('.'), desc)
if isnothing(first_period_idx)
if isnothing(first_period_idx)
typedesc = ""
desc = strip(desc)
else
typedesc = desc[1:(first_period_idx - 1)]
desc = strip(desc[(first_period_idx + 1):end])
typedesc = desc[1:first_period_idx-1]
desc = strip(desc[first_period_idx+1:end])
end
als = keys(filter(x -> x[2] == attribute, _keyAliases)) |> collect |> sort
als = join(map(string, als), ", ")
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
als = join(map(string,als), ", ")
def = _attribute_defaults[attrtype][attribute]
# Looks up the different elements and plots them
println(
"$(printnothing(attribute)) ",
typedesc == "" ? "" : "{$(printnothing(typedesc))}",
"\n",
println("$(printnothing(attribute)) ", typedesc == "" ? "" : "{$(printnothing(typedesc))}", "\n",
als == "" ? "" : "$(printnothing(als))\n",
"\n$(printnothing(desc))\n",
"$(printnothing(attrtype)) attribute, ",
def == "" ? "" : " default: $(printnothing(def))",
)
"$(printnothing(attrtype)) attribute, ", def == "" ? "" : " default: $(printnothing(def))")
end
+25 -8
View File
@@ -1,17 +1,34 @@
should_precompile = true
# Don't edit the following! Instead change the script for `snoop_bot`.
ismultios = false
ismultiversion = false
ismultios = true
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
include("../deps/SnoopCompile/precompile/precompile_Plots.jl")
_precompile_()
else
@static if Sys.islinux()
@static if v"1.5.0-DEV" <= VERSION <= v"1.5.9"
include("../deps/SnoopCompile/precompile/linux/1.5/precompile_Plots.jl")
_precompile_()
else
include("../deps/SnoopCompile/precompile/linux/1.5/precompile_Plots.jl")
_precompile_()
end
else
@static if v"1.5.0-DEV" <= VERSION <= v"1.5.9"
include("../deps/SnoopCompile/precompile/linux/1.5/precompile_Plots.jl")
_precompile_()
else
include("../deps/SnoopCompile/precompile/linux/1.5/precompile_Plots.jl")
_precompile_()
end
end
end # precompile_enclosure
+126 -168
View File
@@ -41,16 +41,17 @@ function all_seriestypes()
sort(collect(sts))
end
# ----------------------------------------------------------------------------------
num_series(x::AMat) = size(x, 2)
num_series(x) = 1
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} =
nothing
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
# for seriestype `line`, need to sort by x values
const POTENTIAL_VECTOR_ARGUMENTS = [
@@ -113,8 +114,8 @@ end
@recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y)
newx = repeat(Float64[1, 2, NaN], n)
newy = vec(Float64[yi for i in 1:3, yi in y])
newx = repeat(Float64[1, 2, NaN], n)
newy = vec(Float64[yi for i = 1:3, yi in y])
x := newx
y := newy
seriestype := :straightline
@@ -124,7 +125,7 @@ end
@recipe function f(::Type{Val{:vline}}, x, y, z)
n = length(y)
newx = vec(Float64[yi for i in 1:3, yi in y])
newx = vec(Float64[yi for i = 1:3, yi in y])
x := newx
y := repeat(Float64[1, 2, NaN], n)
seriestype := :straightline
@@ -135,7 +136,7 @@ end
@recipe function f(::Type{Val{:hspan}}, x, y, z)
n = div(length(y), 2)
newx = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i in 1:n]...)
newy = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
linewidth --> 0
x := newx
y := newy
@@ -146,7 +147,7 @@ end
@recipe function f(::Type{Val{:vspan}}, x, y, z)
n = div(length(y), 2)
newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i in 1:n]...)
newx = vcat([[y[2i - 1], y[2i - 1], y[2i], y[2i], NaN] for i = 1:n]...)
newy = repeat([-Inf, Inf, Inf, -Inf, NaN], outer = n)
linewidth --> 0
x := newx
@@ -164,77 +165,49 @@ end
x := x
y := y
seriestype := :scatter
@series begin
()
end
@series begin
seriestype := :path
label := ""
primary := false
()
end
primary := false
()
end
@deps scatterpath path scatter
# ---------------------------------------------------------------------------
# regression line and scatter
# plots line corresponding to linear regression of y on a constant and x
@recipe function f(::Type{Val{:linearfit}}, x, y, z)
x := x
y := y
seriestype := :scatter
@series begin
()
end
@series begin
y := mean(y) .+ cov(x, y) / var(x) .* (x .- mean(x))
seriestype := :path
label := ""
primary := false
()
end
primary := false
()
end
@specialize
# ---------------------------------------------------------------------------
# steps
make_steps(x, st, even) = x
function make_steps(x::AbstractArray, st, even)
make_steps(x, st) = x
function make_steps(x::AbstractArray, st)
n = length(x)
n == 0 && return zeros(0)
newx = zeros(2n - (even ? 0 : 1))
newx[1] = x[1]
for i in 2:n
newx = zeros(2n - 1)
for i = 1:n
idx = 2i - 1
if st == :mid
newx[idx] = newx[idx - 1] = (x[i] + x[i - 1]) / 2
else
newx[idx] = x[i]
newx[idx] = x[i]
if i > 1
newx[idx - 1] = x[st == :pre ? i : i - 1]
end
end
even && (newx[end] = x[end])
return newx
end
make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t)
make_steps(t::Tuple, st) = Tuple(make_steps(ti, st) for ti in t)
@nospecialize
# create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z)
plotattributes[:x] = make_steps(x, :post, false)
plotattributes[:y] = make_steps(y, :pre, false)
plotattributes[:x] = make_steps(x, :post)
plotattributes[:y] = make_steps(y, :pre)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre, false)
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@@ -252,39 +225,14 @@ make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t)
end
@deps steppre path scatter
# create a path from steps
@recipe function f(::Type{Val{:stepmid}}, x, y, z)
plotattributes[:x] = make_steps(x, :mid, true)
plotattributes[:y] = make_steps(y, :post, true)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, true)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@series begin
seriestype := :scatter
x := x
y := y
label := ""
primary := false
()
end
markershape := :none
end
()
end
@deps stepmid path scatter
# create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z)
plotattributes[:x] = make_steps(x, :pre, false)
plotattributes[:y] = make_steps(y, :post, false)
plotattributes[:x] = make_steps(x, :pre)
plotattributes[:y] = make_steps(y, :post)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, false)
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post)
# create a secondary series for the markers
if plotattributes[:markershape] != :none
@@ -302,6 +250,7 @@ end
end
@deps steppost path scatter
# ---------------------------------------------------------------------------
# sticks
@@ -319,15 +268,15 @@ end
end
end
newx, newy = zeros(3n), zeros(3n)
newz = z !== nothing ? zeros(3n) : nothing
for (i, (xi, yi, zi)) in enumerate(zip(x, y, z !== nothing ? z : 1:n))
newz = z!== nothing ? zeros(3n) : nothing
for i = 1:n
rng = (3i - 2):(3i)
newx[rng] = [xi, xi, NaN]
newx[rng] = [x[i], x[i], NaN]
if z !== nothing
newy[rng] = [yi, yi, NaN]
newz[rng] = [_cycle(fr, i), zi, NaN]
newy[rng] = [y[i], y[i], NaN]
newz[rng] = [_cycle(fr, i), z[i], NaN]
else
newy[rng] = [_cycle(fr, i), yi, NaN]
newy[rng] = [_cycle(fr, i), y[i], NaN]
end
end
x := newx
@@ -337,11 +286,7 @@ end
end
fillrange := nothing
seriestype := :path
if (
plotattributes[:linecolor] == :auto &&
plotattributes[:marker_z] !== nothing &&
plotattributes[:line_z] === nothing
)
if plotattributes[:linecolor] == :auto && plotattributes[:marker_z] !== nothing && plotattributes[:line_z] === nothing
line_z := plotattributes[:marker_z]
end
@@ -366,6 +311,7 @@ end
@specialize
# ---------------------------------------------------------------------------
# bezier curves
@@ -435,7 +381,8 @@ end
# create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y)
procx, procy, xscale, yscale, baseline =
_preprocess_barlike(plotattributes, x, y)
nx, ny = length(procx), length(procy)
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi in procx]
@@ -444,16 +391,14 @@ end
elseif nx == ny + 1
0.5 * diff(cv) + cv[1:(end - 1)]
else
error(
"bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))",
)
error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))")
end
# compute half-width of bars
bw = plotattributes[:bar_width]
hw = if bw === nothing
if nx > 1
0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(procx))))
0.5 * _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(procx)))
else
0.5 * _bar_width
end
@@ -470,8 +415,9 @@ end
fillto = map(x -> _is_positive(x) ? typeof(baseline)(x) : baseline, fillto)
end
# create the bar shapes by adding x/y segments
xseg, yseg = Segments(), Segments()
for i in 1:ny
for i = 1:ny
yi = procy[i]
if !isnan(yi)
center = procx[i]
@@ -495,30 +441,15 @@ end
# switch back
if !isvertical(plotattributes)
xseg, yseg = yseg, xseg
x, y = y, x
end
# reset orientation
orientation := default(:orientation)
# draw the bar shapes
@series begin
seriestype := :shape
series_annotations := nothing
primary := true
x := xseg.pts
y := yseg.pts
()
end
# add empty series
primary := false
seriestype := :scatter
markersize := 0
markeralpha := 0
fillrange := nothing
x := x
y := y
x := xseg.pts
y := yseg.pts
seriestype := :shape
()
end
@deps bar shape
@@ -530,8 +461,8 @@ end
m, n = size(z.surf)
x_pts, y_pts = fill(NaN, 6 * m * n), fill(NaN, 6 * m * n)
fz = zeros(m * n)
for i in 1:m # y
for j in 1:n # x
for i = 1:m # y
for j = 1:n # x
k = (j - 1) * m + i
inds = (6 * (k - 1) + 1):(6 * k - 1)
x_pts[inds] .= [xe[j], xe[j + 1], xe[j + 1], xe[j], xe[j]]
@@ -578,6 +509,7 @@ function _scale_adjusted_values(
end
end
function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real}
if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
@@ -586,6 +518,7 @@ function _binbarlike_baseline(min_value::T, scale::Symbol) where {T<:Real}
end
end
function _preprocess_binbarlike_weights(
::Type{T},
w,
@@ -614,10 +547,12 @@ function _preprocess_binlike(plotattributes, x, y)
edge, weights, xscale, yscale, baseline
end
@nospecialize
@recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y)
if (plotattributes[:bar_width] === nothing)
bar_width := diff(edge)
end
@@ -628,8 +563,10 @@ end
end
@deps barbins bar
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y)
@series begin
x := _bin_centers(edge)
xerror := diff(edge) / 2
@@ -646,7 +583,13 @@ end
@specialize
function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::Symbol)
function _stepbins_path(
edge,
weights,
baseline::Real,
xscale::Symbol,
yscale::Symbol,
)
log_scale_x = xscale in _logScales
log_scale_y = yscale in _logScales
@@ -708,9 +651,11 @@ end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
@nospecialize
axis = plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
axis =
plotattributes[:subplot][Plots.isvertical(plotattributes) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(plotattributes, x, y)
edge, weights, xscale, yscale, baseline =
_preprocess_binlike(plotattributes, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(plotattributes)
@@ -762,9 +707,12 @@ function _auto_binning_nbins(
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
nd = n_samples^(1 / (2 + N))
nd =
N == 2 ?
min(n_samples^(1 / (2 + N)), nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8)) : nd # the >2-dimensional case does not have a nice solution to correlations
nd = N == 2 ?
min(
n_samples^(1 / (2 + N)),
nd / (1 - cor(first(vs), last(vs))^2)^(3 // 8),
) :
nd # the >2-dimensional case does not have a nice solution to correlations
v = vs[dim]
@@ -793,8 +741,11 @@ _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {
StatsBase.histrange(vs[dim], binning, :left)
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} =
_hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} =
binning
_hist_edge(
vs::NTuple{N,AbstractVector},
dim::Integer,
binning::AbstractVector,
) where {N} = binning
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N,Any}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
@@ -824,8 +775,8 @@ function _make_hist(
edges = _hist_edges(localvs, binning)
h = float(
weights === nothing ?
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
StatsBase.fit(
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
StatsBase.fit(
StatsBase.Histogram,
localvs,
StatsBase.Weights(weights),
@@ -886,6 +837,7 @@ end
end
@deps scatterhist scatterbins
@recipe function f(h::StatsBase.Histogram{T,1,E}) where {T,E}
seriestype --> :barbins
@@ -895,7 +847,8 @@ end
:step => :stepbins,
:steppost => :stepbins, # :step can be mapped to :steppost in pre-processing
)
seriestype := get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
seriestype :=
get(st_map, plotattributes[:seriestype], plotattributes[:seriestype])
if plotattributes[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
@@ -909,6 +862,7 @@ end
end
end
@recipe function f(hv::AbstractVector{H}) where {H<:StatsBase.Histogram}
for h in hv
@series begin
@@ -917,6 +871,7 @@ end
end
end
# ---------------------------------------------------------------------------
# Histogram 2D
@@ -943,6 +898,7 @@ end
end
Plots.@deps bins2d heatmap
@recipe function f(::Type{Val{:histogram2d}}, x, y, z)
h = _make_hist(
(x, y),
@@ -958,11 +914,13 @@ Plots.@deps bins2d heatmap
end
@deps histogram2d bins2d
@recipe function f(h::StatsBase.Histogram{T,2,E}) where {T,E}
seriestype --> :bins2d
(h.edges[1], h.edges[2], Surface(h.weights))
end
# ---------------------------------------------------------------------------
# pie
@recipe function f(::Type{Val{:pie}}, x, y, z)
@@ -984,6 +942,7 @@ end
end
@deps pie shape
# ---------------------------------------------------------------------------
# mesh 3d replacement for non-plotly backends
@@ -991,15 +950,12 @@ end
# As long as no i,j,k are supplied this should work with PyPlot and GR
seriestype := :surface
if plotattributes[:connections] !== nothing
throw(
ArgumentError(
"Giving triangles using the connections argument is only supported on Plotly backend.",
),
)
throw(ArgumentError("Giving triangles using the connections argument is only supported on Plotly backend."))
end
()
end
# ---------------------------------------------------------------------------
# scatter 3d
@@ -1017,7 +973,7 @@ end
# ---------------------------------------------------------------------------
# lens! - magnify a region of a plot
lens!(args...; kwargs...) = plot!(args...; seriestype = :lens, kwargs...)
lens!(args...;kwargs...) = plot!(args...; seriestype=:lens, kwargs...)
export lens!
@recipe function f(::Type{Val{:lens}}, plt::AbstractPlot)
sp_index, inset_bbox = plotattributes[:inset_subplots]
@@ -1045,12 +1001,11 @@ export lens!
linecolor := :lightgray
bbx_mag = (x1 + x2) / 2
bby_mag = (y1 + y2) / 2
xi_lens, yi_lens =
intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1))
xi_mag, yi_mag =
intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1))
xi_lens, yi_lens = intersection_point(bbx_mag, bby_mag, bbx, bby, abs(bby2 - bby1), abs(bbx2 - bbx1))
xi_mag, yi_mag = intersection_point(bbx, bby, bbx_mag, bby_mag, abs(y2 - y1), abs(x2 - x1))
# add lines
if xl1 < xi_lens < xl2 && yl1 < yi_lens < yl2
if xl1 < xi_lens < xl2 &&
yl1 < yi_lens < yl2
@series begin
primary := false
subplot := sp_index
@@ -1095,14 +1050,14 @@ function intersection_point(xA, yA, xB, yB, h, w)
else # left
return xB - hw, yB - s * hw
end
# top or bot?
elseif -hw <= hh / s <= hw
# top or bot?
elseif -hw <= hh/s <= hw
if yA > yB
# top
return xB + hh / s, yB + hh
return xB + hh/s, yB + hh
else
# bottom
return xB - hh / s, yB - hh
return xB - hh/s, yB - hh
end
end
end
@@ -1242,15 +1197,15 @@ function quiver_using_arrows(plotattributes::AKW)
if !isa(plotattributes[:arrow], Arrow)
plotattributes[:arrow] = arrow()
end
is_3d = haskey(plotattributes, :z) && !isnothing(plotattributes[:z])
is_3d = haskey(plotattributes,:z) && !isnothing(plotattributes[:z])
velocity = error_zipit(plotattributes[:quiver])
xorig, yorig = plotattributes[:x], plotattributes[:y]
zorig = is_3d ? plotattributes[:z] : []
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
x, y = zeros(0), zeros(0)
is_3d && (z = zeros(0))
for i in 1:max(length(xorig), length(yorig), is_3d ? 0 : length(zorig))
is_3d && ( z = zeros(0))
for i = 1:max(length(xorig), length(yorig), is_3d ? 0 : length(zorig))
# get the starting position
xi = _cycle(xorig, i)
yi = _cycle(yorig, i)
@@ -1300,7 +1255,7 @@ function quiver_using_hack(plotattributes::AKW)
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
pts = P2[]
for i in 1:max(length(xorig), length(yorig))
for i = 1:max(length(xorig), length(yorig))
# get the starting position
xi = _cycle(xorig, i)
@@ -1329,7 +1284,10 @@ function quiver_using_hack(plotattributes::AKW)
U2 *= arrow_w
ppv = p + v
nanappend!(pts, P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1])
nanappend!(
pts,
P2[p, ppv - U1, ppv - U1 + U2, ppv, ppv - U1 - U2, ppv - U1],
)
end
plotattributes[:x], plotattributes[:y] = RecipesPipeline.unzip(pts[2:end])
@@ -1348,6 +1306,7 @@ end
end
@deps quiver shape path
# --------------------------------------------------------------------
# 1 argument
# --------------------------------------------------------------------
@@ -1379,7 +1338,7 @@ end
@nospecialize
# images - colors
@recipe function f(mat::AMat{T}) where {T<:Colorant}
@recipe function f(mat::AMat{T}) where {T <: Colorant}
n, m = axes(mat)
if is_seriestype_supported(:image)
@@ -1403,34 +1362,25 @@ end
coords(shape)
end
@recipe function f(shapes::AVec{<:Shape})
@recipe function f(shapes::AVec{Shape})
seriestype --> :shape
# For backwards compatibility, column vectors of segmenting attributes are
# interpreted as having one element per shape
for attr in union(_segmenting_array_attributes, _segmenting_vector_attributes)
v = get(plotattributes, attr, nothing)
if v isa AVec || v isa AMat && size(v, 2) == 1
@warn "Column vector attribute `$attr` reinterpreted as row vector (one value per shape).\n" *
"Pass a row vector instead (e.g. using `permutedims`) to suppress this warning."
plotattributes[attr] = permutedims(v)
end
end
coords(shapes)
end
@recipe function f(shapes::AMat{<:Shape})
@recipe function f(shapes::AMat{Shape})
seriestype --> :shape
for j in axes(shapes, 2)
@series coords(vec(shapes[:, j]))
end
end
# --------------------------------------------------------------------
# 3 arguments
# --------------------------------------------------------------------
# images - grays
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T<:Gray}
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T <: Gray}
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
@@ -1445,7 +1395,7 @@ end
end
# images - colors
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T<:Colorant}
@recipe function f(x::AVec, y::AVec, mat::AMat{T}) where {T <: Colorant}
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
@@ -1466,7 +1416,7 @@ end
@recipe f(p::GeometryBasics.Point) = [p]
# Special case for 4-tuples in :ohlc series
@recipe f(xyuv::AVec{<:Tuple{R1,R2,R3,R4}}) where {R1,R2,R3,R4} =
@recipe f(xyuv::AVec{<:Tuple{R1, R2, R3, R4}}) where {R1, R2, R3, R4} =
get(plotattributes, :seriestype, :path) == :ohlc ? OHLC[OHLC(t...) for t in xyuv] :
RecipesPipeline.unzip(xyuv)
@@ -1523,7 +1473,8 @@ end
@recipe f(
x::AVec,
ohlc::AVec{Tuple{R1,R2,R3,R4}},
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc]
) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} =
x, OHLC[OHLC(t...) for t in ohlc]
@recipe function f(x::AVec, v::AVec{OHLC})
seriestype := :path
@@ -1542,6 +1493,7 @@ end
# TODO: everything below here should be either changed to a
# series recipe or moved to PlotRecipes
# "Sparsity plot... heatmap of non-zero values of a matrix"
# function spy{T<:Real}(z::AMat{T}; kw...)
# mat = reshape(map(zi->float(zi!=0), z),1,:)
@@ -1568,10 +1520,14 @@ end
yflip := true
aspect_ratio := 1
rs, cs, zs = Plots.findnz(z.surf)
xlims := widen(ignorenan_extrema(cs)..., get(plotattributes, :xscale, :identity))
ylims := widen(ignorenan_extrema(rs)..., get(plotattributes, :yscale, :identity))
markershape --> :circle
markersize --> 1
xlims := ignorenan_extrema(cs)
ylims := ignorenan_extrema(rs)
if plotattributes[:markershape] == :none
markershape := :circle
end
if plotattributes[:markersize] == default(:markersize)
markersize := 1
end
markerstrokewidth := 0
if length(unique(zs)) == 1
seriescolor --> :black
@@ -1589,6 +1545,7 @@ end
@specialize
Plots.findnz(A::AbstractSparseMatrix) = SparseArrays.findnz(A)
# fallback function for finding non-zero elements of non-sparse matrices
@@ -1628,6 +1585,7 @@ end
x, real.(y), imag.(y)
end
# Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246
@userplot PortfolioComposition
@@ -1673,4 +1631,4 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
end
end
@specialize
@specialize
+29 -29
View File
@@ -57,7 +57,6 @@ Plot a histogram.
# 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
@@ -241,6 +240,7 @@ julia> ohlc(y)
"""
@shorthands ohlc
"""
contour(x,y,z)
contour!(x,y,z)
@@ -262,6 +262,7 @@ julia> contour(x, y, (x, y) -> x^2 + y^2)
"An alias for `contour` with fill = true."
@shorthands contourf
@shorthands contour3d
"""
@@ -406,41 +407,42 @@ julia> curves([1,2,3,4],[1,1,2,4])
@shorthands pie
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple; kw...) = plot!(; xlims = lims, kw...)
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple; kw...) = plot!(; ylims = lims, kw...)
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple; kw...) = plot!(; zlims = lims, kw...)
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin, xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin, ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin, zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...)
xticks!(v::TicksArgs; kw...) = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...)
yticks!(v::TicksArgs; kw...) = plot!(; yticks = v, kw...)
xticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} =
plot!(; xticks = (ticks, labels), kw...)
yticks!(ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} =
plot!(; yticks = (ticks, labels), kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"""
annotate!(anns...)
@@ -450,32 +452,30 @@ 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)`).
can be a `String` or `PlotText`.
# 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...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::Tuple...; kw...) = plot!(; annotation = collect(anns), kw...)
annotate!(anns::AVec{<:Tuple}; kw...) = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify y axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
@specialize
@specialize
+21 -19
View File
@@ -1,5 +1,6 @@
function Subplot(::T; parent = RootLayout()) where {T<:AbstractBackend}
function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
Subplot{T}(
parent,
Series[],
@@ -8,7 +9,7 @@ function Subplot(::T; parent = RootLayout()) where {T<:AbstractBackend}
defaultbox,
DefaultsDict(KW(), _subplot_defaults),
nothing,
nothing,
nothing
)
end
@@ -20,7 +21,8 @@ Return the bounding box of a subplot
plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
Base.size(sp::Subplot) = (1, 1)
Base.size(sp::Subplot) = (1,1)
Base.length(sp::Subplot) = 1
Base.getindex(sp::Subplot, r::Int, c::Int) = sp
@@ -41,23 +43,23 @@ series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattribut
function should_add_to_legend(series::Series)
series.plotattributes[:primary] &&
series.plotattributes[:label] != "" &&
!(
series.plotattributes[:seriestype] in (
:hexbin,
:bins2d,
:histogram2d,
:hline,
:vline,
:contour,
:contourf,
:contour3d,
:surface,
:wireframe,
:heatmap,
:image,
)
series.plotattributes[:label] != "" &&
!(
series.plotattributes[:seriestype] in (
:hexbin,
:bins2d,
:histogram2d,
:hline,
:vline,
:contour,
:contourf,
:contour3d,
:surface,
:wireframe,
:heatmap,
:image,
)
)
end
# ----------------------------------------------------------------------
+10 -6
View File
@@ -34,8 +34,11 @@ end
@userplot ShowTheme
_color_functions =
KW(:protanopic => protanopic, :deuteranopic => deuteranopic, :tritanopic => tritanopic)
_color_functions = KW(
:protanopic => protanopic,
:deuteranopic => deuteranopic,
:tritanopic => tritanopic,
)
_get_showtheme_args(thm::Symbol) = thm, identity
_get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func, identity)
@@ -107,8 +110,8 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 4
seriestype := :heatmap
seriescolor := colorgradient
xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
x, y, z
end
@@ -116,8 +119,8 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 5
seriestype := :surface
seriescolor := colorgradient
xticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
yticks := ((-2π):(2π):(2π), string.(-2:2:2, "π"))
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
x, y, z
end
@@ -134,4 +137,5 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
line_z := z
x, y, z
end
end
+7 -16
View File
@@ -6,8 +6,7 @@ const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
const AKW = AbstractDict{Symbol,Any}
const TicksArgs =
Union{AVec{T},Tuple{AVec{T},AVec{S}},Symbol} where {T<:Real,S<:AbstractString}
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
struct PlotsDisplay <: AbstractDisplay end
@@ -60,10 +59,11 @@ Extrema() = Extrema(Inf, -Inf)
# -----------------------------------------------------------
const SubplotMap = Dict{Any,Subplot}
const SubplotMap = Dict{Any, Subplot}
# -----------------------------------------------------------
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type
n::Int # number of series
@@ -78,18 +78,9 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
end
function Plot()
Plot(
backend(),
0,
DefaultsDict(KW(), _plot_defaults),
Series[],
nothing,
Subplot[],
SubplotMap(),
EmptyLayout(),
Subplot[],
false,
)
Plot(backend(), 0, DefaultsDict(KW(), _plot_defaults), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout(),
Subplot[], false)
end
# -----------------------------------------------------------------------
@@ -98,7 +89,7 @@ Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
Base.length(plt::Plot) = length(plt.subplots)
Base.lastindex(plt::Plot) = length(plt)
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r, c]
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
Base.size(plt::Plot) = size(plt.layout)
Base.size(plt::Plot, i::Integer) = size(plt.layout)[i]
Base.ndims(plt::Plot) = 2
+365 -373
View File
File diff suppressed because it is too large Load Diff
+9 -10
View File
@@ -3,17 +3,17 @@ import Plots._current_plots_version
# replace `f(args...)` with `f(rng, args...)` for `f ∈ (rand, randn)`
function replace_rand!(ex) end
function replace_rand!(ex::Expr)
for arg in ex.args
replace_rand!(arg)
end
if ex.head === :call && ex.args[1] (:rand, :randn, :(Plots.fakedata))
pushfirst!(ex.args, ex.args[1])
ex.args[2] = :rng
end
for arg in ex.args
replace_rand!(arg)
end
if ex.head === :call && ex.args[1] (:rand, :randn)
pushfirst!(ex.args, ex.args[1])
ex.args[2] = :rng
end
end
function fix_rand!(ex)
replace_rand!(ex)
pushfirst!(ex.args[1].args, :(rng = StableRNG(PLOTS_SEED)))
pushfirst!(ex.args[1].args, :(rng = StableRNG(1234)))
end
function image_comparison_tests(
@@ -35,7 +35,6 @@ function image_comparison_tests(
fn = "ref$idx.png"
reffn = reference_file(pkg, idx, _current_plots_version)
newfn = joinpath(reference_path(pkg, _current_plots_version), fn)
@debug example.exprs
# test function
func = (fn, idx) -> begin
@@ -59,7 +58,7 @@ function image_comparison_facts(
sigma = [1, 1], # number of pixels to "blur"
tol = 1e-2,
) # acceptable error (percent)
for i in 1:length(Plots._examples)
for i = 1:length(Plots._examples)
i in skip && continue
if only === nothing || i in only
@test image_comparison_tests(pkg, i, debug = debug, sigma = sigma, tol = tol) |>
+5 -49
View File
@@ -1,60 +1,16 @@
using Plots, Test, Dates
@testset "Limits" begin
y = [1.0 * i * i for i in 1:10]
x = [Date(2019, 11, i) for i in 1:10]
y=[1.0*i*i for i in 1:10]
x=[Date(2019,11,i) for i in 1:10]
rx = [x[3], x[5]]
rx=[x[3],x[5]]
p = plot(x, y, widen = false)
vspan!(p, rx, label = "", alpha = 0.2)
p = plot(x,y, widen = false)
vspan!(p, rx, label="", alpha=0.2)
ref_ylims = (y[1], y[end])
ref_xlims = (x[1].instant.periods.value, x[end].instant.periods.value)
@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
+41 -88
View File
@@ -1,4 +1,3 @@
using Plots: guidefont, series_annotations, PLOTS_SEED
import ImageMagick
using VisualRegressionTests
using Plots
@@ -12,13 +11,7 @@ using LibGit2
import GeometryBasics
using Dates
using RecipesBase
using JSON
@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()
@@ -36,20 +29,14 @@ end
end # testset
include("test_defaults.jl")
include("test_pipeline.jl")
include("test_axes.jl")
include("test_contours.jl")
include("test_axis_letter.jl")
include("test_components.jl")
include("test_shorthands.jl")
include("integration_dates.jl")
include("test_recipes.jl")
include("test_hdf5plots.jl")
include("test_pgfplotsx.jl")
include("test_plotly.jl")
include("integration_dates.jl")
reference_dir(args...) =
joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
reference_dir(args...) = joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
function reference_file(backend, i, version)
refdir = reference_dir("Plots", string(backend))
@@ -72,38 +59,35 @@ reference_path(backend, version) = reference_dir("Plots", string(backend), strin
if !isdir(reference_dir())
mkpath(reference_dir())
LibGit2.clone(
"https://github.com/JuliaPlots/PlotReferenceImages.jl.git",
reference_dir(),
)
LibGit2.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git", reference_dir())
end
include("imgcomp.jl")
# don't actually show the plots
Random.seed!(PLOTS_SEED)
default(show = false, reuse = true)
Random.seed!(1234)
default(show=false, reuse=true)
is_ci() = get(ENV, "CI", "false") == "true"
const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" : "1e-5"))
const IMG_TOL = VERSION < v"1.4" && Sys.iswindows() ? 1e-1 : is_ci() ? 1e-2 : 1e-3
## Uncomment the following lines to update reference images for different backends
# @testset "GR" begin
# image_comparison_facts(:gr, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:gr])
# image_comparison_facts(:gr, tol=IMG_TOL, skip = Plots._backend_skips[:gr])
# end
#
# plotly()
# @testset "Plotly" begin
# image_comparison_facts(:plotly, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:plotlyjs])
# image_comparison_facts(:plotly, tol=IMG_TOL, skip = Plots._backend_skips[:plotlyjs])
# end
#
# pyplot()
# @testset "PyPlot" begin
# image_comparison_facts(:pyplot, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pyplot])
# image_comparison_facts(:pyplot, tol=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])
# image_comparison_facts(:pgfplotsx, tol=IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
# end
# 10 Histogram2D
@@ -111,6 +95,7 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
##
@testset "Backends" begin
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@@ -120,11 +105,7 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
image_comparison_facts(:gr, tol=IMG_TOL, skip = Plots._backend_skips[:gr])
end
end
@@ -150,20 +131,12 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test isa(p, Plots.Plot) == true
@test_broken isa(display(p), Nothing) == true
end
end
@testset "Axes" begin
@@ -172,41 +145,25 @@ end
@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)
@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])
Plots.discrete_value!(axis, ["x$i" for i=1:5])
Plots.discrete_value!(axis, ["x$i" for i=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()
@testset "Plot" begin
plots = [
histogram([1, 0, 0, 0, 0, 0]),
plot([missing]),
plot([missing, missing]),
plot(fill(missing, 10)),
plot([missing; 1:4]),
plot([fill(missing, 10); 1:4]),
plot([1 1; 1 missing]),
plot(["a" "b"; missing "d"], [1 2; 3 4]),
]
for plt in plots
display(plt)
end
@test_nowarn plot(x -> x^2, 0, 2)
end
@testset "Bar" begin
p = bar([3, 2, 1], [1, 2, 3])
@test isa(p, Plots.Plot)
@test isa(display(p), Nothing) == true
plots = [histogram([1, 0, 0, 0, 0, 0]),
plot([missing]),
plot([missing; 1:4]),
plot([fill(missing,10); 1:4]),
plot([1 1; 1 missing]),
plot(["a" "b"; missing "d"], [1 2; 3 4])]
for plt in plots
display(plt)
end
@test_nowarn plot(x->x^2,0,2)
end
@testset "EmptyAnim" begin
@@ -216,33 +173,31 @@ end
@test_throws ArgumentError gif(anim)
end
@testset "NaN-separated Segments" begin
segments(args...) = collect(iter_segments(args...))
@testset "Segments" begin
function segments(args...)
segs = UnitRange{Int}[]
for seg in iter_segments(args...)
push!(segs,seg)
end
segs
end
nan10 = fill(NaN, 10)
nan10 = fill(NaN,10)
@test segments(11:20) == [1:10]
@test segments([NaN]) == []
@test segments(nan10) == []
@test segments([nan10; 1:5]) == [11:15]
@test segments([1:5; nan10]) == [1:5]
@test segments([1:5;nan10]) == [1:5]
@test segments([nan10; 1:5; nan10; 1:5; nan10]) == [11:15, 26:30]
@test segments([NaN; 1], 1:10) == [2:2, 4:4, 6:6, 8:8, 10:10]
@test segments([nan10; 1:15], [1:15; nan10]) == [11:15]
end
@testset "Utils" begin
zipped = (
[(1, 2)],
[("a", "b")],
[(1, "a"), (2, "b")],
[(1, 2), (3, 4)],
[(1, 2, 3), (3, 4, 5)],
[(1, 2, 3, 4), (3, 4, 5, 6)],
[(1, 2.0), (missing, missing)],
[(1, missing), (missing, "a")],
[(missing, missing)],
[(missing, missing, missing), ("a", "b", "c")],
)
zipped = ([(1,2)], [("a","b")], [(1,"a"),(2,"b")],
[(1,2),(3,4)], [(1,2,3),(3,4,5)], [(1,2,3,4),(3,4,5,6)],
[(1,2.0),(missing,missing)], [(1,missing),(missing,"a")],
[(missing,missing)], [(missing,missing,missing),("a","b","c")])
for z in zipped
@test isequal(collect(zip(Plots.unzip(z)...)), z)
@test isequal(collect(zip(Plots.unzip(GeometryBasics.Point.(z))...)), z)
@@ -251,7 +206,5 @@ end
op2 = Plots.process_clims((1, 2.0))
data = randn(100, 100)
@test op1(data) == op2(data)
@test Plots.process_clims(nothing) ==
Plots.process_clims(missing) ==
Plots.process_clims(:auto)
@test Plots.process_clims(nothing) == Plots.process_clims(missing) == Plots.process_clims(:auto)
end
+2 -69
View File
@@ -9,8 +9,8 @@ using Plots, Test
end
@testset "Magic axis" begin
@test plot(1, axis = nothing)[1][:xaxis][:ticks] == []
@test plot(1, axis = nothing)[1][:yaxis][:ticks] == []
@test plot(1, axis=nothing)[1][:xaxis][:ticks] == []
@test plot(1, axis=nothing)[1][:yaxis][:ticks] == []
end # testset
@testset "Categorical ticks" begin
@@ -21,70 +21,3 @@ end # testset
@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 "aliases" begin
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α = .07)
@test p[1][:xaxis][:gridalpha] .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.,1.)
p = plot(1:2, xminorgridcolor = :red)
@test p[1][:xaxis][:foreground_color_minor_grid] === RGBA{Float64}(1.,0.,0.,1.)
p = plot(1:2, xgrid_lw = .01)
@test p[1][:xaxis][:gridlinewidth] .01
p = plot(1:2, xminorgrid_lw = .01)
@test p[1][:xaxis][:minorgridlinewidth] .01
p = plot(1:2, xtickor = :out)
@test p[1][:xaxis][:tick_direction] === :out
end
+3 -6
View File
@@ -9,15 +9,12 @@ using Plots, Test
value(m::MyType) = m.val
data = MyType.(sort(randn(20)))
# A recipe that puts the axis letter in the title
@recipe function f(::Type{T}, m::T) where {T<:AbstractArray{<:MyType}}
@recipe function f(::Type{T}, m::T) where T <: AbstractArray{<:MyType}
title --> string(plotattributes[:letter])
value.(m)
end
@testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist],
o in [:vertical, :horizontal]
@test f(data, orientation = o).subplots[1].attr[:title] ==
(o == :vertical ? "x" : "y")
@testset "$f (orientation = $o)" for f in [histogram, barhist, stephist, scatterhist], o in [:vertical, :horizontal]
@test f(data, orientation=o).subplots[1].attr[:title] == (o == :vertical ? "x" : "y")
end
@testset "$f" for f in [hline, hspan]
@test f(data).subplots[1].attr[:title] == "y"
-160
View File
@@ -1,160 +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 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
end
@testset "Brush" begin
@testset "Colors" begin
baseline = brush(1, RGB(0, 0, 0))
@test brush(:black) == baseline
@test brush("black") == baseline
end
@testset "Weight" begin
@test brush(10).size == 10
@test brush(0.1).size == 1
end
@testset "Alpha" begin
@test brush(0.4).alpha == 0.4
@test brush(20).alpha == nothing
end
@testset "Bad Argument" begin
# using test_logs because test_warn seems to not work anymore
@test_logs (:warn, "Unused brush arg: nothing (Nothing)") begin
brush(nothing)
end
end
end
@testset "Fonts" begin
@testset "Scaling" begin
sizesToCheck = [
:titlefontsize,
:legendfontsize,
:legendtitlefontsize,
:xtickfontsize,
:ytickfontsize,
:ztickfontsize,
:xguidefontsize,
:yguidefontsize,
:zguidefontsize,
]
# get inital font sizes
initialSizes = [Plots.default(s) for s in sizesToCheck]
#scale up font sizes
scalefontsizes(2)
# get inital font sizes
doubledSizes = [Plots.default(s) for s in sizesToCheck]
@test doubledSizes == initialSizes * 2
# reset font sizes
resetfontsizes()
finalSizes = [Plots.default(s) for s in sizesToCheck]
@test finalSizes == initialSizes
end
end
@testset "Series Annotations" begin
square = Shape([(0.0, 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
-68
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
+2 -4
View File
@@ -1,12 +1,10 @@
using Plots, Test
const PLOTS_DEFAULTS = Dict(:theme => :wong2, :fontfamily => :palantino)
const PLOTS_DEFAULTS = Dict(:theme => :wong2)
Plots.__init__()
@testset "Loading theme" begin
pl = plot(1:5)
@test pl[1][1][:seriescolor] == RGBA(colorant"black")
@test guidefont(pl[1][:xaxis]).family == "palantino"
@test plot(1:5)[1][1][:seriescolor] == RGBA(colorant"black")
end
empty!(PLOTS_DEFAULTS)
+13 -12
View File
@@ -1,20 +1,21 @@
using Plots, HDF5
@testset "HDF5_Plots" begin
fname = "tmpplotsave.hdf5"
hdf5()
fname = "tmpplotsave.hdf5"
hdf5()
x = 1:10
psrc = plot(x, x .* x) #Create some plot
Plots.hdf5plot_write(psrc, fname)
x = 1:10
psrc=plot(x, x.*x); #Create some plot
Plots.hdf5plot_write(psrc, fname)
#Read back file:
gr() #Choose some fast backend likely to work in test environment.
pread = Plots.hdf5plot_read(fname)
#Read back file:
gr() #Choose some fast backend likely to work in test environment.
pread = Plots.hdf5plot_read(fname)
#Make sure data made it through:
@test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x]
@test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y]
#Make sure data made it through:
@test psrc.subplots[1].series_list[1][:x] == pread.subplots[1].series_list[1][:x]
@test psrc.subplots[1].series_list[1][:y] == pread.subplots[1].series_list[1][:y]
#display(pread) #Don't display. Regression env might not support
#display(pread) #Don't display. Regression env might not support
end #testset
+389 -386
View File
@@ -2,407 +2,410 @@ using Plots, Test
pgfplotsx()
function create_plot(args...; kwargs...)
pgfx_plot = plot(args...; kwargs...)
return pgfx_plot, repr("application/x-tex", pgfx_plot)
pgfx_plot = plot(args...; kwargs...)
return pgfx_plot, repr("application/x-tex", pgfx_plot)
end
function create_plot!(args...; kwargs...)
pgfx_plot = plot!(args...; kwargs...)
return pgfx_plot, repr("application/x-tex", pgfx_plot)
pgfx_plot = plot!(args...; kwargs...)
return pgfx_plot, repr("application/x-tex", pgfx_plot)
end
@testset "PGFPlotsX" begin
pgfx_plot = plot(1:5)
Plots._update_plot_object(pgfx_plot)
@test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument
@test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing
axis = Plots.pgfx_axes(pgfx_plot.o)[1]
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 1
@test !haskey(axis.contents[1].options.dict, "fill")
pgfx_plot = plot(1:5)
Plots._update_plot_object(pgfx_plot)
@test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument
@test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing
axis = Plots.pgfx_axes(pgfx_plot.o)[1]
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 1
@test !haskey(axis.contents[1].options.dict, "fill")
@testset "Legends" begin
legends_plot = plot(rand(5, 2), lab = ["1" ""])
scatter!(legends_plot, rand(5))
Plots._update_plot_object(legends_plot)
axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2
@test !haskey(series[1].options.dict, "forget plot")
@test haskey(series[2].options.dict, "forget plot")
@test !haskey(series[3].options.dict, "forget plot")
end # testset
@testset "Legends" begin
legends_plot = plot(rand(5, 2), lab = ["1" ""])
scatter!(legends_plot, rand(5))
Plots._update_plot_object(legends_plot)
axis_contents = Plots.pgfx_axes(legends_plot.o)[1].contents
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2
@test !haskey(series[1].options.dict, "forget plot")
@test haskey(series[2].options.dict, "forget plot")
@test !haskey(series[3].options.dict, "forget plot")
end # testset
@testset "3D docs example" begin
n = 100
ts = range(0, stop = 8π, length = n)
x = ts .* map(cos, ts)
y = (0.1ts) .* map(sin, ts)
z = 1:n
pl = plot(
x,
y,
z,
zcolor = reverse(z),
m = (10, 0.8, :blues, Plots.stroke(0)),
leg = false,
cbar = true,
w = 5,
)
pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w = 10)
Plots._update_plot_object(pgfx_plot)
if @test_nowarn(
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
)
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
end
end # testset
@testset "Color docs example" begin
y = rand(100)
plot(
0:10:100,
rand(11, 4),
lab = "lines",
w = 3,
palette = :grays,
fill = 0,
α = 0.6,
)
pl = scatter!(
y,
zcolor = abs.(y .- 0.5),
m = (:hot, 0.8, Plots.stroke(1, :green)),
ms = 10 * abs.(y .- 0.5) .+ 4,
lab = ["grad", "", "ient"],
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
@test count(x -> x isa PGFPlotsX.LegendEntry, axis.contents) == 6
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 108 # each marker is its own plot, fillranges create 2 plot-objects
marker = axis.contents[15]
@test marker isa PGFPlotsX.Plot
@test marker.options["mark"] == "*"
@test marker.options["mark options"]["color"] == RGBA{Float64}(colorant"green", 0.8)
@test marker.options["mark options"]["line width"] == 0.75 # 1px is 0.75pt
end # testset
@testset "Plot in pieces" begin
pic = plot(rand(100) / 3, reg = true, fill = (0, :green))
scatter!(pic, rand(100), markersize = 6, c = :orange)
Plots._update_plot_object(pic)
axis_contents = Plots.pgfx_axes(pic.o)[1].contents
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2
@test length(series) == 4
@test haskey(series[1].options.dict, "forget plot")
@test !haskey(series[2].options.dict, "forget plot")
@test haskey(series[3].options.dict, "forget plot")
@test !haskey(series[4].options.dict, "forget plot")
end # testset
@testset "Marker types" begin
markers = filter((m -> begin
m in Plots.supported_markers()
end), Plots._shape_keys)
markers = reshape(markers, 1, length(markers))
n = length(markers)
x = (range(0, stop = 10, length = n + 2))[2:(end - 1)]
y = repeat(reshape(reverse(x), 1, :), n, 1)
scatter(
x,
y,
m = (8, :auto),
lab = map(string, markers),
bg = :linen,
xlim = (0, 10),
ylim = (0, 10),
)
end # testset
@testset "Layout" begin
plot(
Plots.fakedata(100, 10),
layout = 4,
palette = [:grays :blues :hot :rainbow],
bg_inside = [:orange :pink :darkblue :black],
)
end # testset
@testset "Polar plots" begin
Θ = range(0, stop = 1.5π, length = 100)
r = abs.(0.1 * randn(100) + sin.(3Θ))
plot(Θ, r, proj = :polar, m = 2)
end # testset
@testset "Drawing shapes" begin
verts = [
(-1.0, 1.0),
(-1.28, 0.6),
(-0.2, -1.4),
(0.2, -1.4),
(1.28, 0.6),
(1.0, 1.0),
(-1.0, 1.0),
(-0.2, -0.6),
(0.0, -0.2),
(-0.4, 0.6),
(1.28, 0.6),
(0.2, -1.4),
(-0.2, -1.4),
(0.6, 0.2),
(-0.2, 0.2),
(0.0, -0.2),
(0.2, 0.2),
(-0.2, -0.6),
]
x = 0.1:0.2:0.9
y = 0.7 * rand(5) .+ 0.15
plot(
x,
y,
line = (3, :dash, :lightblue),
marker = (Shape(verts), 30, RGBA(0, 0, 0, 0.2)),
bg = :pink,
fg = :darkblue,
xlim = (0, 1),
ylim = (0, 1),
leg = false,
)
end # testset
@testset "Histogram 2D" begin
histogram2d(randn(10000), randn(10000), nbins = 20)
end # testset
@testset "Heatmap-like" begin
xs = [string("x", i) for i in 1:10]
ys = [string("y", i) for i in 1:4]
z = float((1:4) * reshape(1:10, 1, :))
pgfx_plot = heatmap(xs, ys, z, aspect_ratio = 1)
Plots._update_plot_object(pgfx_plot)
if @test_nowarn(
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
)
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1"
end
@testset "3D docs example" begin
n = 100
ts = range(0, stop = 8π, length = n)
x = ts .* map(cos, ts)
y = (0.1ts) .* map(sin, ts)
z = 1:n
pl = plot(
x,
y,
z,
zcolor = reverse(z),
m = (10, 0.8, :blues, Plots.stroke(0)),
leg = false,
cbar = true,
w = 5,
)
pgfx_plot = plot!(pl, zeros(n), zeros(n), 1:n, w = 10)
Plots._update_plot_object(pgfx_plot)
if @test_nowarn(
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
)
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
end
end # testset
@testset "Color docs example" begin
y = rand(100)
plot(
0:10:100,
rand(11, 4),
lab = "lines",
w = 3,
palette = :grays,
fill = 0,
α = 0.6,
)
pl = scatter!(
y,
zcolor = abs.(y .- 0.5),
m = (:hot, 0.8, Plots.stroke(1, :green)),
ms = 10 * abs.(y .- 0.5) .+ 4,
lab = ["grad", "", "ient"],
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
@test count(x -> x isa PGFPlotsX.LegendEntry, axis.contents) == 6
@test count(x -> x isa PGFPlotsX.Plot, axis.contents) == 108 # each marker is its own plot, fillranges create 2 plot-objects
marker = axis.contents[15]
@test marker isa PGFPlotsX.Plot
@test marker.options["mark"] == "*"
@test marker.options["mark options"]["color"] ==
RGBA{Float64}(colorant"green", 0.8)
@test marker.options["mark options"]["line width"] == 0.75 # 1px is 0.75pt
end # testset
@testset "Plot in pieces" begin
pic = plot(rand(100) / 3, reg = true, fill = (0, :green))
scatter!(pic, rand(100), markersize = 6, c = :orange)
Plots._update_plot_object(pic)
axis_contents = Plots.pgfx_axes(pic.o)[1].contents
leg_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis_contents)
series = filter(x -> x isa PGFPlotsX.Plot, axis_contents)
@test length(leg_entries) == 2
@test length(series) == 4
@test haskey(series[1].options.dict, "forget plot")
@test !haskey(series[2].options.dict, "forget plot")
@test haskey(series[3].options.dict, "forget plot")
@test !haskey(series[4].options.dict, "forget plot")
end # testset
@testset "Marker types" begin
markers = filter((m -> begin
m in Plots.supported_markers()
end), Plots._shape_keys)
markers = reshape(markers, 1, length(markers))
n = length(markers)
x = (range(0, stop = 10, length = n + 2))[2:(end-1)]
y = repeat(reshape(reverse(x), 1, :), n, 1)
scatter(
x,
y,
m = (8, :auto),
lab = map(string, markers),
bg = :linen,
xlim = (0, 10),
ylim = (0, 10),
)
end # testset
@testset "Layout" begin
plot(
Plots.fakedata(100, 10),
layout = 4,
palette = [:grays :blues :hot :rainbow],
bg_inside = [:orange :pink :darkblue :black],
)
end # testset
@testset "Polar plots" begin
Θ = range(0, stop = 1.5π, length = 100)
r = abs.(0.1 * randn(100) + sin.(3Θ))
plot(Θ, r, proj = :polar, m = 2)
end # testset
@testset "Drawing shapes" begin
verts = [
(-1.0, 1.0),
(-1.28, 0.6),
(-0.2, -1.4),
(0.2, -1.4),
(1.28, 0.6),
(1.0, 1.0),
(-1.0, 1.0),
(-0.2, -0.6),
(0.0, -0.2),
(-0.4, 0.6),
(1.28, 0.6),
(0.2, -1.4),
(-0.2, -1.4),
(0.6, 0.2),
(-0.2, 0.2),
(0.0, -0.2),
(0.2, 0.2),
(-0.2, -0.6),
]
x = 0.1:0.2:0.9
y = 0.7 * rand(5) .+ 0.15
plot(
x,
y,
line = (3, :dash, :lightblue),
marker = (Shape(verts), 30, RGBA(0, 0, 0, 0.2)),
bg = :pink,
fg = :darkblue,
xlim = (0, 1),
ylim = (0, 1),
leg = false,
)
end # testset
@testset "Histogram 2D" begin
histogram2d(randn(10000), randn(10000), nbins = 20)
end # testset
@testset "Heatmap-like" begin
xs = [string("x", i) for i = 1:10]
ys = [string("y", i) for i = 1:4]
z = float((1:4) * reshape(1:10, 1, :))
pgfx_plot = heatmap(xs, ys, z, aspect_ratio = 1)
Plots._update_plot_object(pgfx_plot)
if @test_nowarn(
haskey(Plots.pgfx_axes(pgfx_plot.o)[1].options.dict, "colorbar") == true
)
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colorbar"] === nothing
@test Plots.pgfx_axes(pgfx_plot.o)[1]["colormap name"] == "plots1"
end
pgfx_plot = wireframe(xs, ys, z, aspect_ratio = 1)
# TODO: clims are wrong
end # testset
@testset "Contours" begin
x = 1:0.5:20
y = 1:0.5:10
f(x, y) = begin
(3x + y^2) * abs(sin(x) + cos(y))
end
X = repeat(reshape(x, 1, :), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
p2 = contour(x, y, Z)
p1 = contour(x, y, f, fill = true)
plot(p1, p2)
# TODO: colorbar for filled contours
end # testset
@testset "Varying colors" begin
t = range(0, stop = 1, length = 100)
θ = (6π) .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z = t, linewidth = 3, legend = false)
p2 = scatter(x, y, marker_z = ((x, y) -> begin
pgfx_plot = wireframe(xs, ys, z, aspect_ratio = 1)
# TODO: clims are wrong
end # testset
@testset "Contours" begin
x = 1:0.5:20
y = 1:0.5:10
f(x, y) = begin
(3x + y^2) * abs(sin(x) + cos(y))
end
X = repeat(reshape(x, 1, :), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
p2 = contour(x, y, Z)
p1 = contour(x, y, f, fill = true)
plot(p1, p2)
# TODO: colorbar for filled contours
end # testset
@testset "Varying colors" begin
t = range(0, stop = 1, length = 100)
θ = (6π) .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z = t, linewidth = 3, legend = false)
p2 = scatter(
x,
y,
marker_z = ((x, y) -> begin
x + y
end), color = :bwr, legend = false)
plot(p1, p2)
end # testset
@testset "Framestyles" begin
scatter(
fill(randn(10), 6),
fill(randn(10), 6),
framestyle = [:box :semi :origin :zerolines :grid :none],
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = permutedims(1:6),
layout = 6,
label = "",
markerstrokewidth = 0,
ticks = -2:2,
)
# TODO: support :semi
end # testset
@testset "Quiver" begin
x = (-2pi):0.2:(2 * pi)
y = sin.(x)
end),
color = :bwr,
legend = false,
)
plot(p1, p2)
end # testset
@testset "Framestyles" begin
scatter(
fill(randn(10), 6),
fill(randn(10), 6),
framestyle = [:box :semi :origin :zerolines :grid :none],
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = permutedims(1:6),
layout = 6,
label = "",
markerstrokewidth = 0,
ticks = -2:2,
)
# TODO: support :semi
end # testset
@testset "Quiver" begin
x = (-2pi):0.2:(2*pi)
y = sin.(x)
u = ones(length(x))
v = cos.(x)
arrow_plot = plot(x, y, quiver = (u, v), arrow = true)
# TODO: could adjust limits to fit arrows if too long, but how?
# TODO: get latex available on CI
# mktempdir() do path
# @test_nowarn savefig(arrow_plot, path*"arrow.pdf")
# end
end # testset
@testset "Annotations" begin
y = rand(10)
pgfx_plot =
plot(y, annotations = (3, y[3], Plots.text("this is \\#3", :left)), leg = false)
Plots._update_plot_object(pgfx_plot)
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 1
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 1
end
end
annotate!([
(5, y[5], Plots.text("this is \\#5", 16, :red, :center)),
(10, y[10], Plots.text("this is \\#10", :right, 20, "courier")),
])
Plots._update_plot_object(pgfx_plot)
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 3
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 3
end
end
annotation_plot = scatter!(
range(2, stop = 8, length = 6),
rand(6),
marker = (50, 0.2, :orange),
series_annotations = [
"series",
"annotations",
"map",
"to",
"series",
Plots.text("data", :green),
],
)
Plots._update_plot_object(annotation_plot)
axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 9
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(annotation_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 9
end
# test .tikz extension
file_path = joinpath(path, "annotations.tikz")
@test_nowarn savefig(annotation_plot, file_path)
@test_nowarn open(file_path) do io
end
end
end # testset
@testset "Ribbon" begin
aa = rand(10)
bb = rand(10)
cc = rand(10)
conf = [aa - cc bb - cc]
ribbon_plot = plot(collect(1:10), fill(1, 10), ribbon = (conf[:, 1], conf[:, 2]))
Plots._update_plot_object(ribbon_plot)
axis = Plots.pgfx_axes(ribbon_plot.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 3
@test haskey(plots[1].options.dict, "fill")
@test haskey(plots[2].options.dict, "fill")
@test !haskey(plots[3].options.dict, "fill")
@test ribbon_plot.o !== nothing
@test ribbon_plot.o.the_plot !== nothing
end # testset
@testset "Markers and Paths" begin
pl = plot(
5 .- ones(9),
markershape = [:utriangle, :rect],
markersize = 8,
color = [:red, :black],
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 9
end # testset
@testset "Groups and Subplots" begin
group = rand(map((i -> begin
"group $(i)"
end), 1:4), 100)
pl = plot(
rand(100),
layout = @layout([a b; c]),
group = group,
linetype = [:bar :scatter :steppre],
linecolor = :match,
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
legend_entries = filter(x -> x isa PGFPlotsX.LegendEntry, axis.contents)
@test length(legend_entries) == 2
end
u = ones(length(x))
v = cos.(x)
arrow_plot = plot(x, y, quiver = (u, v), arrow = true)
# TODO: could adjust limits to fit arrows if too long, but how?
# TODO: get latex available on CI
# mktempdir() do path
# @test_nowarn savefig(arrow_plot, path*"arrow.pdf")
# end
end # testset
@testset "Annotations" begin
y = rand(10)
pgfx_plot = plot(
y,
annotations = (3, y[3], Plots.text("this is \\#3", :left)),
leg = false,
)
Plots._update_plot_object(pgfx_plot)
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 1
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 1
end
end
annotate!([
(5, y[5], Plots.text("this is \\#5", 16, :red, :center)),
(10, y[10], Plots.text("this is \\#10", :right, 20, "courier")),
])
Plots._update_plot_object(pgfx_plot)
axis_content = Plots.pgfx_axes(pgfx_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 3
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(pgfx_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 3
end
end
annotation_plot = scatter!(
range(2, stop = 8, length = 6),
rand(6),
marker = (50, 0.2, :orange),
series_annotations = [
"series",
"annotations",
"map",
"to",
"series",
Plots.text("data", :green),
],
)
Plots._update_plot_object(annotation_plot)
axis_content = Plots.pgfx_axes(annotation_plot.o)[1].contents
nodes = filter(x -> !isa(x, PGFPlotsX.Plot), axis_content)
@test length(nodes) == 9
mktempdir() do path
file_path = joinpath(path, "annotations.tex")
@test_nowarn savefig(annotation_plot, file_path)
open(file_path) do io
lines = readlines(io)
@test count(s -> occursin("node", s), lines) == 9
end
# test .tikz extension
file_path = joinpath(path, "annotations.tikz")
@test_nowarn savefig(annotation_plot, file_path)
@test_nowarn open(file_path) do io
end
end
end # testset
@testset "Ribbon" begin
aa = rand(10)
bb = rand(10)
cc = rand(10)
conf = [aa - cc bb - cc]
ribbon_plot =
plot(collect(1:10), fill(1, 10), ribbon = (conf[:, 1], conf[:, 2]))
Plots._update_plot_object(ribbon_plot)
axis = Plots.pgfx_axes(ribbon_plot.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 3
@test haskey(plots[1].options.dict, "fill")
@test haskey(plots[2].options.dict, "fill")
@test !haskey(plots[3].options.dict, "fill")
@test ribbon_plot.o !== nothing
@test ribbon_plot.o.the_plot !== nothing
end # testset
@testset "Markers and Paths" begin
pl = plot(
5 .- ones(9),
markershape = [:utriangle, :rect],
markersize = 8,
color = [:red, :black],
)
Plots._update_plot_object(pl)
axis = Plots.pgfx_axes(pl.o)[1]
plots = filter(x -> x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 9
end # testset
end # testset
@testset "Extra kwargs" begin
pl = plot(1:5, test = "me")
@test pl[1][1].plotattributes[:extra_kwargs][:test] == "me"
pl = plot(1:5, test = "me", extra_kwargs = :subplot)
@test pl[1].attr[:extra_kwargs][:test] == "me"
pl = plot(1:5, test = "me", extra_kwargs = :plot)
@test pl.attr[:extra_plot_kwargs][:test] == "me"
pl = plot(
1:5,
extra_kwargs = Dict(
:plot => Dict(:test => "me"),
:series => Dict(:and => "me too"),
),
)
@test pl.attr[:extra_plot_kwargs][:test] == "me"
@test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too"
pl = plot(
plot(1:5, title = "Line"),
scatter(
1:5,
title = "Scatter",
extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")),
),
)
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test !haskey(axes[1].options.dict, "axis line shift")
@test haskey(axes[2].options.dict, "axis line shift")
pl =
plot(x -> x, -1:1; add = raw"\node at (0,0.5) {\huge hi};", extra_kwargs = :subplot)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
plot!(pl)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
pl = plot(1:5, test = "me")
@test pl[1][1].plotattributes[:extra_kwargs][:test] == "me"
pl = plot(1:5, test = "me", extra_kwargs = :subplot)
@test pl[1].attr[:extra_kwargs][:test] == "me"
pl = plot(1:5, test = "me", extra_kwargs = :plot)
@test pl.attr[:extra_plot_kwargs][:test] == "me"
pl = plot(
1:5,
extra_kwargs = Dict(
:plot => Dict(:test => "me"),
:series => Dict(:and => "me too"),
),
)
@test pl.attr[:extra_plot_kwargs][:test] == "me"
@test pl[1][1].plotattributes[:extra_kwargs][:and] == "me too"
pl = plot(
plot(1:5, title = "Line"),
scatter(
1:5,
title = "Scatter",
extra_kwargs = Dict(:subplot => Dict("axis line shift" => "10pt")),
),
)
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test !haskey(axes[1].options.dict, "axis line shift")
@test haskey(axes[2].options.dict, "axis line shift")
pl = plot(
x -> x,
-1:1;
add = raw"\node at (0,0.5) {\huge hi};",
extra_kwargs = :subplot,
)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
plot!(pl)
@test pl[1][:extra_kwargs] == Dict(:add => raw"\node at (0,0.5) {\huge hi};")
Plots._update_plot_object(pl)
axes = Plots.pgfx_axes(pl.o)
@test filter(x -> x isa String, axes[1].contents)[1] ==
raw"\node at (0,0.5) {\huge hi};"
end # testset
@testset "Titlefonts" begin
pl = plot(1:5, title = "Test me", titlefont = (2, :left))
@test pl[1][:title] == "Test me"
@test pl[1][:titlefontsize] == 2
@test pl[1][:titlefonthalign] == :left
Plots._update_plot_object(pl)
ax_opt = Plots.pgfx_axes(pl.o)[1].options
@test ax_opt["title"] == "Test me"
@test(haskey(ax_opt.dict, "title style")) isa Test.Pass
pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left))
@test pl[:plot_title] == "Test me"
@test pl[:plot_titlefontsize] == 2
@test pl[:plot_titlefonthalign] == :left
pl = heatmap(rand(3, 3), colorbar_title = "Test me", colorbar_titlefont = (12, :right))
@test pl[1][:colorbar_title] == "Test me"
@test pl[1][:colorbar_titlefontsize] == 12
@test pl[1][:colorbar_titlefonthalign] == :right
pl = plot(1:5, title = "Test me", titlefont = (2, :left))
@test pl[1][:title] == "Test me"
@test pl[1][:titlefontsize] == 2
@test pl[1][:titlefonthalign] == :left
Plots._update_plot_object(pl)
ax_opt = Plots.pgfx_axes(pl.o)[1].options
@test ax_opt["title"] == "Test me"
@test(haskey(ax_opt.dict, "title style")) isa Test.Pass
pl = plot(1:5, plot_title = "Test me", plot_titlefont = (2, :left))
@test pl[:plot_title] == "Test me"
@test pl[:plot_titlefontsize] == 2
@test pl[:plot_titlefonthalign] == :left
pl = heatmap(
rand(3, 3),
colorbar_title = "Test me",
colorbar_titlefont = (12, :right),
)
@test pl[1][:colorbar_title] == "Test me"
@test pl[1][:colorbar_titlefontsize] == 12
@test pl[1][:colorbar_titlefonthalign] == :right
end # testset
-19
View File
@@ -1,19 +0,0 @@
using Plots, Test
using RecipesPipeline
@testset "plot" begin
pl = plot(1:5)
pl2 = plot(pl, tex_output_standalone = true)
@test pl[:tex_output_standalone] == false
@test pl2[:tex_output_standalone] == true
plot!(pl, tex_output_standalone = true)
@test pl[:tex_output_standalone] == true
end
@testset "get_axis_limits" begin
x = [0.1, 5]
p1 = plot(x, [5, 0.1], yscale = :log10)
p2 = plot!(identity)
@test all(RecipesPipeline.get_axis_limits(p1, :x) .== x)
@test all(RecipesPipeline.get_axis_limits(p2, :x) .== x)
end
-57
View File
@@ -1,57 +0,0 @@
using Plots, Test
@testset "Plotly" begin
@testset "Basic" begin
@test plotly() == Plots.PlotlyBackend()
@test backend() == Plots.PlotlyBackend()
p = plot(rand(10))
@test isa(p, Plots.Plot) == true
end
@testset "Contours" begin
x = (-2π):0.1:(2π)
y = (-π):0.1:π
z = cos.(y) .* sin.(x')
@testset "Contour numbers" begin
@testset "Default" begin
@test Plots.plotly_series(contour(x, y, z))[1][:ncontours] ==
Plots._series_defaults[:levels] + 2
end
@testset "Specified number" begin
@test Plots.plotly_series(contour(x, y, z, levels = 10))[1][:ncontours] ==
12
end
end
@testset "Contour values" begin
@testset "Range" begin
levels = -1:0.5:1
p = contour(x, y, z, levels = levels)
@test p[1][1].plotattributes[:levels] == levels
@test Plots.plotly_series(p)[1][:contours][:start] == first(levels)
@test Plots.plotly_series(p)[1][:contours][:end] == last(levels)
@test Plots.plotly_series(p)[1][:contours][:size] == step(levels)
end
@testset "Set of contours" begin
levels = [-1, -0.25, 0, 0.25, 1]
levels_range =
range(first(levels), stop = last(levels), length = length(levels))
p = contour(x, y, z, levels = levels)
@test p[1][1].plotattributes[:levels] == levels
series_dict = @test_logs (
:warn,
"setting arbitrary contour levels with Plotly backend " *
"is not supported; use a range to set equally-spaced contours or an " *
"integer to set the approximate number of contours with the keyword " *
"`levels`. Setting levels to -1.0:0.5:1.0",
) Plots.plotly_series(p)
@test series_dict[1][:contours][:start] == first(levels_range)
@test series_dict[1][:contours][:end] == last(levels_range)
@test series_dict[1][:contours][:size] == step(levels_range)
end
end
end
end
+14 -38
View File
@@ -1,49 +1,25 @@
using Plots, Test
using OffsetArrays
@testset "lens!" begin
pl = plot(1:5)
lens!(pl, [1, 2], [1, 2], inset = (1, bbox(0.0, 0.0, 0.2, 0.2)), colorbar = false)
lens!(pl, [1,2], [1,2], inset = (1, bbox(0.0,0.0,0.2,0.2)), colorbar = false)
@test length(pl.series_list) == 4
@test pl[2][:colorbar] == :none
end # testset
@testset "vline, vspan" begin
vl = vline([1], widen = false)
@test Plots.xlims(vl) == (1, 2)
@test Plots.ylims(vl) == (1, 2)
vl = vline([1], xlims = (0, 2), widen = false)
@test Plots.xlims(vl) == (0, 2)
vl = vline([1], ylims = (-3, 5), widen = false)
@test Plots.ylims(vl) == (-3, 5)
@test Plots.xlims(vl) == (1,2)
@test Plots.ylims(vl) == (1,2)
vl = vline([1], xlims=(0,2), widen = false)
@test Plots.xlims(vl) == (0,2)
vl = vline([1], ylims=(-3,5), widen = false)
@test Plots.ylims(vl) == (-3,5)
vsp = vspan([1, 3], widen = false)
@test Plots.xlims(vsp) == (1, 3)
@test Plots.ylims(vsp) == (0, 1) # TODO: might be problematic on log-scales
vsp = vspan([1, 3], xlims = (-2, 5), widen = false)
@test Plots.xlims(vsp) == (-2, 5)
vsp = vspan([1, 3], ylims = (-2, 5), widen = false)
@test Plots.ylims(vsp) == (-2, 5)
vsp = vspan([1,3], widen = false)
@test Plots.xlims(vsp) == (1,3)
@test Plots.ylims(vsp) == (0,1) # TODO: might be problematic on log-scales
vsp = vspan([1,3], xlims=(-2,5), widen = false)
@test Plots.xlims(vsp) == (-2,5)
vsp = vspan([1,3], ylims=(-2,5), widen = false)
@test Plots.ylims(vsp) == (-2,5)
end # testset
@testset "offset axes" begin
tri = OffsetVector(vcat(1:5, 4:-1:1), 11:19)
sticks = plot(tri, seriestype = :sticks)
@test length(sticks) == 1
end
@testset "framestyle axes" begin
pl = plot(-1:1, -1:1, -1:1)
sp = pl.subplots[1]
defaultret = Plots.axis_drawing_info_3d(sp, :x)
for letter in [:x, :y, :z]
for fr in [:box :semi :origin :zerolines :grid :none]
prevha = UInt64(0)
push!(sp.attr, :framestyle => fr)
ret = Plots.axis_drawing_info_3d(sp, letter)
ha = hash(string(ret))
@test ha != prevha
prevha = ha
end
end
end
-48
View File
@@ -1,48 +0,0 @@
using Plots, Test
@testset "Shorthands" begin
@testset "Set Lims" begin
p = plot(rand(10))
xlims!((1, 20))
@test xlims(p) == (1, 20)
ylims!((-1, 1))
@test ylims(p) == (-1, 1)
zlims!((-1, 1))
@test zlims(p) == (-1, 1)
xlims!(-1, 11)
@test xlims(p) == (-1, 11)
ylims!((-10, 10))
@test ylims(p) == (-10, 10)
zlims!((-10, 10))
@test zlims(p) == (-10, 10)
end
@testset "Set Ticks" begin
p = plot([0, 2, 3, 4, 5, 6, 7, 8, 9, 10])
xticks = 2:6
xticks!(xticks)
@test Plots.get_subplot(current(), 1).attr[:xaxis][:ticks] == xticks
yticks = 0.2:0.1:0.7
yticks!(yticks)
@test Plots.get_subplot(current(), 1).attr[:yaxis][:ticks] == yticks
xticks = [5, 6, 7.5]
xlabels = ["a", "b", "c"]
xticks!(xticks, xlabels)
@test Plots.get_subplot(current(), 1).attr[:xaxis][:ticks] == (xticks, xlabels)
yticks = [0.5, 0.6, 0.75]
ylabels = ["z", "y", "x"]
yticks!(yticks, ylabels)
@test Plots.get_subplot(current(), 1).attr[:yaxis][:ticks] == (yticks, ylabels)
end
end