Compare commits

...

86 Commits

Author SHA1 Message Date
Simon Christ f0ad66da36 1.22.4 [skip ci] 2021-10-05 19:25:45 +02:00
Nicholas Bauer aca2aa49b8 Generalize GR tick label rotations (#3782)
* gr tick rotations

* consistency

* start of angle offset work

* Working!

* simplify logic

* gr tick rotations

* consistency

* start of angle offset work

* Working!

* simplify logic

* all offsets

* Rebase

* tick factor reversion

* Fix for 3d plots

* simplification

* offset update

* bump offset

* Remove conflict error

* Resolve merge conflict error.

* Resolve merge conflict error

* 3d done

* remove excess

* adjust offset

* restore offset

* fix sign check

Co-authored-by: t-bltg <tf.bltg@gmail.com>
Co-authored-by: Simon Christ <SimonChrist@gmx.de>
2021-10-05 13:44:12 +02:00
t-bltg 9d56e72f6a Update .zenodo.json
Fix broken .json
2021-10-05 09:43:40 +02:00
Lee Phillips f06225655d Allow styling of magnification shape in lens!() (#3860)
* Allow styling of magnification shape in lens!()

The guide lines that indicate the region of the plot magnified in the
inset lens plot, called the magnification shape, are hard-coded with
the :lightgray color and are drawn with the default other line
attributes. This is often too light to be seen clearly and could be a
problem for publication. This commit allows the user to set the
linecolor, linewidth, and linestyle in the call to lens!().

* Update src/recipes.jl

Co-authored-by: t-bltg <tf.bltg@gmail.com>

* Update .zenodo.json

Co-authored-by: t-bltg <tf.bltg@gmail.com>
Co-authored-by: Simon Christ <SimonChrist@gmx.de>
2021-10-04 17:38:59 +02:00
github-actions[bot] 4f0f84f400 Format .jl files [skip ci] (#3861)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-10-04 13:23:01 +02:00
Jan Schneider a65cda8b7e change docs link to httpS (#3852)
always bugs me to get a warning from my browser about the not secure connection.
Could someone also update the About section at the right of the Github page to a https URL?
2021-09-28 16:15:26 +02:00
Simon Christ 37744d7b6a 1.22.3 [skip ci] 2021-09-27 19:24:47 +02:00
Jan Schneider 09a66224ce Update Plots.jl's colorbar_titel maps to PGFPlotsX's color bar style={ylabel} (#3848)
* Update PGFPlotsX colorbar_titel map to ylabel

For most of the backends supported by Polts.jl the `colorbar_title` attribute maps to the attribute in the backend that ultimately is displayed on the vertical axis of the colorbar, which is vertically aligned. Not for PGFPlotsX as in this backend the `title` attribute is displayed on top of the colorbar while the `ylabel` is shown on the vertical bar.

* Update .zenodo.json

added my name to the contributors list
2021-09-27 16:16:16 +02:00
Nicholas Bauer 405bc0820b Speed up get_clims (#3839)
* For Shape type, cut off process

* Remove fillcolor for now

* Address type inference failure instead

* Store value instead of re-evaluating

* Works, but not ideal

* Unnecessary to update here, I think

* return type

* Remove unnecessary default arg

* Typo

* Change to clims

* missed one

* reconfigured to free up clims property

* fix

* Remove debug println, add hook for updating clims after series added

* restore docstring

* typo

* Change to _update_subplot_colorbars
2021-09-27 14:01:18 +02:00
github-actions[bot] 1c89bd8727 Update precompile_*.jl file [skip ci] (#3841)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-26 15:44:10 +02:00
github-actions[bot] 8e17a182f9 Format .jl files [skip ci] (#3846)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-26 15:42:31 +02:00
t-bltg 032c5d1638 UnicodePlots: support markers (#3845) 2021-09-25 12:18:41 +02:00
BerndR 8d95333d1e Legend positioning for 3d plots in plotly (#3840)
* Remove hardoced numbers, shift for 3d plots

* Revert changes

* Fixed some missed reverts
2021-09-23 19:14:55 +02:00
github-actions[bot] 7bfc97285c Update precompile_*.jl file [skip ci] (#3828)
Co-authored-by: BeastyBlacksmith <BeastyBlacksmith@users.noreply.github.com>
2021-09-23 10:26:58 +02:00
Simon Christ acca707f34 1.22.2 [skip ci] 2021-09-22 21:21:13 +02:00
Nicholas Bauer 6fa3dae166 Fix type inference failure in get_clims (#3838)
* For Shape type, cut off process

* Remove fillcolor for now

* NaN

* Address type inference failure instead
2021-09-22 19:18:57 +02:00
Lukas Hauertmann 866cb0c335 Add :mesh3d seriesstyle for PyPlot backend (#3835)
* Add `:mesh3d` seriesstyle for PyPlot backend

via `Poly3DCollection`.

* Add `:connections` to lists of supported keywords

for the backends which support `:mesh3d` as series type.

* Remove #47 from list of skipping examples for PyPlot

* Add support for only-triangle syntax for `:connections` kw

for PyPlot

* Add 1-based indexing syntax for `connections` kw in `:mesh3d`

* Update description for example `#47` (`:mesh3d`)

* Hotfix 1-based indexing for mesh3d in pgfplotsx
2021-09-22 17:12:11 +02:00
t-bltg 4d40bae9cc Update bug.md
update supported backends
2021-09-21 00:28:51 +02:00
github-actions[bot] 5a48002d31 Format .jl files [skip ci] (#3829)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-20 16:10:29 +02:00
t-bltg 0cd81243ad UnicodePlots: compact plots 2021-09-18 14:13:37 +02:00
t-bltg ed3bab0e6f 1.22.1 [skip ci] 2021-09-17 22:11:50 +02:00
github-actions[bot] 4621c18b23 Update precompile_*.jl file [skip ci] (#3822)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-17 22:10:48 +02:00
BerndR 4f8a265c6a Fix generic aliases (#3824) 2021-09-17 21:43:26 +02:00
t-bltg e2539a3d19 UnicodePlots: adjust layout width per column (#3825) 2021-09-17 21:42:50 +02:00
t-bltg 85739932f0 Negate condition on :warn_on_unsupported (#3816) 2021-09-17 14:55:43 +02:00
t-bltg 9d84e53bcb Test cleanup (#3821) 2021-09-17 12:00:40 +02:00
zhanibek 82f31c48b7 pyplot fixing ticks=:native 2021-09-17 16:30:22 +09:00
zhanibek 81571fe534 fix typos 2021-09-17 14:44:16 +09:00
zhanibek 293b8b112e instructions for matplotlib update 2021-09-17 14:38:24 +09:00
t-bltg d988d4c9d1 1.22.0 [skip ci] 2021-09-15 12:54:42 +02:00
github-actions[bot] 85bd3ea53f Update precompile_*.jl file [skip ci] (#3810)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-15 12:53:58 +02:00
t-bltg cd6a8c87b6 GR: fix NaN tick size (#3813) 2021-09-15 12:28:53 +02:00
t-bltg 175c87cec6 Avoid Vararg usage (#3809) 2021-09-15 12:28:24 +02:00
t-bltg c3f45dd712 UnicodePlots: minor fixes (#3812) 2021-09-15 11:21:41 +02:00
t-bltg 198a59b621 UnicodePlots: propagate xyscale (#3811) 2021-09-15 01:29:23 +02:00
t-bltg c5d7283473 Update examples.jl
UnicodePlots: annotations are supported
2021-09-14 21:02:30 +02:00
t-bltg 7a1bc88f66 Use hyphens to specify version ranges 2021-09-14 20:27:44 +02:00
github-actions[bot] ad5cd2f1da Update precompile_*.jl file [skip ci] (#3807)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-14 19:01:40 +02:00
t-bltg 6cf01229bb UnicodePlots: support :annotations (#3804) 2021-09-14 18:46:46 +02:00
t-bltg 0a9d30f7ac Fix invalid axes aliases (#3803)
* Fix invalid axes aliases

* Add test

* Enhance testing
2021-09-14 18:00:23 +02:00
github-actions[bot] 7da990b23f Format .jl files [skip ci] (#3801)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-13 09:18:59 +02:00
github-actions[bot] 942fb38dcd Update precompile_*.jl file [skip ci] (#3797)
Co-authored-by: isentropic <isentropic@users.noreply.github.com>
2021-09-13 09:18:18 +02:00
Zhanibek 7ba99d1b06 handling fonts better, moving to stable 3.4 (#3793)
* handling fonts better, moving to stable 3.4

* better math parent font matching
2021-09-11 13:43:42 +09:00
t-bltg 6b82a82d04 Update examples.jl 2021-09-06 13:18:22 +02:00
t-bltg 7c882a7288 Update Project.toml 2021-09-06 12:48:26 +02:00
github-actions[bot] 5343873f72 Update precompile_*.jl file [skip ci] (#3752)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-06 12:47:06 +02:00
t-bltg e3a5f2b11e UnicodePlots: support log scales (#3796) 2021-09-06 12:45:29 +02:00
github-actions[bot] 34758c82a3 Format .jl files [skip ci] (#3795)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-09-06 11:52:32 +02:00
t-bltg 748104c807 UnicodePlots: fix NaN segments plot (#3794) 2021-09-04 12:46:34 +02:00
t-bltg 0d2bc3f227 UnicodePlots: Update URL 2021-09-02 22:20:54 +02:00
t-bltg c45352d153 fix UnicodePlots.jl/issues/125 (#3791) 2021-09-02 17:59:02 +02:00
Josef Heinen b833b6582a Update Project.toml
Bump GR version
2021-09-01 16:55:16 +02:00
t-bltg b28a261b39 1.21.3 [skip ci] 2021-09-01 14:06:42 +02:00
t-bltg 1a1cc08992 UnicodePlots: fixes 2021-09-01 13:10:09 +02:00
t-bltg 31d33e6be4 UnicodePlots: Allow simple nesting 2021-09-01 12:48:31 +02:00
t-bltg 2dc812aa15 UnicodePlots: support layout (#3787) 2021-09-01 11:26:29 +02:00
t-bltg bdbe300412 Pyplot: fix building docs (#3775) 2021-09-01 11:24:16 +02:00
Nicholas Bauer 70b635dbe1 Cache axis args in a dictionary (#3775)
Co-authored-by: t-bltg <tf.bltg@gmail.com>
Co-authored-by: Simon Christ <SimonChrist@gmx.de>
2021-08-31 21:36:58 +02:00
t-bltg 1e44dd7035 Unicodeplots: "join" subplots 2021-08-31 00:21:11 +02:00
t-bltg 4744152f86 Add newline between subplots 2021-08-30 23:25:19 +02:00
t-bltg dc51f2c159 v1.21.2 [skip ci] 2021-08-30 22:22:05 +02:00
t-bltg cc1f662b3a UnicodePlots: rm forced width/height (arbitrary) 2021-08-30 17:50:41 +02:00
t-bltg 7b77527f80 UnicodePlots: display fix, simplify axis labels 2021-08-30 14:04:00 +02:00
github-actions[bot] 8b6073c088 Format .jl files [skip ci] (#3780)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-08-29 10:53:46 +02:00
t-bltg 09d35d7b9f UnicodePlots: heatmap support (#3774)
* UnicodePlots: heatmap support

* Fix type check
2021-08-28 21:29:04 +02:00
Simon Christ 0a9da21443 sanitize axis strings (#3772) 2021-08-28 21:08:21 +02:00
Simon Christ ea686c331b improve axis decorations (#3756)
* improve handling of LaTeXStrings in tick labels

* respect guidefonthalign
2021-08-28 21:08:03 +02:00
t-bltg 25a36bab85 merge root codecov.yml [skip ci] 2021-08-28 17:05:13 +02:00
t-bltg b227fb8943 move codecov.yml 2021-08-28 00:12:43 +02:00
t-bltg 22651e8728 UnicodePlots: disable some unsupported examples 2021-08-26 19:54:58 +02:00
Nicholas Bauer 5acf967a9e v1.21.1 | No exception thrown in apply_recipe fallback (#3765)
* No exception thrown in `apply_recipe` fallback

Throwing an exception here can vastly slow down plotting, as it happens frequently. Returning an error value instead, which the calling function can check, can speed up plotting 2x. An accompanying change is necessary in RecipesPipeline.jl, assuming this value is suitable.

* Bumped compat for RecipesPipeline, tentative

* Bump patch version

* Fix wrong versioning

Co-authored-by: t-bltg <tf.bltg@gmail.com>
2021-08-26 17:46:28 +02:00
Simon Christ 5afeba656b check if .zenodo.json is valid 2021-08-26 17:17:26 +02:00
LukasKrumwiede 7b8bd5b253 Implementation of filling the space between and under curves for gaston (#3755) 2021-08-26 16:58:05 +02:00
Pearl Li ded808477d Add hatched fill for GR and PyPlot (#3107) 2021-08-26 16:55:56 +02:00
Simon Christ 854d5ba5c9 1.21.0 [skip ci] 2021-08-26 16:21:47 +02:00
t-bltg 07a619e5ae Replace deprecated Base.download with Downloads.download (#3766)
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
2021-08-26 00:12:33 +02:00
t-bltg 1426c95fd4 fix formatting action 2021-08-25 22:42:23 +02:00
Andy Nowacki 52ec432cfa Plotly: Enable specified contour values for ranges; warn otherwise (#3757) 2021-08-25 13:40:54 +02:00
t-bltg 0742d475bc CI: julia-uploadcodecov is deprecated (#3761) 2021-08-22 12:00:12 +02:00
Josef Heinen 10802baf6e Added support for 3d surface meshes 2021-08-22 09:17:42 +02:00
t-bltg c67da7d7b8 UnicodePlots: allow passing arbitrary colors (RGBA, symbols, integers, ...) (#3758) 2021-08-19 22:19:38 +02:00
t-bltg f85f668f18 Merge pull request #3759 from t-bltg/fmt
CI: run JuliaFormatter on schedule
2021-08-19 22:17:47 +02:00
Simon Christ c4208c7560 fix broken file 2021-08-19 21:07:04 +02:00
t-bltg 35fd604e07 run JuliaFormatter on schedule 2021-08-19 17:51:53 +02:00
t-bltg 214663aa4b Merge pull request #3750 from t-bltg/col
UnicodePlots: fix setting linecolor
2021-08-15 12:40:19 +02:00
t-bltg d56a03975f UnicodePlots: fix setting linecolor 2021-08-15 00:39:04 +02:00
33 changed files with 1417 additions and 635 deletions
+2 -1
View File
@@ -20,10 +20,11 @@ Backend | yes | no | untested
-------------|-----|-----|---------
gr (default) | | |
pyplot | | |
plotly | | |
plotlyjs | | |
pgfplotsx | | |
unicodeplots | | |
inspectdr | | |
gaston | | |
### Versions
+5 -4
View File
@@ -76,10 +76,11 @@ jobs:
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("StatsPlots"); Pkg.test("StatsPlots")'
$TESTCMD -e 'using Pkg; Pkg.activate(tempdir()); Pkg.develop(path=abspath(".")); Pkg.add("GraphRecipes"); Pkg.test("GraphRecipes")'
- name: Codecov
uses: julia-actions/julia-uploadcodecov@latest
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# Codecov
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
Skip:
if: "contains(github.event.head_commit.message, '[skip ci]')"
@@ -13,14 +13,10 @@ jobs:
with:
version: 1
# Setup
- name: Ubuntu TESTCMD
run: echo "TESTCMD=xvfb-run --auto-servernum julia" >> $GITHUB_ENV
# Check format
- name: Install JuliaFormatter and format
run: |
git diff --name-only --exit-code
$TESTCMD -e 'using Pkg; pkg"add JuliaFormatter CSTParser#master"'
$TESTCMD -e 'using JuliaFormatter; format(["src", "test"])'
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
@@ -0,0 +1,35 @@
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 }}"
+11 -1
View File
@@ -688,10 +688,20 @@
{
"name": "@t-bltg",
"type": "Other"
}
},
{
"name": "Fred Callaway",
"type": "Other"
},
{
"name": "Jan Thorben Schneider",
"type": "Other"
},
{
"orcid": "0000-0003-4102-2460",
"affiliation": "Alogus Research Corporation",
"name": "Lee Phillips",
"type": "Other"
}
],
"upload_type": "software"
+9 -7
View File
@@ -1,12 +1,13 @@
name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"]
version = "1.20.1"
version = "1.22.4"
[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"
@@ -34,23 +35,24 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat]
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"
FFMPEG = "0.2 - 0.4"
FixedPointNumbers = "0.6 - 0.8"
GR = "0.53 - 0.59"
GeometryBasics = "0.2, 0.3.1, 0.4"
JSON = "0.21, 1"
Latexify = "0.14, 0.15"
Latexify = "0.14 - 0.15"
Measures = "0.3"
NaNMath = "0.3"
PlotThemes = "2"
PlotUtils = "1"
RecipesBase = "1"
RecipesPipeline = "0.3"
RecipesPipeline = "0.3.5, 0.4"
Reexport = "0.2, 1.0"
Requires = "1"
Scratch = "1"
Showoff = "0.3.1, 1.0"
StatsBase = "0.32, 0.33"
StatsBase = "0.32 - 0.33"
UnicodePlots = "2.4"
julia = "1.5"
[extras]
+1 -1
View File
@@ -10,7 +10,7 @@
[gitter-url]: https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
[docs-url]: http://docs.juliaplots.org/latest/
[docs-url]: https://docs.juliaplots.org/latest/
[![][gh-ci-img]][gh-ci-url]
[![][pkgeval-img]][pkgeval-url]
+3
View File
@@ -1,3 +1,6 @@
github_checks:
annotations: false
ignore:
- "src/backends/inspectdr.jl"
- "src/backends/orca.jl"
+33 -9
View File
@@ -76,6 +76,8 @@ function _precompile_()
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})
@@ -92,6 +94,7 @@ function _precompile_()
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})
@@ -123,6 +126,7 @@ function _precompile_()
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!),Plot{PlotlyBackend},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:markersize, :c, :seriestype), Tuple{Int64, Symbol, Symbol}},typeof(plot!),Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{GRBackend},Vector{Int64},Vector{Float64}})
Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:seriestype, :inset), Tuple{Symbol, Tuple{Int64, BoundingBox{Tuple{Length{:w, Float64}, Length{:h, Float64}}, Tuple{Length{:w, Float64}, Length{:h, Float64}}}}}},typeof(plot!),Plot{PlotlyBackend},Vector{Int64},Vector{Float64}})
@@ -135,6 +139,8 @@ function _precompile_()
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{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}})
@@ -151,6 +157,7 @@ function _precompile_()
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}})
@@ -230,7 +237,7 @@ function _precompile_()
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{GRBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.plot_setup!),Plot{PlotlyBackend},Dict{Symbol, Any},Vector{Dict{Symbol, Any}}})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_attributes!),Plot{GRBackend},DefaultsDict})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_axis_args!),Plot{GRBackend},Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(RecipesPipeline.preprocess_axis_args!),Plot{PlotlyBackend},Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(RecipesPipeline.process_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})
@@ -243,14 +250,16 @@ function _precompile_()
Base.precompile(Tuple{typeof(_cbar_unique),Vector{PlotUtils.ContinuousColorGradient},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}}},String})
Base.precompile(Tuple{typeof(_cbar_unique),Vector{Symbol},String})
Base.precompile(Tuple{typeof(_cycle),Base.OneTo{Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),StepRange{Int64, Int64},Vector{Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},StepRange{Int64, Int64}})
Base.precompile(Tuple{typeof(_cycle),Vector{Float64},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(_slice_series_args!),DefaultsDict,Plot{GRBackend},Subplot{GRBackend},Int64})
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})
@@ -268,9 +277,11 @@ function _precompile_()
Base.precompile(Tuple{typeof(error_coords),Vector{Float64},Vector{Float64},Vector{Float64}})
Base.precompile(Tuple{typeof(error_zipit),Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}})
Base.precompile(Tuple{typeof(fakedata),Int64,Int64})
Base.precompile(Tuple{typeof(get_clims),Subplot{GRBackend},Series,Function})
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})
@@ -280,20 +291,16 @@ function _precompile_()
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,Vector{Int64},Vector{Int64},Tuple{Float64, Float64},Int64,Int64})
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}})
@@ -328,14 +335,15 @@ function _precompile_()
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},Float64,Symbol})
Base.precompile(Tuple{typeof(processGridArg!),Dict{Symbol, Any},Symbol,Symbol})
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Matrix{Symbol}})
Base.precompile(Tuple{typeof(processLineArg),Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Matrix{Symbol}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},RGBA{Float64}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Shape{Float64, Float64}})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Stroke})
Base.precompile(Tuple{typeof(processMarkerArg),Dict{Symbol, Any},Symbol})
Base.precompile(Tuple{typeof(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}})
@@ -349,21 +357,37 @@ function _precompile_()
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(unzip),Vector{Tuple{Float64, Float64, Float64}}})
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Float64, Float64}}})
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Int64, Int64}}})
Base.precompile(Tuple{typeof(unzip),Vector{Tuple{Vector{Float64}, Vector{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#126")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#126")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64}},Float64,Bool})
isdefined(Plots, Symbol("#add_major_or_minor_segments#127")) && Base.precompile(Tuple{getfield(Plots, Symbol("#add_major_or_minor_segments#127")),Vector{Float64},Bool,Segments{Tuple{Float64, Float64, Float64}},Float64,Bool})
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,))
+1
View File
@@ -31,6 +31,7 @@ using Base.Meta
@reexport using PlotThemes
import Showoff
import StatsBase
import Downloads
import JSON
using Requires
+2 -1
View File
@@ -14,6 +14,7 @@ const _arg_desc = KW(
: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",
@@ -30,7 +31,7 @@ const _arg_desc = KW(
: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.",
: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`).",
+178 -106
View File
@@ -24,6 +24,14 @@ function add_aliases(sym::Symbol, aliases::Symbol...)
return nothing
end
function add_axes_aliases(sym::Symbol, aliases::Symbol...; generic::Bool = true)
sym in keys(_axis_defaults) || throw(ArgumentError("Invalid `$sym`"))
generic && add_aliases(sym, aliases...)
for letter in (:x, :y, :z)
add_aliases(Symbol(letter, sym), (Symbol(letter, a) for a in aliases)...)
end
end
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
for (k, v) in aliases
s = string(k)
@@ -276,7 +284,7 @@ function hasgrid(arg::Symbol, letter)
arg in (:all, :both, :on) || occursin(string(letter), string(arg))
else
@warn(
"Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead."
"Unknown grid argument $arg; $(get_attr_symbol(letter, :grid)) was set to `true` instead."
)
true
end
@@ -316,7 +324,7 @@ function showaxis(arg::Symbol, letter)
arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg))
else
@warn(
"Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead."
"Unknown showaxis argument $arg; $(get_attr_symbol(letter, :showaxis)) was set to `true` instead."
)
true
end
@@ -348,6 +356,7 @@ const _series_defaults = KW(
:fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match,
:fillalpha => nothing,
:fillstyle => nothing,
:markershape => :none,
:markercolor => :match,
:markeralpha => nothing,
@@ -570,11 +579,6 @@ function reset_axis_defaults_byletter!()
end
reset_axis_defaults_byletter!()
for letter in (:x, :y, :z), k in keys(_axis_defaults)
# allow the underscore version too: xguide or x_guide
add_aliases(Symbol(letter, k), Symbol(letter, "_", k))
end
const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults]
const _initial_defaults = deepcopy(_all_defaults)
@@ -619,6 +623,20 @@ const _all_subplot_args = sort(union([_subplot_args; _magic_subplot_args]))
const _all_series_args = sort(union([_series_args; _magic_series_args]))
const _all_plot_args = _plot_args
for letter in (:x, :y, :z)
_attrsymbolcache[letter] = Dict{Symbol,Symbol}()
for k in keys(_axis_defaults)
# populate attribute cache
lk = Symbol(letter, k)
_attrsymbolcache[letter][k] = lk
# allow the underscore version too: xguide or x_guide
add_aliases(lk, Symbol(letter, "_", k))
end
for k in (_magic_axis_args..., :(_discrete_indices))
_attrsymbolcache[letter][k] = Symbol(letter, k)
end
end
const _all_args =
sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args]))
@@ -754,30 +772,7 @@ add_aliases(
:fgcolour_subplot,
:fg_colour_subplot,
)
add_aliases(
:foreground_color_grid,
:fg_grid,
:fggrid,
:fgcolor_grid,
:fg_color_grid,
:foreground_grid,
:foreground_colour_grid,
:fgcolour_grid,
:fg_colour_grid,
:gridcolor,
)
add_aliases(
:foreground_color_minor_grid,
:fg_minor_grid,
:fgminorgrid,
:fgcolor_minorgrid,
:fg_color_minorgrid,
:foreground_minorgrid,
:foreground_colour_minor_grid,
:fgcolour_minorgrid,
:fg_colour_minor_grid,
:minorgridcolor,
)
add_aliases(
:foreground_color_title,
:fg_title,
@@ -845,7 +840,80 @@ add_aliases(:linealpha, :la, :lalpha, :lα, :lineopacity, :lopacity)
add_aliases(:markeralpha, :ma, :malpha, :mα, :markeropacity, :mopacity)
add_aliases(:markerstrokealpha, :msa, :msalpha, :msα, :markerstrokeopacity, :msopacity)
add_aliases(:fillalpha, :fa, :falpha, :fα, :fillopacity, :fopacity)
add_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
# axes attributes
add_axes_aliases(:guide, :label, :lab, :l; generic = false)
add_axes_aliases(:lims, :lim, :limit, :limits, :range)
add_axes_aliases(:ticks, :tick)
add_axes_aliases(:rotation, :rot, :r)
add_axes_aliases(:guidefontsize, :labelfontsize)
add_axes_aliases(:gridalpha, :ga, :galpha, :gα, :gridopacity, :gopacity)
add_axes_aliases(
:gridstyle,
:grid_style,
:gridlinestyle,
:grid_linestyle,
:grid_ls,
:gridls,
)
add_axes_aliases(
:foreground_color_grid,
:fg_grid,
:fggrid,
:fgcolor_grid,
:fg_color_grid,
:foreground_grid,
:foreground_colour_grid,
:fgcolour_grid,
:fg_colour_grid,
:gridcolor,
)
add_axes_aliases(
:foreground_color_minor_grid,
:fg_minor_grid,
:fgminorgrid,
:fgcolor_minorgrid,
:fg_color_minorgrid,
:foreground_minorgrid,
:foreground_colour_minor_grid,
:fgcolour_minorgrid,
:fg_colour_minor_grid,
:minorgridcolor,
)
add_axes_aliases(
:gridlinewidth,
:gridwidth,
:grid_linewidth,
:grid_width,
:gridlw,
:grid_lw,
)
add_axes_aliases(
:minorgridstyle,
:minorgrid_style,
:minorgridlinestyle,
:minorgrid_linestyle,
:minorgrid_ls,
:minorgridls,
)
add_axes_aliases(
:minorgridlinewidth,
:minorgridwidth,
:minorgrid_linewidth,
:minorgrid_width,
:minorgridlw,
:minorgrid_lw,
)
add_axes_aliases(
:tick_direction,
:tickdirection,
:tick_dir,
:tickdir,
:tick_orientation,
:tickorientation,
:tick_or,
:tickor,
)
# series attributes
add_aliases(:seriestype, :st, :t, :typ, :linetype, :lt)
@@ -864,19 +932,7 @@ add_aliases(:group, :g, :grouping)
add_aliases(:bins, :bin, :nbin, :nbins, :nb)
add_aliases(:ribbon, :rib)
add_aliases(:annotations, :ann, :anns, :annotate, :annotation)
add_aliases(:xguide, :xlabel, :xlab, :xl)
add_aliases(:xlims, :xlim, :xlimit, :xlimits, :xrange)
add_aliases(:xticks, :xtick)
add_aliases(:xrotation, :xrot, :xr)
add_aliases(:yguide, :ylabel, :ylab, :yl)
add_aliases(:ylims, :ylim, :ylimit, :ylimits, :yrange)
add_aliases(:yticks, :ytick)
add_aliases(:yrotation, :yrot, :yr)
add_aliases(:zguide, :zlabel, :zlab, :zl)
add_aliases(:zlims, :zlim, :zlimit, :zlimits)
add_aliases(:zticks, :ztick)
add_aliases(:zrotation, :zrot, :zr)
add_aliases(:guidefontsize, :labelfontsize)
add_aliases(
:fill_z,
:fillz,
@@ -945,24 +1001,7 @@ add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir)
add_aliases(:inset_subplots, :inset, :floating)
add_aliases(:stride, :wirefame_stride, :surface_stride, :surf_str, :str)
add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :grid_lw)
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
add_aliases(
:minorgridlinewidth,
:minorgridwidth,
:minorgrid_linewidth,
:minorgrid_width,
:minorgridlw,
:minorgrid_lw,
)
add_aliases(
:minorgridstyle,
:minorgrid_style,
:minorgridlinestyle,
:minorgrid_linestyle,
:minorgrid_ls,
:minorgridls,
)
add_aliases(
:framestyle,
:frame_style,
@@ -976,16 +1015,7 @@ add_aliases(
:border_style,
:border,
)
add_aliases(
:tick_direction,
:tickdirection,
:tick_dir,
:tickdir,
:tick_orientation,
:tickorientation,
:tick_or,
:tickor,
)
add_aliases(:camera, :cam, :viewangle, :view_angle)
add_aliases(:contour_labels, :contourlabels, :clabels, :clabs)
add_aliases(:warn_on_unsupported, :warn)
@@ -1117,6 +1147,7 @@ function processLineArg(plotattributes::AKW, arg)
arg.color == :auto ? :auto : plot_color(arg.color)
)
arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha)
arg.style === nothing || (plotattributes[:fillstyle] = arg.style)
elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows)
plotattributes[:arrow] = arg
@@ -1188,6 +1219,7 @@ function processFillArg(plotattributes::AKW, arg)
arg.color == :auto ? :auto : plot_color(arg.color)
)
arg.alpha === nothing || (plotattributes[:fillalpha] = arg.alpha)
arg.style === nothing || (plotattributes[:fillstyle] = arg.style)
elseif typeof(arg) <: Bool
plotattributes[:fillrange] = arg ? 0 : nothing
@@ -1213,69 +1245,79 @@ end
function processGridArg!(plotattributes::AKW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
plotattributes[Symbol(letter, :grid)] = hasgrid(arg, letter)
plotattributes[get_attr_symbol(letter, :grid)] = hasgrid(arg, letter)
elseif allStyles(arg)
plotattributes[Symbol(letter, :gridstyle)] = arg
plotattributes[get_attr_symbol(letter, :gridstyle)] = arg
elseif typeof(arg) <: Stroke
arg.width === nothing ||
(plotattributes[Symbol(letter, :gridlinewidth)] = arg.width)
(plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg.width)
arg.color === nothing || (
plotattributes[Symbol(letter, :foreground_color_grid)] =
plotattributes[get_attr_symbol(letter, :foreground_color_grid)] =
arg.color in (:auto, :match) ? :match : plot_color(arg.color)
)
arg.alpha === nothing || (plotattributes[Symbol(letter, :gridalpha)] = arg.alpha)
arg.style === nothing || (plotattributes[Symbol(letter, :gridstyle)] = arg.style)
arg.alpha === nothing ||
(plotattributes[get_attr_symbol(letter, :gridalpha)] = arg.alpha)
arg.style === nothing ||
(plotattributes[get_attr_symbol(letter, :gridstyle)] = arg.style)
# linealpha
elseif allAlphas(arg)
plotattributes[Symbol(letter, :gridalpha)] = arg
plotattributes[get_attr_symbol(letter, :gridalpha)] = arg
# linewidth
elseif allReals(arg)
plotattributes[Symbol(letter, :gridlinewidth)] = arg
plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg
# color
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_grid))
elseif !handleColors!(
plotattributes,
arg,
get_attr_symbol(letter, :foreground_color_grid),
)
@warn("Skipped grid arg $arg.")
end
end
function processMinorGridArg!(plotattributes::AKW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
plotattributes[Symbol(letter, :minorgrid)] = hasgrid(arg, letter)
plotattributes[get_attr_symbol(letter, :minorgrid)] = hasgrid(arg, letter)
elseif allStyles(arg)
plotattributes[Symbol(letter, :minorgridstyle)] = arg
plotattributes[Symbol(letter, :minorgrid)] = true
plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
elseif typeof(arg) <: Stroke
arg.width === nothing ||
(plotattributes[Symbol(letter, :minorgridlinewidth)] = arg.width)
(plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg.width)
arg.color === nothing || (
plotattributes[Symbol(letter, :foreground_color_minor_grid)] =
plotattributes[get_attr_symbol(letter, :foreground_color_minor_grid)] =
arg.color in (:auto, :match) ? :match : plot_color(arg.color)
)
arg.alpha === nothing ||
(plotattributes[Symbol(letter, :minorgridalpha)] = arg.alpha)
(plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg.alpha)
arg.style === nothing ||
(plotattributes[Symbol(letter, :minorgridstyle)] = arg.style)
plotattributes[Symbol(letter, :minorgrid)] = true
(plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg.style)
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
# linealpha
elseif allAlphas(arg)
plotattributes[Symbol(letter, :minorgridalpha)] = arg
plotattributes[Symbol(letter, :minorgrid)] = true
plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
# linewidth
elseif allReals(arg)
plotattributes[Symbol(letter, :minorgridlinewidth)] = arg
plotattributes[Symbol(letter, :minorgrid)] = true
plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
# color
elseif handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_minor_grid))
plotattributes[Symbol(letter, :minorgrid)] = true
elseif handleColors!(
plotattributes,
arg,
get_attr_symbol(letter, :foreground_color_minor_grid),
)
plotattributes[get_attr_symbol(letter, :minorgrid)] = true
else
@warn("Skipped grid arg $arg.")
end
@@ -1341,7 +1383,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
end
# handle axis args
for letter in (:x, :y, :z)
asym = Symbol(letter, :axis)
asym = get_attr_symbol(letter, :axis)
args = RecipesPipeline.pop_kw!(plotattributes, asym, ())
if !(typeof(args) <: Axis)
for arg in wraptuple(args)
@@ -1368,7 +1410,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :grid)
gridsym = get_attr_symbol(letter, :grid)
args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ())
for arg in wraptuple(args)
processGridArg!(plotattributes, arg, letter)
@@ -1383,7 +1425,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
end
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :minorgrid)
gridsym = get_attr_symbol(letter, :minorgrid)
args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ())
for arg in wraptuple(args)
processMinorGridArg!(plotattributes, arg, letter)
@@ -1394,16 +1436,20 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
args = RecipesPipeline.pop_kw!(plotattributes, fontname, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg)
end
end
end
# handle individual axes font args
for letter in (:x, :y, :z)
for fontname in (:tickfont, :guidefont)
args = RecipesPipeline.pop_kw!(plotattributes, Symbol(letter, fontname), ())
args = RecipesPipeline.pop_kw!(
plotattributes,
get_attr_symbol(letter, fontname),
(),
)
for arg in wraptuple(args)
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg)
end
end
end
@@ -1412,7 +1458,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
if haskey(plotattributes, k) && k !== :link
v = plotattributes[k]
for letter in (:x, :y, :z)
lk = Symbol(letter, k)
lk = get_attr_symbol(letter, k)
if !is_explicit(plotattributes, lk)
plotattributes[lk] = v
end
@@ -1502,6 +1548,11 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW)
plotattributes[:framestyle] = _framestyleAliases[plotattributes[:framestyle]]
end
# contours
if haskey(plotattributes, :levels)
check_contour_levels(plotattributes[:levels])
end
# warnings for moved recipes
st = get(plotattributes, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
@@ -1534,7 +1585,7 @@ function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes)
end
if !isempty(_to_warn) &&
!get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported])
get(plotattributes, :warn_on_unsupported, _plot_defaults[:warn_on_unsupported])
for k in sort(collect(_to_warn))
push!(already_warned, k)
@warn(
@@ -1629,6 +1680,26 @@ convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# -----------------------------------------------------------------------------
"""Throw an error if the `levels` keyword argument is not of the correct type
or `levels` is less than 1"""
function check_contour_levels(levels)
if !(levels isa Union{Integer,AVec})
throw(
ArgumentError(
"the levels keyword argument must be an integer or AbstractVector",
),
)
elseif levels isa Integer && levels <= 0
throw(
ArgumentError(
"must pass a positive number of contours to the levels keyword argument",
),
)
end
end
# -----------------------------------------------------------------------------
# 1-row matrices will give an element
# multi-row matrices will give a column
# InputWrapper just gives the contents
@@ -1894,7 +1965,8 @@ function _update_axis(
end
# then get those args that were passed with a leading letter: `xlabel = "X"`
lk = Symbol(letter, k)
lk = get_attr_symbol(letter, k)
if haskey(plotattributes_in, lk)
kw[k] = slice_arg(plotattributes_in[lk], subplot_index)
end
@@ -1951,7 +2023,7 @@ function _update_subplot_args(
lims_warned = false
for letter in (:x, :y, :z)
_update_axis(plt, sp, plotattributes_in, letter, subplot_index)
lk = Symbol(letter, :lims)
lk = get_attr_symbol(letter, :lims)
# warn against using `Range` in x,y,z lims
if !lims_warned &&
+32 -27
View File
@@ -23,7 +23,7 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
end
function get_axis(sp::Subplot, letter::Symbol)
axissym = Symbol(letter, :axis)
axissym = get_attr_symbol(letter, :axis)
if haskey(sp.attr, axissym)
sp.attr[axissym]
else
@@ -35,40 +35,44 @@ function process_axis_arg!(plotattributes::AKW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
plotattributes[Symbol(letter, :tickfont)] = arg
plotattributes[Symbol(letter, :guidefont)] = arg
plotattributes[get_attr_symbol(letter, :tickfont)] = arg
plotattributes[get_attr_symbol(letter, :guidefont)] = arg
elseif arg in _allScales
plotattributes[Symbol(letter, :scale)] = arg
plotattributes[get_attr_symbol(letter, :scale)] = arg
elseif arg in (:flip, :invert, :inverted)
plotattributes[Symbol(letter, :flip)] = true
plotattributes[get_attr_symbol(letter, :flip)] = true
elseif T <: AbstractString
plotattributes[Symbol(letter, :guide)] = arg
plotattributes[get_attr_symbol(letter, :guide)] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
plotattributes[Symbol(letter, sym)] = arg
plotattributes[get_attr_symbol(letter, sym)] = arg
# xticks/yticks
elseif T <: AVec
plotattributes[Symbol(letter, :ticks)] = arg
plotattributes[get_attr_symbol(letter, :ticks)] = arg
elseif arg === nothing
plotattributes[Symbol(letter, :ticks)] = []
plotattributes[get_attr_symbol(letter, :ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
plotattributes[Symbol(letter, :showaxis)] = showaxis(arg, letter)
plotattributes[get_attr_symbol(letter, :showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number
plotattributes[Symbol(letter, :rotation)] = arg
plotattributes[get_attr_symbol(letter, :rotation)] = arg
elseif typeof(arg) <: Function
plotattributes[Symbol(letter, :formatter)] = arg
plotattributes[get_attr_symbol(letter, :formatter)] = arg
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
elseif !handleColors!(
plotattributes,
arg,
get_attr_symbol(letter, :foreground_color_axis),
)
@warn("Skipped $(letter)axis arg $arg")
end
end
@@ -297,7 +301,7 @@ for l in (:x, :y, :z)
end
end
# get_ticks from axis symbol :x, :y, or :z
get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[Symbol(s, :axis)])
get_ticks(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}
@@ -393,7 +397,7 @@ end
function reset_extrema!(sp::Subplot)
for asym in (:x, :y, :z)
sp[Symbol(asym, :axis)][:extrema] = Extrema()
sp[get_attr_symbol(asym, :axis)][:extrema] = Extrema()
end
for series in sp.series_list
expand_extrema!(sp, series.plotattributes)
@@ -446,7 +450,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
)
data = [NaN]
end
axis = sp[Symbol(letter, "axis")]
axis = sp[get_attr_symbol(letter, :axis)]
if isa(data, Volume)
expand_extrema!(sp[:xaxis], data.x_extents)
@@ -463,7 +467,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
plotattributes[letter], plotattributes[Symbol(letter, "_discrete_indices")] =
plotattributes[letter],
plotattributes[get_attr_symbol(letter, :(_discrete_indices))] =
discrete_value!(axis, data)
expand_extrema!(axis, plotattributes[letter])
end
@@ -502,7 +507,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
plotattributes[:bar_width] =
_bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(data))))
end
axis = sp.attr[Symbol(dsym, :axis)]
axis = sp.attr[get_attr_symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end
@@ -511,8 +516,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW)
if plotattributes[:seriestype] == :heatmap
for letter in (:x, :y)
data = plotattributes[letter]
axis = sp[Symbol(letter, "axis")]
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
axis = sp[get_attr_symbol(letter, :axis)]
scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
@@ -586,10 +591,10 @@ end
function axis_limits(
sp,
letter,
should_widen = default_should_widen(sp[Symbol(letter, :axis)]),
should_widen = default_should_widen(sp[get_attr_symbol(letter, :axis)]),
consider_aspect = true,
)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
ex = axis[:extrema]
amin, amax = ex.emin, ex.emax
lims = axis[:lims]
@@ -724,10 +729,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 = Symbol(letter, :axis)
asym = get_attr_symbol(letter, :axis)
isy = letter === :y
oletter = isy ? :x : :y
oasym = Symbol(oletter, :axis)
oasym = get_attr_symbol(oletter, :axis)
# get axis objects, ticks and minor ticks
ax, oax = sp[asym], sp[oasym]
@@ -856,9 +861,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[Symbol(letter, :axis)]
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
ax = sp[get_attr_symbol(letter, :axis)]
nax = sp[get_attr_symbol(near_letter, :axis)]
fax = sp[get_attr_symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
+48 -8
View File
@@ -247,7 +247,7 @@ function merge_with_base_supported(v::AVec)
for vi in v
if haskey(_axis_defaults, vi)
for letter in (:x, :y, :z)
push!(v, Symbol(letter, vi))
push!(v, get_attr_symbol(letter, vi))
end
end
end
@@ -402,6 +402,7 @@ const _gr_attr = merge_with_base_supported([
:tick_direction,
:camera,
:contour_labels,
:connections,
])
const _gr_seriestype = [
:path,
@@ -521,6 +522,7 @@ const _plotly_attr = merge_with_base_supported([
:tick_direction,
:camera,
:contour_labels,
:connections,
])
const _plotly_seriestype = [
@@ -777,6 +779,7 @@ const _pyplot_attr = merge_with_base_supported([
:tick_direction,
:camera,
:contour_labels,
:connections,
])
const _pyplot_seriestype = [
:path,
@@ -793,6 +796,7 @@ const _pyplot_seriestype = [
:contour3d,
:path3d,
:scatter3d,
:mesh3d,
:surface,
:wireframe,
]
@@ -860,6 +864,7 @@ const _gaston_attr = merge_with_base_supported([
# :framestyle,
# :camera,
# :contour_labels,
:connections,
])
const _gaston_seriestype = [
@@ -910,16 +915,22 @@ const _gaston_scale = [:identity, :ln, :log2, :log10]
# unicodeplots
const _unicodeplots_attr = merge_with_base_supported([
:annotations,
:bins,
:guide,
# :grid,
:label,
:layout,
:legend,
:seriescolor,
:seriesalpha,
:lims,
:linealpha,
:linecolor,
:linestyle,
:markershape,
:bins,
:seriesalpha,
:seriescolor,
:scale,
:title,
:guide,
:lims,
])
const _unicodeplots_seriestype = [
:path,
@@ -928,11 +939,39 @@ const _unicodeplots_seriestype = [
# :bar,
:shape,
:histogram2d,
:heatmap,
:spy,
]
const _unicodeplots_style = [:auto, :solid]
const _unicodeplots_marker = [:none, :auto, :circle]
const _unicodeplots_scale = [:identity]
const _unicodeplots_marker = [
:none,
:auto,
:pixel,
# vvvvvvvvvv shapes
:circle,
:rect,
:star5,
:diamond,
:hexagon,
:cross,
:xcross,
:utriangle,
:dtriangle,
:rtriangle,
:ltriangle,
:pentagon,
# :heptagon,
# :octagon,
:star4,
:star6,
# :star7,
:star8,
:vline,
:hline,
:+,
:x,
]
const _unicodeplots_scale = [:identity, :ln, :log2, :log10]
# Additional constants
const _canvas_type = Ref(:auto)
@@ -1233,6 +1272,7 @@ const _pgfplotsx_attr = merge_with_base_supported([
:tick_direction,
:camera,
:contour_labels,
:connections,
])
const _pgfplotsx_seriestype = [
:path,
+5 -5
View File
@@ -331,7 +331,7 @@ end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
style = []
kw = KW()
@@ -342,7 +342,7 @@ function pgf_axis(sp::Subplot, letter)
framestyle = pgf_framestyle(sp[:framestyle])
# axis guide
kw[Symbol(letter, :label)] = axis[:guide]
kw[get_attr_symbol(letter, :label)] = axis[:guide]
# axis label position
labelpos = ""
@@ -378,7 +378,7 @@ function pgf_axis(sp::Subplot, letter)
# scale
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
kw[Symbol(letter, :mode)] = "log"
kw[get_attr_symbol(letter, :mode)] = "log"
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
end
@@ -400,8 +400,8 @@ function pgf_axis(sp::Subplot, letter)
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]
kw[get_attr_symbol(letter, :min)] = lims[1]
kw[get_attr_symbol(letter, :max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none
+11 -4
View File
@@ -225,13 +225,13 @@ function gaston_add_series(plt::Plot{GastonBackend}, series::Series)
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, nothing, sc))
push!(curves, Gaston.Curve(x[rng], y[rng], nothing, fr, sc))
end
end
else
@@ -304,8 +304,15 @@ function gaston_seriesconf!(
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 series[:markershape] == :none # simplepath
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)
@@ -365,7 +372,7 @@ function gaston_parse_axes_args(
for letter in (:x, :y, :z)
(letter == :z && dims == 2) && continue
axis = sp.attr[Symbol(letter, :axis)]
axis = sp.attr[get_attr_symbol(letter, :axis)]
# label names
push!(
axesconf,
+127 -61
View File
@@ -136,6 +136,12 @@ gr_set_arrowstyle(s::Symbol) = GR.setarrowstyle(
),
)
gr_set_fillstyle(::Nothing) = GR.setfillintstyle(GR.INTSTYLE_SOLID)
function gr_set_fillstyle(s::Symbol)
GR.setfillintstyle(GR.INTSTYLE_HATCH)
GR.setfillstyle(get(((/) = 9, (\) = 10, (|) = 7, (-) = 8, (+) = 11, (x) = 6), s, 9))
end
# --------------------------------------------------------------------------------------
# draw line segments, splitting x/y into contiguous/finite segments
@@ -664,32 +670,20 @@ function gr_display(plt::Plot, fmt = "")
end
function gr_set_tickfont(sp, letter)
axis = sp[Symbol(letter, :axis)]
# invalidate alignment changes for small rotations (|θ| < 45°)
trigger(rot) = abs(sind(rot)) < abs(cosd(rot)) ? 0 : sign(rot)
rot = axis[:rotation]
if letter === :x || (RecipesPipeline.is3d(sp) && letter === :y)
halign = (:left, :hcenter, :right)[trigger(rot) + 2]
valign = (axis[:mirror] ? :bottom : :top, :vcenter)[trigger(abs(rot)) + 1]
else
halign = (axis[:mirror] ? :left : :right, :hcenter)[trigger(abs(rot)) + 1]
valign = (:top, :vcenter, :bottom)[trigger(rot) + 2]
end
axis = sp[get_attr_symbol(letter, :axis)]
gr_set_font(
tickfont(axis),
sp,
halign = halign,
valign = valign,
rotation = axis[:rotation],
color = axis[:tickfontcolor],
)
end
# size of the text with no rotation
function gr_text_size(str)
GR.savestate()
GR.selntran(0)
GR.setcharup(0, 1)
xs, ys = gr_inqtext(0, 0, string(str))
l, r = extrema(xs)
b, t = extrema(ys)
@@ -699,9 +693,11 @@ function gr_text_size(str)
return w, h
end
# size of the text with rotation applied
function gr_text_size(str, rot)
GR.savestate()
GR.selntran(0)
GR.setcharup(0, 1)
xs, ys = gr_inqtext(0, 0, string(str))
l, r = extrema(xs)
b, t = extrema(ys)
@@ -714,12 +710,21 @@ end
text_box_width(w, h, rot) = abs(cosd(rot)) * w + abs(cosd(rot + 90)) * h
text_box_height(w, h, rot) = abs(sind(rot)) * w + abs(sind(rot + 90)) * h
function gr_get_3d_axis_angle(cvs, nt, ft, letter)
length(cvs) < 2 && return 0
tickpoints = [gr_w3tondc(sort_3d_axes(cv, nt, ft, letter)...) for cv cvs]
dx = tickpoints[2][1] - tickpoints[1][1]
dy = tickpoints[2][2] - tickpoints[1][2]
return atand(dy, dx)
end
function gr_get_ticks_size(ticks, rot)
w, h = 0.0, 0.0
for (cv, dv) in zip(ticks...)
wi, hi = gr_text_size(dv, rot)
w = max(w, wi)
h = max(h, hi)
w = NaNMath.max(w, wi)
h = NaNMath.max(h, hi)
end
return w, h
end
@@ -1058,7 +1063,9 @@ function gr_add_legend(sp, leg, viewport_plotarea)
series[:ribbon] === nothing
)
fc = get_fillcolor(series, clims)
gr_set_fill(fc) #, series[:fillalpha])
gr_set_fill(fc)
fs = get_fillstyle(series, i)
gr_set_fillstyle(fs)
l, r = xpos - leg.width_factor * 3.5, xpos - leg.width_factor / 2
b, t = ypos - 0.4 * leg.dy, ypos + 0.4 * leg.dy
x = [l, r, r, l, l]
@@ -1448,7 +1455,7 @@ end
function gr_draw_axis(sp, letter, viewport_plotarea)
ax = axis_drawing_info(sp, letter)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
# draw segments
gr_draw_grid(sp, axis, ax.grid_segments)
@@ -1464,7 +1471,7 @@ end
function gr_draw_axis_3d(sp, letter, viewport_plotarea)
ax = axis_drawing_info_3d(sp, letter)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
# draw segments
gr_draw_grid(sp, axis, ax.grid_segments, gr_polyline3d)
@@ -1545,20 +1552,42 @@ function gr_draw_ticks(sp, axis, segments, func = gr_polyline)
end
function gr_label_ticks(sp, letter, ticks)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
isy = letter === :y
oletter = isy ? :x : :y
oaxis = sp[Symbol(oletter, :axis)]
oaxis = sp[get_attr_symbol(oletter, :axis)]
oamin, oamax = axis_limits(sp, oletter)
gr_set_tickfont(sp, letter)
out_factor = ifelse(axis[:tick_direction] === :out, 1.5, 1)
x_offset = isy ? -1.5e-2 * out_factor : 0
y_offset = isy ? 0 : -8e-3 * out_factor
x_base_offset = isy ? -1.5e-2 * out_factor : 0
y_base_offset = isy ? 0 : -8e-3 * out_factor
rot = axis[:rotation] % 360
ov = sp[:framestyle] == :origin ? 0 : xor(oaxis[:flip], axis[:mirror]) ? oamax : oamin
sgn = axis[:mirror] ? -1 : 1
sgn2 = iseven(Int(floor(rot / 90))) ? -1 : 1
sgn3 = if isy
-360 < rot < -180 || 0 < rot < 180 ? 1 : -1
else
rot < -270 || -90 < rot < 90 || rot > 270 ? 1 : -1
end
for (cv, dv) in zip(ticks...)
x, y = GR.wctondc(reverse_if((cv, ov), isy)...)
sz_rot = gr_text_size(dv, rot)
sz = gr_text_size(dv)
x_offset = x_base_offset
y_offset = y_base_offset
if isy
x_offset += -first(sz_rot) / 2
if rot % 90 != 0
y_offset += sgn2 * last(sz_rot) / 2 + sgn3 * last(sz) * cosd(rot) / 2
end
else
if rot % 90 != 0
x_offset += sgn2 * first(sz_rot) / 2 + sgn3 * last(sz) * sind(rot) / 2
end
y_offset += -last(sz_rot) / 2
end
gr_text(x + sgn * x_offset, y + sgn * y_offset, dv)
end
end
@@ -1569,19 +1598,22 @@ function gr_label_ticks_3d(sp, letter, ticks)
near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x
ax = sp[Symbol(letter, :axis)]
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
isy = letter === :y
isz = letter === :z
ax = sp[get_attr_symbol(letter, :axis)]
nax = sp[get_attr_symbol(near_letter, :axis)]
fax = sp[get_attr_symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
famin, famax = axis_limits(sp, far_letter)
n0, n1 = letter === :y ? (namax, namin) : (namin, namax)
n0, n1 = isy ? (namax, namin) : (namin, namax)
# find out which axes we are dealing with
i = findfirst(==(letter), (:x, :y, :z))
letters = axes_shift((:x, :y, :z), 1 - i)
asyms = Symbol.(letters, :axis)
asyms = get_attr_symbol.(letters, :axis)
# get axis objects, ticks and minor ticks
# regardless of the `letter` we now use the convention that `x` in variable names refer to
@@ -1593,32 +1625,57 @@ function gr_label_ticks_3d(sp, letter, ticks)
nt = sp[:framestyle] == :origin ? 0 : ax[:mirror] ? n1 : n0
ft = sp[:framestyle] == :origin ? 0 : ax[:mirror] ? famax : famin
xoffset = if letter === :x
(sp[:yaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:xaxis][:tick_direction] == :out ? 1.5 : 1)
elseif letter === :y
(sp[:yaxis][:mirror] ? -1 : 1) * 1e-2 * (sp[:yaxis][:tick_direction] == :out ? 1.5 : 1)
else
(sp[:zaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:zaxis][:tick_direction] == :out ? 1.5 : 1)
end
yoffset = if letter === :x
(sp[:xaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:xaxis][:tick_direction] == :out ? 1.5 : 1)
elseif letter === :y
(sp[:yaxis][:mirror] ? 1 : -1) * 1e-2 * (sp[:yaxis][:tick_direction] == :out ? 1.5 : 1)
else
0
end
rot = mod(ax[:rotation], 360)
sgn = ax[:mirror] ? -1 : 1
cvs, dvs = ticks
ax[:flip] && reverse!(cvs)
axisθ = isz ? 270 : mod(gr_get_3d_axis_angle(cvs, nt, ft, letter), 360) # issue: doesn't work with 1 tick
axisϕ = mod(axisθ - 90, 360)
out_factor = ifelse(ax[:tick_direction] === :out, 1.5, 1)
axisoffset = out_factor * 1.2e-2
x_base_offset = axisoffset * cosd(axisϕ)
y_base_offset = axisoffset * sind(axisϕ)
sgn2a = sgn2b = sgn3 = 0
if axisθ != 0 || rot % 90 != 0
sgn2a = (axisθ != 90) &&
(axisθ == 0 && (rot < 90 || 180 rot < 270)) ||
(axisθ == 270) ||
(axisθ < 90 && (axisθ < rot < 90 || axisθ + 180 < rot < 270)) ||
(axisθ > 270 && (rot < 90 || axisθ - 180 < rot < 270 || rot > axisθ)) ? -1 : 1
end
if (axisθ - 90) % 180 != 0 || (rot - 90) % 180 != 0
sgn2b = axisθ == 0 ||
(axisθ == 90 && (90 rot < 180 || 270 rot < 360)) ||
(axisθ == 270 && (rot < 90 || 180 rot < 270)) ||
(axisθ < 90 && (axisθ < rot < 180 || axisθ + 180 < rot)) ||
(axisθ > 270 && (rot < axisθ - 180 || 180 rot < axisθ)) ? -1 : 1
end
if !(axisθ == 0 && rot % 180 == 0) && ((rot - 90) % 180 != 0)
sgn3 = (axisθ == 0 && 90 < rot < 270) ||
(axisθ == 90 && rot < 180) ||
(axisθ == 270 && rot > 180) ||
(axisθ < 90 && (rot < axisθ || 90 rot < 180 || axisθ + 180 < rot < 270)) ||
(axisθ > 270 && (90 rot < axisθ - 180 || 180 rot < 270 || rot > axisθ)) ? -1 : 1
end
for (cv, dv) in zip((cvs, dvs)...)
xi, yi = gr_w3tondc(sort_3d_axes(cv, nt, ft, letter)...)
gr_text(xi + xoffset, yi + yoffset, dv)
sz_rot = gr_text_size(dv, rot)
sz = gr_text_size(dv)
x_offset = x_base_offset + sgn2a * first(sz_rot) / 2 + sgn3 * last(sz) * sind(rot) / 2
y_offset = y_base_offset + sgn2b * last(sz_rot) / 2 + sgn3 * last(sz) * cosd(rot) / 2
gr_text(xi + sgn * x_offset, yi + sgn * y_offset, dv)
end
end
function gr_label_axis(sp, letter, viewport_plotarea)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
mirror = axis[:mirror]
# guide
if axis[:guide] != ""
@@ -1662,13 +1719,13 @@ function gr_label_axis(sp, letter, viewport_plotarea)
end
function gr_label_axis_3d(sp, letter)
ax = sp[Symbol(letter, :axis)]
ax = sp[get_attr_symbol(letter, :axis)]
if ax[:guide] != ""
near_letter = letter in (:x, :z) ? :y : :x
far_letter = letter in (:x, :y) ? :z : :x
nax = sp[Symbol(near_letter, :axis)]
fax = sp[Symbol(far_letter, :axis)]
nax = sp[get_attr_symbol(near_letter, :axis)]
fax = sp[get_attr_symbol(far_letter, :axis)]
amin, amax = axis_limits(sp, letter)
namin, namax = axis_limits(sp, near_letter)
@@ -1824,6 +1881,8 @@ function gr_draw_segments(series, x, y, fillrange, clims)
i, rng = segment.attr_index, segment.range
fc = get_fillcolor(series, clims, i)
gr_set_fillcolor(fc)
fs = get_fillstyle(series, i)
gr_set_fillstyle(fs)
fx = _cycle(x, vcat(rng, reverse(rng)))
fy = vcat(_cycle(fr_from, rng), _cycle(fr_to, reverse(rng)))
gr_set_transparency(fc, get_fillalpha(series, i))
@@ -1912,6 +1971,8 @@ function gr_draw_shapes(series, clims)
# draw the interior
fc = get_fillcolor(series, clims, i)
gr_set_fill(fc)
fs = get_fillstyle(series, i)
gr_set_fillstyle(fs)
gr_set_transparency(fc, get_fillalpha(series, i))
GR.fillarea(xseg, yseg)
@@ -1947,19 +2008,23 @@ function gr_draw_surface(series, x, y, z, clims)
e_kwargs = series[:extra_kwargs]
st = series[:seriestype]
if st === :surface
fillalpha = get_fillalpha(series)
fillcolor = get_fillcolor(series)
# NOTE: setting nx = 0 or ny = 0 disables GR.gridit interpolation
nx, ny = get(e_kwargs, :nx, 200), get(e_kwargs, :ny, 200)
if length(x) == length(y) == length(z) && nx > 0 && ny > 0
x, y, z = GR.gridit(x, y, z, nx, ny)
end
d_opt = get(e_kwargs, :display_option, GR.OPTION_COLORED_MESH)
if (!isnothing(fillalpha) && fillalpha < 1) || alpha(first(fillcolor)) < 1
gr_set_transparency(fillcolor, fillalpha)
GR.surface(x, y, z, d_opt)
if ndims(x) == ndims(y) == ndims(z) == 2
GR.gr3.surface(x', y', z, GR.OPTION_3D_MESH)
else
GR.gr3.surface(x, y, z, d_opt)
fillalpha = get_fillalpha(series)
fillcolor = get_fillcolor(series)
# NOTE: setting nx = 0 or ny = 0 disables GR.gridit interpolation
nx, ny = get(e_kwargs, :nx, 200), get(e_kwargs, :ny, 200)
if length(x) == length(y) == length(z) && nx > 0 && ny > 0
x, y, z = GR.gridit(x, y, z, nx, ny)
end
d_opt = get(e_kwargs, :display_option, GR.OPTION_COLORED_MESH)
if (!isnothing(fillalpha) && fillalpha < 1) || alpha(first(fillcolor)) < 1
gr_set_transparency(fillcolor, fillalpha)
GR.surface(x, y, z, d_opt)
else
GR.gr3.surface(x, y, z, d_opt)
end
end
elseif st === :wireframe
GR.setfillcolorind(0)
@@ -2068,3 +2133,4 @@ function _display(plt::Plot{GRBackend})
end
closeall(::GRBackend) = GR.emergencyclosegks()
+48 -13
View File
@@ -203,7 +203,7 @@ function (pgfx_plot::PGFPlotsXPlot)(plt::Plot{PGFPlotsXBackend})
if hascolorbar(sp)
cticks = get_colorbar_ticks(sp)[2]
colorbar_style = PGFPlotsX.Options("title" => sp[:colorbar_title])
colorbar_style = PGFPlotsX.Options("ylabel" => sp[:colorbar_title])
if sp[:colorbar] === :top
push!(
colorbar_style,
@@ -512,10 +512,29 @@ 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 ",
)
if opt[:connections] isa Tuple{Array,Array,Array}
# 0-based indexing
ptable = join(
[string(i, " ", j, " ", k, "\\\\") for (i, j, k) in zip(opt[:connections]...)],
"\n ",
)
elseif typeof(opt[:connections]) <: AbstractVector{NTuple{3,Int}}
# 1-based indexing
ptable = join(
[
string(i - 1, " ", j - 1, " ", k - 1, "\\\\") for
(i, j, k) in opt[:connections]
],
"\n ",
)
else
throw(
ArgumentError(
"Argument connections has to be either a tuple of three arrays (0-based indexing)
or an AbstractVector{NTuple{3,Int}} (1-based indexing).",
),
)
end
push!(
series_opt,
"patch" => nothing,
@@ -1174,6 +1193,12 @@ function pgfx_sanitize_plot!(plt)
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)
end
end
end
end
end
@@ -1194,7 +1219,7 @@ function pgfx_sanitize_plot!(plt)
end
# --------------------------------------------------------------------------------------
function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
axis = sp[Symbol(letter, :axis)]
axis = sp[get_attr_symbol(letter, :axis)]
# turn off scaled ticks
push!(opt, "scaled $(letter) ticks" => "false", string(letter, :label) => axis[:guide])
@@ -1232,6 +1257,12 @@ 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)),
"color" => cstr,
"draw opacity" => α,
@@ -1279,21 +1310,25 @@ function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter)
push!(opt, string(letter, "tick") => string("{", join(tick_values, ","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = Vector{String}(undef, length(ticks[2]))
tick_labels = similar(ticks[2])
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
tick_labels[i] = string(base, "^", power)
end
push!(
opt,
string(letter, "ticklabels") =>
string("{\$", join(tick_labels, "\$,\$"), "\$}"),
)
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
elseif axis[:showaxis]
tick_labels =
ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
if axis[:formatter] in (:scientific, :auto)
if axis[:formatter] in (:scientific, :auto) && tick_labels isa Vector{String}
tick_labels = string.("\$", convert_sci_unicode.(tick_labels), "\$")
tick_labels = replace.(tick_labels, Ref("×" => "\\times"))
end
+43 -8
View File
@@ -362,6 +362,7 @@ end
function plotly_legend_pos(pos::Symbol)
xleft = 0.07
xright = 1.0
ybot = 0.07
ytop = 1.0
xcenter = 0.55
@@ -372,14 +373,14 @@ 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"),
right = (coords = [xright, 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"),
bottomright = (coords = [xright, ybot], xanchor = "right", yanchor = "bottom"),
topright = (coords = [xright, ytop], xanchor = "right", yanchor = "top"),
topleft = (coords = [xleft, ytop], 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"),
@@ -400,7 +401,7 @@ function plotly_legend_pos(pos::Symbol)
xanchor = "lower",
yanchor = "right",
),
default = (coords = [1.0, 1.0], xanchor = "auto", yanchor = "auto"),
default = (coords = [xright, ytop], xanchor = "auto", yanchor = "auto"),
)
legend_position =
@@ -499,7 +500,7 @@ function plotly_close_shapes(x, y)
end
function plotly_data(series::Series, letter::Symbol, data)
axis = series[:subplot][Symbol(letter, :axis)]
axis = series[:subplot][get_attr_symbol(letter, :axis)]
data = if axis[:ticks] == :native && data !== nothing
plotly_native_data(axis, data)
@@ -617,11 +618,34 @@ function plotly_series(plt::Plot, series::Series)
filled = isfilledcontour(series)
plotattributes_out[:type] = "contour"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
plotattributes_out[:ncontours] = series[:levels] + 2
plotattributes_out[:contours] = KW(
:coloring => filled ? "fill" : "lines",
:showlabels => series[:contour_labels] == true,
)
# 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[:showscale] = hascolorbar(sp) && hascolorbar(series)
@@ -655,6 +679,7 @@ function plotly_series(plt::Plot, series::Series)
if series[:connections] !== nothing
if typeof(series[:connections]) <: Tuple{Array,Array,Array}
# 0-based indexing
i, j, k = series[:connections]
if !(length(i) == length(j) == length(k))
throw(
@@ -666,10 +691,20 @@ function plotly_series(plt::Plot, series::Series)
plotattributes_out[:i] = i
plotattributes_out[:j] = j
plotattributes_out[:k] = k
elseif typeof(series[:connections]) <: AbstractVector{NTuple{3,Int}}
# 1-based indexing
i, j, k = broadcast(
i -> [inds[i] - 1 for inds in series[:connections]],
(1, 2, 3),
)
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.",
"Argument connections has to be either a tuple of three arrays (0-based indexing)
or an AbstractVector{NTuple{3,Int}} (1-based indexing).",
),
)
end
+246 -112
View File
@@ -24,11 +24,30 @@ pycollections = PyPlot.pyimport("matplotlib.collections")
pyart3d = PyPlot.art3D
pyrcparams = PyPlot.PyDict(PyPlot.matplotlib."rcParams")
# "support" matplotlib v1.5
# "support" matplotlib v3.4
if PyPlot.version < v"3.4"
@warn("""You are using Matplotlib $(PyPlot.version), which is no longer
officialy supported by the Plots community. To ensure smooth Plots.jl
integration update your Matplotlib library to a version >= 3.4.0
If you have used Conda.jl to install PyPlot (default installation),
upgrade your matplotlib via Conda.jl and rebuild the PyPlot.
If you are not sure, here are the default instructions:
In Julia REPL:
```
import Pkg;
Pkg.add("Conda")
import Conda
Conda.update()
Pkg.build("PyPlot")
```
""")
end
set_facecolor_sym = if PyPlot.version < v"2"
@warn(
"You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0"
)
:set_axis_bgcolor
else
:set_facecolor
@@ -60,6 +79,14 @@ end
# # anything else just gets a bluesred gradient
# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
for k in (:linthresh, :base, :label)
# add PyPlot specific symbols to cache
_attrsymbolcache[k] = Dict{Symbol,Symbol}()
for letter in (:x, :y, :z, Symbol(""), :top, :bottom, :left, :right)
_attrsymbolcache[k][letter] = Symbol(k, letter)
end
end
py_handle_surface(v) = v
py_handle_surface(z::Surface) = z.surf
@@ -162,6 +189,25 @@ function py_fillstepstyle(seriestype::Symbol)
return nothing
end
py_fillstyle(::Nothing) = nothing
py_fillstyle(fillstyle::Symbol) = string(fillstyle)
function py_get_matching_math_font(parent_fontfamily)
# matplotlib supported math fonts according to
# https://matplotlib.org/stable/tutorials/text/mathtext.html
py_math_supported_fonts = Dict{String,String}(
"sans-serif" => "dejavusans",
"serif" => "dejavuserif",
"cm" => "cm",
"stix" => "stix",
"stixsans" => "stixsans",
)
# Fallback to "dejavusans" or "dejavuserif" in case the parentfont is different
# from supported by matplotlib fonts
matching_font(font) = occursin("serif", lowercase(font)) ? "dejavuserif" : "dejavusans"
return get(py_math_supported_fonts, parent_fontfamily, matching_font(parent_fontfamily))
end
# # untested... return a FontProperties object from a Plots.Font
# function py_font(font::Font)
# pyfont["FontProperties"](
@@ -390,8 +436,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
elseif isvector(levels)
extrakw[:levels] = levels
()
else
error("Only numbers and vectors are supported with levels keyword")
end
# add custom frame shapes to markershape?
@@ -654,6 +698,50 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
end
if st == :mesh3d
polygons = if series[:connections] isa AbstractVector{<:AbstractVector{Int}}
# Combination of any polygon types
broadcast(inds -> broadcast(i -> [x[i], y[i], z[i]], inds), series[:connections])
elseif series[:connections] isa AbstractVector{NTuple{N,Int}} where {N}
# Only N-gons - connections have to be 1-based (indexing)
broadcast(inds -> broadcast(i -> [x[i], y[i], z[i]], inds), series[:connections])
elseif series[:connections] isa NTuple{3,<:AbstractVector{Int}}
# Only triangles - connections have to be 0-based (indexing)
ci, cj, ck = series[:connections]
if !(length(ci) == length(cj) == length(ck))
throw(
ArgumentError(
"Argument connections must consist of equally sized arrays.",
),
)
end
broadcast(
j -> broadcast(i -> [x[i], y[i], z[i]], [ci[j] + 1, cj[j] + 1, ck[j] + 1]),
eachindex(ci),
)
else
throw(
ArgumentError(
"Unsupported `:connections` type $(typeof(series[:connections])) for seriestype=$st",
),
)
end
col = mplot3d.art3d.Poly3DCollection(
polygons,
linewidths = py_thickness_scale(plt, series[:linewidth]),
edgecolor = py_color(get_linecolor(series)),
facecolor = py_color(series[:fillcolor]),
alpha = get_fillalpha(series),
zorder = series[:series_plotindex],
)
handle = ax."add_collection3d"(col)
# Fix for handle: https://stackoverflow.com/questions/54994600/pyplot-legend-poly3dcollection-object-has-no-attribute-edgecolors2d
# It seems there aren't two different alpha values for edge and face
handle._facecolors2d = py_color(series[:fillcolor])
handle._edgecolors2d = py_color(get_linecolor(series))
push!(handles, handle)
end
if st == :image
xmin, xmax = ignorenan_extrema(series[:x])
ymin, ymax = ignorenan_extrema(series[:y])
@@ -711,24 +799,45 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
for segment in series_segments(series)
i, rng = segment.attr_index, segment.range
if length(rng) > 1
lc = get_linecolor(series, clims, i)
la = get_linealpha(series, i)
ls = get_linestyle(series, i)
fc = get_fillcolor(series, clims, i)
fa = get_fillalpha(series, i)
fs = get_fillstyle(series, i)
has_fs = !isnothing(fs)
path = pypath."Path"(hcat(x[rng], y[rng]))
# shape outline (and potentially solid fill)
patches = pypatches."PathPatch"(
path;
label = series[:label],
zorder = series[:series_plotindex],
edgecolor = py_color(
get_linecolor(series, clims, i),
get_linealpha(series, i),
),
facecolor = py_color(
get_fillcolor(series, clims, i),
get_fillalpha(series, i),
),
edgecolor = py_color(lc, la),
facecolor = py_color(fc, has_fs ? 0 : fa),
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
linestyle = py_linestyle(st, get_linestyle(series, i)),
fill = true,
linestyle = py_linestyle(st, ls),
fill = !has_fs,
)
push!(handle, ax."add_patch"(patches))
# shape hatched fill
# hatch color/alpha are controlled by edge (not face) color/alpha
if has_fs
patches = pypatches."PathPatch"(
path;
label = "",
zorder = series[:series_plotindex],
edgecolor = py_color(fc, fa),
facecolor = py_color(fc, 0), # don't fill with solid background
hatch = py_fillstyle(fs),
linewidth = 0, # don't replot shape outline (doesn't affect hatch linewidth)
linestyle = py_linestyle(st, ls),
fill = false,
)
push!(handle, ax."add_patch"(patches))
end
end
end
push!(handles, handle)
@@ -756,16 +865,23 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng)
end
la = get_linealpha(series, i)
fc = get_fillcolor(series, clims, i)
fa = get_fillalpha(series, i)
fs = get_fillstyle(series, i)
has_fs = !isnothing(fs)
handle = getproperty(ax, f)(
args...,
trues(n),
false,
py_fillstepstyle(st);
zorder = series[:series_plotindex],
facecolor = py_color(
get_fillcolor(series, clims, i),
get_fillalpha(series, i),
),
# hatch color/alpha are controlled by edge (not face) color/alpha
# if has_fs, set edge color/alpha <- fill color/alpha and face alpha <- 0
edgecolor = py_color(fc, has_fs ? fa : la),
facecolor = py_color(fc, has_fs ? 0 : fa),
hatch = py_fillstyle(fs),
linewidths = 0,
)
push!(handles, handle)
@@ -787,22 +903,13 @@ function py_set_lims(ax, sp::Subplot, axis::Axis)
getproperty(ax, Symbol("set_", letter, "lim"))(lfrom, lto)
end
function py_surround_latextext(latexstring, env)
if !isempty(latexstring) && latexstring[1] == '$' && latexstring[end] == '$'
unenclosed = latexstring[2:(end - 1)]
else
unenclosed = latexstring
end
PyPlot.LaTeXStrings.latexstring(env, "{", unenclosed, "}")
end
function py_set_ticks(sp, ax, ticks, letter, env)
function py_set_ticks(sp, ax, ticks, letter)
ticks == :auto && return
axis = getproperty(ax, Symbol(letter, "axis"))
axis = getproperty(ax, get_attr_symbol(letter, :axis))
if ticks == :none || ticks === nothing || ticks == false
kw = KW()
for dir in (:top, :bottom, :left, :right)
kw[dir] = kw[Symbol(:label, dir)] = false
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
end
axis."set_tick_params"(; which = "both", kw...)
return
@@ -813,14 +920,7 @@ function py_set_ticks(sp, ax, ticks, letter, env)
axis."set_ticks"(ticks)
elseif ttype == :ticks_and_labels
axis."set_ticks"(ticks[1])
if get(sp[:extra_kwargs], :rawticklabels, false)
tick_labels = ticks[2]
else
tick_labels = [py_surround_latextext(ticklabel, env) for ticklabel in ticks[2]]
end
axis."set_ticklabels"(tick_labels)
axis."set_ticklabels"(ticks[2])
else
error("Invalid input for $(letter)ticks: $ticks")
end
@@ -858,15 +958,15 @@ function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol)
arg = if scale == :identity
"linear"
else
kw[Symbol(:base, pyletter)] = if scale == :ln
kw[get_attr_symbol(:base, pyletter)] = if scale == :ln
elseif scale == :log2
2
elseif scale == :log10
10
end
axis = sp[Symbol(letter, :axis)]
kw[Symbol(:linthresh, pyletter)] =
axis = sp[get_attr_symbol(letter, :axis)]
kw[get_attr_symbol(:linthresh, pyletter)] =
NaNMath.max(1e-16, py_compute_axis_minval(sp, axis))
"symlog"
end
@@ -893,7 +993,7 @@ end
function py_set_axis_colors(sp, ax, a::Axis)
py_set_spine_color(ax.spines, py_color(a[:foreground_color_border]))
axissym = Symbol(a[:letter], :axis)
axissym = get_attr_symbol(a[:letter], :axis)
if PyPlot.PyCall.hasproperty(ax, axissym)
tickcolor =
sp[:framestyle] in (:zerolines, :grid) ?
@@ -961,6 +1061,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
py_thickness_scale(plt, sp[:titlefontsize]),
)
getproperty(ax, func)."set_family"(sp[:titlefontfamily])
getproperty(ax, func)."set_math_fontfamily"(
py_get_matching_math_font(sp[:titlefontfamily]),
)
getproperty(ax, func)."set_color"(py_color(sp[:titlefontcolor]))
# ax[:set_title](sp[:title], loc = loc)
end
@@ -1053,6 +1156,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
sp[:colorbar_title],
size = py_thickness_scale(plt, sp[:colorbar_titlefontsize]),
family = sp[:colorbar_titlefontfamily],
math_fontfamily = py_get_matching_math_font(sp[:colorbar_titlefontfamily]),
color = py_color(sp[:colorbar_titlefontcolor]),
)
@@ -1060,9 +1164,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
cb."formatter".set_powerlimits((-Inf, Inf))
cb."update_ticks"()
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
ticks = get_colorbar_ticks(sp)
if sp[:colorbar] in (:top, :bottom)
axis = sp[:xaxis] # colorbar inherits from x axis
cbar_axis = cb."ax"."xaxis"
@@ -1074,11 +1176,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
py_set_scale(cb.ax, sp, sp[:colorbar_scale], ticks_letter)
sp[:colorbar_ticks] == :native ? nothing :
py_set_ticks(sp, cb.ax, ticks, ticks_letter, env)
py_set_ticks(sp, cb.ax, ticks, ticks_letter)
for lab in cbar_axis."get_ticklabels"()
lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize]))
lab."set_family"(sp[:colorbar_tickfontfamily])
lab."set_math_fontfamily"(
py_get_matching_math_font(sp[:colorbar_tickfontfamily]),
)
lab."set_color"(py_color(sp[:colorbar_tickfontcolor]))
end
@@ -1164,7 +1269,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
# axis attributes
for letter in (:x, :y, :z)
axissym = Symbol(letter, :axis)
axissym = get_attr_symbol(letter, :axis)
PyPlot.PyCall.hasproperty(ax, axissym) || continue
axis = sp[axissym]
pyaxis = getproperty(ax, axissym)
@@ -1174,7 +1279,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
py_set_scale(ax, sp, axis)
axis[:ticks] == :native ? nothing : py_set_lims(ax, sp, axis)
py_set_lims(ax, sp, axis)
if ispolar(sp) && letter == :y
ax."set_rlabel_position"(90)
end
@@ -1188,6 +1293,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
fontProperties = PyPlot.PyCall.PyDict(
Dict(
"family" => axis[:tickfontfamily],
"math_fontfamily" =>
py_get_matching_math_font(axis[:tickfontfamily]),
"size" => py_thickness_scale(plt, axis[:tickfontsize]),
"rotation" => axis[:tickfontrotation],
),
@@ -1207,10 +1314,14 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
)
end
# workaround to set mathtext.fontspec per Text element
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
py_set_ticks(sp, ax, ticks, letter)
if axis[:ticks] == :native # It is easier to reset than to account for this
py_set_lims(ax, sp, axis)
pyaxis.set_major_locator(pyticker.AutoLocator())
pyaxis.set_major_formatter(pyticker.ScalarFormatter())
end
axis[:ticks] == :native ? nothing : py_set_ticks(sp, ax, ticks, letter, env)
# Tick marks
intensity = 0.5 # This value corresponds to scaling of other grid elements
pyaxis."set_tick_params"(
@@ -1226,6 +1337,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
pyaxis."label"."set_fontsize"(py_thickness_scale(plt, axis[:guidefontsize]))
pyaxis."label"."set_family"(axis[:guidefontfamily])
pyaxis."label"."set_math_fontfamily"(
py_get_matching_math_font(axis[:guidefontfamily]),
)
if (RecipesPipeline.is3d(sp))
pyaxis."set_rotate_label"(false)
@@ -1298,7 +1412,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if !ispolar(sp)
ax.spines[string(dir)].set_visible(false)
end
kw[dir] = kw[Symbol(:label, dir)] = false
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
end
ax."xaxis"."set_tick_params"(; which = "both", kw...)
end
@@ -1308,7 +1422,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if !ispolar(sp)
ax.spines[string(dir)].set_visible(false)
end
kw[dir] = kw[Symbol(:label, dir)] = false
kw[dir] = kw[get_attr_symbol(:label, dir)] = false
end
ax."yaxis"."set_tick_params"(; which = "both", kw...)
end
@@ -1457,67 +1571,85 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
if should_add_to_legend(series)
clims = get_clims(sp, series)
# add a line/marker and a label
push!(
handles,
if series[:seriestype] == :shape || series[:fillrange] !== nothing
pypatches."Patch"(
edgecolor = py_color(
single_color(get_linecolor(series, clims)),
get_linealpha(series),
),
facecolor = py_color(
single_color(get_fillcolor(series, clims)),
get_fillalpha(series),
),
linewidth = py_thickness_scale(
plt,
clamp(get_linewidth(series), 0, 5),
),
linestyle = py_linestyle(
series[:seriestype],
get_linestyle(series),
),
if series[:seriestype] == :shape || series[:fillrange] !== nothing
lc = get_linecolor(series, clims)
la = get_linealpha(series)
ls = get_linestyle(series)
fc = get_fillcolor(series, clims)
fa = get_fillalpha(series)
fs = get_fillstyle(series)
has_fs = !isnothing(fs)
# line (and potentially solid fill)
line_handle = pypatches."Patch"(
edgecolor = py_color(single_color(lc), la),
facecolor = py_color(single_color(fc), has_fs ? 0 : fa),
linewidth = py_thickness_scale(
plt,
clamp(get_linewidth(series), 0, 5),
),
linestyle = py_linestyle(series[:seriestype], ls),
capstyle = "butt",
)
# hatched fill
# hatch color/alpha are controlled by edge (not face) color/alpha
if has_fs
fill_handle = pypatches."Patch"(
edgecolor = py_color(single_color(fc), fa),
facecolor = py_color(single_color(fc), 0), # don't fill with solid background
hatch = py_fillstyle(fs),
linewidth = 0, # don't replot shape outline (doesn't affect hatch linewidth)
linestyle = py_linestyle(series[:seriestype], ls),
capstyle = "butt",
)
elseif series[:seriestype] in
(:path, :straightline, :scatter, :steppre, :stepmid, :steppost)
hasline = get_linewidth(series) > 0
PyPlot.plt."Line2D"(
(0, 1),
(0, 0),
color = py_color(
single_color(get_linecolor(series, clims)),
get_linealpha(series),
),
linewidth = py_thickness_scale(
plt,
hasline * sp[:legendfontsize] / 8,
),
linestyle = py_linestyle(:path, get_linestyle(series)),
solid_capstyle = "butt",
solid_joinstyle = "miter",
dash_capstyle = "butt",
dash_joinstyle = "miter",
marker = py_marker(_cycle(series[:markershape], 1)),
markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]),
markeredgecolor = py_color(
single_color(get_markerstrokecolor(series)),
get_markerstrokealpha(series),
),
markerfacecolor = py_color(
single_color(get_markercolor(series, clims)),
get_markeralpha(series),
),
markeredgewidth = py_thickness_scale(
plt,
0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] /
first(series[:markersize]),
), # retain the markersize/markerstroke ratio from the markers on the plot
)
# plot two handles on top of each other by passing in a tuple
# https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html
push!(handles, (line_handle, fill_handle))
else
series[:serieshandle][1]
end,
)
# plot line handle (which includes solid fill) only
push!(handles, line_handle)
end
elseif series[:seriestype] in
(:path, :straightline, :scatter, :steppre, :stepmid, :steppost)
hasline = get_linewidth(series) > 0
handle = PyPlot.plt."Line2D"(
(0, 1),
(0, 0),
color = py_color(
single_color(get_linecolor(series, clims)),
get_linealpha(series),
),
linewidth = py_thickness_scale(
plt,
hasline * sp[:legendfontsize] / 8,
),
linestyle = py_linestyle(:path, get_linestyle(series)),
solid_capstyle = "butt",
solid_joinstyle = "miter",
dash_capstyle = "butt",
dash_joinstyle = "miter",
marker = py_marker(_cycle(series[:markershape], 1)),
markersize = py_thickness_scale(plt, 0.8 * sp[:legendfontsize]),
markeredgecolor = py_color(
single_color(get_markerstrokecolor(series)),
get_markerstrokealpha(series),
),
markerfacecolor = py_color(
single_color(get_markercolor(series, clims)),
get_markeralpha(series),
),
markeredgewidth = py_thickness_scale(
plt,
0.8 * get_markerstrokewidth(series) * sp[:legendfontsize] /
first(series[:markersize]),
), # retain the markersize/markerstroke ratio from the markers on the plot
)
push!(handles, handle)
else
push!(handles, series[:serieshandle][1])
end
push!(labels, series[:label])
end
end
@@ -1547,6 +1679,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
leg."get_title"(),
color = py_color(sp[:legendtitlefontcolor]),
family = sp[:legendtitlefontfamily],
math_fontfamily = py_get_matching_math_font(sp[:legendtitlefontfamily]),
fontsize = py_thickness_scale(plt, sp[:legendtitlefontsize]),
)
end
@@ -1556,6 +1689,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
txt,
color = py_color(sp[:legendfontcolor]),
family = sp[:legendfontfamily],
math_fontfamily = py_get_matching_math_font(sp[:legendtitlefontfamily]),
fontsize = py_thickness_scale(plt, sp[:legendfontsize]),
)
end
+193 -128
View File
@@ -1,186 +1,251 @@
# https://github.com/Evizero/UnicodePlots.jl
# https://github.com/JuliaPlots/UnicodePlots.jl
# don't warn on unsupported... there's just too many warnings!!
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes) = nothing
# --------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------
const _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 rebuildUnicodePlot!(plt::Plot, width, height)
plt.o = []
# 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[]
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xlim = axis_limits(sp, :x)
ylim = axis_limits(sp, :y)
xlim = collect(axis_limits(sp, :x))
ylim = collect(axis_limits(sp, :y))
# make vectors
xlim = [xlim[1], xlim[2]]
ylim = [ylim[1], ylim[2]]
# we set x/y to have a single point, since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
# we set x/y to have a single point,
# since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot,
# it shouldn't actually be shown
x = Float64[xlim[1]]
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
ct = _canvas_type[]
canvas_type = if ct == :auto
isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
# 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
else
_canvas_map()[ct]
ct
end
# 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,
kw = (
compact = true,
title = sp[:title],
xlabel = xaxis[:guide],
ylabel = yaxis[:guide],
xscale = xaxis[:scale],
yscale = yaxis[:scale],
border = isijulia() ? :ascii : :solid,
xlim = xlim,
ylim = ylim,
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
o = UnicodePlots.Plot(x, y, _canvas_map[canvas_type]; kw...)
for series in series_list(sp)
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
o = addUnicodeSeries!(sp, o, kw, series, sp[:legend] != :none)
end
# save the object
push!(plt.o, o)
for ann in sp[:annotations]
x, y, val = locate_annotation(sp, ann...)
o = UnicodePlots.annotate!(
o,
x,
y,
val.str;
color = up_color(val.font.color),
halign = val.font.halign,
valign = val.font.valign,
)
end
push!(plt.o, o) # save the object
end
end
# add a single series
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
up_color(col::UnicodePlots.UserColorType) = col
up_color(col::RGBA) =
(c = convert(ARGB32, col); map(Int, (red(c).i, green(c).i, blue(c).i)))
up_color(col) = :auto
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
# add a single series
function addUnicodeSeries!(
sp::Subplot{UnicodePlotsBackend},
up::UnicodePlots.Plot,
kw,
series,
addlegend::Bool,
)
st = series[:seriestype]
# get the series data and label
x, y = if st == :straightline
straightline_data(plotattributes)
straightline_data(series)
elseif st == :shape
shape_data(plotattributes)
shape_data(series)
else
[collect(float(plotattributes[s])) for s in (:x, :y)]
float(series[:x]), float(series[:y])
end
label = addlegend ? plotattributes[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color =
plotattributes[:linecolor] in UnicodePlots.color_cycle ?
plotattributes[:linecolor] : :auto
# special handling (src/interface)
if st == :histogram2d
kw[:xlim][:] .= kw[:ylim][:] .= 0
return UnicodePlots.densityplot(x, y; kw...)
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;
zlabel = sp[:colorbar_title],
colormap = cmap,
kw...,
)
elseif st == :spy
return UnicodePlots.spy(series[:z].surf; kw...)
end
# 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)
series_kw = (;)
# 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!
series_kw = (; marker = series[:markershape])
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)
up = func(
up,
x[rng],
y[rng];
color = up_color(lc),
name = n == 1 ? label : "",
series_kw...,
)
end
for (xi, yi, str, fnt) in EachAnn(series[:series_annotations], x, y)
up = UnicodePlots.annotate!(
up,
xi,
yi,
str;
color = up_color(fnt.color),
halign = fnt.halign,
valign = fnt.valign,
)
end
return up
end
# -------------------------------
# ------------------------------------------------------------------------------------------
# since this is such a hack, it's only callable using `png`... should error during normal `show`
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
# since this is such a hack, it's only callable using `png`...
# should error during normal `show`
function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
fn = addExtension(fn, "png")
# 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
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
sleep(0.5)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
# use osx screen capture when my terminal is maximized
# and cursor starts at the bottom (I know, right?)
run(`screencapture -R50,600,700,420 $fn`)
# END HACK (phew)
return
elseif Sys.islinux()
run(`clear`)
gui(plt)
run(`import -window $(ENV["WINDOWID"]) $fn`)
return
end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
error(
"Can only savepng on MacOS or Linux with UnicodePlots " *
"(though even then I wouldn't do it)",
)
end
# -------------------------------
# we don't do very much for subplots... just stack them vertically
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
w, h = plt[:size]
plt.attr[:color_palette] = [RGB(0, 0, 0)]
rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
end
# ------------------------------------------------------------------------------------------
Base.show(plt::Plot{UnicodePlotsBackend}) = show(stdout, plt)
Base.show(io::IO, plt::Plot{UnicodePlotsBackend}) = _show(io, MIME("text/plain"), plt)
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
foreach(x -> show(io, x), plt.o)
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)
w_max = zeros(Int, nc)
buf = IOBuffer()
cbuf = IOContext(buf, :color => true)
re_col = r"\x1B\[[0-9;]*[a-zA-Z]"
sps = 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, re_col => "")
lines_colored[r, c] = lc = split(colored, "\n")
lines_uncolored[r, c] = lu = split(uncolored, "\n")
lmax = max(length(lc), lmax)
w_max[c] = max(maximum(length.(lu)), w_max[c])
end
end
end
l_max[r] = lmax
end
empty = String[' '^w for w in w_max]
for r in 1:nr
for n in 1:l_max[r]
for c in 1:nc
pre = c == 1 ? '\0' : ' '
lc = lines_colored[r, c]
if lc === nothing || length(lc) < n
print(io, pre, empty[c])
else
lu = lines_uncolored[r, c]
print(io, pre, lc[n], ' '^(w_max[c] - length(lu[n])))
end
end
println(io)
end
r < nr && println(io)
end
nothing
end
function _display(plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
map(show, plt.o)
map(display, plt.o)
nothing
end
+16 -16
View File
@@ -5,33 +5,32 @@ 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]))
get_clims(sp::Subplot)::Tuple{Float64,Float64} = sp[:crange]
get_clims(series::Series)::Tuple{Float64,Float64} = series[:crange]
get_clims(sp::Subplot, series::Series)::Tuple{Float64,Float64} =
series[:colorbar_entry] ? sp[:crange] : series[:crange]
function update_clims(sp::Subplot, op = process_clims(sp[:clims]))::Tuple{Float64,Float64}
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
zmin, zmax = _update_clims(zmin, zmax, update_clims(series, op)...)
else
update_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)
return sp[:crange] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
update_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
values of the input. The value is stored as a series property, which is retrieved by `get_clims`.
"""
function get_clims(series::Series, op = ignorenan_extrema)
function update_clims(series::Series, op = ignorenan_extrema)::Tuple{Float64,Float64}
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
for vals in (
@@ -46,7 +45,7 @@ function get_clims(series::Series, op = ignorenan_extrema)
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
return series[:crange] = zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
@@ -94,4 +93,5 @@ end
function _update_subplot_colorbars(sp::Subplot)
# Dynamic callback from the pipeline if needed
update_clims(sp)
end
+3 -3
View File
@@ -321,7 +321,7 @@ function scalefontsizes(factor::Number)
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
scalefontsize(Symbol(letter, k), factor)
scalefontsize(get_attr_symbol(letter, k), factor)
end
end
end
@@ -343,9 +343,9 @@ function scalefontsizes()
for letter in (:x, :y, :z)
for k in keys(_initial_ax_fontsizes)
if k in keys(_initial_fontsizes)
f = default(Symbol(letter, k))
f = default(get_attr_symbol(letter, k))
factor = f / _initial_fontsizes[k]
scalefontsize(Symbol(letter, k), 1.0 / factor)
scalefontsize(get_attr_symbol(letter, k), 1.0 / factor)
end
end
end
+39 -14
View File
@@ -125,7 +125,8 @@ const _examples = PlotExample[
:(
begin
import FileIO
path = download(
import Downloads
path = Downloads.download(
"http://juliaplots.org/PlotReferenceImages.jl/Plots/pyplot/0.7.0/ref1.png",
)
img = FileIO.load(path)
@@ -961,8 +962,10 @@ const _examples = PlotExample[
"""
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.
The connections can be specified in two ways: Either as a tuple of vectors where 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. Or as a vector of NTuple{3,Ints} where each element
contains the 1-based indices of the three points of a triangle.
""",
[
:(
@@ -978,13 +981,14 @@ const _examples = PlotExample[
i = [0, 0, 0, 1]
j = [1, 2, 3, 2]
k = [2, 3, 1, 3]
# Or: cns = [(1, 2, 3), (1, 3, 4), (1, 4, 2), (2, 3, 4)] (1-based indexing)
# the four triangles gives above give a tetrahedron
mesh3d(
x,
y,
z;
connections = (i, j, k),
connections = (i, j, k), # connections = cns
title = "triangles",
xlabel = "x",
ylabel = "y",
@@ -1234,21 +1238,42 @@ const _examples = PlotExample[
_animation_examples = [2, 31]
_backend_skips = Dict(
:gr => [25, 30],
:pyplot => [2, 25, 30, 31, 47, 49, 55],
:pyplot => [2, 25, 30, 31, 49, 55],
:plotlyjs => [2, 21, 24, 25, 30, 31, 49, 51, 55],
:plotly => [2, 21, 24, 25, 30, 31, 49, 50, 51, 55],
: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
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, 10, 22, 24, 28, 38, 43, 45, 47, 49, 50, 51, 55],
:unicodeplots => [
5, # limits issue
6, # embedded images unsupported
16, # nested layout unsupported
21, # custom markers unsupported
22, # contours unsupported
24, # 3D unsupported
26, # nested layout unsupported
27, # polar plots 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
49, # polar heatmap
50, # 3D surface unsupported
51, # embedded images unsupported
52, # 3D quiver unsupported
55, # 3D unsupported
],
:gaston => [
2, # animations
31, # animations
+1 -1
View File
@@ -98,7 +98,7 @@ function __init__()
global plotly_local_file_path[] =
joinpath(@get_scratch!("plotly"), _plotly_min_js_filename)
if !isfile(plotly_local_file_path[])
download(
Downloads.download(
"https://cdn.plot.ly/$(_plotly_min_js_filename)",
plotly_local_file_path[],
)
+3 -2
View File
@@ -250,12 +250,12 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
v = v[series_idx(kw_list, kw)]
end
for letter in (:x, :y, :z)
attr[Symbol(letter, k)] = v
attr[get_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 = Symbol(letter, k)
lk = get_attr_symbol(letter, k)
if haskey(attr, lk)
kw[lk] = attr[lk]
end
@@ -416,4 +416,5 @@ function _add_the_series(plt, sp, plotattributes)
push!(plt.series_list, series)
push!(sp.series_list, series)
_series_added(plt, series)
_update_subplot_colorbars(sp)
end
+3 -4
View File
@@ -7,10 +7,9 @@ ismultiversion = false
@static if !should_precompile
# nothing
elseif !ismultios && !ismultiversion
@static if isfile(joinpath(
@__DIR__,
"../deps/SnoopCompile/precompile/precompile_Plots.jl",
))
@static if isfile(
joinpath(@__DIR__, "../deps/SnoopCompile/precompile/precompile_Plots.jl"),
)
include("../deps/SnoopCompile/precompile/precompile_Plots.jl")
_precompile_()
end
+8 -2
View File
@@ -47,7 +47,7 @@ num_series(x::AMat) = size(x, 2)
num_series(x) = 1
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} =
throw(MethodError(T, "Unmatched plot recipe: $T"))
nothing
# ---------------------------------------------------------------------------
@@ -1042,7 +1042,13 @@ export lens!
series_plotindex := backup[:series_plotindex]
seriestype := :path
primary := false
linecolor := :lightgray
linecolor := get(backup, :linecolor, :lightgray)
if haskey(backup, :linestyle)
linestyle := backup[:linestyle]
end
if haskey(backup, :linewidth)
linewidth := backup[:linewidth]
end
bbx_mag = (x1 + x2) / 2
bby_mag = (y1 + y2) / 2
xi_lens, yi_lens =
+40 -13
View File
@@ -205,14 +205,15 @@ maketuple(x::Tuple{T,S}) where {T,S} = x
for i in 2:4
@eval begin
RecipesPipeline.unzip(
v::Union{AVec{<:Tuple{Vararg{T,$i} where T}},AVec{<:GeometryBasics.Point{$i}}},
v::Union{AVec{<:NTuple{$i,T} where {T}},AVec{<:GeometryBasics.Point{$i}}},
) = $(Expr(:tuple, (:([t[$j] for t in v]) for j in 1:i)...))
end
end
RecipesPipeline.unzip(
::Union{AVec{<:GeometryBasics.Point{N}},AVec{<:Tuple{Vararg{T,N} where T}}},
::Union{AVec{<:GeometryBasics.Point{N}},AVec{<:NTuple{N,T} where {T}}},
) where {N} = error("$N-dimensional unzip not implemented.")
RecipesPipeline.unzip(::Union{AVec{<:GeometryBasics.Point},AVec{<:Tuple}}) =
error("Can't unzip points of different dimensions.")
@@ -538,6 +539,7 @@ get_gradient(cp::ColorPalette) = cgrad(cp, categorical = true)
get_linewidth(series, i::Int = 1) = _cycle(series[:linewidth], i)
get_linestyle(series, i::Int = 1) = _cycle(series[:linestyle], i)
get_fillstyle(series, i::Int = 1) = _cycle(series[:fillstyle], i)
function get_markerstrokecolor(series, i::Int = 1)
msc = series[:markerstrokecolor]
@@ -556,6 +558,7 @@ const _segmenting_vector_attributes = (
:linestyle,
:fillcolor,
:fillalpha,
:fillstyle,
:markercolor,
:markeralpha,
:markersize,
@@ -814,7 +817,7 @@ end
function extend_series_data!(series::Series, v, letter)
copy_series!(series, letter)
d = extend_by_data!(series[letter], v)
expand_extrema!(series[:subplot][Symbol(letter, :axis)], d)
expand_extrema!(series[:subplot][get_attr_symbol(letter, :axis)], d)
return d
end
@@ -1178,16 +1181,10 @@ end
_document_argument(S::AbstractString) =
_fmt_paragraph("`$S`: " * _arg_desc[Symbol(S)], leadingspaces = 6 + length(S))
function mesh3d_triangles(x, y, z, cns)
if typeof(cns) <: Tuple{Array,Array,Array}
ci, cj, ck = cns
if !(length(ci) == length(cj) == length(ck))
throw(
ArgumentError("Argument connections must consist of equally sized arrays."),
)
end
else
throw(ArgumentError("Argument connections has to be a tuple of three arrays."))
function mesh3d_triangles(x, y, z, cns::Tuple{Array,Array,Array})
ci, cj, ck = cns
if !(length(ci) == length(cj) == length(ck))
throw(ArgumentError("Argument connections must consist of equally sized arrays."))
end
X = zeros(eltype(x), 4length(ci))
Y = zeros(eltype(y), 4length(cj))
@@ -1212,3 +1209,33 @@ function mesh3d_triangles(x, y, z, cns)
end
return X, Y, Z
end
function mesh3d_triangles(x, y, z, cns::AbstractVector{NTuple{3,Int}})
X = zeros(eltype(x), 4length(cns))
Y = zeros(eltype(y), 4length(cns))
Z = zeros(eltype(z), 4length(cns))
@inbounds for I in 1:length(cns)
i = cns[I][1] # connections are 1-based
j = cns[I][2]
k = cns[I][3]
m = 4(I - 1) + 1
n = m + 1
o = m + 2
p = m + 3
X[m] = X[p] = x[i]
Y[m] = Y[p] = y[i]
Z[m] = Z[p] = z[i]
X[n] = x[j]
Y[n] = y[j]
Z[n] = z[j]
X[o] = x[k]
Y[o] = y[k]
Z[o] = z[k]
end
return X, Y, Z
end
# cache joined symbols so they can be looked up instead of constructed each time
const _attrsymbolcache = Dict{Symbol,Dict{Symbol,Symbol}}()
get_attr_symbol(letter::Symbol, keyword::String) = get_attr_symbol(letter, Symbol(keyword))
get_attr_symbol(letter::Symbol, keyword::Symbol) = _attrsymbolcache[letter][keyword]
+90 -78
View File
@@ -1,17 +1,26 @@
using Plots: guidefont, series_annotations, PLOTS_SEED
import ImageMagick
using VisualRegressionTests
using Plots
using Random
using StableRNGs
using Test
using TestImages
using FileIO
using Gtk
using LibGit2
import GeometryBasics
using Dates
using RecipesBase
using StableRNGs
using TestImages
using LibGit2
using Random
using FileIO
using Plots
using Dates
using JSON
using Test
using Gtk
import GeometryBasics
import ImageMagick
@testset "Infrastructure" begin
@test_nowarn JSON.Parser.parse(
String(read(joinpath(dirname(pathof(Plots)), "..", ".zenodo.json"))),
)
end
@testset "Plotly standalone" begin
@test_nowarn Plots._init_ijulia_plotting()
@@ -26,11 +35,12 @@ using RecipesBase
end
Plots.plotly_local_file_path[] = nothing
Plots.use_local_dependencies[] = temp
end # testset
end
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")
@@ -38,6 +48,7 @@ include("integration_dates.jl")
include("test_recipes.jl")
include("test_hdf5plots.jl")
include("test_pgfplotsx.jl")
include("test_plotly.jl")
reference_dir(args...) =
joinpath(homedir(), ".julia", "dev", "PlotReferenceImages", args...)
@@ -46,7 +57,6 @@ function reference_file(backend, i, version)
refdir = reference_dir("Plots", string(backend))
fn = "ref$i.png"
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
reffn = joinpath(refdir, string(version), fn)
for v in versions
tmpfn = joinpath(refdir, string(v), fn)
@@ -55,7 +65,6 @@ function reference_file(backend, i, version)
break
end
end
return reffn
end
@@ -70,9 +79,10 @@ if !isdir(reference_dir())
end
include("imgcomp.jl")
# don't actually show the plots
Random.seed!(PLOTS_SEED)
default(show = false, reuse = true)
default(show = false, reuse = true) # don't actually show the plots
is_ci() = get(ENV, "CI", "false") == "true"
const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" : "1e-5"))
@@ -97,66 +107,8 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
# image_comparison_facts(:pgfplotsx, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
# end
# 10 Histogram2D
##
@testset "Backends" begin
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
end
end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
p = plot(rand(10))
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
p = bar(randn(10))
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
p = plot([1, 2], [3, 4])
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@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])
hline!(p, [3.1])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
@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)])
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
p = plot()
axis = p.subplots[1][:xaxis]
@@ -172,10 +124,12 @@ end
end
@testset "NoFail" begin
#ensure backend with tested display
# ensure backend with tested display
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
dsp = TextDisplay(IOContext(IOBuffer(), :color => true))
@testset "Plot" begin
plots = [
histogram([1, 0, 0, 0, 0, 0]),
@@ -188,15 +142,15 @@ end
plot(["a" "b"; missing "d"], [1 2; 3 4]),
]
for plt in plots
display(plt)
display(dsp, plt)
end
@test_nowarn plot(x -> x^2, 0, 2)
end
@testset "Bar" begin
p = bar([3, 2, 1], [1, 2, 3])
@test isa(p, Plots.Plot)
@test isa(display(p), Nothing) == true
@test p isa Plots.Plot
@test display(dsp, p) isa Nothing
end
end
@@ -246,3 +200,61 @@ end
Plots.process_clims(missing) ==
Plots.process_clims(:auto)
end
@testset "Backends" begin
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
io = IOContext(IOBuffer(), :color => true)
# lets just make sure it runs without error
p = plot(rand(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = bar(randn(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([1, 2], [3, 4])
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
hline!(p, [3.1])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test p isa Plots.Plot
@test_broken display(p) isa Nothing
end
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
end
end
end
+54
View File
@@ -63,3 +63,57 @@ end
@test twpl[:top_margin] == 2Plots.cm
@test twpl[:bottom_margin] == 2Plots.cm
end
@testset "axis-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α = 0.07)
@test p[1][:xaxis][:gridalpha] 0.07
p = plot(1:2, xgridls = :dashdot)
@test p[1][:xaxis][:gridstyle] === :dashdot
p = plot(1:2, xgridcolor = :red)
@test p[1][:xaxis][:foreground_color_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
p = plot(1:2, xminorgridcolor = :red)
@test p[1][:xaxis][:foreground_color_minor_grid] === RGBA{Float64}(1.0, 0.0, 0.0, 1.0)
p = plot(1:2, xgrid_lw = 0.01)
@test p[1][:xaxis][:gridlinewidth] 0.01
p = plot(1:2, xminorgrid_lw = 0.01)
@test p[1][:xaxis][:minorgridlinewidth] 0.01
p = plot(1:2, xtickor = :out)
@test p[1][:xaxis][:tick_direction] === :out
end
@testset "aliases" begin
compare(p::Plots.Plot, s::Symbol, val, op) =
op(p[1][:xaxis][s], val) && op(p[1][:yaxis][s], val) && op(p[1][:zaxis][s], val)
p = plot(1:2, guide = "all labels")
@test compare(p, :guide, "all labels", ===)
p = plot(1:2, label = "test")
@test compare(p, :guide, "", ===)
p = plot(1:2, lim = (0, 3))
@test xlims(p) === ylims(p) === zlims(p) === (0, 3)
p = plot(1:2, tick = [1.25, 1.5, 1.75])
@test compare(p, :ticks, [1.25, 1.5, 1.75], ==)
p = plot(1:2, labelfontsize = 4)
@test compare(p, :guidefontsize, 4, ==)
p = plot(1:2, gα = 0.07)
@test compare(p, :gridalpha, 0.07, )
p = plot(1:2, gridls = :dashdot)
@test compare(p, :gridstyle, :dashdot, ===)
p = plot(1:2, gridcolor = :red)
@test compare(p, :foreground_color_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
p = plot(1:2, minorgridcolor = :red)
@test compare(p, :foreground_color_minor_grid, RGBA{Float64}(1.0, 0.0, 0.0, 1.0), ===)
p = plot(1:2, grid_lw = 0.01)
@test compare(p, :gridlinewidth, 0.01, )
p = plot(1:2, minorgrid_lw = 0.01)
@test compare(p, :minorgridlinewidth, 0.01, )
p = plot(1:2, tickor = :out)
@test compare(p, :tick_direction, :out, ===)
end
+68
View File
@@ -0,0 +1,68 @@
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
+57
View File
@@ -0,0 +1,57 @@
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