Compare commits

..

135 Commits

Author SHA1 Message Date
Daniel Schwabeneder 71246620aa Merge pull request #2414 from daschw/release
bump version
2020-02-25 10:09:49 +01:00
Daniel Schwabeneder 6e3181375c bump version 2020-02-25 10:08:45 +01:00
Daniel Schwabeneder e7b1dc0cac Merge pull request #2413 from daschw/hdf5
AKWs in HDF5 backend
2020-02-25 09:58:05 +01:00
Daniel Schwabeneder d78bb56316 AKWs in HDF5 backend 2020-02-25 09:40:05 +01:00
Daniel Schwabeneder 648c5ac587 Merge pull request #2409 from daschw/readme
fix travis and appveyor links in readme
2020-02-24 10:23:00 +01:00
Daniel Schwabeneder df7d28dc99 fix travis and appveyor links in readme 2020-02-24 10:21:23 +01:00
Daniel Schwabeneder 4d28a49c70 Merge pull request #2408 from JuliaPlots/compathelper/new_version/2020-02-24-02-05-25-661-4174007980
CompatHelper: bump compat for "FFMPEG" to "0.3"
2020-02-24 10:15:37 +01:00
github-actions[bot] ef3e7af329 CompatHelper: bump compat for "FFMPEG" to "0.3" 2020-02-24 02:05:26 +00:00
Yuval 3221b80aeb Merge pull request #2402 from yha/gr-scientific-ticks
Fix GR scientific notation for explicit ticks
2020-02-17 16:58:04 +02:00
Daniel Schwabeneder 13fc936e1f Merge pull request #2403 from daschw/animate
Fix animations for `import Plots`
2020-02-16 11:01:10 +01:00
Daniel Schwabeneder 4e5b1aa6e5 add missing Plots. 2020-02-16 09:55:57 +01:00
Daniel Schwabeneder cb577f0ef3 fix animate for import Plots 2020-02-16 09:52:55 +01:00
yha b23dd39e06 Fix GR scientific notation for explicit ticks 2020-02-13 18:14:15 +02:00
Daniel Schwabeneder 7498b3c769 Merge pull request #2398 from daschw/docs
prepare for docs rewrite
2020-02-13 11:32:01 +01:00
Daniel Schwabeneder 0c0a2c215c Merge pull request #2396 from GaaH/add-txt-extension
save unicodeplots with .txt extension
2020-02-12 09:12:42 +01:00
Daniel Schwabeneder b682bc8e96 prepare for docs rewrite 2020-02-12 07:28:30 +01:00
Gaëtan Caillaut 205345a8d3 save unicodeplots with .txt extension 2020-02-11 18:36:26 +01:00
Daniel Schwabeneder faff9cebe4 Merge pull request #2393 from daschw/pkgeval
add PkgEval badge to readme
2020-02-11 15:35:26 +01:00
Daniel Schwabeneder bcd1bc1009 add PkgEval badge to readme 2020-02-11 14:39:21 +01:00
Daniel Schwabeneder f2ca493a14 Merge pull request #2390 from daschw/release
tag minor release
2020-02-10 16:14:59 +01:00
Daniel Schwabeneder 54301fa97a up version 2020-02-10 16:13:19 +01:00
Daniel Schwabeneder 20a290792f Merge pull request #2388 from daschw/akw
Some fixes for KW -> Attr transition
2020-02-09 09:26:00 +01:00
Daniel Schwabeneder 31f5490517 fix typo 2020-02-08 23:57:48 +01:00
Daniel Schwabeneder 8554e632bd more reset_kw!s 2020-02-08 23:49:50 +01:00
Daniel Schwabeneder 70d0d786e2 fix fg_color 2020-02-08 23:48:35 +01:00
Daniel Schwabeneder 5af5ec7313 more AKWs 2020-02-08 23:29:09 +01:00
Daniel Schwabeneder 7fab2f1c6b Merge pull request #2387 from JuliaTagBot/master
Install TagBot as a GitHub Action
2020-02-08 20:07:01 +01:00
Daniel Schwabeneder 461ef20225 Merge pull request #2385 from daschw/hover
fix plotly hover in test image 6
2020-02-08 16:16:00 +01:00
Daniel Schwabeneder 4357fde5ea Merge pull request #2386 from daschw/attr
Missing methods for Attr
2020-02-08 16:15:43 +01:00
Daniel Schwabeneder f93977b1a4 implement get! and delete! for Attr 2020-02-08 15:52:32 +01:00
Julia TagBot 2e77d0df98 Install TagBot as a GitHub Action 2020-02-08 20:31:27 +07:00
Daniel Schwabeneder fc40b0e0ac fix plotly hover in test image 6 2020-02-07 23:12:34 +01:00
Daniel Schwabeneder 85aca2aa67 Merge pull request #2384 from daschw/testing
update julia version in travis and appveyor configs
2020-02-07 22:53:19 +01:00
Daniel Schwabeneder 961d6be9f9 julia version in travis and appveyor configs 2020-02-07 18:08:08 +01:00
Michael Krabbe Borregaard 33553eb055 update version and dep of RecipesBase 2020-02-06 12:08:35 +01:00
Michael Krabbe Borregaard fbe8dcaf78 Merge pull request #2373 from yha/attr-defaults
Implement plotattributes with defaults. Fixes "-->" in series recipes.
2020-02-06 12:01:30 +01:00
Daniel Schwabeneder b5f54afed2 Merge pull request #2378 from daschw/plotly-hover
show datapoints on hover by default for plotly
2020-02-05 14:22:40 +01:00
Michael Krabbe Borregaard c99fcc3dcd Merge pull request #2381 from pfitzseb/sp/htmlplots
only show plotly plots as html in Juno
2020-02-05 11:53:17 +01:00
Sebastian Pfitzner 4a7ea82862 only show plotly plots as html in Juno 2020-02-05 11:49:54 +01:00
Michael Krabbe Borregaard 3bad6e9b4c Merge pull request #2379 from JuliaPlots/compathelper/new_version/2020-02-03-15-04-12-054-56131472
CompatHelper: bump compat for "FixedPointNumbers" to "0.8"
2020-02-03 17:46:43 +01:00
github-actions[bot] 96ab1537d3 CompatHelper: bump compat for "FixedPointNumbers" to "0.8" 2020-02-03 15:04:13 +00:00
Daniel Schwabeneder c62714d188 show datapoints on hover by default for plotly 2020-02-03 14:27:01 +01:00
Simon Christ 2b6a90766a Restore fill between functions (#2374)
* skeleton

* remove groupplots

* working insets, fix background opacity

* insets resp. to window

* only shift

* a shift solution

* remove frames

* fix padding

* format code

* Revert "skeleton" restore fill between functions

This reverts commit 80903a2789.

* correct location
2020-01-29 14:49:19 +01:00
yha 366d598ff0 Implement plotattributes with defaults. Fixes "-->" in series recipes. 2020-01-29 01:25:04 +02:00
Daniel Schwabeneder 84a8039022 Merge pull request #2371 from daschw/label
Allow `label = nothing, :none, false`
2020-01-28 10:30:28 +01:00
daschw 8011c9f675 Allow label = nothing, :none, false 2020-01-27 21:30:05 +01:00
Josef Heinen d709b53ec7 Merge pull request #2370 from jheinen/master
bump GR version to 0.46.0
2020-01-27 16:56:20 +01:00
Josef Heinen 39c97ecdc5 bump GR version to 0.46 2020-01-27 16:25:43 +01:00
Josef Heinen 45c434b5ed Adjust DPI factor for PNG output
This is just a temporary workaround.
In a future version, a corresponding DPI adjustment should be
implemented in GR.
2020-01-24 16:04:19 +01:00
Josef Heinen 312f98e380 Use GR builtin marker routine 2020-01-24 15:00:31 +01:00
Josef Heinen d093d1ad7e Fix linewidth and markersize for GR 0.45.0 2020-01-24 13:34:33 +01:00
Josef Heinen 22e8718e85 Merge pull request #4 from jheinen/compathelper/new_version/2020-01-24-11-03-47-200-2951760626
CompatHelper: bump compat for "GR" to "0.45"
2020-01-24 12:48:21 +01:00
github-actions[bot] e489787535 CompatHelper: bump compat for "GR" to "0.45" 2020-01-24 11:03:48 +00:00
Michael Krabbe Borregaard 73ff286162 Merge pull request #2364 from yha/heatmap-fillcolor
Fix heatmap with non-gradient fillcolor
2020-01-22 19:51:10 +01:00
yha c75f6f5a9d Fix heatmap with non-gradient fillcolor 2020-01-20 17:53:47 +02:00
Michael Krabbe Borregaard 33d04c3e6b Merge pull request #2351 from o01eg/fix-2350
Treat types without length as a single element
2020-01-20 11:51:40 +01:00
O01eg 2ede388c15 Treat types without length as single element
Fixes #2350
Workaround for types like Dates.Date which can be used for coordinates
but doesn't have Base.length defined.
2020-01-20 13:49:10 +03:00
Simon Christ 745189981b rework layouts (#2356)
* skeleton

* remove groupplots

* working insets, fix background opacity

* fix pgfx_axes

* insets resp. to window

* only shift

* a shift solution

* remove frames

* fix padding

* format code
2020-01-17 11:05:22 +01:00
Simon Christ dd70192de4 Merge pull request #2354 from BeastyBlacksmith/pgfplotsx
@JuliaRegistrator register()
2020-01-10 22:26:19 +01:00
Simon Christ 5fc2f6cf3b bump version 2020-01-10 22:25:05 +01:00
Simon Christ 2c6f54579d informative assertion message 2020-01-08 15:33:49 +01:00
Simon Christ 9bcab45cb8 fix tests 2020-01-08 15:16:07 +01:00
Simon Christ 3b7464e739 allow vector fillranges 2020-01-08 15:10:00 +01:00
Simon Christ 11c86b2d30 remove shows 2020-01-08 14:39:10 +01:00
Simon Christ 7a521ef21f basic tuple implementation 2020-01-08 14:38:18 +01:00
Simon Christ 7fb1a6a517 implement fill between functions 2020-01-03 21:13:01 +01:00
Simon Christ f20582e528 implement pgfx_preamble() 2020-01-03 21:13:01 +01:00
Simon Christ 92e609876d fix dimensions 2020-01-03 21:12:40 +01:00
Simon Christ 5a251e5702 support asymmetric ribbons 2020-01-03 21:12:27 +01:00
Simon Christ 33cf0e66ec Merge pull request #2332 from JuliaPlots/compathelper/new_version/2019-12-17-01-02-53-961-1642667966
CompatHelper: bump compat for "FixedPointNumbers" to "0.7"
2019-12-31 12:59:11 +01:00
Simon Christ 9d75916244 Merge pull request #2347 from o01eg/fix-pgfplotx-tests
Fix compat bounds for tests of the PGXPlotsX backend
2019-12-31 12:20:35 +01:00
O01eg 6ed18617d5 Fix tests for PGXPlotsX backend
The backend uses push! and append! methods introduced in 1.2.0
2019-12-31 13:43:41 +03:00
Simon Christ 2022aebb07 Update Project.toml 2019-12-17 15:24:20 +01:00
Simon Christ b73c38fe69 Merge pull request #2310 from BeastyBlacksmith/pgfplotsx
fix ribbons and interaction between background and fill between
2019-12-17 15:23:26 +01:00
github-actions[bot] 11322d0d8b CompatHelper: bump compat for "FixedPointNumbers" to "0.7" 2019-12-17 01:02:55 +00:00
Daniel Schwabeneder 82479d48b9 Merge pull request #2325 from daschw/axes-3d
Improve GR 3D axes
2019-12-13 23:48:25 +01:00
Daniel Schwabeneder a07fd5d3db Merge pull request #2328 from daschw/showtheme
update showtheme
2019-12-13 23:37:15 +01:00
daschw 10ab3ae974 update showtheme 2019-12-13 23:35:05 +01:00
Daniel Schwabeneder b908202c47 Merge pull request #2327 from daschw/theme
copy theme defaults
2019-12-13 21:14:45 +01:00
daschw 61d4c84ef4 copy theme defaults 2019-12-13 19:44:37 +01:00
Daniel Schwabeneder 68a0baf299 update and reactivate precompile 2019-12-13 14:55:16 +01:00
Daniel Schwabeneder aef75cb073 add guides and fix 3d bg_inside 2019-12-13 14:16:05 +01:00
Daniel Schwabeneder c5fe90d135 move zaxis to the left 2019-12-13 14:16:05 +01:00
Daniel Schwabeneder 85e5f2e971 increase right margin for outer legend 2019-12-13 14:16:05 +01:00
Daniel Schwabeneder 58bf14fc85 minor preparations for guides 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder 0d09975fba avoid precompilation temporarily 2019-12-13 14:16:04 +01:00
daschw 06afcedf56 implement 3d tick labels 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder c7cc76b2b6 increase plotarea for 3d plots in gr 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder 84b108f6d0 3d axes grid and ticks in gr 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder cb6f0772b7 avoid multiple calls to axis_drawing_info 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder 4263ced69b implement axes_drawing_info_3d 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder f5c6b06eb6 fix 3d Segments constructor 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder 05ef841d63 simplify axes_drawing_info 2019-12-13 14:16:04 +01:00
Daniel Schwabeneder 140afeb53d Merge pull request #2320 from korsbo/layout_colon
Support colons in layout keyword argument.
2019-12-12 09:35:56 +01:00
Daniel Schwabeneder 639a09bccb Merge pull request #2322 from JuliaPlots/compathelper/new_version/2019-12-12-03-02-29-808-2906006334
CompatHelper: bump compat for "Requires" to "1.0"
2019-12-12 09:32:10 +01:00
github-actions[bot] f105d41e54 CompatHelper: bump compat for "Requires" to "1.0" 2019-12-12 03:02:30 +00:00
Niklas Korsbo 140a429e09 Fix regression of layout_args. 2019-12-11 12:27:44 +00:00
Simon Christ 28d5e0bb7d commented too much 2019-12-11 13:23:50 +01:00
Simon Christ 3dec7fe394 comment save tests 2019-12-11 13:09:48 +01:00
Niklas Korsbo e54eb53665 Fix layout specification bug. 2019-12-11 11:11:14 +00:00
Niklas Korsbo 9b3cf3a818 Support colons in layout kwarg. 2019-12-11 10:58:39 +00:00
Daniel Schwabeneder 3d306578f1 Merge pull request #2317 from daschw/gr-logticks
fix extra blank space in GR with log axis and engineering notation
2019-12-11 09:28:21 +01:00
Michael Krabbe Borregaard e615718f1b up version 2019-12-10 22:15:57 +01:00
Daniel Schwabeneder fbbbd40353 fix extra blank space in GR with log axis and engineering notation 2019-12-10 13:12:35 +01:00
Simon Christ 0e694a9767 forget extra ribbon plot legend entries 2019-12-09 11:21:33 +01:00
Simon Christ 203e351cef fix scalar ribbon 2019-12-09 11:17:37 +01:00
Simon Christ 74ec895aca fix unintended filling of simple lines 2019-12-07 15:18:47 +01:00
Daniel Schwabeneder 3459bcd817 Merge pull request #2304 from michakraus/master
Generalized array fixes
2019-12-07 11:04:13 +01:00
Simon Christ d2c0840c43 fix dimensions 2019-12-06 19:37:35 +01:00
Simon Christ 9534bae4ef support asymmetric ribbons 2019-12-06 18:22:02 +01:00
Simon Christ 2a720a7491 better ribbon tests 2019-12-06 16:04:10 +01:00
Simon Christ 7b31e5f9b8 fix ribbon legend 2019-12-06 15:04:22 +01:00
Simon Christ d0be1e7d1d use UUIDs 2019-12-06 14:45:56 +01:00
Simon Christ 8434741599 add test 2019-12-06 14:42:35 +01:00
Simon Christ cfe1ede25a fix ribbon 2019-12-06 14:40:34 +01:00
Simon Christ ecc891279e fix background + fill between 2019-12-06 14:36:24 +01:00
Michael Kraus 750f96cca7 allow for generalized arrays in pgfplots backend 2019-12-06 09:34:40 +01:00
Daniel Schwabeneder 5051e06be0 Merge pull request #2306 from daschw/orca
Allow saving to pdf, svg and eps for plotly() via ORCA
2019-12-05 16:38:55 +01:00
Michael Kraus cde041e977 update SegmentsIterator to allow for generalized arrays 2019-12-05 14:09:05 +01:00
Daniel Schwabeneder 0fdf46fd2e Allow saving to pdf, svg and eps for plotly() via ORCA 2019-12-05 14:06:44 +01:00
Daniel Schwabeneder c902c3ff35 Merge pull request #2305 from daschw/clims
fix clims calculation for line_z etc.
2019-12-05 13:10:53 +01:00
Daniel Schwabeneder f0b006d3c9 fix clims calculation for line_z etc. 2019-12-05 12:52:44 +01:00
Michael Kraus 044daf08d4 generalized array fixes replacing length() and size() with eachindex() and axes(), etc. 2019-12-05 10:09:07 +01:00
Daniel Schwabeneder 0b5b8b2cc2 Merge pull request #2298 from daschw/minorticks
add checks in get_minor_ticks
2019-12-04 16:07:28 +01:00
Daniel Schwabeneder fae5c45cc4 Merge pull request #2302 from daschw/clims
Ignore clims of series without z colors
2019-12-04 16:07:13 +01:00
Daniel Schwabeneder 3bc8ffda58 Ignore clims of series without z colors 2019-12-04 15:41:37 +01:00
Josef Heinen 589713cb75 Merge remote-tracking branch 'upstream/master' 2019-12-03 21:25:42 +01:00
Josef Heinen ca9ce5427d Merge pull request #2299 from yha/uniform-heatmaps
Use GR.drawimage for uniform heatmaps
2019-12-03 21:05:40 +01:00
Josef Heinen 374809d3cf gr: optimize 'heatmap' logic 2019-12-03 17:50:40 +01:00
yha e1d45dec5d Use GR.drawimage for uniform heatmaps; Fix for general color spaces. 2019-12-03 17:40:55 +02:00
Daniel Schwabeneder bf60d6482f Merge pull request #2296 from BeastyBlacksmith/pgfplotsx-heatmap
fix pgfplotsx heatmap
2019-12-03 14:04:23 +01:00
Daniel Schwabeneder e04858c975 Merge pull request #2295 from BeastyBlacksmith/pgfplotsx
fix fillrange legends
2019-12-03 14:03:23 +01:00
Daniel Schwabeneder e0148ba1a8 add checks in get_minor_ticks 2019-12-03 14:01:36 +01:00
Simon Christ ee521107d3 fix heatmap 2019-12-03 00:31:00 +01:00
Simon Christ acbce64be9 fix fillrange legends 2019-12-02 16:31:10 +01:00
34 changed files with 2651 additions and 1765 deletions
+11
View File
@@ -0,0 +1,11 @@
name: TagBot
on:
schedule:
- cron: 0 * * * *
jobs:
TagBot:
runs-on: ubuntu-latest
steps:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -5,7 +5,7 @@ os:
# - osx
julia:
- 1
- 1.2
- 1.3
- nightly
matrix:
+6 -6
View File
@@ -3,14 +3,14 @@
#### notes on release changes, ongoing development, and future planned work
- Minor version 0.17 is the last one to support Julia 0.6!!
- Minor version 0.11 is the last one to support Julia 0.5!!
- Critical bugfixes only
- `backports` branch is for Julia 0.5
---
## (current master)
## 0.28.3
- support generalized array interface
- save to pdf, svg and eps in plotlyjs
- fix for clims in line_z
- optimize heatmap logic in gr
## 0.26.3
- fix `vline` with dates
- fix PyPlot logscale bug
+7 -6
View File
@@ -1,7 +1,7 @@
name = "Plots"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
author = ["Tom Breloff (@tbreloff)"]
version = "0.28.2"
version = "0.29.2"
[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
@@ -32,18 +32,19 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat]
Contour = "0.5"
FFMPEG = "0.2"
FixedPointNumbers = "0.6"
GR = "0.44"
FFMPEG = "0.2, 0.3"
FixedPointNumbers = "0.6, 0.7, 0.8"
GR = "0.46"
GeometryTypes = "0.7"
JSON = "0.21"
Measures = "0.3"
NaNMath = "0.3"
PGFPlotsX = "1.2.0"
PlotThemes = "1"
PlotUtils = "0.6.1"
RecipesBase = "0.6, 0.7"
RecipesBase = "0.8"
Reexport = "0.2"
Requires = "0.5"
Requires = "0.5, 1.0"
Showoff = "0.3.1"
StatsBase = "0.32"
julia = "1"
+20 -8
View File
@@ -1,13 +1,25 @@
# Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/mkborregaard/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<a href="http://docs.juliaplots.org/latest/" target="_blank"><img src="https://img.shields.io/badge/docs-latest-blue.svg" alt="Latest documentation"></a>
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
<!-- [![codecov.io](http://codecov.io/github/tbreloff/Plots.jl/coverage.svg?branch=master)](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
[travis-img]: https://img.shields.io/travis/JuliaPlots/Plots.jl?logo=travis
[travis-url]: https://travis-ci.org/JuliaPlots/Plots.jl
[appveyor-img]: https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true
[appveyor-url]: https://ci.appveyor.com/project/mkborregaard/plots-jl
[pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/P/Plots.svg
[pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html
[gitter-img]: https://badges.gitter.im/tbreloff/Plots.jl.svg
[gitter-url]: https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
[docs-img]: https://img.shields.io/badge/docs-stable-blue.svg
[docs-url]: http://docs.juliaplots.org/latest/
[![][travis-img]][travis-url]
[![][appveyor-img]][appveyor-url]
[![][pkgeval-img]][pkgeval-url]
[![][gitter-img]][gitter-url]
[![][docs-img]][docs-url]
#### Created by Tom Breloff (@tbreloff)
+1 -1
View File
@@ -2,7 +2,7 @@ environment:
matrix:
# - julia_version: 0.7
- julia_version: 1
- julia_version: 1.2
- julia_version: 1.3
- julia_version: nightly
platform:
+1 -1
View File
@@ -11,7 +11,7 @@ import SparseArrays: findnz
using FFMPEG
@reexport using RecipesBase
import RecipesBase: plot, plot!, animate
import RecipesBase: plot, plot!, animate, is_explicit
using Base.Meta
@reexport using PlotUtils
@reexport using PlotThemes
+3 -3
View File
@@ -163,16 +163,16 @@ function _animate(forloop::Expr, args...; callgif = false)
error("Unsupported animate filter: $args")
end
push!(block.args, :(if $filterexpr; frame($animsym); end))
push!(block.args, :(if $filterexpr; Plots.frame($animsym); end))
push!(block.args, :(global $countersym += 1))
# add a final call to `gif(anim)`?
retval = callgif ? :(gif($animsym)) : animsym
retval = callgif ? :(Plots.gif($animsym)) : animsym
# full expression:
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Animation() # init animation object
$animsym = Plots.Animation() # init animation object
global $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
$retval # return the animation object, or the gif
+108 -100
View File
@@ -90,7 +90,7 @@ like_surface(seriestype::Symbol) = seriestype in _surface_like
is3d(seriestype::Symbol) = seriestype in _3dTypes
is3d(series::Series) = is3d(series.plotattributes)
is3d(plotattributes::KW) = trueOrAllTrue(is3d, Symbol(plotattributes[:seriestype]))
is3d(plotattributes::AKW) = trueOrAllTrue(is3d, Symbol(plotattributes[:seriestype]))
is3d(sp::Subplot) = string(sp.attr[:projection]) == "3d"
ispolar(sp::Subplot) = string(sp.attr[:projection]) == "polar"
@@ -418,37 +418,26 @@ const _suppress_warnings = Set{Symbol}([
# add defaults for the letter versions
const _axis_defaults_byletter = KW()
for letter in (:x,:y,:z)
for k in keys(_axis_defaults)
# for k in (
# :guide,
# :lims,
# :ticks,
# :scale,
# :rotation,
# :flip,
# :link,
# :tickfont,
# :guidefont,
# :foreground_color_axis,
# :foreground_color_border,
# :foreground_color_text,
# :foreground_color_guide,
# :discrete_values,
# :formatter,
# )
_axis_defaults_byletter[Symbol(letter,k)] = :match
# allow the underscore version too: xguide or x_guide
add_aliases(Symbol(letter, k), Symbol(letter, "_", k))
function reset_axis_defaults_byletter!()
for letter in (:x,:y,:z)
_axis_defaults_byletter[letter] = KW()
for (k,v) in _axis_defaults
_axis_defaults_byletter[letter][k] = v
end
end
end
reset_axis_defaults_byletter!()
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,
_axis_defaults_byletter
_subplot_defaults
]
const _initial_defaults = deepcopy(_all_defaults)
@@ -463,6 +452,12 @@ const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefonts
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
is_subplot_attr(k) = haskey(_subplot_defaults, k)
is_series_attr(k) = haskey(_series_defaults, k)
#is_axis_attr(k) = haskey(_axis_defaults_byletter, k)
is_axis_attr(k) = haskey(_axis_defaults, Symbol(chop(string(k); head=1, tail=0)))
is_axis_attr_noletter(k) = haskey(_axis_defaults, k)
RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k)
# -----------------------------------------------------------------------------
@@ -475,7 +470,7 @@ autopick(notarr, idx::Integer) = notarr
autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
autopick_ignore_none_auto(notarr, idx::Integer) = notarr
function aliasesAndAutopick(plotattributes::KW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
function aliasesAndAutopick(plotattributes::AKW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
if plotattributes[sym] == :auto
plotattributes[sym] = autopick_ignore_none_auto(options, plotIndex)
elseif haskey(aliases, plotattributes[sym])
@@ -611,6 +606,16 @@ end
# -----------------------------------------------------------------------------
function parse_axis_kw(s::Symbol)
s = string(s)
for letter in ('x', 'y', 'z')
if startswith(s, letter)
return (Symbol(letter), Symbol(chop(s, head=1, tail=0)))
end
end
return nothing
end
# update the defaults globally
"""
@@ -629,6 +634,10 @@ function default(k::Symbol)
if haskey(_axis_defaults, k)
return _axis_defaults[k]
end
if (axis_k = parse_axis_kw(k)) !== nothing
letter, key = axis_k
return _axis_defaults_byletter[letter][key]
end
k in _suppress_warnings || error("Unknown key: ", k)
end
@@ -644,6 +653,11 @@ function default(k::Symbol, v)
_axis_defaults[k] = v
return v
end
if (axis_k = parse_axis_kw(k)) !== nothing
letter, key = axis_k
_axis_defaults_byletter[letter][key] = v
return v
end
k in _suppress_warnings || error("Unknown key: ", k)
end
@@ -655,19 +669,20 @@ function default(; kw...)
end
end
function default(plotattributes::KW, k::Symbol)
function default(plotattributes::AKW, k::Symbol)
get(plotattributes, k, default(k))
end
function reset_defaults()
foreach(merge!, _all_defaults, _initial_defaults)
merge!(_axis_defaults, _initial_axis_defaults)
reset_axis_defaults_byletter!()
end
# -----------------------------------------------------------------------------
# if arg is a valid color value, then set plotattributes[csym] and return true
function handleColors!(plotattributes::KW, arg, csym::Symbol)
function handleColors!(plotattributes::AKW, arg, csym::Symbol)
try
if arg == :auto
plotattributes[csym] = :auto
@@ -684,7 +699,7 @@ end
function processLineArg(plotattributes::KW, arg)
function processLineArg(plotattributes::AKW, arg)
# seriestype
if allLineTypes(arg)
plotattributes[:seriestype] = arg
@@ -723,7 +738,7 @@ function processLineArg(plotattributes::KW, arg)
end
function processMarkerArg(plotattributes::KW, arg)
function processMarkerArg(plotattributes::AKW, arg)
# markershape
if allShapes(arg)
plotattributes[:markershape] = arg
@@ -763,7 +778,7 @@ function processMarkerArg(plotattributes::KW, arg)
end
function processFillArg(plotattributes::KW, arg)
function processFillArg(plotattributes::AKW, arg)
# fr = get(plotattributes, :fillrange, 0)
if typeof(arg) <: Brush
arg.size === nothing || (plotattributes[:fillrange] = arg.size)
@@ -786,7 +801,6 @@ function processFillArg(plotattributes::KW, arg)
plotattributes[:fillrange] = arg
elseif !handleColors!(plotattributes, arg, :fillcolor)
plotattributes[:fillrange] = arg
end
# plotattributes[:fillrange] = fr
@@ -794,7 +808,7 @@ function processFillArg(plotattributes::KW, arg)
end
function processGridArg!(plotattributes::KW, arg, letter)
function processGridArg!(plotattributes::AKW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
plotattributes[Symbol(letter, :grid)] = hasgrid(arg, letter)
@@ -822,7 +836,7 @@ function processGridArg!(plotattributes::KW, arg, letter)
end
end
function processMinorGridArg!(plotattributes::KW, arg, letter)
function processMinorGridArg!(plotattributes::AKW, arg, letter)
if arg in _allGridArgs || isa(arg, Bool)
plotattributes[Symbol(letter, :minorgrid)] = hasgrid(arg, letter)
@@ -855,7 +869,7 @@ function processMinorGridArg!(plotattributes::KW, arg, letter)
end
end
function processFontArg!(plotattributes::KW, fontname::Symbol, arg)
function processFontArg!(plotattributes::AKW, fontname::Symbol, arg)
T = typeof(arg)
if T <: Font
plotattributes[Symbol(fontname, :family)] = arg.family
@@ -892,7 +906,7 @@ _replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape
function _add_markershape(plotattributes::KW)
function _add_markershape(plotattributes::AKW)
# add the markershape if it needs to be added... hack to allow "m=10" to add a shape,
# and still allow overriding in _apply_recipe
ms = pop!(plotattributes, :markershape_to_add, :none)
@@ -902,7 +916,7 @@ function _add_markershape(plotattributes::KW)
end
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
function preprocessArgs!(plotattributes::KW)
function preprocessArgs!(plotattributes::AKW)
replaceAliases!(plotattributes, _keyAliases)
# clear all axis stuff
@@ -922,7 +936,7 @@ function preprocessArgs!(plotattributes::KW)
# end
# handle axis args common to all axis
args = pop!(plotattributes, :axis, ())
args = pop_kw!(plotattributes, :axis, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
process_axis_arg!(plotattributes, arg, letter)
@@ -931,7 +945,7 @@ function preprocessArgs!(plotattributes::KW)
# handle axis args
for letter in (:x, :y, :z)
asym = Symbol(letter, :axis)
args = pop!(plotattributes, asym, ())
args = pop_kw!(plotattributes, asym, ())
if !(typeof(args) <: Axis)
for arg in wraptuple(args)
process_axis_arg!(plotattributes, arg, letter)
@@ -949,7 +963,7 @@ function preprocessArgs!(plotattributes::KW)
end
# handle grid args common to all axes
args = pop!(plotattributes, :grid, ())
args = pop_kw!(plotattributes, :grid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processGridArg!(plotattributes, arg, letter)
@@ -958,13 +972,13 @@ function preprocessArgs!(plotattributes::KW)
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :grid)
args = pop!(plotattributes, gridsym, ())
args = pop_kw!(plotattributes, gridsym, ())
for arg in wraptuple(args)
processGridArg!(plotattributes, arg, letter)
end
end
# handle minor grid args common to all axes
args = pop!(plotattributes, :minorgrid, ())
args = pop_kw!(plotattributes, :minorgrid, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processMinorGridArg!(plotattributes, arg, letter)
@@ -973,21 +987,21 @@ function preprocessArgs!(plotattributes::KW)
# handle individual axes grid args
for letter in (:x, :y, :z)
gridsym = Symbol(letter, :minorgrid)
args = pop!(plotattributes, gridsym, ())
args = pop_kw!(plotattributes, gridsym, ())
for arg in wraptuple(args)
processMinorGridArg!(plotattributes, arg, letter)
end
end
# fonts
for fontname in (:titlefont, :legendfont, :legendtitlefont)
args = pop!(plotattributes, fontname, ())
args = pop_kw!(plotattributes, fontname, ())
for arg in wraptuple(args)
processFontArg!(plotattributes, fontname, arg)
end
end
# handle font args common to all axes
for fontname in (:tickfont, :guidefont)
args = pop!(plotattributes, fontname, ())
args = pop_kw!(plotattributes, fontname, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
@@ -997,7 +1011,7 @@ function preprocessArgs!(plotattributes::KW)
# handle individual axes font args
for letter in (:x, :y, :z)
for fontname in (:tickfont, :guidefont)
args = pop!(plotattributes, Symbol(letter, fontname), ())
args = pop_kw!(plotattributes, Symbol(letter, fontname), ())
for arg in wraptuple(args)
processFontArg!(plotattributes, Symbol(letter, fontname), arg)
end
@@ -1005,7 +1019,7 @@ function preprocessArgs!(plotattributes::KW)
end
# handle line args
for arg in wraptuple(pop!(plotattributes, :line, ()))
for arg in wraptuple(pop_kw!(plotattributes, :line, ()))
processLineArg(plotattributes, arg)
end
@@ -1019,7 +1033,7 @@ function preprocessArgs!(plotattributes::KW)
processMarkerArg(plotattributes, arg)
anymarker = true
end
delete!(plotattributes, :marker)
reset_kw!(plotattributes, :marker)
if haskey(plotattributes, :markershape)
plotattributes[:markershape] = _replace_markershape(plotattributes[:markershape])
if plotattributes[:markershape] == :none && plotattributes[:seriestype] in (:scatter, :scatterbins, :scatterhist, :scatter3d) #the default should be :auto, not :none, so that :none can be set explicitly and would be respected
@@ -1033,7 +1047,7 @@ function preprocessArgs!(plotattributes::KW)
for arg in wraptuple(get(plotattributes, :fill, ()))
processFillArg(plotattributes, arg)
end
delete!(plotattributes, :fill)
reset_kw!(plotattributes, :fill)
# handle series annotations
if haskey(plotattributes, :series_annotations)
@@ -1098,7 +1112,7 @@ function extractGroupArgs(v::AVec, args...; legendEntry = string)
if n > 100
@warn("You created n=$n groups... Is that intended?")
end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
groupIds = Vector{Int}[filter(i -> v[i] == glab, eachindex(v)) for glab in groupLabels]
GroupBy(map(legendEntry, groupLabels), groupIds)
end
@@ -1106,7 +1120,7 @@ legendEntryFromTuple(ns::Tuple) = join(ns, ' ')
# this is when given a tuple of vectors of values to group by
function extractGroupArgs(vs::Tuple, args...)
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
v = map(tuple, vs...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
@@ -1116,7 +1130,7 @@ legendEntryFromTuple(ns::NamedTuple) =
join(["$k = $v" for (k, v) in pairs(ns)], ", ")
function extractGroupArgs(vs::NamedTuple, args...)
isempty(vs) && return GroupBy([""], [1:size(args[1],1)])
isempty(vs) && return GroupBy([""], [axes(args[1],1)])
v = map(NamedTuple{keys(vs)}tuple, values(vs)...)
extractGroupArgs(v, args...; legendEntry = legendEntryFromTuple)
end
@@ -1131,13 +1145,13 @@ end
filter_data(v::AVec, idxfilter::AVec{Int}) = v[idxfilter]
filter_data(v, idxfilter) = v
function filter_data!(plotattributes::KW, idxfilter)
function filter_data!(plotattributes::AKW, idxfilter)
for s in (:x, :y, :z)
plotattributes[s] = filter_data(get(plotattributes, s, nothing), idxfilter)
end
end
function _filter_input_data!(plotattributes::KW)
function _filter_input_data!(plotattributes::AKW)
idxfilter = pop!(plotattributes, :idxfilter, nothing)
if idxfilter !== nothing
filter_data!(plotattributes, idxfilter)
@@ -1150,7 +1164,7 @@ end
const _already_warned = Dict{Symbol,Set{Symbol}}()
const _to_warn = Set{Symbol}()
function warnOnUnsupported_args(pkg::AbstractBackend, plotattributes::KW)
function warnOnUnsupported_args(pkg::AbstractBackend, plotattributes)
empty!(_to_warn)
bend = backend_name(pkg)
already_warned = get!(_already_warned, bend, Set{Symbol}())
@@ -1174,7 +1188,7 @@ end
# _markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
# _markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
function warnOnUnsupported(pkg::AbstractBackend, plotattributes::KW)
function warnOnUnsupported(pkg::AbstractBackend, plotattributes)
if !is_seriestype_supported(pkg, plotattributes[:seriestype])
@warn("seriestype $(plotattributes[:seriestype]) is unsupported with $pkg. Choose from: $(supported_seriestypes(pkg))")
end
@@ -1186,7 +1200,7 @@ function warnOnUnsupported(pkg::AbstractBackend, plotattributes::KW)
end
end
function warnOnUnsupported_scales(pkg::AbstractBackend, plotattributes::KW)
function warnOnUnsupported_scales(pkg::AbstractBackend, plotattributes::AKW)
for k in (:xscale, :yscale, :zscale, :scale)
if haskey(plotattributes, k)
v = plotattributes[k]
@@ -1225,24 +1239,26 @@ convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# anything else is returned as-is
function slice_arg(v::AMat, idx::Int)
c = mod1(idx, size(v,2))
size(v,1) == 1 ? v[1,c] : v[:,c]
m,n = axes(v)
size(v,1) == 1 ? v[first(m),n[c]] : v[:,n[c]]
end
slice_arg(wrapper::InputWrapper, idx) = wrapper.obj
slice_arg(v, idx) = v
# given an argument key (k), we want to extract the argument value for this index.
# matrices are sliced by column, otherwise we
# if nothing is set (or container is empty), return the default or the existing value.
function slice_arg!(plotattributes_in::KW,plotattributes_out::KW, k::Symbol, default_value, idx::Int, remove_pair::Bool)
v = get(plotattributes_in, k, get(plotattributes_out, k, default_value))
plotattributes_out[k] = if haskey(plotattributes_in, k) && typeof(v) <: AMat && !isempty(v)
# given an argument key (k), extract the argument value for this index,
# and set into plotattributes[k]. Matrices are sliced by column.
# if nothing is set (or container is empty), return the existing value.
function slice_arg!(plotattributes_in, plotattributes_out,
k::Symbol, idx::Int, remove_pair::Bool)
v = get(plotattributes_in, k, plotattributes_out[k])
plotattributes_out[k] = if haskey(plotattributes_in, k) && typeof(v) <: AMat && !isempty(v)
slice_arg(v, idx)
else
v
end
if remove_pair
delete!(plotattributes_in, k)
reset_kw!(plotattributes_in, k)
end
return
end
@@ -1251,7 +1267,7 @@ end
# # if the value is `:match` then we take whatever match_color is.
# # this is mainly used for cascading defaults for foreground and background colors
# function color_or_match!(plotattributes::KW, k::Symbol, match_color)
# function color_or_match!(plotattributes::AKW, k::Symbol, match_color)
# v = plotattributes[k]
# plotattributes[k] = if v == :match
# match_color
@@ -1262,15 +1278,9 @@ end
# end
# end
function color_or_nothing!(plotattributes::KW, k::Symbol)
function color_or_nothing!(plotattributes, k::Symbol)
v = plotattributes[k]
plotattributes[k] = if v === nothing || v == false
RGBA{Float64}(0,0,0,0)
elseif v != :match
plot_color(v)
else
v
end
plotattributes[k] = v == :match ? v : plot_color(v)
return
end
@@ -1369,18 +1379,18 @@ Base.get(series::Series, k::Symbol, v) = get(series.plotattributes, k, v)
# -----------------------------------------------------------------------------
function fg_color(plotattributes::KW)
fg = default(plotattributes, :foreground_color)
function fg_color(plotattributes::AKW)
fg = get(plotattributes, :foreground_color, :auto)
if fg == :auto
bg = plot_color(default(plotattributes, :background_color))
bg = plot_color(get(plotattributes, :background_color, :white))
fg = isdark(bg) ? colorant"white" : colorant"black"
else
plot_color(fg)
end
end
function fg_color_sp(plotattributes::KW)
fgsp = default(plotattributes, :foreground_color_subplot)
function fg_color_sp(plotattributes::AKW)
fgsp = get(plotattributes, :foreground_color_subplot, :match)
if fg == :match
fg_color(plotattributes)
else
@@ -1391,13 +1401,13 @@ end
# update attr from an input dictionary
function _update_plot_args(plt::Plot, plotattributes_in::KW)
function _update_plot_args(plt::Plot, plotattributes_in::AKW)
for (k,v) in _plot_defaults
slice_arg!(plotattributes_in, plt.attr, k, v, 1, true)
slice_arg!(plotattributes_in, plt.attr, k, 1, true)
end
# handle colors
plotattributes= plt.attr
plotattributes= plt.attr
plt[:background_color] = plot_color(plotattributes[:background_color])
plt[:foreground_color] = fg_color(plotattributes)
# bg = plot_color(plt.attr[:background_color])
@@ -1444,7 +1454,7 @@ function _update_subplot_colors(sp::Subplot)
return
end
function _update_axis(plt::Plot, sp::Subplot, plotattributes_in::KW, letter::Symbol, subplot_index::Int)
function _update_axis(plt::Plot, sp::Subplot, plotattributes_in::AKW, letter::Symbol, subplot_index::Int)
# get (maybe initialize) the axis
axis = get_axis(sp, letter)
@@ -1460,13 +1470,13 @@ function _update_axis(plt::Plot, sp::Subplot, plotattributes_in::KW, letter::Sym
return
end
function _update_axis(axis::Axis, plotattributes_in::KW, letter::Symbol, subplot_index::Int)
function _update_axis(axis::Axis, plotattributes_in::AKW, letter::Symbol, subplot_index::Int)
# grab magic args (for example `xaxis = (:flip, :log)`)
args = wraptuple(get(plotattributes_in, Symbol(letter, :axis), ()))
# build the KW of arguments from the letter version (i.e. xticks --> ticks)
kw = KW()
for (k,v) in _axis_defaults
for k in keys(_axis_defaults)
# first get the args without the letter: `tickfont = font(10)`
# note: we don't pop because we want this to apply to all axes! (delete after all have finished)
if haskey(plotattributes_in, k)
@@ -1511,12 +1521,12 @@ function _update_axis_links(plt::Plot, axis::Axis, letter::Symbol)
end
# update a subplots args and axes
function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in::KW, subplot_index::Int, remove_pair::Bool)
anns = pop!(sp.attr, :annotations, [])
function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in, subplot_index::Int, remove_pair::Bool)
anns = pop_kw!(sp.attr, :annotations)
# grab those args which apply to this subplot
for (k,v) in _subplot_defaults
slice_arg!(plotattributes_in, sp.attr, k, v, subplot_index, remove_pair)
# # grab those args which apply to this subplot
for k in keys(_subplot_defaults)
slice_arg!(plotattributes_in, sp.attr, k, subplot_index, remove_pair)
end
_update_subplot_periphery(sp, anns)
@@ -1550,30 +1560,27 @@ function get_series_color(c::AbstractArray, sp::Subplot, n::Int, seriestype)
map(x->get_series_color(x, sp, n, seriestype), c)
end
function ensure_gradient!(plotattributes::KW, csym::Symbol, asym::Symbol)
function ensure_gradient!(plotattributes::AKW, csym::Symbol, asym::Symbol)
if !isa(plotattributes[csym], ColorGradient)
plotattributes[csym] = typeof(plotattributes[asym]) <: AbstractVector ? cgrad() : cgrad(alpha = plotattributes[asym])
end
end
function _replace_linewidth(plotattributes::KW)
function _replace_linewidth(plotattributes::AKW)
# get a good default linewidth... 0 for surface and heatmaps
if get(plotattributes, :linewidth, :auto) == :auto
if plotattributes[:linewidth] == :auto
plotattributes[:linewidth] = (get(plotattributes, :seriestype, :path) in (:surface,:heatmap,:image) ? 0 : 1)
end
end
function _add_defaults!(plotattributes::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# add default values to our dictionary, being careful not to delete what we just added!
for (k,v) in _series_defaults
slice_arg!(plotattributes, plotattributes, k, v, commandIndex, false)
function _slice_series_args!(plotattributes::AKW, plt::Plot, sp::Subplot, commandIndex::Int)
for k in keys(_series_defaults)
haskey(plotattributes, k) && slice_arg!(plotattributes, plotattributes, k, commandIndex, false)
end
return plotattributes
end
function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
function _update_series_attributes!(plotattributes::AKW, plt::Plot, sp::Subplot)
pkg = plt.backend
globalIndex = plotattributes[:series_plotindex]
plotIndex = _series_index(plotattributes, sp)
@@ -1643,6 +1650,7 @@ function _update_series_attributes!(plotattributes::KW, plt::Plot, sp::Subplot)
# set label
label = plotattributes[:label]
label = (label == "AUTO" ? "y$globalIndex" : label)
label = label in (:none, nothing, false) ? "" : label
plotattributes[:label] = label
_replace_linewidth(plotattributes)
+327 -90
View File
@@ -7,29 +7,20 @@
# -------------------------------------------------------------------------
function Axis(sp::Subplot, letter::Symbol, args...; kw...)
# init with values from _plot_defaults
plotattributes = KW(
explicit = KW(
:letter => letter,
# :extrema => (Inf, -Inf),
:extrema => Extrema(),
:discrete_map => Dict(), # map discrete values to discrete indices
:continuous_values => zeros(0),
:discrete_values => [],
:use_minor => false,
:show => true, # show or hide the axis? (useful for linked subplots)
)
# get defaults from letter version, unless match
for (k,v) in _axis_defaults
lk = Symbol(letter, k)
lv = _axis_defaults_byletter[lk]
plotattributes[k] = (lv == :match ? v : lv)
end
# merge!(plotattributes, _axis_defaults)
plotattributes[:discrete_values] = []
attr = Attr(explicit, _axis_defaults_byletter[letter])
# update the defaults
attr!(Axis([sp], plotattributes), args...; kw...)
attr!(Axis([sp], attr), args...; kw...)
end
function get_axis(sp::Subplot, letter::Symbol)
@@ -41,7 +32,7 @@ function get_axis(sp::Subplot, letter::Symbol)
end::Axis
end
function process_axis_arg!(plotattributes::KW, arg, letter = "")
function process_axis_arg!(plotattributes::AKW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
@@ -311,7 +302,9 @@ function get_minor_ticks(sp, axis, ticks)
minorticks = typeof(ticks[1])[]
for (i,hi) in enumerate(ticks[2:end])
lo = ticks[i]
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
if isfinite(lo) && hi > lo
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
end
end
minorticks[amin .<= minorticks .<= amax]
end
@@ -359,7 +352,7 @@ function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
end
function expand_extrema!(sp::Subplot, plotattributes::KW)
function expand_extrema!(sp::Subplot, plotattributes::AKW)
vert = isvertical(plotattributes)
# first expand for the data
@@ -575,10 +568,10 @@ end
# add the discrete value for each item. return the continuous values and the indices
function discrete_value!(axis::Axis, v::AVec)
n = length(v)
cvec = zeros(n)
discrete_indices = zeros(Int, n)
for i=1:n
n = eachindex(v)
cvec = zeros(axes(v))
discrete_indices = similar(Array{Int}, axes(v))
for i in n
cvec[i], discrete_indices[i] = discrete_value!(axis, v[i])
end
cvec, discrete_indices
@@ -586,10 +579,10 @@ end
# add the discrete value for each item. return the continuous values and the indices
function discrete_value!(axis::Axis, v::AMat)
n,m = size(v)
cmat = zeros(n,m)
discrete_indices = zeros(Int, n, m)
for i=1:n, j=1:m
n,m = axes(v)
cmat = zeros(axes(v))
discrete_indices = similar(Array{Int}, axes(v))
for i in n, j in m
cmat[i,j], discrete_indices[i,j] = discrete_value!(axis, v[i,j])
end
cmat, discrete_indices
@@ -635,13 +628,13 @@ function axis_drawing_info(sp::Subplot)
if sp[:framestyle] != :none
# xaxis
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
if xaxis[:showaxis]
if sp[:framestyle] != :grid
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
push!(xaxis_segs, (xmin, y1), (xmax, y1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1
@@ -654,55 +647,48 @@ function axis_drawing_info(sp::Subplot)
if !(xaxis[:ticks] in (:none, nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.015 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(ymax) - f(ymin)))
(-t, t)
else
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for xtick in xticks[1]
if xaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
end
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
end
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid]
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(ymin) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
t2 = invf(f(ymax) - 0.01 * (f(ymax) - f(ymin)) * ticks_in)
t3 = invf(f(0) + 0.01 * (f(ymax) - f(ymin)) * ticks_in)
for xminortick in xminorticks
if xaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xminortick, tick_start), (xminortick, tick_stop)) # bottom tick
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(ymax) - f(ymin)))
(-t, t)
else
t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for xtick in xminorticks
if xaxis[:showaxis]
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
end
xaxis[:minorgrid] && push!(xminorgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:minorgrid] && push!(xminorgrid_segs, (xminortick, ymin), (xminortick, ymax)) # vertical grid
end
end
# yaxis
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
if yaxis[:showaxis]
if sp[:framestyle] != :grid
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
push!(yaxis_segs, (x1, ymin), (x1, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1
@@ -715,46 +701,297 @@ function axis_drawing_info(sp::Subplot)
if !(yaxis[:ticks] in (:none, nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.015 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(xmax) - f(xmin)))
(-t, t)
else
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t = invf(f(x1) + 0.012 * (f(x2) - f(x1)) * ticks_in)
(x1, t)
end
for ytick in yticks[1]
if yaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid]
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t1 = invf(f(xmin) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
t2 = invf(f(xmax) - 0.01 * (f(xmax) - f(xmin)) * ticks_in)
t3 = invf(f(0) + 0.01 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yminorticks
if yaxis[:showaxis]
tick_start, tick_stop = if sp[:framestyle] == :origin
(0, t3)
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(xmax) - f(xmin)))
(-t, t)
else
t = invf(f(x1) + 0.006 * (f(x2) - f(x1)) * ticks_in)
(x1, t)
end
for ytick in yminorticks
if yaxis[:showaxis]
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end
yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:minorgrid] && push!(yminorgrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
end
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs
end
function axis_drawing_info_3d(sp::Subplot)
xaxis, yaxis, zaxis = sp[:xaxis], sp[:yaxis], sp[:zaxis]
xmin, xmax = axis_limits(sp, :x)
ymin, ymax = axis_limits(sp, :y)
zmin, zmax = axis_limits(sp, :z)
xticks = get_ticks(sp, xaxis)
yticks = get_ticks(sp, yaxis)
zticks = get_ticks(sp, zaxis)
xminorticks = get_minor_ticks(sp, xaxis, xticks)
yminorticks = get_minor_ticks(sp, yaxis, yticks)
zminorticks = get_minor_ticks(sp, zaxis, zticks)
xaxis_segs = Segments(3)
yaxis_segs = Segments(3)
zaxis_segs = Segments(3)
xtick_segs = Segments(3)
ytick_segs = Segments(3)
ztick_segs = Segments(3)
xgrid_segs = Segments(3)
ygrid_segs = Segments(3)
zgrid_segs = Segments(3)
xminorgrid_segs = Segments(3)
yminorgrid_segs = Segments(3)
zminorgrid_segs = Segments(3)
xborder_segs = Segments(3)
yborder_segs = Segments(3)
zborder_segs = Segments(3)
if sp[:framestyle] != :none
# xaxis
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
z1, z2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(xaxis[:mirror], zaxis[:flip]) ? (zmax, zmin) : (zmin, zmax)
end
if xaxis[:showaxis]
if sp[:framestyle] != :grid
push!(xaxis_segs, (xmin, y1, z1), (xmax, y1, z1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(xticks in (:none, nothing, false)) && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2, z2), (xmax, y2, z2)) # top spine
end
if !(xaxis[:ticks] in (:none, nothing, false))
f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale])
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(ymax) - f(ymin)))
(-t, t)
else
ticks_in = xaxis[:tick_direction] == :out ? -1 : 1
t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for xtick in xticks[1]
if xaxis[:showaxis]
push!(xtick_segs, (xtick, tick_start, z1), (xtick, tick_stop, z1)) # bottom tick
end
if xaxis[:grid]
if sp[:framestyle] in (:origin, :zerolines)
push!(xgrid_segs, (xtick, ymin, 0.0), (xtick, ymax, 0.0))
push!(xgrid_segs, (xtick, 0.0, zmin), (xtick, 0.0, zmax))
else
push!(xgrid_segs, (xtick, y1, z1), (xtick, y2, z1))
push!(xgrid_segs, (xtick, y2, z1), (xtick, y2, z2))
end
end
end
if !(xaxis[:minorticks] in (:none, nothing, false)) || xaxis[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(ymax) - f(ymin)))
(-t, t)
else
t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for xtick in xminorticks
if xaxis[:showaxis]
push!(xtick_segs, (xtick, tick_start, z1), (xtick, tick_stop, z1)) # bottom tick
end
if xaxis[:minorgrid]
if sp[:framestyle] in (:origin, :zerolines)
push!(xminorgrid_segs, (xtick, ymin, 0.0), (xtick, ymax, 0.0))
push!(xminorgrid_segs, (xtick, 0.0, zmin), (xtick, 0.0, zmax))
else
push!(xminorgrid_segs, (xtick, y1, z1), (xtick, y2, z1))
push!(xminorgrid_segs, (xtick, y2, z1), (xtick, y2, z2))
end
end
end
end
end
# yaxis
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmin, xmax) : (xmax, xmin)
end
z1, z2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(yaxis[:mirror], zaxis[:flip]) ? (zmax, zmin) : (zmin, zmax)
end
if yaxis[:showaxis]
if sp[:framestyle] != :grid
push!(yaxis_segs, (x1, ymin, z1), (x1, ymax, z1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(yticks in (:none, nothing,false)) && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin, z2), (x2, ymax, z2)) # right spine
end
if !(yaxis[:ticks] in (:none, nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(xmax) - f(xmin)))
(-t, t)
else
ticks_in = yaxis[:tick_direction] == :out ? -1 : 1
t = invf(f(x1) + 0.012 * (f(x2) - f(x1)) * ticks_in)
(x1, t)
end
for ytick in yticks[1]
if yaxis[:showaxis]
push!(ytick_segs, (tick_start, ytick, z1), (tick_stop, ytick, z1)) # left tick
end
if yaxis[:grid]
if sp[:framestyle] in (:origin, :zerolines)
push!(ygrid_segs, (xmin, ytick, 0.0), (xmax, ytick, 0.0))
push!(ygrid_segs, (0.0, ytick, zmin), (0.0, ytick, zmax))
else
push!(ygrid_segs, (x1, ytick, z1), (x2, ytick, z1))
push!(ygrid_segs, (x2, ytick, z1), (x2, ytick, z2))
end
end
end
if !(yaxis[:minorticks] in (:none, nothing, false)) || yaxis[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(xmax) - f(xmin)))
(-t, t)
else
t = invf(f(x1) + 0.006 * (f(x2) - f(x1)) * ticks_in)
(x1, t)
end
for ytick in yminorticks
if yaxis[:showaxis]
push!(ytick_segs, (tick_start, ytick, z1), (tick_stop, ytick, z1)) # left tick
end
if yaxis[:minorgrid]
if sp[:framestyle] in (:origin, :zerolines)
push!(yminorgrid_segs, (xmin, ytick, 0.0), (xmax, ytick, 0.0))
push!(yminorgrid_segs, (0.0, ytick, zmin), (0.0, ytick, zmax))
else
push!(yminorgrid_segs, (x1, ytick, z1), (x2, ytick, z1))
push!(yminorgrid_segs, (x2, ytick, z1), (x2, ytick, z2))
end
end
end
end
end
# zaxis
x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(zaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
end
y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
0.0, 0.0
else
xor(zaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
end
if zaxis[:showaxis]
if sp[:framestyle] != :grid
push!(zaxis_segs, (x1, y1, zmin), (x1, y1, zmax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && !(zticks in (:none, nothing,false)) && length(zticks) > 1
showticks = zticks[1] .!= 0
zticks = (zticks[1][showticks], zticks[2][showticks])
end
end
sp[:framestyle] in (:semi, :box) && push!(zborder_segs, (x2, y2, zmin), (x2, y2, zmax))
end
if !(zaxis[:ticks] in (:none, nothing, false))
f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale])
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.012 * (f(ymax) - f(ymin)))
(-t, t)
else
ticks_in = zaxis[:tick_direction] == :out ? -1 : 1
t = invf(f(y1) + 0.012 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for ztick in zticks[1]
if zaxis[:showaxis]
push!(ztick_segs, (x1, tick_start, ztick), (x1, tick_stop, ztick)) # left tick
end
if zaxis[:grid]
if sp[:framestyle] in (:origin, :zerolines)
push!(zgrid_segs, (xmin, 0.0, ztick), (xmax, 0.0, ztick))
push!(ygrid_segs, (0.0, ymin, ztick), (0.0, ymax, ztick))
else
push!(ygrid_segs, (x1, y1, ztick), (x1, y2, ztick))
push!(ygrid_segs, (x1, y2, ztick), (x2, y2, ztick))
end
end
end
if !(zaxis[:minorticks] in (:none, nothing, false)) || zaxis[:minorgrid]
tick_start, tick_stop = if sp[:framestyle] == :origin
t = invf(f(0) + 0.006 * (f(ymax) - f(ymin)))
(-t, t)
else
t = invf(f(y1) + 0.006 * (f(y2) - f(y1)) * ticks_in)
(y1, t)
end
for ztick in zminorticks
if zaxis[:showaxis]
push!(ztick_segs, (x1, tick_start, ztick), (x1, tick_stop, ztick)) # left tick
end
if zaxis[:minorgrid]
if sp[:framestyle] in (:origin, :zerolines)
push!(zminorgrid_segs, (xmin, 0.0, ztick), (xmax, 0.0, ztick))
push!(zminorgrid_segs, (0.0, ymin, ztick), (0.0, ymax, ztick))
else
push!(zminorgrid_segs, (x1, y1, ztick), (x1, y2, ztick))
push!(zminorgrid_segs, (x1, y2, ztick), (x2, y2, ztick))
end
end
end
end
end
end
xticks, yticks, zticks, xaxis_segs, yaxis_segs, zaxis_segs, xtick_segs, ytick_segs, ztick_segs, xgrid_segs, ygrid_segs, zgrid_segs, xminorgrid_segs, yminorgrid_segs, zminorgrid_segs, xborder_segs, yborder_segs, zborder_segs
end
+501 -170
View File
@@ -69,6 +69,19 @@ const gr_font_family = Dict(
# --------------------------------------------------------------------------------------
gr_color(c) = gr_color(c, color_type(c))
gr_color(c, ::Type{<:AbstractRGB}) = UInt32( round(UInt, clamp(alpha(c) * 255, 0, 255)) << 24 +
round(UInt, clamp(blue(c) * 255, 0, 255)) << 16 +
round(UInt, clamp(green(c) * 255, 0, 255)) << 8 +
round(UInt, clamp(red(c) * 255, 0, 255)) )
function gr_color(c, ::Type{<:AbstractGray})
g = round(UInt, clamp(gray(c) * 255, 0, 255))
α = round(UInt, clamp(alpha(c) * 255, 0, 255))
rgba = UInt32( α<<24 + g<<16 + g<<8 + g )
end
gr_color(c, ::Type) = gr_color(RGBA(c), RGB)
function gr_getcolorind(c)
gr_set_transparency(float(alpha(c)))
convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c)))
@@ -77,6 +90,7 @@ end
gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(_cycle(c,1)))
gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1)))
gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(_cycle(c,1)))
gr_set_bordercolor(c) = GR.setbordercolorind(gr_getcolorind(_cycle(c,1)))
gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(_cycle(c,1)))
gr_set_transparency(α::Real) = GR.settransparency(clamp(α, 0, 1))
gr_set_transparency(::Nothing) = GR.settransparency(1)
@@ -142,6 +156,48 @@ function gr_polyline(x, y, func = GR.polyline; arrowside = :none, arrowstyle = :
end
end
function gr_polyline3d(x, y, z, func = GR.polyline3d; arrowside = :none, arrowstyle = :simple)
iend = 0
n = length(x)
while iend < n-1
# set istart to the first index that is finite
istart = -1
for j = iend+1:n
if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j])
istart = j
break
end
end
if istart > 0
# iend is the last finite index
iend = -1
for j = istart+1:n
if isfinite(x[j]) && isfinite(y[j]) && isfinite(z[j])
iend = j
else
break
end
end
end
# if we found a start and end, draw the line segment, otherwise we're done
if istart > 0 && iend > 0
func(x[istart:iend], y[istart:iend], z[istart:iend])
if arrowside in (:head,:both)
gr_set_arrowstyle(arrowstyle)
GR.drawarrow(x[iend-1], y[iend-1], z[iend-1], x[iend], y[iend], z[iend])
end
if arrowside in (:tail,:both)
gr_set_arrowstyle(arrowstyle)
GR.drawarrow(x[istart+1], y[istart+1], z[istart+1], x[istart], y[istart], z[istart])
end
else
break
end
end
end
gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
function gr_inqtext(x, y, s)
@@ -176,15 +232,13 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
sinf = sind.(a)
cosf = cosd.(a)
rtick_values, rtick_labels = get_ticks(sp, yaxis)
if yaxis[:formatter] in (:scientific, :auto) && yaxis[:ticks] in (:auto, :native)
rtick_labels = convert_sci_unicode.(rtick_labels)
end
rtick_labels = gr_tick_label.((yaxis,), rtick_labels)
#draw angular grid
if xaxis[:grid]
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:gridalpha])
for i in 1:length(α)
for i in eachindex(α)
GR.polyline([sinf[i], 0], [cosf[i], 0])
end
end
@@ -193,7 +247,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:gridalpha])
for i in 1:length(rtick_values)
for i in eachindex(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
if r <= 1.0 && r >= 0.0
GR.drawarc(-r, r, -r, r, 0, 359)
@@ -210,7 +264,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
#draw angular ticks
if xaxis[:showaxis]
GR.drawarc(-1, 1, -1, 1, 0, 359)
for i in 1:length(α)
for i in eachindex(α)
x, y = GR.wctondc(1.1 * sinf[i], 1.1 * cosf[i])
GR.textext(x, y, string((360-α[i])%360, "^o"))
end
@@ -218,7 +272,7 @@ function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
#draw radial ticks
if yaxis[:showaxis]
for i in 1:length(rtick_values)
for i in eachindex(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
if r <= 1.0 && r >= 0.0
x, y = GR.wctondc(0.05, r)
@@ -236,18 +290,6 @@ gr_y_axislims(sp::Subplot) = axis_limits(sp, :y)
gr_z_axislims(sp::Subplot) = axis_limits(sp, :z)
gr_xy_axislims(sp::Subplot) = gr_x_axislims(sp)..., gr_y_axislims(sp)...
function gr_lims(sp::Subplot, axis::Axis, adjust::Bool, expand = nothing)
if expand !== nothing
expand_extrema!(axis, expand)
end
lims = axis_limits(sp, axis[:letter])
if adjust
GR.adjustrange(lims...)
else
lims
end
end
function gr_fill_viewport(vp::AVec{Float64}, c)
GR.savestate()
@@ -275,11 +317,15 @@ function gr_draw_marker(xi, yi, msize, shape::Shape)
GR.selntran(1)
end
function nominal_size()
w, h = gr_plot_size
min(w, h) / 500
end
# draw ONE symbol marker
function gr_draw_marker(xi, yi, msize::Number, shape::Symbol)
GR.setmarkertype(gr_markertype[shape])
w, h = gr_plot_size
GR.setmarkersize(0.3msize / ((w + h) * 0.001))
GR.setmarkersize(0.3msize / nominal_size())
GR.polymarker([xi], [yi])
end
@@ -292,26 +338,16 @@ function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize
shapes = series[:markershape]
if shapes != :none
for i=1:length(x)
for i=eachindex(x)
msi = _cycle(msize, i)
shape = _cycle(shapes, i)
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
i
GR.setborderwidth(series[:markerstrokewidth]);
gr_set_bordercolor(get_markerstrokecolor(series, i));
gr_set_markercolor(get_markercolor(series, clims, i));
gr_set_transparency(get_markeralpha(series, i))
# draw a filled in shape, slightly bigger, to estimate a stroke
if series[:markerstrokewidth] > 0
c = get_markerstrokecolor(series, i)
cfunc(c)
gr_set_transparency(c, get_markerstrokealpha(series, i))
gr_draw_marker(x[i], y[i], msi + series[:markerstrokewidth], shape)
end
# draw the shape - don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
c = get_markercolor(series, clims, i)
cfunc(c)
gr_set_transparency(c, get_markeralpha(series, i))
gr_draw_marker(x[i], y[i], msi, shape)
end
gr_draw_marker(x[i], y[i], msi, shape)
end
end
end
@@ -321,7 +357,7 @@ end
function gr_set_line(lw, style, c) #, a)
GR.setlinetype(gr_linetype[style])
w, h = gr_plot_size
GR.setlinewidth(_gr_thickness_scaling[1] * max(0, lw / ((w + h) * 0.001)))
GR.setlinewidth(_gr_thickness_scaling[1] * max(0, lw / nominal_size()))
gr_set_linecolor(c) #, a)
end
@@ -357,6 +393,12 @@ function gr_nans_to_infs!(z)
end
end
function gr_w3tondc(x, y, z)
xw, yw, zw = GR.wc3towc(x, y, z)
x, y = GR.wctondc(xw, yw)
return x, y
end
# --------------------------------------------------------------------------------------
# viewport plot area
@@ -375,16 +417,8 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi
viewport[2] = viewport_canvas[2] * (right(bb) / w)
viewport[3] = viewport_canvas[4] * (1.0 - bottom(bb) / h)
viewport[4] = viewport_canvas[4] * (1.0 - top(bb) / h)
if is3d(sp)
vp = viewport[:]
extent = min(vp[2] - vp[1], vp[4] - vp[3])
viewport[1] = 0.5 * (vp[1] + vp[2] - extent)
viewport[2] = 0.5 * (vp[1] + vp[2] + extent)
viewport[3] = 0.5 * (vp[3] + vp[4] - extent)
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
end
if hascolorbar(sp)
viewport[2] -= gr_colorbar_ratio
viewport[2] -= gr_colorbar_ratio * (1 + is3d(sp) / 2)
end
viewport
end
@@ -554,13 +588,13 @@ function gr_legend_pos(sp::Subplot, w, h)
if occursin("right", str)
if occursin("outer", str)
# As per https://github.com/jheinen/GR.jl/blob/master/src/jlgr.jl#L525
xpos = viewport_plotarea[2] + 0.11 + ymirror * gr_yaxis_width(sp)
xpos = viewport_plotarea[2] + 0.11 + ymirror * gr_axis_width(sp, sp[:yaxis])
else
xpos = viewport_plotarea[2] - 0.05 - w
end
elseif occursin("left", str)
if occursin("outer", str)
xpos = viewport_plotarea[1] - 0.05 - w - !ymirror * gr_yaxis_width(sp)
xpos = viewport_plotarea[1] - 0.05 - w - !ymirror * gr_axis_width(sp, sp[:yaxis])
else
xpos = viewport_plotarea[1] + 0.11
end
@@ -569,13 +603,13 @@ function gr_legend_pos(sp::Subplot, w, h)
end
if occursin("top", str)
if s == :outertop
ypos = viewport_plotarea[4] + 0.02 + h + xmirror * gr_xaxis_height(sp)
ypos = viewport_plotarea[4] + 0.02 + h + xmirror * gr_axis_height(sp, sp[:xaxis])
else
ypos = viewport_plotarea[4] - 0.06
end
elseif occursin("bottom", str)
if s == :outerbottom
ypos = viewport_plotarea[3] - 0.05 - !xmirror * gr_xaxis_height(sp)
ypos = viewport_plotarea[3] - 0.05 - !xmirror * gr_axis_height(sp, sp[:xaxis])
else
ypos = viewport_plotarea[3] + h + 0.06
end
@@ -734,26 +768,37 @@ function gr_get_ticks_size(ticks, rot)
return w, h
end
function gr_xaxis_height(sp)
xaxis = sp[:xaxis]
xticks, yticks = axis_drawing_info(sp)[1:2]
gr_set_font(tickfont(xaxis))
h = (xticks in (nothing, false, :none) ? 0 : last(gr_get_ticks_size(xticks, xaxis[:rotation])))
if xaxis[:guide] != ""
gr_set_font(guidefont(xaxis))
h += last(gr_text_size(xaxis[:guide]))
gr_tick_label(axis,label) = (axis[:formatter] in (:scientific, :auto)) ?
gr_convert_sci_tick_label(label) :
label
function gr_convert_sci_tick_label(label)
caret_split = split(label,'^')
if length(caret_split) == 2
base, exponent = caret_split
label = "$base^{$exponent}"
end
convert_sci_unicode(label)
end
function gr_axis_height(sp, axis)
ticks = get_ticks(sp, axis)
gr_set_font(tickfont(axis))
h = (ticks in (nothing, false, :none) ? 0 : last(gr_get_ticks_size(ticks, axis[:rotation])))
if axis[:guide] != ""
gr_set_font(guidefont(axis))
h += last(gr_text_size(axis[:guide]))
end
return h
end
function gr_yaxis_width(sp)
yaxis = sp[:yaxis]
xticks, yticks = axis_drawing_info(sp)[1:2]
gr_set_font(tickfont(yaxis))
w = (xticks in (nothing, false, :none) ? 0 : first(gr_get_ticks_size(yticks, yaxis[:rotation])))
if yaxis[:guide] != ""
gr_set_font(guidefont(yaxis))
w += last(gr_text_size(yaxis[:guide]))
function gr_axis_width(sp, axis)
ticks = get_ticks(sp, axis)
gr_set_font(tickfont(axis))
w = (ticks in (nothing, false, :none) ? 0 : first(gr_get_ticks_size(ticks, axis[:rotation])))
if axis[:guide] != ""
gr_set_font(guidefont(axis))
w += last(gr_text_size(axis[:guide]))
end
return w
end
@@ -777,48 +822,132 @@ function _update_min_padding!(sp::Subplot{GRBackend})
h = 1mm + gr_plot_size[2] * l * px
toppad += h
end
# Add margin for x and y ticks
xticks, yticks = axis_drawing_info(sp)[1:2]
if !(xticks in (nothing, false, :none))
flip, mirror = gr_set_xticks_font(sp)
l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation]))
h = 1mm + gr_plot_size[2] * l * px
if mirror
toppad += h
else
bottompad += h
if is3d(sp)
xaxis, yaxis, zaxis = sp[:xaxis], sp[:yaxis], sp[:zaxis]
xticks, yticks, zticks = get_ticks(sp, xaxis), get_ticks(sp, yaxis), get_ticks(sp, zaxis)
# Add margin for x and y ticks
h = 0mm
if !(xticks in (nothing, false, :none))
gr_set_font(
tickfont(xaxis),
halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2],
valign = (xaxis[:mirror] ? :bottom : :top),
rotation = xaxis[:rotation]
)
l = 0.01 + last(gr_get_ticks_size(xticks, xaxis[:rotation]))
h = max(h, 1mm + gr_plot_size[2] * l * px)
end
end
if !(yticks in (nothing, false, :none))
flip, mirror = gr_set_yticks_font(sp)
l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation]))
w = 1mm + gr_plot_size[1] * l * px
if mirror
rightpad += w
else
leftpad += w
if !(yticks in (nothing, false, :none))
gr_set_font(
tickfont(yaxis),
halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2],
valign = (yaxis[:mirror] ? :bottom : :top),
rotation = yaxis[:rotation]
)
l = 0.01 + last(gr_get_ticks_size(yticks, yaxis[:rotation]))
h = max(h, 1mm + gr_plot_size[2] * l * px)
end
end
# Add margin for x label
if sp[:xaxis][:guide] != ""
gr_set_font(guidefont(sp[:xaxis]))
l = last(gr_text_size(sp[:xaxis][:guide]))
h = 1mm + gr_plot_size[2] * l * px
if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true)
toppad += h
else
bottompad += h
if h > 0mm
if xaxis[:mirror] || yaxis[:mirror]
toppad += h
end
if !xaxis[:mirror] || !yaxis[:mirror]
bottompad += h
end
end
end
# Add margin for y label
if sp[:yaxis][:guide] != ""
gr_set_font(guidefont(sp[:yaxis]))
l = last(gr_text_size(sp[:yaxis][:guide]))
w = 1mm + gr_plot_size[2] * l * px
if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true)
rightpad += w
else
leftpad += w
if !(zticks in (nothing, false, :none))
gr_set_font(
tickfont(zaxis),
halign = (zaxis[:mirror] ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2],
rotation = zaxis[:rotation]
)
l = 0.01 + first(gr_get_ticks_size(zticks, zaxis[:rotation]))
w = 1mm + gr_plot_size[1] * l * px
if zaxis[:mirror]
rightpad += w
else
leftpad += w
end
end
# Add margin for x or y label
h = 0mm
if xaxis[:guide] != ""
gr_set_font(guidefont(sp[:xaxis]))
l = last(gr_text_size(sp[:xaxis][:guide]))
h = max(h, 1mm + gr_plot_size[2] * l * px)
end
if yaxis[:guide] != ""
gr_set_font(guidefont(sp[:yaxis]))
l = last(gr_text_size(sp[:yaxis][:guide]))
h = max(h, 1mm + gr_plot_size[2] * l * px)
end
if h > 0mm
if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
toppad += h
else
bottompad += h
end
end
# Add margin for z label
if zaxis[:guide] != ""
gr_set_font(guidefont(sp[:zaxis]))
l = last(gr_text_size(sp[:zaxis][:guide]))
w = 1mm + gr_plot_size[2] * l * px
if zaxis[:guide_position] == :right || (zaxis[:guide_position] == :auto && zaxis[:mirror] == true)
rightpad += w
else
leftpad += w
end
end
else
# Add margin for x and y ticks
xticks, yticks = get_ticks(sp, sp[:xaxis]), get_ticks(sp, sp[:yaxis])
if !(xticks in (nothing, false, :none))
flip, mirror = gr_set_xticks_font(sp)
l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation]))
h = 1mm + gr_plot_size[2] * l * px
if mirror
toppad += h
else
bottompad += h
end
end
if !(yticks in (nothing, false, :none))
flip, mirror = gr_set_yticks_font(sp)
l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation]))
w = 1mm + gr_plot_size[1] * l * px
if mirror
rightpad += w
else
leftpad += w
end
end
# Add margin for x label
if sp[:xaxis][:guide] != ""
gr_set_font(guidefont(sp[:xaxis]))
l = last(gr_text_size(sp[:xaxis][:guide]))
h = 1mm + gr_plot_size[2] * l * px
if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true)
toppad += h
else
bottompad += h
end
end
# Add margin for y label
if sp[:yaxis][:guide] != ""
gr_set_font(guidefont(sp[:yaxis]))
l = last(gr_text_size(sp[:yaxis][:guide]))
w = 1mm + gr_plot_size[2] * l * px
if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true)
rightpad += w
else
leftpad += w
end
end
end
if sp[:colorbar_title] != ""
@@ -827,6 +956,11 @@ function _update_min_padding!(sp::Subplot{GRBackend})
sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad])
end
function is_equally_spaced(v)
d = collect(v[2:end] .- v[1:end-1])
all(d .≈ d[1])
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
_update_min_padding!(sp)
@@ -890,7 +1024,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
leg_str = string(sp[:legend])
if occursin("outer", leg_str)
if occursin("right", leg_str)
viewport_plotarea[2] -= legendw + 0.11
viewport_plotarea[2] -= legendw + 0.12
elseif occursin("left", leg_str)
viewport_plotarea[1] += legendw + 0.11
elseif occursin("top", leg_str)
@@ -902,7 +1036,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# fill in the plot area background
bg = plot_color(sp[:background_color_inside])
gr_fill_viewport(viewport_plotarea, bg)
is3d(sp) || gr_fill_viewport(viewport_plotarea, bg)
# reduced from before... set some flags based on the series in this subplot
# TODO: can these be generic flags?
@@ -977,39 +1111,204 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setlinewidth(sp.plt[:thickness_scaling])
if is3d(sp)
# TODO do we really need a different clims computation here from the one
# computed above using get_clims(sp)?
zmin, zmax = gr_lims(sp, zaxis, true)
clims3d = sp[:clims]
if is_2tuple(clims3d)
isfinite(clims3d[1]) && (zmin = clims3d[1])
isfinite(clims3d[2]) && (zmax = clims3d[2])
end
zmin, zmax = axis_limits(sp, :z)
GR.setspace(zmin, zmax, round.(Int, sp[:camera])...)
xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2
ticksize = 0.01 * (viewport_plotarea[2] - viewport_plotarea[1])
xticks, yticks, zticks, xaxis_segs, yaxis_segs, zaxis_segs, xtick_segs, ytick_segs, ztick_segs, xgrid_segs, ygrid_segs, zgrid_segs, xminorgrid_segs, yminorgrid_segs, zminorgrid_segs, xborder_segs, yborder_segs, zborder_segs = axis_drawing_info_3d(sp)
# fill the plot area
gr_set_fill(sp[:background_color_inside])
plot_area_x = [xmin, xmin, xmin, xmax, xmax, xmax, xmin]
plot_area_y = [ymin, ymin, ymax, ymax, ymax, ymin, ymin]
plot_area_z = [zmin, zmax, zmax, zmax, zmin, zmin, zmin]
x_bg, y_bg = unzip(GR.wc3towc.(plot_area_x, plot_area_y, plot_area_z))
GR.fillarea(x_bg, y_bg)
# draw the grid lines
if xaxis[:grid]
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:gridalpha])
GR.grid3d(xtick, 0, 0, xmin, ymax, zmin, 2, 0, 0)
gr_polyline3d(coords(xgrid_segs)...)
end
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:gridalpha])
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
gr_polyline3d(coords(ygrid_segs)...)
end
if zaxis[:grid]
gr_set_line(zaxis[:gridlinewidth], zaxis[:gridstyle], zaxis[:foreground_color_grid])
gr_set_transparency(zaxis[:foreground_color_grid], zaxis[:gridalpha])
GR.grid3d(0, 0, ztick, xmin, ymax, zmin, 0, 0, 2)
gr_polyline3d(coords(zgrid_segs)...)
end
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
gr_set_transparency(xaxis[:foreground_color_axis])
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
if xaxis[:minorgrid]
gr_set_line(xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], xaxis[:foreground_color_minor_grid])
gr_set_transparency(xaxis[:foreground_color_minor_grid], xaxis[:minorgridalpha])
gr_polyline3d(coords(xminorgrid_segs)...)
end
if yaxis[:minorgrid]
gr_set_line(yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], yaxis[:foreground_color_minor_grid])
gr_set_transparency(yaxis[:foreground_color_minor_grid], yaxis[:minorgridalpha])
gr_polyline3d(coords(yminorgrid_segs)...)
end
if zaxis[:minorgrid]
gr_set_line(zaxis[:minorgridlinewidth], zaxis[:minorgridstyle], zaxis[:foreground_color_minor_grid])
gr_set_transparency(zaxis[:foreground_color_minor_grid], zaxis[:minorgridalpha])
gr_polyline3d(coords(zminorgrid_segs)...)
end
gr_set_transparency(1.0)
# axis lines
if xaxis[:showaxis]
gr_set_line(1, :solid, xaxis[:foreground_color_border])
GR.setclip(0)
gr_polyline3d(coords(xaxis_segs)...)
end
if yaxis[:showaxis]
gr_set_line(1, :solid, yaxis[:foreground_color_border])
GR.setclip(0)
gr_polyline3d(coords(yaxis_segs)...)
end
if zaxis[:showaxis]
gr_set_line(1, :solid, zaxis[:foreground_color_border])
GR.setclip(0)
gr_polyline3d(coords(zaxis_segs)...)
end
GR.setclip(1)
# axis ticks
if xaxis[:showaxis]
if sp[:framestyle] in (:zerolines, :grid)
gr_set_line(1, :solid, xaxis[:foreground_color_grid])
gr_set_transparency(xaxis[:foreground_color_grid], xaxis[:tick_direction] == :out ? xaxis[:gridalpha] : 0)
else
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline3d(coords(xtick_segs)...)
end
if yaxis[:showaxis]
if sp[:framestyle] in (:zerolines, :grid)
gr_set_line(1, :solid, yaxis[:foreground_color_grid])
gr_set_transparency(yaxis[:foreground_color_grid], yaxis[:tick_direction] == :out ? yaxis[:gridalpha] : 0)
else
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline3d(coords(ytick_segs)...)
end
if zaxis[:showaxis]
if sp[:framestyle] in (:zerolines, :grid)
gr_set_line(1, :solid, zaxis[:foreground_color_grid])
gr_set_transparency(zaxis[:foreground_color_grid], zaxis[:tick_direction] == :out ? zaxis[:gridalpha] : 0)
else
gr_set_line(1, :solid, zaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline3d(coords(ztick_segs)...)
end
GR.setclip(1)
# tick marks
if !(xticks in (:none, nothing, false)) && xaxis[:showaxis]
# x labels
gr_set_font(
tickfont(xaxis),
halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2],
valign = (xaxis[:mirror] ? :bottom : :top),
rotation = xaxis[:rotation]
)
yt = if sp[:framestyle] == :origin
0
elseif xor(xaxis[:mirror], yaxis[:flip])
ymax
else
ymin
end
zt = if sp[:framestyle] == :origin
0
elseif xor(xaxis[:mirror], zaxis[:flip])
zmax
else
zmin
end
for (cv, dv) in zip(xticks...)
xi, yi = gr_w3tondc(cv, yt, zt)
xi += (yaxis[:mirror] ? 1 : -1) * 1e-2 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0)
yi += (xaxis[:mirror] ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0)
gr_text(xi, yi, gr_tick_label(xaxis, dv))
end
end
if !(yticks in (:none, nothing, false)) && yaxis[:showaxis]
# y labels
gr_set_font(
tickfont(yaxis),
halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2],
valign = (yaxis[:mirror] ? :bottom : :top),
rotation = yaxis[:rotation]
)
xt = if sp[:framestyle] == :origin
0
elseif xor(yaxis[:mirror], xaxis[:flip])
xmin
else
xmax
end
zt = if sp[:framestyle] == :origin
0
elseif xor(yaxis[:mirror], zaxis[:flip])
zmax
else
zmin
end
for (cv, dv) in zip(yticks...)
xi, yi = gr_w3tondc(xt, cv, zt)
gr_text(xi + (yaxis[:mirror] ? -1 : 1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0),
yi + (yaxis[:mirror] ? 1 : -1) * 5e-3 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0),
gr_tick_label(yaxis, dv))
end
end
if !(zticks in (:none, nothing, false)) && zaxis[:showaxis]
# z labels
gr_set_font(
tickfont(zaxis),
halign = (zaxis[:mirror] ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(zaxis[:rotation]) + 2],
rotation = zaxis[:rotation]
)
xt = if sp[:framestyle] == :origin
0
elseif xor(zaxis[:mirror], xaxis[:flip])
xmax
else
xmin
end
yt = if sp[:framestyle] == :origin
0
elseif xor(zaxis[:mirror], yaxis[:flip])
ymax
else
ymin
end
for (cv, dv) in zip(zticks...)
xi, yi = gr_w3tondc(xt, yt, cv)
gr_text(xi + (zaxis[:mirror] ? 1 : -1) * 1e-2 * (zaxis[:tick_direction] == :out ? 1.5 : 1.0),
yi, gr_tick_label(zaxis, dv))
end
end
#
# # border
# intensity = sp[:framestyle] == :semi ? 0.5 : 1.0
# if sp[:framestyle] in (:box, :semi)
# gr_set_line(intensity, :solid, xaxis[:foreground_color_border])
# gr_set_transparency(xaxis[:foreground_color_border], intensity)
# gr_polyline3d(coords(xborder_segs)...)
# gr_set_line(intensity, :solid, yaxis[:foreground_color_border])
# gr_set_transparency(yaxis[:foreground_color_border], intensity)
# gr_polyline3d(coords(yborder_segs)...)
# end
elseif ispolar(sp)
r = gr_set_viewport_polar()
@@ -1093,18 +1392,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# x labels
flip, mirror = gr_set_xticks_font(sp)
for (cv, dv) in zip(xticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? ymax : ymin)
# @show cv dv ymin xi yi flip mirror (flip $ mirror)
if xaxis[:ticks] in (:auto, :native)
# ensure correct dispatch in gr_text for automatic log ticks
if xaxis[:scale] in _logScales
dv = string(dv, "\\ ")
elseif xaxis[:formatter] in (:scientific, :auto)
dv = convert_sci_unicode(dv)
end
end
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0), string(dv))
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3 * (xaxis[:tick_direction] == :out ? 1.5 : 1.0),
gr_tick_label(xaxis, dv))
end
end
@@ -1112,18 +1402,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# y labels
flip, mirror = gr_set_yticks_font(sp)
for (cv, dv) in zip(yticks...)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(sp[:framestyle] == :origin ? 0 : xor(flip, mirror) ? xmax : xmin, cv)
# @show cv dv xmin xi yi
if yaxis[:ticks] in (:auto, :native)
# ensure correct dispatch in gr_text for automatic log ticks
if yaxis[:scale] in _logScales
dv = string(dv, "\\ ")
elseif yaxis[:formatter] in (:scientific, :auto)
dv = convert_sci_unicode(dv)
end
end
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0), yi, string(dv))
gr_text(xi + (mirror ? 1 : -1) * 1e-2 * (yaxis[:tick_direction] == :out ? 1.5 : 1.0),
yi,
gr_tick_label(yaxis, dv))
end
end
@@ -1159,12 +1441,54 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_text(xpos, viewport_subplot[4], sp[:title])
end
if is3d(sp)
gr_set_font(guidefont(xaxis))
GR.titles3d(xaxis[:guide], yaxis[:guide], zaxis[:guide])
else
xticks, yticks = axis_drawing_info(sp)[1:2]
if xaxis[:guide] != ""
h = 0.01 + gr_xaxis_height(sp)
gr_set_font(
guidefont(xaxis),
halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2],
valign = (xaxis[:mirror] ? :bottom : :top),
rotation = xaxis[:rotation]
)
yg = xor(xaxis[:mirror], yaxis[:flip]) ? ymax : ymin
zg = xor(xaxis[:mirror], zaxis[:flip]) ? zmax : zmin
xg = (xmin + xmax) / 2
xndc, yndc = gr_w3tondc(xg, yg, zg)
h = gr_axis_height(sp, xaxis)
gr_text(xndc - h, yndc - h, xaxis[:guide])
end
if yaxis[:guide] != ""
gr_set_font(
guidefont(yaxis),
halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2],
valign = (yaxis[:mirror] ? :bottom : :top),
rotation = yaxis[:rotation]
)
xg = xor(yaxis[:mirror], xaxis[:flip]) ? xmin : xmax
yg = (ymin + ymax) / 2
zg = xor(yaxis[:mirror], zaxis[:flip]) ? zmax : zmin
xndc, yndc = gr_w3tondc(xg, yg, zg)
h = gr_axis_height(sp, yaxis)
gr_text(xndc + h, yndc - h, yaxis[:guide])
end
if zaxis[:guide] != ""
gr_set_font(
guidefont(zaxis),
halign = (:left, :hcenter, :right)[sign(zaxis[:rotation]) + 2],
valign = (zaxis[:mirror] ? :bottom : :top),
rotation = zaxis[:rotation]
)
xg = xor(zaxis[:mirror], xaxis[:flip]) ? xmax : xmin
yg = xor(zaxis[:mirror], yaxis[:flip]) ? ymax : ymin
zg = (zmin + zmax) / 2
xndc, yndc = gr_w3tondc(xg, yg, zg)
w = gr_axis_width(sp, zaxis)
GR.setcharup(-1, 0)
gr_text(xndc - w, yndc, zaxis[:guide])
end
else
if xaxis[:guide] != ""
h = 0.01 + gr_axis_height(sp, xaxis)
gr_set_font(guidefont(xaxis))
if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
@@ -1176,7 +1500,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if yaxis[:guide] != ""
w = 0.02 + gr_yaxis_width(sp)
w = 0.02 + gr_axis_width(sp, yaxis)
gr_set_font(guidefont(yaxis))
GR.setcharup(-1, 0)
if yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true)
@@ -1275,7 +1599,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :contour
GR.setspace(clims[1], clims[2], 0, 90)
GR.setlinetype(gr_linetype[get_linestyle(series)])
GR.setlinewidth(max(0, get_linewidth(series) / (sum(gr_plot_size) * 0.001)))
GR.setlinewidth(max(0, get_linewidth(series)) / nominal_size())
is_lc_black = let black=plot_color(:black)
plot_color(series[:linecolor]) in (black,[black])
end
@@ -1318,9 +1642,24 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale], series[:y], sp[:yaxis][:scale], size(series[:z]))
w, h = length(x) - 1, length(y) - 1
z_normalized = map(x -> GR.jlgr.normalize_color(x, zmin, zmax), z)
z_normalized = map(x -> isnan(x) ? 256/255 : x, z_normalized) # results in color index = 1256 -> transparent
colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized]
GR.nonuniformcellarray(x, y, w, h, colors)
if is_uniformly_spaced(x) && is_uniformly_spaced(y)
# For uniformly spaced data use GR.drawimage, which can be
# much faster than GR.nonuniformcellarray, especially for
# pdf output, and also supports alpha values.
# Note that drawimage draws uniformly spaced data correctly
# even on log scales, where it is visually non-uniform.
fillgrad = _as_gradient(series[:fillcolor])
colors = plot_color.(fillgrad[z_normalized], series[:fillalpha])
colors[isnan.(z_normalized)] .= RGBA(0,0,0,0)
rgba = gr_color.(colors)
GR.drawimage(first(x), last(x), last(y), first(y), w, h, rgba)
else
(something(series[:fillalpha],1) < 1 || any(_gr_gradient_alpha .< 1)) && @warn(
"GR: transparency not supported in non-uniform heatmaps. Alpha values ignored.")
z_normalized = map(x -> isnan(x) ? 256/255 : x, z_normalized) # results in color index = 1256 -> transparent
colors = Int32[round(Int32, 1000 + _i * 255) for _i in z_normalized]
GR.nonuniformcellarray(x, y, w, h, colors)
end
else
phimin, phimax = 0.0, 360.0 # nonuniform polar array is not yet supported in GR.jl
nx, ny = length(series[:x]), length(series[:y])
@@ -1439,15 +1778,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
z = transpose_z(series, series[:z].surf, true)'
w, h = size(z)
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
if eltype(z) <: Colors.AbstractGray
grey = round.(UInt8, clamp.(float(z) * 255, 0, 255))
rgba = map(c -> UInt32( 0xff000000 + UInt(c)<<16 + UInt(c)<<8 + UInt(c) ), grey)
else
rgba = map(c -> UInt32( round(UInt, clamp(alpha(c) * 255, 0, 255)) << 24 +
round(UInt, clamp(blue(c) * 255, 0, 255)) << 16 +
round(UInt, clamp(green(c) * 255, 0, 255)) << 8 +
round(UInt, clamp(red(c) * 255, 0, 255)) ), z)
end
rgba = gr_color.(z)
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
end
@@ -1549,7 +1880,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
for ann in sp[:annotations]
x, y, val = locate_annotation(sp, ann...)
x, y = if is3d(sp)
# GR.wc3towc(x, y, z)
gr_w3tondc(x, y, z)
else
GR.wctondc(x, y)
end
+4 -4
View File
@@ -109,7 +109,7 @@ _hdf5_datapath(subpath::String) = "$_hdf5_dataroot/$subpath"
_hdf5_map_str2telem(k::String) = HDF5PLOT_MAP_STR2TELEM[k]
_hdf5_map_str2telem(v::Vector) = HDF5PLOT_MAP_STR2TELEM[v[1]]
function _hdf5_merge!(dest::Dict, src::Dict)
function _hdf5_merge!(dest, src)
for (k, v) in src
if isa(v, Axis)
_hdf5_merge!(dest[k].plotattributes, v.plotattributes)
@@ -295,7 +295,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Tuple)
end
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
end
function _hdf5plot_gwrite(grp, k::String, plotattributes::Dict)
function _hdf5plot_gwrite(grp, k::String, plotattributes::AKW)
# @warn("Cannot write dict: $k=$plotattributes")
end
function _hdf5plot_gwrite(grp, k::String, v::AbstractRange)
@@ -376,7 +376,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Subplot)
_hdf5plot_writetype(grp, Subplot)
return
end
function _hdf5plot_write(grp, plotattributes::Dict)
function _hdf5plot_write(grp, plotattributes::AKW)
for (k, v) in plotattributes
kstr = string(k)
_hdf5plot_gwrite(grp, kstr, v)
@@ -567,7 +567,7 @@ function _hdf5plot_read(grp, k::String)
end
#Read in values in group to populate plotattributes:
function _hdf5plot_read(grp, plotattributes::Dict)
function _hdf5plot_read(grp, plotattributes::AKW)
gnames = names(grp)
for k in gnames
try
+10 -1
View File
@@ -12,4 +12,13 @@ function plotlybase_syncplot(plt::Plot)
return plt.o
end
_show(io::IO, ::MIME{Symbol("image/png")}, plt::Plot{PlotlyBackend}) = ORCA.PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = "png")
const _orca_mimeformats = Dict(
"application/pdf" => "pdf",
"image/png" => "png",
"image/svg+xml" => "svg",
"image/eps" => "eps",
)
for (mime, fmt) in _orca_mimeformats
@eval _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PlotlyBackend}) = ORCA.PlotlyBase.savefig(io, plotlybase_syncplot(plt), format = $fmt)
end
+11 -11
View File
@@ -180,11 +180,11 @@ function pgf_series(sp::Subplot, series::Series)
end
# PGFPlots can't handle non-Vector?
args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
collect(a)
else
a
end, args)
# args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
# collect(a)
# else
# a
# end, args)
if st in (:contour, :histogram2d)
style = []
@@ -482,12 +482,12 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
fg_alpha = alpha(plot_color(sp[:foreground_color_legend]))
push!(style, string(
"legend style = {",
pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid", ), ",",
"fill = $cstr,",
"fill opacity = $bg_alpha,",
"text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),",
"font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)),
"legend style = {",
pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], fg_alpha, "solid", ), ",",
"fill = $cstr,",
"fill opacity = $bg_alpha,",
"text opacity = $(alpha(plot_color(sp[:legendfontcolor]))),",
"font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)),
"}",
))
+578 -363
View File
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -351,7 +351,7 @@ end
function plotly_colorscale(grad::ColorGradient, α)
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in 1:length(grad.colors)]
[[grad.values[i], rgba_string(plot_color(grad.colors[i], α))] for i in eachindex(grad.colors)]
end
plotly_colorscale(c::Colorant,α) = plotly_colorscale(_as_gradient(c),α)
function plotly_colorscale(c::AbstractVector{<:RGBA}, α)
@@ -392,7 +392,7 @@ end
# we split by NaNs and then construct/destruct the shapes to get the closed coords
function plotly_close_shapes(x, y)
xs, ys = nansplit(x), nansplit(y)
for i=1:length(xs)
for i=eachindex(xs)
shape = Shape(xs[i], ys[i])
xs[i], ys[i] = coords(shape)
end
@@ -415,6 +415,7 @@ function plotly_data(series::Series, letter::Symbol, data)
end
end
plotly_data(v) = v !== nothing ? collect(v) : v
plotly_data(v::AbstractArray) = v
plotly_data(surf::Surface) = surf.surf
plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
@@ -779,9 +780,9 @@ end
function plotly_hover!(plotattributes_out::KW, hover)
# hover text
if hover in (:none, false)
if hover === nothing || all(in([:none, false]), hover)
plotattributes_out[:hoverinfo] = "none"
elseif hover !== nothing
elseif any(!isnothing, hover)
plotattributes_out[:hoverinfo] = "text"
plotattributes_out[:text] = hover
end
@@ -859,6 +860,8 @@ end
# ----------------------------------------------------------------
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyBackend}) = true
function _show(io::IO, ::MIME"application/vnd.plotly.v1+json", plot::Plot{PlotlyBackend})
plotly_show_js(io, plot)
end
+2
View File
@@ -52,3 +52,5 @@ function closeall(::PlotlyJSBackend)
close(current().o)
end
end
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot{PlotlyJSBackend}) = true
+4 -4
View File
@@ -187,7 +187,7 @@ end
# end
function get_locator_and_formatter(vals::AVec)
pyticker."FixedLocator"(1:length(vals)), pyticker."FixedFormatter"(vals)
pyticker."FixedLocator"(eachindex(vals)), pyticker."FixedFormatter"(vals)
end
function add_pyfixedformatter(cbar, vals::AVec)
@@ -535,7 +535,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
shapes = series[:markershape]
msc = py_markerstrokecolor(series)
lw = py_thickness_scale(plt, series[:markerstrokewidth])
for i=1:length(y)
for i=eachindex(y)
extrakw[:c] = _cycle(markercolor, i)
push!(handle, ax."scatter"(_cycle(x,i), _cycle(y,i);
@@ -564,7 +564,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
delete!(extrakw, :c)
for i=1:length(y)
for i=eachindex(y)
cur_marker = py_marker(_cycle(shapes,i))
if ( cur_marker == prev_marker )
@@ -1013,7 +1013,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
kw = KW()
if !isempty(sp[:zaxis][:discrete_values]) && colorbar_series[:seriestype] == :heatmap
locator, formatter = get_locator_and_formatter(sp[:zaxis][:discrete_values])
# kw[:values] = 1:length(sp[:zaxis][:discrete_values])
# kw[:values] = eachindex(sp[:zaxis][:discrete_values])
kw[:values] = sp[:zaxis][:continuous_values]
kw[:ticks] = locator
kw[:format] = formatter
+1 -1
View File
@@ -92,7 +92,7 @@ end
# add a single series
function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
function addUnicodeSeries!(o, plotattributes, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = plotattributes[:seriestype]
if st == :histogram2d
+6 -4
View File
@@ -187,7 +187,7 @@ end
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
sx, sy = coords(shape)
cx, cy = c
for i=1:length(sx)
for i=eachindex(sx)
sx[i] = (sx[i] - cx) * x + cx
sy[i] = (sy[i] - cy) * y + cy
end
@@ -202,7 +202,7 @@ end
"translate a Shape in space"
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = coords(shape)
for i=1:length(sx)
for i=eachindex(sx)
sx[i] += x
sy[i] += y
end
@@ -230,7 +230,7 @@ end
function rotate!(shape::Shape, Θ::Real, c = center(shape))
x, y = coords(shape)
cx, cy = c
for i=1:length(x)
for i=eachindex(x)
xi = rotate_x(x[i], y[i], Θ, cx, cy)
yi = rotate_y(x[i], y[i], Θ, cx, cy)
x[i], y[i] = xi, yi
@@ -591,7 +591,9 @@ annotations(sa::SeriesAnnotations) = sa
function process_annotation(sp::Subplot, xs, ys, labs, font = font())
anns = []
labs = makevec(labs)
for i in 1:max(length(xs), length(ys), length(labs))
xlength = length(methods(length, (typeof(xs),))) == 0 ? 1 : length(xs)
ylength = length(methods(length, (typeof(ys),))) == 0 ? 1 : length(ys)
for i in 1:max(xlength, ylength, length(labs))
x, y, lab = _cycle(xs, i), _cycle(ys, i), _cycle(labs, i)
if lab == :auto
alphabet = "abcdefghijklmnopqrstuvwxyz"
+4 -3
View File
@@ -433,7 +433,7 @@ each line segment or marker in the plot.
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z=t, linewidth=3, legend=false)
p2 = scatter(x, y, marker_z=(x,y)->x+y, color=:bluesreds, legend=false)
p2 = scatter(x, y, marker_z=+, color=:bluesreds, legend=false)
plot(p1, p2)
end)]
),
@@ -507,7 +507,8 @@ _backend_skips = Dict(
:gr => [25, 30],
:pyplot => [25, 30],
:plotlyjs => [2, 21, 24, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30],
:plotly => [2, 21, 24, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30, 31, 34, 37, 38, 39],
)
@@ -545,7 +546,7 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth
skip = [], only = nothing)
Plots._debugMode.on = debug
plts = Dict()
for i in 1:length(_examples)
for i in eachindex(_examples)
only !== nothing && !(i in only) && continue
i in skip && continue
try
+25 -8
View File
@@ -464,12 +464,12 @@ end
# constructors
# pass the layout arg through
function layout_args(plotattributes::KW)
layout_args(get(plotattributes, :layout, default(:layout)))
function layout_args(plotattributes::AKW)
layout_args(plotattributes[:layout])
end
function layout_args(plotattributes::KW, n_override::Integer)
layout, n = layout_args(get(plotattributes, :layout, n_override))
function layout_args(plotattributes::AKW, n_override::Integer)
layout, n = layout_args(n_override, get(plotattributes, :layout, n_override))
if n != n_override
error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.")
end
@@ -481,12 +481,27 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n
end
function layout_args(sztup::NTuple{2,I}) where I<:Integer
function layout_args(sztup::NTuple{2, Integer})
nr, nc = sztup
GridLayout(nr, nc), nr*nc
end
function layout_args(sztup::NTuple{3,I}) where I<:Integer
layout_args(n_override::Integer, n::Integer) = layout_args(n)
layout_args(n, sztup::NTuple{2, Integer}) = layout_args(sztup)
function layout_args(n, sztup::Tuple{Colon, Integer})
nc = sztup[2]
nr = ceil(Int, n / nc)
GridLayout(nr, nc), n
end
function layout_args(n, sztup::Tuple{Integer, Colon})
nr = sztup[1]
nc = ceil(Int, n / nr)
GridLayout(nr, nc), n
end
function layout_args(sztup::NTuple{3, Integer})
n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n
@@ -499,6 +514,8 @@ function layout_args(layout::GridLayout)
layout, n
end
layout_args(n_override::Integer, layout::GridLayout) = layout_args(layout)
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
@@ -599,7 +616,7 @@ end
# ----------------------------------------------------------------------
# @layout macro
function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
function add_layout_pct!(kw::AKW, v::Expr, idx::Integer, nidx::Integer)
# dump(v)
# something like {0.2w}?
if v.head == :call && v.args[1] == :*
@@ -620,7 +637,7 @@ function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
error("Couldn't match layout curly (idx=$idx): $v")
end
function add_layout_pct!(kw::KW, v::Number, idx::Integer)
function add_layout_pct!(kw::AKW, v::Number, idx::Integer)
# kw[idx == 1 ? :w : :h] = v*pct
idx == 1 && (kw[:w] = v*pct)
(idx == 2 || nidx == 1) && (kw[:h] = v*pct)
+9 -1
View File
@@ -60,6 +60,13 @@ function html(plt::Plot, fn::AbstractString)
end
html(fn::AbstractString) = html(current(), fn)
function txt(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "txt")
io = open(fn, "w")
show(io, MIME("text/plain"), plt)
close(io)
end
txt(fn::AbstractString) = txt(current(), fn)
# ----------------------------------------------------------------
@@ -73,6 +80,7 @@ const _savemap = Dict(
"tex" => tex,
"html" => html,
"tikz" => tex,
"txt" => txt,
)
function getExtension(fn::AbstractString)
@@ -262,6 +270,6 @@ function _showjuno(io::IO, m::MIME"image/svg+xml", plt)
end
end
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot) = showable(MIME"text/html"(), plt)
Base.showable(::MIME"application/prs.juno.plotpane+html", plt::Plot) = false
_showjuno(io::IO, m, plt) = _show(io, m, plt)
+25 -22
View File
@@ -3,16 +3,16 @@
# ------------------------------------------------------------------
# preprocessing
function command_idx(kw_list::AVec{KW}, kw::KW)
function series_idx(kw_list::AVec{KW}, kw::AKW)
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
end
function _expand_seriestype_array(plotattributes::KW, args)
function _expand_seriestype_array(plotattributes::AKW, args)
sts = get(plotattributes, :seriestype, :path)
if typeof(sts) <: AbstractArray
delete!(plotattributes, :seriestype)
reset_kw!(plotattributes, :seriestype)
rd = Vector{RecipeData}(undef, size(sts, 1))
for r in 1:size(sts, 1)
for r in axes(sts, 1)
dc = copy(plotattributes)
dc[:seriestype] = sts[r:r,:]
rd[r] = RecipeData(dc, args)
@@ -23,7 +23,7 @@ function _expand_seriestype_array(plotattributes::KW, args)
end
end
function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{RecipeData})
function _preprocess_args(plotattributes::AKW, args, still_to_process::Vector{RecipeData})
# the grouping mechanism is a recipe on a GroupBy object
# we simply add the GroupBy object to the front of the args list to allow
# the recipe to be applied
@@ -42,9 +42,11 @@ function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{Rec
for (k,v) in plotattributes
for defdict in (_subplot_defaults,
_axis_defaults,
_axis_defaults_byletter)
_axis_defaults_byletter[:x],
_axis_defaults_byletter[:y],
_axis_defaults_byletter[:z])
if haskey(defdict, k)
delete!(plotattributes, k)
reset_kw!(plotattributes, k)
end
end
end
@@ -57,7 +59,7 @@ end
# user recipes
function _process_userrecipes(plt::Plot, plotattributes::KW, args)
function _process_userrecipes(plt::Plot, plotattributes::AKW, args)
still_to_process = RecipeData[]
args = _preprocess_args(plotattributes, args, still_to_process)
@@ -108,7 +110,7 @@ function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeD
return
end
function _preprocess_userrecipe(kw::KW)
function _preprocess_userrecipe(kw::AKW)
_add_markershape(kw)
# if there was a grouping, filter the data here
@@ -132,7 +134,7 @@ function _preprocess_userrecipe(kw::KW)
return
end
function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
function _add_errorbar_kw(kw_list::Vector{KW}, kw::AKW)
# handle error bars by creating new recipedata data... these will have
# the same recipedata index as the recipedata they are copied from
for esym in (:xerror, :yerror)
@@ -147,7 +149,7 @@ function _add_errorbar_kw(kw_list::Vector{KW}, kw::KW)
end
end
function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
function _add_smooth_kw(kw_list::Vector{KW}, kw::AKW)
# handle smoothing by adding a new series
if get(kw, :smooth, false)
x, y = kw[:x], kw[:y]
@@ -172,7 +174,7 @@ end
# to generate a list of RecipeData objects (data + attributes).
# If we applied a "plot recipe" without error, then add the returned datalist's KWs,
# otherwise we just add the original KW.
function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_process::Vector{KW})
function _process_plotrecipe(plt::Plot, kw::AKW, kw_list::Vector{KW}, still_to_process::Vector{KW})
if !isa(get(kw, :seriestype, nothing), Symbol)
# seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
push!(kw_list, kw)
@@ -203,7 +205,7 @@ end
# ------------------------------------------------------------------
# setup plot and subplot
function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
function _plot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# merge in anything meant for the Plot
for kw in kw_list, (k,v) in kw
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
@@ -252,7 +254,7 @@ function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
plt[:inset_subplots] = nothing
end
function _subplot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW})
# we'll keep a map of subplot to an attribute override dict.
# Subplot/Axis attributes set by a user/series recipe apply only to the
# Subplot object which they belong to.
@@ -261,16 +263,16 @@ function _subplot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
for kw in kw_list
# get the Subplot object to which the series belongs.
sps = get(kw, :subplot, :auto)
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
sp = get_subplot(plt, _cycle(sps == :auto ? plt.subplots : plt.subplots[sps], series_idx(kw_list,kw)))
kw[:subplot] = sp
# extract subplot/axis attributes from kw and add to sp_attr
attr = KW()
for (k,v) in collect(kw)
if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
if is_subplot_attr(k) || is_axis_attr(k)
attr[k] = pop!(kw, k)
end
if haskey(_axis_defaults, k)
if is_axis_attr_noletter(k)
v = pop!(kw, k)
for letter in (:x,:y,:z)
attr[Symbol(letter,k)] = v
@@ -303,7 +305,7 @@ end
# getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes
function _prepare_subplot(plt::Plot{T}, plotattributes::KW) where T
function _prepare_subplot(plt::Plot{T}, plotattributes::AKW) where T
st::Symbol = plotattributes[:seriestype]
sp::Subplot{T} = plotattributes[:subplot]
sp_idx = get_subplot_index(plt, sp)
@@ -327,7 +329,7 @@ end
# ------------------------------------------------------------------
# series types
function _override_seriestype_check(plotattributes::KW, st::Symbol)
function _override_seriestype_check(plotattributes::AKW, st::Symbol)
# do we want to override the series type?
if !is3d(st) && !(st in (:contour,:contour3d))
z = plotattributes[:z]
@@ -339,7 +341,7 @@ function _override_seriestype_check(plotattributes::KW, st::Symbol)
st
end
function _prepare_annotations(sp::Subplot, plotattributes::KW)
function _prepare_annotations(sp::Subplot, plotattributes::AKW)
# strip out series annotations (those which are based on series x/y coords)
# and add them to the subplot attr
sp_anns = annotations(sp[:annotations])
@@ -356,7 +358,7 @@ function _prepare_annotations(sp::Subplot, plotattributes::KW)
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
end
function _expand_subplot_extrema(sp::Subplot, plotattributes::KW, st::Symbol)
function _expand_subplot_extrema(sp::Subplot, plotattributes::AKW, st::Symbol)
# adjust extrema and discrete info
if st == :image
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
@@ -385,7 +387,8 @@ end
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
function _process_seriesrecipe(plt::Plot, plotattributes::KW)
function _process_seriesrecipe(plt::Plot, plotattributes::AKW)
#println("process $(typeof(plotattributes))")
# replace seriestype aliases
st = Symbol(plotattributes[:seriestype])
st = plotattributes[:seriestype] = get(_typeAliases, st, st)
+8 -9
View File
@@ -96,7 +96,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
series_attr = KW()
for (k,v) in plotattributes
if haskey(_series_defaults, k)
if is_series_attr(k)
series_attr[k] = pop!(plotattributes,k)
end
end
@@ -119,7 +119,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
sp.attr[:subplot_index] = idx
for series in serieslist
merge!(series.plotattributes, series_attr)
_add_defaults!(series.plotattributes, plt, sp, cmdidx)
_slice_series_args!(series.plotattributes, plt, sp, cmdidx)
push!(plt.series_list, series)
_series_added(plt, series)
cmdidx += 1
@@ -163,7 +163,7 @@ end
# this is the core plotting function. recursively apply recipes to build
# a list of series KW dicts.
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
function _plot!(plt::Plot, plotattributes::AKW, args::Tuple)
plotattributes[:plot_object] = plt
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
@@ -217,21 +217,20 @@ function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
for kw in kw_list
sp::Subplot = kw[:subplot]
# idx = get_subplot_index(plt, sp)
# # we update subplot args in case something like the color palatte is part of the recipe
# _update_subplot_args(plt, sp, kw, idx, true)
# in series attributes given as vector with one element per series,
# select the value for current series
_slice_series_args!(kw, plt, sp, series_idx(kw_list,kw))
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, sp, command_idx(kw_list,kw))
series_attr = Attr(kw, _series_defaults)
# now we have a fully specified series, with colors chosen. we must recursively handle
# series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype,
# we check for a recipe that will convert that series type into one made up of lower-level components.
# For example, a histogram is just a bar plot with binned data, a bar plot is really a filled step plot,
# and a step plot is really just a path. So any backend that supports drawing a path will implicitly
# be able to support step, bar, and histogram plots (and any recipes that use those components).
_process_seriesrecipe(plt, kw)
_process_seriesrecipe(plt, series_attr)
end
# --------------------------------
+778 -863
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -47,7 +47,7 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
RecipesBase.apply_recipe(plotattributes::AKW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError(T, "Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
@@ -364,7 +364,7 @@ end
0.5 * _bar_width
end
else
Float64[0.5_cycle(bw,i) for i=1:length(procx)]
Float64[0.5_cycle(bw,i) for i=eachindex(procx)]
end
# make fillto a vector... default fills to 0
@@ -813,7 +813,7 @@ end
# ---------------------------------------------------------------------------
# Error Bars
function error_style!(plotattributes::KW)
function error_style!(plotattributes::AKW)
plotattributes[:seriestype] = :path
plotattributes[:linecolor] = plotattributes[:markerstrokecolor]
plotattributes[:linewidth] = plotattributes[:markerstrokewidth]
@@ -874,8 +874,8 @@ end
# ---------------------------------------------------------------------------
# quiver
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
function quiver_using_arrows(plotattributes::KW)
# function apply_series_recipe(plotattributes::AKW, ::Type{Val{:quiver}})
function quiver_using_arrows(plotattributes::AKW)
plotattributes[:label] = ""
plotattributes[:seriestype] = :path
if !isa(plotattributes[:arrow], Arrow)
@@ -913,8 +913,8 @@ function quiver_using_arrows(plotattributes::KW)
# KW[plotattributes]
end
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
function quiver_using_hack(plotattributes::KW)
# function apply_series_recipe(plotattributes::AKW, ::Type{Val{:quiver}})
function quiver_using_hack(plotattributes::AKW)
plotattributes[:label] = ""
plotattributes[:seriestype] = :shape
@@ -959,7 +959,7 @@ function quiver_using_hack(plotattributes::KW)
# KW[plotattributes]
end
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
# function apply_series_recipe(plotattributes::AKW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z)
if :arrow in supported_attrs()
quiver_using_arrows(plotattributes)
@@ -998,7 +998,7 @@ function get_xy(o::OHLC, x, xdiff)
end
# get the joined vector
function get_xy(v::AVec{OHLC}, x = 1:length(v))
function get_xy(v::AVec{OHLC}, x = eachindex(v))
xdiff = 0.3ignorenan_mean(abs.(diff(x)))
x_out, y_out = zeros(0), zeros(0)
for (i,ohlc) in enumerate(v)
@@ -1056,8 +1056,8 @@ end
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
seriestype := :spy
mat = g.args[1]
n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat)
n,m = axes(mat)
Plots.SliceIt, m, n, Surface(mat)
end
@recipe function f(::Type{Val{:spy}}, x,y,z)
@@ -1185,7 +1185,7 @@ end
seriestype := :shape
# create a filled polygon for each item
for c=1:size(weights,2)
for c=axes(weights,2)
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1]))
sy = vcat(returns, reverse(returns))
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
@@ -1206,9 +1206,9 @@ julia> areaplot(1:3, [1 2 3; 7 8 9; 4 5 6], seriescolor = [:red :green :blue], f
@recipe function f(a::AreaPlot)
data = cumsum(a.args[end], dims=2)
x = length(a.args) == 1 ? (1:size(data, 1)) : a.args[1]
x = length(a.args) == 1 ? (axes(data, 1)) : a.args[1]
seriestype := :line
for i in 1:size(data, 2)
for i in axes(data, 2)
@series begin
fillrange := i > 1 ? data[:,i-1] : 0
x, data[:,i]
+22 -21
View File
@@ -13,6 +13,7 @@ const DataPoint = Union{MaybeNumber, MaybeString}
prepareSeriesData(x) = error("Cannot convert $(typeof(x)) to series data for plotting")
prepareSeriesData(::Nothing) = nothing
prepareSeriesData(t::Tuple{T, T}) where {T<:Number} = t
prepareSeriesData(f::Function) = f
prepareSeriesData(a::AbstractArray{<:MaybeNumber}) = replace!(
x -> ismissing(x) || isinf(x) ? NaN : x,
@@ -47,7 +48,7 @@ function convertToAnyVector(v::AMat{<:DataPoint}, plotattributes)
if all3D(plotattributes)
Any[prepareSeriesData(Surface(v))]
else
Any[prepareSeriesData(v[:, i]) for i in 1:size(v, 2)]
Any[prepareSeriesData(v[:, i]) for i in axes(v, 2)]
end
end
@@ -70,13 +71,13 @@ process_ribbon(ribbon::Tuple{Any,Any}, plotattributes) = collect(zip(convertToAn
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
compute_x(x::Nothing, y, z) = 1:size(y,1)
compute_x(x::Nothing, y::Nothing, z) = axes(z,1)
compute_x(x::Nothing, y, z) = axes(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
compute_y(x::Nothing, y::Nothing, z) = axes(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
@@ -266,7 +267,7 @@ end
# # --------------------------------------------------------------------
# helper function to ensure relevant attributes are wrapped by Surface
function wrap_surfaces(plotattributes::KW)
function wrap_surfaces(plotattributes::AKW)
if haskey(plotattributes, :fill_z)
v = plotattributes[:fill_z]
if !isa(v, Surface)
@@ -277,14 +278,14 @@ end
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
all3D(plotattributes) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
# return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat,Missing}
if all3D(plotattributes)
n,m = size(mat)
n,m = axes(mat)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Surface(mat)
SliceIt, m, n, Surface(mat)
else
SliceIt, nothing, mat, nothing
end
@@ -294,9 +295,9 @@ end
@recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix
if all3D(plotattributes)
mat = fmt.data
n,m = size(mat)
n,m = axes(mat)
wrap_surfaces(plotattributes)
SliceIt, 1:m, 1:n, Formatted(Surface(mat), fmt.formatter)
SliceIt, m, n, Formatted(Surface(mat), fmt.formatter)
else
SliceIt, nothing, fmt, nothing
end
@@ -319,35 +320,35 @@ function clamp_greys!(mat::AMat{T}) where T<:Gray
end
@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
n, m = axes(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(clamp_greys!(mat))
SliceIt, m, n, Surface(clamp_greys!(mat))
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
SliceIt, m, n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
end
end
# # images - colors
@recipe function f(mat::AMat{T}) where T<:Colorant
n, m = size(mat)
n, m = axes(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
SliceIt, m, n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
z, plotattributes[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
SliceIt, m, n, Surface(z)
end
end
@@ -366,7 +367,7 @@ end
@recipe function f(shapes::AMat{Shape})
seriestype --> :shape
for j in 1:size(shapes,2)
for j in axes(shapes,2)
@series coords(vec(shapes[:,j]))
end
end
@@ -583,7 +584,7 @@ end
# end
splittable_kw(key, val, lengthGroup) = false
splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && size(val,1) == lengthGroup
splittable_kw(key, val::AbstractArray, lengthGroup) = !(key in (:group, :color_palette)) && length(axes(val,1)) == lengthGroup
splittable_kw(key, val::Tuple, lengthGroup) = all(splittable_kw.(key, val, lengthGroup))
splittable_kw(key, val::SeriesAnnotations, lengthGroup) = splittable_kw(key, val.strs, lengthGroup)
@@ -597,7 +598,7 @@ end
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(undef, length(keys(x_ind)), length(groupby.groupLabels))
fill!(y_mat, def_val)
for i in 1:length(groupby.groupLabels)
for i in eachindex(groupby.groupLabels)
xi = x[groupby.groupIds[i]]
yi = y[groupby.groupIds[i]]
y_mat[getindex.(Ref(x_ind), xi), i] = yi
@@ -630,7 +631,7 @@ group_as_matrix(t) = false
if length(g.args) == 1
x = zeros(Int, lengthGroup)
for indexes in groupby.groupIds
x[indexes] = 1:length(indexes)
x[indexes] = eachindex(indexes)
end
last_args = g.args
else
@@ -638,7 +639,7 @@ group_as_matrix(t) = false
last_args = g.args[2:end]
end
x_u = unique(sort(x))
x_ind = Dict(zip(x_u, 1:length(x_u)))
x_ind = Dict(zip(x_u, eachindex(x_u)))
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
:($key) := groupedvec2mat(x_ind, x, val, groupby)
+1 -1
View File
@@ -7,7 +7,7 @@ function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
(20mm, 5mm, 2mm, 10mm),
defaultbox,
defaultbox,
KW(),
Attr(KW(), _subplot_defaults),
nothing,
nothing
)
+7 -4
View File
@@ -4,11 +4,11 @@
Specify the colour theme for plots.
"""
function theme(s::Symbol; kw...)
defaults = PlotThemes._themes[s].defaults
defaults = copy(PlotThemes._themes[s].defaults)
_theme(s, defaults; kw...)
end
function _theme(s::Symbol, defaults::KW; kw...)
function _theme(s::Symbol, defaults::AKW; kw...)
# Reset to defaults to overwrite active theme
reset_defaults()
@@ -120,7 +120,8 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 4
seriestype := :heatmap
seriescolor := colorgradient
ticks := -5:5:5
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
x, y, z
end
@@ -128,12 +129,14 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
subplot := 5
seriestype := :surface
seriescolor := colorgradient
xticks := (-2π:2π:2π, string.(-2:2:2, "π"))
yticks := (-2π:2π:2π, string.(-2:2:2, "π"))
x, y, z
end
n = 100
ts = range(0, stop = 10π, length = n)
x = ts .* cos.(ts)
x = (0.1ts) .* cos.(ts)
y = (0.1ts) .* sin.(ts)
z = 1:n
+59 -6
View File
@@ -5,6 +5,7 @@
const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
const AKW = AbstractDict{Symbol,Any}
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
struct PlotsDisplay <: AbstractDisplay end
@@ -18,10 +19,63 @@ wrap(obj::T) where {T} = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
struct Attr <: AbstractDict{Symbol,Any}
explicit::KW
defaults::KW
end
Base.getindex(attr::Attr, k) = haskey(attr.explicit,k) ?
attr.explicit[k] : attr.defaults[k]
Base.haskey(attr::Attr, k) = haskey(attr.explicit,k) || haskey(attr.defaults,k)
Base.get(attr::Attr, k, default) = haskey(attr, k) ? attr[k] : default
function Base.get!(attr::Attr, k, default)
v = if haskey(attr, k)
attr[k]
else
attr.defaults[k] = default
end
return v
end
function Base.delete!(attr::Attr, k)
haskey(attr.explicit, k) && delete!(attr.explicit, k)
haskey(attr.defaults, k) && delete!(attr.defaults, k)
end
Base.length(attr::Attr) = length(union(keys(attr.explicit), keys(attr.defaults)))
function Base.iterate(attr::Attr)
exp_keys = keys(attr.explicit)
def_keys = setdiff(keys(attr.defaults), exp_keys)
key_list = collect(Iterators.flatten((exp_keys, def_keys)))
iterate(attr, (key_list, 1))
end
function Base.iterate(attr::Attr, (key_list, i))
i > length(key_list) && return nothing
k = key_list[i]
(k=>attr[k], (key_list, i+1))
end
Base.copy(attr::Attr) = Attr(copy(attr.explicit), attr.defaults)
RecipesBase.is_explicit(attr::Attr, k) = haskey(attr.explicit,k)
isdefault(attr::Attr, k) = !is_explicit(attr,k) && haskey(attr.defaults,k)
Base.setindex!(attr::Attr, v, k) = attr.explicit[k] = v
# Reset to default value and return dict
reset_kw!(attr::Attr, k) = is_explicit(attr, k) ? delete!(attr.explicit, k) : attr
# Reset to default value and return old value
pop_kw!(attr::Attr, k) = is_explicit(attr, k) ? pop!(attr.explicit, k) : attr.defaults[k]
pop_kw!(attr::Attr, k, default) = is_explicit(attr, k) ? pop!(attr.explicit, k) : get(attr.defaults, k, default)
# Fallbacks for dicts without defaults
reset_kw!(d::AKW, k) = delete!(d, k)
pop_kw!(d::AKW, k) = pop!(d, k)
pop_kw!(d::AKW, k, default) = pop!(d, k, default)
# -----------------------------------------------------------
mutable struct Series
plotattributes::KW
plotattributes::Attr
end
attr(series::Series, k::Symbol) = series.plotattributes[k]
@@ -36,7 +90,7 @@ mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox # the canvas area which is available to this subplot
plotarea::BoundingBox # the part where the data goes
attr::KW # args specific to this subplot
attr::Attr # args specific to this subplot
o # can store backend-specific data... like a pyplot ax
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
end
@@ -48,7 +102,7 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
mutable struct Axis
sps::Vector{Subplot}
plotattributes::KW
plotattributes::Attr
end
mutable struct Extrema
@@ -67,8 +121,7 @@ const SubplotMap = Dict{Any, Subplot}
mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type
n::Int # number of series
attr::KW # arguments for the whole plot
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
attr::Attr # arguments for the whole plot
series_list::Vector{Series} # arguments for each series
o # the backend's plot object
subplots::Vector{Subplot}
@@ -79,7 +132,7 @@ mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
end
function Plot()
Plot(backend(), 0, KW(), KW(), Series[], nothing,
Plot(backend(), 0, Attr(KW(), _plot_defaults), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout(),
Subplot[], false)
end
+41 -32
View File
@@ -43,7 +43,7 @@ function barHack(; kw...)
# estimate the edges
dists = diff(midpoints) * 0.5
edges = zeros(length(midpoints)+1)
for i in 1:length(edges)
for i in eachindex(edges)
if i == 1
edge = midpoints[1] - dists[1]
elseif i == length(edges)
@@ -56,7 +56,7 @@ function barHack(; kw...)
x = Float64[]
y = Float64[]
for i in 1:length(heights)
for i in eachindex(heights)
e1, e2 = edges[i:i+1]
append!(x, [e1, e1, e2, e2])
append!(y, [fillrange, heights[i], heights[i], fillrange])
@@ -129,7 +129,7 @@ function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
# newz, ColorGradient(colors)
end
function imageHack(plotattributes::KW)
function imageHack(plotattributes::AKW)
is_seriestype_supported(:heatmap) || error("Neither :image or :heatmap are supported!")
plotattributes[:seriestype] = :heatmap
plotattributes[:z], plotattributes[:fillcolor] = replace_image_with_heatmap(plotattributes[:z].surf)
@@ -145,16 +145,18 @@ end
Segments() = Segments(Float64)
Segments(::Type{T}) where {T} = Segments(T[])
Segments(p::Int) = Segments(NTuple{2,Float64}[])
Segments(p::Int) = Segments(NTuple{p, Float64}[])
# Segments() = Segments(zeros(0))
to_nan(::Type{Float64}) = NaN
to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN)
to_nan(::Type{NTuple{3,Float64}}) = (NaN, NaN, NaN)
coords(segs::Segments{Float64}) = segs.pts
coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts]
coords(segs::Segments{NTuple{3,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts], Float64[p[3] for p in segs.pts]
function Base.push!(segments::Segments{T}, vs...) where T
if !isempty(segments.pts)
@@ -182,13 +184,15 @@ end
mutable struct SegmentsIterator
args::Tuple
n::Int
n1::Int
n2::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
SegmentsIterator(tup, n)
n1 = minimum(map(firstindex, tup))
n2 = maximum(map(lastindex, tup))
SegmentsIterator(tup, n1, n2)
end
function iter_segments(series::Series)
@@ -197,9 +201,9 @@ function iter_segments(series::Series)
return UnitRange{Int}[]
elseif has_attribute_segments(series)
if series[:seriestype] in (:scatter, :scatter3d)
return [[i] for i in 1:length(y)]
return [[i] for i in eachindex(y)]
else
return [i:(i + 1) for i in 1:(length(y) - 1)]
return [i:(i + 1) for i in firstindex(y):lastindex(y)-1]
end
else
segs = UnitRange{Int}[]
@@ -217,13 +221,13 @@ anynan(args::Tuple) = i -> anynan(i,args)
anynan(istart::Int, iend::Int, args::Tuple) = any(anynan(args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(anynan(args), istart:iend)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
i = findfirst(!anynan(itr.args), nextidx:itr.n)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = itr.n1)
i = findfirst(!anynan(itr.args), nextidx:itr.n2)
i === nothing && return nothing
nextval = nextidx + i - 1
j = findfirst(anynan(itr.args), nextval:itr.n)
nextnan = j === nothing ? itr.n + 1 : nextval + j - 1
j = findfirst(anynan(itr.args), nextval:itr.n2)
nextnan = j === nothing ? itr.n2 + 1 : nextval + j - 1
nextval:nextnan-1, nextnan
end
@@ -314,13 +318,13 @@ function replaceType(vec, val)
push!(vec, val)
end
function replaceAlias!(plotattributes::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
function replaceAlias!(plotattributes::AKW, k::Symbol, aliases::Dict{Symbol,Symbol})
if haskey(aliases, k)
plotattributes[aliases[k]] = pop!(plotattributes, k)
plotattributes[aliases[k]] = pop_kw!(plotattributes, k)
end
end
function replaceAliases!(plotattributes::KW, aliases::Dict{Symbol,Symbol})
function replaceAliases!(plotattributes::AKW, aliases::Dict{Symbol,Symbol})
ks = collect(keys(plotattributes))
for k in ks
replaceAlias!(plotattributes, k, aliases)
@@ -344,8 +348,8 @@ const _scale_base = Dict{Symbol, Real}(
function _heatmap_edges(v::AVec, isedges::Bool = false)
length(v) == 1 && return v[1] .+ [-0.5, 0.5]
if isedges return v end
# `isedges = true` means that v is a vector which already describes edges
if isedges return v end
# `isedges = true` means that v is a vector which already describes edges
# and does not need to be extended.
vmin, vmax = ignorenan_extrema(v)
extra_min = (v[2] - v[1]) / 2
@@ -361,20 +365,25 @@ end
function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size::Tuple{Int, Int})
nx, ny = length(x), length(y)
# ismidpoints = z_size == (ny, nx) # This fails some tests, but would actually be
# ismidpoints = z_size == (ny, nx) # This fails some tests, but would actually be
# the correct check, since (4, 3) != (3, 4) and a missleading plot is produced.
ismidpoints = prod(z_size) == (ny * nx)
ismidpoints = prod(z_size) == (ny * nx)
isedges = z_size == (ny - 1, nx - 1)
if !ismidpoints && !isedges
error("""Length of x & y does not match the size of z.
error("""Length of x & y does not match the size of z.
Must be either `size(z) == (length(y), length(x))` (x & y define midpoints)
or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""")
end
x, y = heatmap_edges(x, xscale, isedges),
x, y = heatmap_edges(x, xscale, isedges),
heatmap_edges(y, yscale, isedges)
return x, y
end
function is_uniformly_spaced(v; tol=1e-6)
dv = diff(v)
maximum(dv) - minimum(dv) < tol * mean(abs.(dv))
end
function convert_to_polar(theta, r, r_extrema = ignorenan_extrema(r))
rmin, rmax = r_extrema
r = (r .- rmin) ./ (rmax .- rmin)
@@ -406,7 +415,7 @@ isscalar(::Any) = false
is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2
isvertical(plotattributes::KW) = get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(plotattributes::AKW) = get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.plotattributes)
@@ -490,7 +499,7 @@ function make_fillrange_side(y, rib)
end
# turn a ribbon into a fillrange
function make_fillrange_from_ribbon(kw::KW)
function make_fillrange_from_ribbon(kw::AKW)
y, rib = kw[:y], kw[:ribbon]
rib = wraptuple(rib)
rib1, rib2 = -first(rib), last(rib)
@@ -552,7 +561,7 @@ function get_clims(sp::Subplot)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1)
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series)
@@ -566,7 +575,7 @@ function get_clims(sp::Subplot, series::Series)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1)
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(series::Series)
@@ -579,10 +588,10 @@ function get_clims(series::Series)
zmin, zmax = _update_clims(zmin, zmax, ignorenan_extrema(vals)...)
end
end
return zmin < zmax ? (zmin, zmax) : (-0.1, 0.1)
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
_update_clims(zmin, zmax, emin, emax) = min(zmin, emin), max(zmax, emax)
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
@@ -820,7 +829,7 @@ end
debugshow(io, x) = show(io, x)
debugshow(io, x::AbstractArray) = print(io, summary(x))
function dumpdict(io::IO, plotattributes::KW, prefix = "", alwaysshow = false)
function dumpdict(io::IO, plotattributes::AKW, prefix = "", alwaysshow = false)
_debugMode.on || alwaysshow || return
println(io)
if prefix != ""
@@ -833,8 +842,8 @@ function dumpdict(io::IO, plotattributes::KW, prefix = "", alwaysshow = false)
end
println(io)
end
DD(io::IO, plotattributes::KW, prefix = "") = dumpdict(io, plotattributes, prefix, true)
DD(plotattributes::KW, prefix = "") = DD(stdout, plotattributes, prefix)
DD(io::IO, plotattributes::AKW, prefix = "") = dumpdict(io, plotattributes, prefix, true)
DD(plotattributes::AKW, prefix = "") = DD(stdout, plotattributes, prefix)
function dumpcallstack()
error() # well... you wanted the stacktrace, didn't you?!?
@@ -1149,7 +1158,7 @@ function convert_sci_unicode(label::AbstractString)
for key in keys(unicode_dict)
label = replace(label, key => unicode_dict[key])
end
if occursin("10^{", label)
if occursin("×10^{", label)
label = string(label, "}")
end
label
+16
View File
@@ -7,6 +7,7 @@ using FileIO
using Gtk
using LibGit2
using GeometryTypes
using Dates
include("test_pgfplotsx.jl")
@@ -67,6 +68,21 @@ img_tol = is_ci() ? 10e-2 : 10e-2
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, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test isa(p, Plots.Plot) == true
@test isa(display(p), Nothing) == true
end
end
+33 -3
View File
@@ -16,6 +16,9 @@ end
Plots._update_plot_object(pgfx_plot)
@test pgfx_plot.o.the_plot isa PGFPlotsX.TikzDocument
@test pgfx_plot.series_list[1].plotattributes[:quiver] === nothing
axis = Plots.pgfx_axes(pgfx_plot.o)[1]
@test count( x-> x isa PGFPlotsX.Plot, axis.contents ) == 1
@test !haskey(axis.contents[1].options.dict, "fill")
@testset "3D docs example" begin
n = 100
@@ -124,13 +127,40 @@ end
u = ones(length(x))
v = cos.(x)
plot( x, y, quiver = (u, v), arrow = true )
arrow_plot = plot( x, y, quiver = (u, v), arrow = true )
# TODO: could adjust limits to fit arrows if too long, but how?
# TODO: get latex available on CI
# mktempdir() do path
# @test_nowarn savefig(arrow_plot, path*"arrow.pdf")
# end
end # testset
@testset "Annotations" begin
y = rand(10)
plot(y, annotations=(3, y[3], Plots.text("this is \\#3", :left)), leg=false)
annotate!([(5, y[5], Plots.text("this is \\#5", 16, :red, :center)), (10, y[10], Plots.text("this is \\#10", :right, 20, "courier"))])
scatter!(range(2, stop=8, length=6), rand(6), marker=(50, 0.2, :orange), series_annotations=["series", "annotations", "map", "to", "series", Plots.text("data", :green)])
annotation_plot = scatter!(range(2, stop=8, length=6), rand(6), marker=(50, 0.2, :orange), series_annotations=["series", "annotations", "map", "to", "series", Plots.text("data", :green)])
# mktempdir() do path
# @test_nowarn savefig(annotation_plot, path*"annotation.pdf")
# end
end # testset
end # testset
@testset "Ribbon" begin
aa = rand(10)
bb = rand(10)
cc = rand(10)
conf = [aa-cc bb-cc]
ribbon_plot = plot(collect(1:10),fill(1,10), ribbon=(conf[:,1],conf[:,2]))
Plots._update_plot_object(ribbon_plot)
axis = Plots.pgfx_axes(ribbon_plot.o)[1]
plots = filter(x->x isa PGFPlotsX.Plot, axis.contents)
@test length(plots) == 4
@test !haskey(plots[1].options.dict, "fill")
@test !haskey(plots[2].options.dict, "fill")
@test !haskey(plots[3].options.dict, "fill")
@test haskey(plots[4].options.dict, "fill")
@test ribbon_plot.o !== nothing
@test ribbon_plot.o.the_plot !== nothing
# mktempdir() do path
# @test_nowarn savefig(ribbon_plot, path*"ribbon.svg")
# end
end # testset
end # testset