Compare commits

..

157 Commits

Author SHA1 Message Date
Michael Krabbe Borregaard 4f667291bd remove spurious warning 2018-08-28 21:39:02 +02:00
Michael Krabbe Borregaard 49ad3a51aa update news 2018-08-28 14:49:42 +02:00
Michael Krabbe Borregaard f2e98acc65 Merge pull request #1681 from mkborregaard/plotattributes
change all instances of `d` to `plotattributes.
2018-08-28 14:39:44 +02:00
Michael Krabbe Borregaard b68adde751 up recipesbase and julia dep versions 2018-08-28 14:38:53 +02:00
Michael Krabbe Borregaard 7220eca7a8 Clean up after rebase 2018-08-28 10:13:33 +02:00
Michael Krabbe Borregaard 10dd9b5120 fix errors 2018-08-28 10:10:13 +02:00
Michael Krabbe Borregaard 7590c133fd replace d -> plotattributes in the rest of the files 2018-08-28 10:10:13 +02:00
Michael Krabbe Borregaard 2873685517 Replace d -> plotattributes in most files 2018-08-28 10:10:13 +02:00
Michael Krabbe Borregaard 91ec39e141 Merge pull request #1696 from JeffFessler/patch-1
Add :match_dimensions to address #1694
2018-08-26 22:58:31 +02:00
Michael Krabbe Borregaard 602dbdf1d2 Merge pull request #1695 from JuliaPlots/pv/group
RFC WIP: sort x axis in group_as_matrix
2018-08-26 22:57:04 +02:00
Daniel Schwabeneder 3eabaf074a Merge pull request #1691 from daschw/performance
Performance improvements
2018-08-26 22:52:50 +02:00
Daniel Schwabeneder a81178121f implement pyplot 2018-08-26 22:41:40 +02:00
Daniel Schwabeneder e1a83aab1d implement plotly 2018-08-26 22:41:40 +02:00
Daniel Schwabeneder 84601bacdb gr implementation 2018-08-26 22:41:40 +02:00
Daniel Schwabeneder e991e2bf37 implement additional get_***color methods 2018-08-26 22:41:40 +02:00
Daniel Schwabeneder 9b6fc4bc6b Merge pull request #1667 from pfitzseb/sp/betterdisplay
WIP: Actually use PlotsDisplay()
2018-08-26 22:05:29 +02:00
Daniel Schwabeneder c9e832600c Merge pull request #1700 from daschw/pkg3
Fix tests
2018-08-26 22:04:02 +02:00
Daniel Schwabeneder 25190d945d Merge pull request #1689 from tkf/pkg3
Fix CI
2018-08-26 21:16:15 +02:00
Daniel Schwabeneder b2f2ffcfed fix tests 2018-08-26 21:11:23 +02:00
Jeff Fessler 00821c1ae3 Add :match_dimensions to address #1694
see also #273 and #196, for f(x,y) vs f(y,x), and transpose=true
2018-08-25 14:49:52 -04:00
Pietro Vertechi 937acbc218 sort x axis in group_as_matrix 2018-08-25 19:04:42 +01:00
Takafumi Arakaki e0f9313b8b Use import PlotReferenceImages 2018-08-25 07:16:42 -07:00
Takafumi Arakaki 6d0d8ea90a Use qualified name Statistics.mean 2018-08-25 07:16:42 -07:00
Takafumi Arakaki ebf32390ef Import Gtk in interactive session 2018-08-24 17:16:52 -07:00
Takafumi Arakaki eefea15069 Don't use Base.mean 2018-08-24 17:14:19 -07:00
Takafumi Arakaki 531dd43284 Add FileIO to test/REQUIRE 2018-08-24 17:14:19 -07:00
Takafumi Arakaki e483ce85dc Install unregistered packages in test/runtests.jl 2018-08-24 17:14:19 -07:00
Takafumi Arakaki 80da14c1fb Use pathof(PlotReferenceImages) instead of Pkg.dir 2018-08-24 17:14:19 -07:00
Takafumi Arakaki 374580a3d6 Import Pkg 2018-08-24 17:14:19 -07:00
Takafumi Arakaki 4a51e4e7fb Import Random 2018-08-24 17:14:19 -07:00
Takafumi Arakaki 7fcd008f2f Fix appveyor.yml 2018-08-23 14:32:05 -07:00
Takafumi Arakaki def5be630a Use Pkg3 API in travis_commands.jl 2018-08-23 14:27:21 -07:00
Michael Krabbe Borregaard de3848ff53 Merge pull request #1688 from mkborregaard/add_undef
Add some undefs to Array constructors
2018-08-23 22:24:17 +02:00
Michael Krabbe Borregaard 8d4ab6bb94 Also fix broadcast on dict 2018-08-23 16:51:15 +02:00
Michael Krabbe Borregaard 28ac117d68 Add some undefs to Array constructors 2018-08-23 16:31:28 +02:00
Daniel Schwabeneder 69bdd6db83 Merge pull request #1643 from tkf/single-colorbar
Make sure only one colorbar is drawn with GR
2018-08-22 09:37:59 +02:00
Daniel Schwabeneder cd270dd407 Merge pull request #1657 from tkf/colorbar_title
Implement colorbar_title for GR
2018-08-22 09:34:03 +02:00
Daniel Schwabeneder b4944a6f81 Merge pull request #1664 from mortenpi/fix-pyplot-savefig
Fix savefig with latexstring for pyplot
2018-08-22 09:18:45 +02:00
Michael Krabbe Borregaard 4049bf20c2 Merge pull request #1686 from JuliaPlots/pv/nt
Fix NamedTuple integration
2018-08-21 23:40:24 +02:00
Michael Krabbe Borregaard 805ca0d378 Merge pull request #1678 from improbable22/remove-P2-P3
Remove P2 & P3 from export
2018-08-21 22:01:59 +02:00
Pietro Vertechi fcaae346a7 Fix NamedTuple integration 2018-08-21 18:17:47 +01:00
Michael Krabbe Borregaard 0684102511 Merge pull request #1674 from djsegal/djsegal/colorbar
Add way to give colorbar_title for pgfplots
2018-08-19 21:29:38 +02:00
Michael Krabbe Borregaard 6ca87f6d33 Merge pull request #1680 from JuliaPlots/mkb/doc_badge
Replace link to docs with docs badge
2018-08-19 15:54:10 +02:00
Michael Krabbe Borregaard 3c96831cdc fix_1 2018-08-19 15:53:36 +02:00
Michael Krabbe Borregaard b551f6714b Replace link to docs with docs badge 2018-08-19 15:49:05 +02:00
Sebastian c005cc211f Add example 2018-08-19 13:52:26 +02:00
Unknown 92b0d5c0be Add line_z and update arg_desc.jl 2018-08-19 13:52:26 +02:00
SebastianM-C 45dc9e5c0d Add 2D marker_z with Functions 2018-08-19 13:52:26 +02:00
djsegal 7c505949fc Add “colorbar_title” to pgfplots 2018-08-19 02:25:04 -04:00
improbable22 905accdb7d Remove P2 & P3 from export
As in #1675, important stuff!
2018-08-19 07:20:17 +02:00
Michael Krabbe Borregaard 30f3e3cf56 Merge pull request #1676 from mkborregaard/plotattr
make plotattr work again
2018-08-18 23:24:54 +02:00
Michael Krabbe Borregaard 71131fd00c make plotattr work again 2018-08-18 23:24:14 +02:00
Michael Krabbe Borregaard 60b8b0080c Merge pull request #1670 from mkborregaard/master
Address UInt round problem - see #1665
2018-08-17 20:58:01 +02:00
Michael Krabbe Borregaard b30ff9b41b Merge pull request #1671 from mkborregaard/getrgb_patch
Add vector function for rgb
2018-08-17 11:21:01 +02:00
Michael Krabbe Borregaard cf1a0e3c33 Add vector function for rgb 2018-08-17 11:19:57 +02:00
Michael Krabbe Borregaard e94fe13178 Merge pull request #1668 from anowacki/an/1665
Remove broadcasting of getSeriesRGBColor
2018-08-17 11:17:15 +02:00
Michael Krabbe Borregaard b2c4561a7d gr: round to UInt not Int
Fixes an error with 32-bit system compatibility
2018-08-17 10:50:05 +02:00
Andy Nowacki ef63c8d66e Remove broadcasting of getSeriesRGBColor
No longer broadcast over d[:seriescolor] when updating
series attributes.  This fixes #1665, where in Julia
v1.0 the PlotUtils ColorGradient type is assumed to
be iterable (JuliaLang/julia/#18618).
2018-08-16 15:28:36 +01:00
Sebastian Pfitzner 00be8a2237 make sure display order is correct if Plots is loaded before the REPL 2018-08-16 12:34:33 +02:00
Sebastian Pfitzner 6593e3cfe6 actually use __init__ 2018-08-16 12:23:23 +02:00
Sebastian Pfitzner ac73798b9d actually use PlotsDisplay()
instead of overloading display for REPLDisplay
2018-08-16 11:59:56 +02:00
Michael Krabbe Borregaard 1697b99bbc Merge pull request #1663 from mkborregaard/travis-0.7
update travis script; fix #1658
2018-08-16 11:21:00 +02:00
Takafumi Arakaki b56238089c Use TEXT_VALIGN_TOP 2018-08-15 21:24:20 -07:00
Morten Piibeleht 47d8aa871b Do not import latexstring into the global scope
It will not be visible to functions in Plots anyway. Instead, labelfunc
now explicitly specifies that it uses LaTeXStrings.latexstring.
2018-08-16 11:05:39 +12:00
Morten Piibeleht 87627b8320 Wrap latexstring use in an at-require
latexstring comes from the LaTeXStrings package, which is conditionally
loaded by pyplot().

Fix #1659.
2018-08-16 11:03:21 +12:00
Michael Krabbe Borregaard c419f87b64 update travis script; fix #1658 2018-08-15 23:20:18 +02:00
Michael Krabbe Borregaard 9ae22a1ad7 Merge pull request #1660 from CarloLucibello/glv
fix glvisualize require
2018-08-15 16:01:01 +02:00
CarloLucibello b4dfd35be6 fix glvisualize require 2018-08-15 09:30:52 -04:00
Takafumi Arakaki 2acd088226 Implement colorbar_title for GR 2018-08-14 20:28:22 -07:00
Michael Krabbe Borregaard 2d217edc15 update news.md 2018-08-14 23:56:21 +02:00
Michael Krabbe Borregaard b55d13bc21 Merge pull request #1655 from roshanshariff/julia-1.0
Fix julia 0.7 deprecated syntax in Plotly backend.
2018-08-14 23:53:35 +02:00
Michael Krabbe Borregaard 1f9468e029 Merge pull request #1656 from mkborregaard/pyplot
Add more packages to PyPlot string
2018-08-14 23:53:03 +02:00
Roshan Shariff 593804096d Fix julia 0.7 deprecated syntax in Plotly backend. 2018-08-14 15:38:55 -06:00
Michael Krabbe Borregaard befb14682d Add more packages to PyPlot string 2018-08-14 23:28:18 +02:00
Michael Krabbe Borregaard 07a6700ab6 Merge pull request #1654 from ma-laforge/hdf5
Deal w/deprecation of Nullable.
2018-08-14 22:57:17 +02:00
MA Laforge 8131953e49 Deal w/deprecation of Nullable.
Also use new LinearIndices API.
2018-08-14 13:04:22 -07:00
Michael Krabbe Borregaard 7e360aa915 Merge pull request #1651 from mkborregaard/master
Update instances of `findfirst` to 1.0 syntax
2018-08-14 10:24:40 +02:00
Michael Krabbe Borregaard 0710fba638 Update instances of findfirst to 1.0 syntax 2018-08-14 10:24:10 +02:00
Michael Krabbe Borregaard afb7a17e5f Merge pull request #1650 from mkborregaard/master
1.0 updates to animations
2018-08-14 09:20:34 +02:00
Michael Krabbe Borregaard badf302756 Explicitly specify assignment to global 2018-08-14 09:19:32 +02:00
Michael Krabbe Borregaard 99941dde8f info --> @info 2018-08-14 09:13:27 +02:00
Michael Krabbe Borregaard e5c55b6962 Merge pull request #1647 from joshday/patch-1
import findnz from SparseArrays
2018-08-13 15:05:42 +02:00
Josh Day 7a7f4cb306 import findnz from SparseArrays 2018-08-13 08:58:38 -04:00
Michael Krabbe Borregaard d084e31065 Merge pull request #1644 from mkborregaard/master
Don't broadcast `plot_color`; fix #1641
2018-08-13 10:08:57 +02:00
Michael Krabbe Borregaard 12008ef1c6 Don't broadcast plot_color; fix #1641
On 1.0 you can no longer pass a singleton argument to broadcast without escaping with `Ref`. But - `plot_color` has `Vector` methods, so it should be fine to not broadcast here. The example from the PR that introduced the broadcast here still works on this PR https://github.com/JuliaPlots/Plots.jl/pull/1467#issue-178940271
2018-08-13 10:07:03 +02:00
Takafumi Arakaki 23ec52c6b4 Make sure only one colorbar is drawn with GR
closes #1642
2018-08-13 00:06:12 -07:00
Michael Krabbe Borregaard 6dc0823b73 Merge pull request #1637 from mkborregaard/master
update news.md
2018-08-11 18:26:18 +01:00
Michael Krabbe Borregaard 0f9220c965 update news.md 2018-08-11 18:25:49 +01:00
Michael Krabbe Borregaard 5c21261aea Merge pull request #1636 from oschulz/fixes-julia-v1.0
More fixes for Julia v1.0
2018-08-11 13:51:28 +01:00
Oliver Schulz 1fda0df03e Fix _stepbins_path (new Julia v0.7/v1.0 iteration API) 2018-08-11 13:41:33 +01:00
Oliver Schulz d4406bb806 Use length(eachindex(...)) instead of length(linearindices(...)) 2018-08-11 13:21:06 +01:00
Michael Krabbe Borregaard b1095e29bc Merge pull request #1635 from mkborregaard/master
Final 1.0 fixes
2018-08-11 11:25:54 +01:00
Michael Krabbe Borregaard 3e56aa43e4 linspace -> range 2018-08-11 11:24:54 +01:00
Michael Krabbe Borregaard c2dc030fae fieldnames(x) -> fieldnames(typeof(x)) 2018-08-11 11:24:45 +01:00
Michael Krabbe Borregaard 340cd0a1fe Merge pull request #1634 from mkborregaard/master
replace warn -> @warn
2018-08-10 18:16:37 +01:00
Michael Krabbe Borregaard 2844e706a9 warn -> @warn 2018-08-10 18:14:14 +01:00
Michael Krabbe Borregaard 55ee64b4e6 Merge pull request #1630 from mkborregaard/fix1.0
1.0 fixes WIP RFC
2018-08-10 11:02:58 +01:00
Michael Krabbe Borregaard 3849700a28 readstring -> read 2018-08-09 17:03:44 +01:00
Michael Krabbe Borregaard 3dd0049973 No longer overload broadcast 2018-08-09 17:00:17 +01:00
Michael Krabbe Borregaard 8e6ccf1b20 typo fix 2018-08-09 16:55:30 +01:00
Michael Krabbe Borregaard c544dbbbb7 rename mimewritable 2018-08-09 16:53:37 +01:00
Michael Krabbe Borregaard 5205ac38ad Implement new iterator protocol 2018-08-09 16:53:27 +01:00
Michael Krabbe Borregaard 0143807515 Remove deprecated endof 2018-08-09 16:52:43 +01:00
Michael Krabbe Borregaard 5176ab1382 Merge pull request #1625 from mkborregaard/master
No longer include files for Revise
2018-08-09 16:31:56 +01:00
Daniel Schwabeneder b0d54f7c5d Merge pull request #1623 from JuliaPlots/fbot/deps
Fix deprecations
2018-08-09 14:16:47 +02:00
Michael Krabbe Borregaard 96f0335af4 No longer include files for Revise
This is no longer necessary in 0.7
2018-08-09 12:46:09 +01:00
Michael Krabbe Borregaard 572f8ebfde Merge pull request #1624 from mkborregaard/master
Remove Dates from Require again
2018-08-09 12:42:33 +01:00
Michael Krabbe Borregaard 07a8d844d2 Remove dates again 2018-08-09 12:41:56 +01:00
Michael Krabbe Borregaard c48abef5f8 Merge pull request #1622 from mkborregaard/master
Change dep to julia 0.7 and add Dates to Require
2018-08-09 09:28:23 +01:00
Michael Krabbe Borregaard 9b3679792d change dep to 0.7 and add Dates to require 2018-08-09 09:26:36 +01:00
Michael Krabbe Borregaard cb00983db3 Allow bin to be a heterogeneous Tuple
fix #https://github.com/JuliaPlots/StatPlots.jl/issues/156
2018-08-09 09:13:34 +01:00
femtocleaner[bot] 83686866cc Fix deprecations 2018-08-08 12:42:18 +00:00
Daniel Schwabeneder 7a49249384 Merge pull request #1619 from daschw/init
fix merge conflicts
2018-08-08 10:34:40 +03:00
Daniel Schwabeneder 0548793bfd remove Juno requires code 2018-08-08 09:28:30 +02:00
Daniel Schwabeneder cd770f70c0 fix merge conflict relicts 2018-08-08 09:24:37 +02:00
Daniel Schwabeneder a3f1950a18 Merge pull request #1616 from apalugniok/ticks
Make xticks!/yticks! behave like plot(xticks!/yticks! = ). (Fixes #1605)
2018-08-07 07:15:16 -08:00
Daniel Schwabeneder 1874c28cad Merge pull request #1601 from daschw/requires
RFC: use Requires.jl for backend dependencies
2018-08-07 07:14:21 -08:00
Daniel Schwabeneder 317f01a6b4 fix init.jl 2018-08-06 18:02:19 +02:00
Daniel Schwabeneder 5e8eff074d require PyCall 2018-08-06 17:55:02 +02:00
Andrew Palugniok db028f2774 Make xticks!/yticks! behave like plot(xticks!/yticks! = ) 2018-08-05 14:29:00 +01:00
Daniel Schwabeneder a82a154be9 remove old juno inti code 2018-08-04 06:45:18 +02:00
Daniel Schwabeneder af01927807 add init.jl 2018-08-04 06:44:12 +02:00
Daniel Schwabeneder f60aac93ab use Requires.jl for backend dependencies 2018-08-04 06:44:12 +02:00
Daniel Schwabeneder 4860bf3f19 Merge pull request #1615 from pfitzseb/sp/junodisplay
Fix display on Juno 0.7
2018-08-04 06:05:00 +02:00
Sebastian Pfitzner adf2af82b4 fix display on Juno 0.7 2018-08-03 12:37:12 +02:00
Josef Heinen 8d16563014 Update gr.jl 2018-08-01 13:12:48 +02:00
Daniel Schwabeneder da765a5eec Merge pull request #1610 from daschw/pyplot-thickness
fix pyplot thickness_scaling (fix #1606)
2018-07-28 08:53:03 +02:00
Daniel Schwabeneder 85b3aefd67 add init.jl 2018-07-20 17:15:43 +02:00
Daniel Schwabeneder af0dabec99 use Requires.jl for backend dependencies 2018-07-19 22:33:36 +02:00
Daniel Schwabeneder de85983247 Merge pull request #1596 from wfrgra/minorgrid
Minorgrid and minor ticks
2018-07-17 17:54:38 +02:00
Will Grant 7eaae3a6d5 Add full keyword control of minor grid 2018-07-16 17:37:19 +10:00
Will Grant 403b57c076 extend ticks beyond major grid, to axis limits 2018-07-11 17:59:47 +10:00
Will Grant dd434b89d2 add minor grid and tick marks. Works, but doesn't extend beyond major ticks 2018-07-11 17:17:45 +10:00
Daniel Schwabeneder 1a3d58e09b Merge pull request #1594 from fredrikekre/fe/0.72
additional fixes
2018-07-05 09:01:26 +02:00
Fredrik Ekre 89ae239743 adjust CI scripts 2018-07-05 08:46:17 +02:00
Fredrik Ekre c785d1509b additional fixes 2018-07-05 08:33:14 +02:00
Daniel Schwabeneder 9e412555bb Merge pull request #1585 from JuliaPlots/julia0.7
Switch to 0.7 on master
2018-07-05 08:14:03 +02:00
Daniel Schwabeneder 0717805773 more deprecation fixes 2018-07-04 22:33:51 +02:00
Daniel Schwabeneder d045c5a390 Merge pull request #1592 from JuliaPlots/revert-1591-fbot/deps
Revert "Fix deprecations"
2018-07-04 21:10:31 +02:00
Daniel Schwabeneder 3cc0d0c735 Revert "Fix deprecations" 2018-07-04 21:10:08 +02:00
Daniel Schwabeneder 9a3c727532 Merge pull request #1591 from JuliaPlots/fbot/deps
Fix deprecations
2018-07-04 21:08:10 +02:00
Daniel Schwabeneder a7f2484d45 fix some deprecation warnings 2018-07-04 20:56:13 +02:00
Daniel Schwabeneder 96d97699a0 Merge pull request #1588 from daschw/julia0.7
fix Pkg.installed
2018-07-03 20:02:22 +02:00
Daniel Schwabeneder e92e832258 fix Pkg.installed 2018-07-03 19:59:03 +02:00
femtocleaner[bot] 3a769549d8 Fix deprecations 2018-07-02 20:33:16 +00:00
femtocleaner[bot] d68829820b Fix deprecations 2018-06-30 23:15:27 +00:00
Daniel Schwabeneder 9cf3036ab5 Merge pull request #1587 from daschw/julia0.7
remove StatPlots from tests
2018-07-02 00:28:22 +02:00
Daniel Schwabeneder 2467eb71c1 remove StatPlots from tests 2018-07-02 00:26:23 +02:00
Daniel Schwabeneder 345bb5d1aa Merge pull request #1586 from daschw/julia0.7
use Pkg in travis commands
2018-07-02 00:19:54 +02:00
Daniel Schwabeneder 8d50828998 Merge branch 'julia0.7' into julia0.7 2018-07-02 00:03:27 +02:00
Daniel Schwabeneder 201de82baf fix some things in tests 2018-07-02 00:00:40 +02:00
Daniel Schwabeneder 99519ac3da use Pkg in travis commands 2018-07-01 23:48:56 +02:00
Daniel Schwabeneder a575ab7c74 Merge branch 'master' into julia0.7 2018-07-01 23:30:40 +02:00
Daniel Schwabeneder c4f79814df Merge pull request #1584 from daschw/julia0.7
julia 0.7 fixes
2018-07-01 23:24:38 +02:00
Daniel Schwabeneder 6135f6271c julia 0.7 fixes 2018-07-01 21:40:48 +02:00
Michael K. Borregaard 5b0ba79a35 Update Travis commands for 0.7 2018-05-04 10:53:21 +02:00
Michael Krabbe Borregaard 173c7b2aec Update julia version to 0.7
Isn't working yet.
2018-05-03 20:46:32 +02:00
51 changed files with 2263 additions and 2128 deletions
+1
View File
@@ -5,3 +5,4 @@
examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
deps/build.log
+9 -8
View File
@@ -4,10 +4,11 @@ os:
- linux
# - osx
julia:
- 0.6
matrix:
allow_failures:
- julia: nightly
# - 0.7
- nightly
# matrix:
# allow_failures:
# - julia: nightly
# # before install:
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
@@ -42,10 +43,10 @@ before_install:
notifications:
email: true
# uncomment the following lines to override the default test script
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
- julia test/travis_commands.jl
# script:
# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
# - julia -e 'import Pkg; Pkg.add(Pkg.PackageSpec(path=pwd())); Pkg.build("Plots")'
# - julia test/travis_commands.jl
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
+35 -1
View File
@@ -10,7 +10,41 @@
---
## (current master)
- All new development should target Julia 0.7!
- All new development should target Julia 1.x!
## 0.20.0
Many updates, min julia 1.0
- change display type to use PlotsDisplay (fixes Juno integration)
- change all internal uses of `d` to `plotattributes` (no user change)
- change spy implementation to use `scatter` not `heatmap`
- sort x axes when passing a vector of strings as x
- improve performance of marker_z
- update CI to 1.0
- minor depwarn ifixes
- only draw one colorbar with GR
- add colorbar_title to GR and pgfplots
- fix savefig with latexstrings for PyPlot
- fix NamedTuple integration
- don't export `P2` and `P3`
- make it possible to use 2-argument function as argument to marker_z
- make `plotattr` work again
## 0.19.3
- fix some julia 0.7 deprecations
- fix 32-bit OS functionality
## 0.19.2
- several small fixes for 1.0 compatibility
## 0.19.1
- don't broadcast plot_color
## 0.19.0
- Refactor conditional loading to use Requires
- Many fixes for 1.0 compatibility
## 0.18.0
- update minor version to 0.7
## 0.17.4
- fix thickness_scaling for pyplot
+1 -2
View File
@@ -3,6 +3,7 @@
[![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) -->
@@ -21,5 +22,3 @@ Plots is a plotting API and toolset. My goals with the package are:
- **Consistent**. Don't commit to one graphics package, use the same code everywhere.
- **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
View the [full documentation](http://docs.juliaplots.org/latest).
+2 -2
View File
@@ -1,6 +1,6 @@
julia 0.6
julia 1.0
RecipesBase 0.2.3
RecipesBase 0.6.0
PlotUtils 0.4.1
PlotThemes 0.1.3
Reexport
+12 -10
View File
@@ -1,15 +1,14 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
# - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
matrix:
allow_failures:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" #check and address
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
# matrix:
# allow_failures:
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
# - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
notifications:
- provider: Email
@@ -32,8 +31,11 @@ install:
build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo(); Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
- C:\projects\julia\bin\julia -e "
using InteractiveUtils, Pkg;
versioninfo();
Pkg.clone(pwd(), \"Plots\");
Pkg.build(\"Plots\")"
test_script:
# - C:\projects\julia\bin\julia -e "Pkg.test(\"Plots\")"
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
- C:\projects\julia\bin\julia -e "using Pkg; Pkg.test(\"Plots\")"
+1 -1
View File
@@ -3,6 +3,6 @@
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
end
+27 -42
View File
@@ -1,11 +1,11 @@
__precompile__(true)
module Plots
using Reexport
import StaticArrays
using StaticArrays.FixedSizeArrays
using Dates, Printf, Statistics, Base64, LinearAlgebra
import SparseArrays: findnz
@reexport using RecipesBase
import RecipesBase: plot, plot!, animate
@@ -104,8 +104,6 @@ export
rotate,
rotate!,
center,
P2,
P3,
BezierCurve,
plotattr
@@ -118,7 +116,7 @@ ignorenan_minimum(x) = Base.minimum(x)
ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
ignorenan_maximum(x) = Base.maximum(x)
ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
ignorenan_mean(x) = Base.mean(x)
ignorenan_mean(x) = Statistics.mean(x)
ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x)
@@ -170,6 +168,7 @@ include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
include("init.jl")
# ---------------------------------------------------------
@@ -235,10 +234,10 @@ zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmi
"Set xticks for an existing plot"
xticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
yticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
yticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
@@ -264,29 +263,29 @@ xgrid!(args...; kw...) = plot!(; xgrid = args
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
xticks!(plt::PlotOrSubplot,
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
global xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
global ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
global xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
global ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
global zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
global xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
global ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
global zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
global xticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
global yticks!(plt::PlotOrSubplot, ticks::TicksArgs; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
global xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
yticks!(plt::PlotOrSubplot,
global yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
global xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
global ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
global annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
global annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
global xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
global yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
global xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)
global yaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; yaxis = args, kw...)
end
@@ -294,18 +293,4 @@ end
const CURRENT_BACKEND = CurrentBackend(:none)
# for compatibility with Requires.jl:
@init begin
if isdefined(Main, :PLOTS_DEFAULTS)
if haskey(Main.PLOTS_DEFAULTS, :theme)
theme(Main.PLOTS_DEFAULTS[:theme])
end
for (k,v) in Main.PLOTS_DEFAULTS
k == :theme || default(k, v)
end
end
end
# ---------------------------------------------------------
end # module
+3 -3
View File
@@ -87,7 +87,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString,
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
end
show_msg && info("Saved animation to ", fn)
show_msg && @info("Saved animation to ", fn)
AnimatedGif(fn)
end
@@ -142,7 +142,7 @@ function _animate(forloop::Expr, args...; callgif = false)
end
push!(block.args, :(if $filterexpr; frame($animsym); end))
push!(block.args, :($countersym += 1))
push!(block.args, :(global $countersym += 1))
# add a final call to `gif(anim)`?
retval = callgif ? :(gif($animsym)) : animsym
@@ -151,7 +151,7 @@ function _animate(forloop::Expr, args...; callgif = false)
esc(quote
$freqassert # if filtering, check frequency is an Integer > 0
$animsym = Animation() # init animation object
$countersym = 1 # init iteration counter
global $countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
$retval # return the animation object, or the gif
end)
+9 -3
View File
@@ -21,14 +21,14 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(min(x), stop = extrema(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
@@ -139,6 +139,12 @@ const _arg_desc = KW(
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
:minorticks => "Integer. Intervals to divide the gap between major ticks into",
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
+334 -273
View File
File diff suppressed because it is too large Load Diff
+134 -59
View File
@@ -8,7 +8,7 @@
function Axis(sp::Subplot, letter::Symbol, args...; kw...)
# init with values from _plot_defaults
d = KW(
plotattributes = KW(
:letter => letter,
# :extrema => (Inf, -Inf),
:extrema => Extrema(),
@@ -22,14 +22,14 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
for (k,v) in _axis_defaults
lk = Symbol(letter, k)
lv = _axis_defaults_byletter[lk]
d[k] = (lv == :match ? v : lv)
plotattributes[k] = (lv == :match ? v : lv)
end
# merge!(d, _axis_defaults)
d[:discrete_values] = []
# merge!(plotattributes, _axis_defaults)
plotattributes[:discrete_values] = []
# update the defaults
attr!(Axis([sp], d), args...; kw...)
attr!(Axis([sp], plotattributes), args...; kw...)
end
function get_axis(sp::Subplot, letter::Symbol)
@@ -41,46 +41,46 @@ function get_axis(sp::Subplot, letter::Symbol)
end::Axis
end
function process_axis_arg!(d::KW, arg, letter = "")
function process_axis_arg!(plotattributes::KW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
d[Symbol(letter,:tickfont)] = arg
d[Symbol(letter,:guidefont)] = arg
plotattributes[Symbol(letter,:tickfont)] = arg
plotattributes[Symbol(letter,:guidefont)] = arg
elseif arg in _allScales
d[Symbol(letter,:scale)] = arg
plotattributes[Symbol(letter,:scale)] = arg
elseif arg in (:flip, :invert, :inverted)
d[Symbol(letter,:flip)] = true
plotattributes[Symbol(letter,:flip)] = true
elseif T <: AbstractString
d[Symbol(letter,:guide)] = arg
plotattributes[Symbol(letter,:guide)] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
d[Symbol(letter,sym)] = arg
plotattributes[Symbol(letter,sym)] = arg
# xticks/yticks
elseif T <: AVec
d[Symbol(letter,:ticks)] = arg
plotattributes[Symbol(letter,:ticks)] = arg
elseif arg == nothing
d[Symbol(letter,:ticks)] = []
plotattributes[Symbol(letter,:ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
d[Symbol(letter,:showaxis)] = showaxis(arg, letter)
plotattributes[Symbol(letter,:showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number
d[Symbol(letter,:rotation)] = arg
plotattributes[Symbol(letter,:rotation)] = arg
elseif typeof(arg) <: Function
d[Symbol(letter,:formatter)] = arg
plotattributes[Symbol(letter,:formatter)] = arg
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_axis))
warn("Skipped $(letter)axis arg $arg")
elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis))
@warn("Skipped $(letter)axis arg $arg")
end
end
@@ -88,28 +88,28 @@ end
# update an Axis object with magic args and keywords
function attr!(axis::Axis, args...; kw...)
# first process args
d = axis.d
plotattributes = axis.plotattributes
for arg in args
process_axis_arg!(d, arg)
process_axis_arg!(plotattributes, arg)
end
# then override for any keywords... only those keywords that already exists in d
# then override for any keywords... only those keywords that already exists in plotattributes
for (k,v) in kw
if haskey(d, k)
if haskey(plotattributes, k)
if k == :discrete_values
# add these discrete values to the axis
for vi in v
discrete_value!(axis, vi)
end
else
d[k] = v
plotattributes[k] = v
end
end
end
# replace scale aliases
if haskey(_scaleAliases, d[:scale])
d[:scale] = _scaleAliases[d[:scale]]
if haskey(_scaleAliases, plotattributes[:scale])
plotattributes[:scale] = _scaleAliases[plotattributes[:scale]]
end
axis
@@ -117,10 +117,10 @@ end
# -------------------------------------------------------------------------
Base.show(io::IO, axis::Axis) = dumpdict(axis.d, "Axis", true)
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.d, k)
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.d, v, ks...)
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
Base.show(io::IO, axis::Axis) = dumpdict(axis.plotattributes, "Axis", true)
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.plotattributes, k)
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.plotattributes, v, ks...)
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.plotattributes, k)
ignorenan_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
@@ -251,7 +251,7 @@ function get_ticks(axis::Axis)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in linspace(1, n, 15)]
Int[round(Int,i) for i in range(1, stop=n, length=15)]
else # if ticks == :all
1:n
end
@@ -265,7 +265,7 @@ function get_ticks(axis::Axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in linspace(1, length(dvals), ticks)]
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
@@ -286,6 +286,34 @@ _transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])
function get_minor_ticks(axis,ticks)
axis[:minorticks] in (nothing, false) && !axis[:minorgrid] && return nothing
ticks = ticks[1]
length(ticks) < 2 && return nothing
amin, amax = axis_limits(axis)
#Add one phantom tick either side of the ticks to ensure minor ticks extend to the axis limits
if length(ticks) > 2
ratio = (ticks[3] - ticks[2])/(ticks[2] - ticks[1])
elseif axis[:scale] == :none
ratio = 1
else
return nothing
end
first_step = ticks[2] - ticks[1]
last_step = ticks[end] - ticks[end-1]
ticks = [ticks[1] - first_step/ratio; ticks; ticks[end] + last_step*ratio]
#Default to 5 intervals between major ticks
n = typeof(axis[:minorticks]) <: Integer && axis[:minorticks] > 1 ? axis[:minorticks] : 5
minorticks = typeof(ticks[1])[]
for (i,hi) in enumerate(ticks[2:end])
lo = ticks[i]
append!(minorticks,collect(lo + (hi-lo)/n :(hi-lo)/n: hi - (hi-lo)/2n))
end
minorticks[amin .<= minorticks .<= amax]
end
# -------------------------------------------------------------------------
@@ -294,7 +322,7 @@ function reset_extrema!(sp::Subplot)
sp[Symbol(asym,:axis)][:extrema] = Extrema()
end
for series in sp.series_list
expand_extrema!(sp, series.d)
expand_extrema!(sp, series.plotattributes)
end
end
@@ -310,7 +338,7 @@ function expand_extrema!(axis::Axis, v::Number)
end
# these shouldn't impact the extrema
expand_extrema!(axis::Axis, ::Void) = axis[:extrema]
expand_extrema!(axis::Axis, ::Nothing) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
@@ -329,17 +357,17 @@ function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
end
function expand_extrema!(sp::Subplot, d::KW)
vert = isvertical(d)
function expand_extrema!(sp::Subplot, plotattributes::KW)
vert = isvertical(plotattributes)
# first expand for the data
for letter in (:x, :y, :z)
data = d[if vert
data = plotattributes[if vert
letter
else
letter == :x ? :y : letter == :y ? :x : :z
end]
if letter != :z && d[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
if letter != :z && plotattributes[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2]
data = [NaN]
end
axis = sp[Symbol(letter, "axis")]
@@ -351,30 +379,30 @@ function expand_extrema!(sp::Subplot, d::KW)
elseif eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
if !(eltype(data) <: Number)
# huh... must have been a mis-typed surface? lets swap it out
data = d[letter] = Surface(Matrix{Float64}(data.surf))
data = plotattributes[letter] = Surface(Matrix{Float64}(data.surf))
end
expand_extrema!(axis, data)
elseif data != nothing
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
d[letter], d[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
expand_extrema!(axis, d[letter])
plotattributes[letter], plotattributes[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
expand_extrema!(axis, plotattributes[letter])
end
end
# # expand for fillrange/bar_width
# fillaxis, baraxis = sp.attr[:yaxis], sp.attr[:xaxis]
# if isvertical(d)
# if isvertical(plotattributes)
# fillaxis, baraxis = baraxis, fillaxis
# end
# expand for fillrange
fr = d[:fillrange]
if fr == nothing && d[:seriestype] == :bar
fr = plotattributes[:fillrange]
if fr == nothing && plotattributes[:seriestype] == :bar
fr = 0.0
end
if fr != nothing && !all3D(d)
if fr != nothing && !all3D(plotattributes)
axis = sp.attr[vert ? :yaxis : :xaxis]
if typeof(fr) <: Tuple
for fri in fr
@@ -386,13 +414,13 @@ function expand_extrema!(sp::Subplot, d::KW)
end
# expand for bar_width
if d[:seriestype] == :bar
if plotattributes[:seriestype] == :bar
dsym = vert ? :x : :y
data = d[dsym]
data = plotattributes[dsym]
bw = d[:bar_width]
bw = plotattributes[:bar_width]
if bw == nothing
bw = d[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
bw = plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x->x>0,diff(sort(data))))
end
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw))
@@ -400,11 +428,11 @@ function expand_extrema!(sp::Subplot, d::KW)
end
# expand for heatmaps
if d[:seriestype] == :heatmap
if plotattributes[:seriestype] == :heatmap
for letter in (:x, :y)
data = d[letter]
data = plotattributes[letter]
axis = sp[Symbol(letter, "axis")]
scale = get(d, Symbol(letter, "scale"), :identity)
scale = get(plotattributes, Symbol(letter, "scale"), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
@@ -434,7 +462,7 @@ function default_should_widen(axis::Axis)
if !is_2tuple(axis[:lims])
for sp in axis.sps
for series in series_list(sp)
if series.d[:seriestype] in _widen_seriestypes
if series.plotattributes[:seriestype] in _widen_seriestypes
should_widen = true
end
end
@@ -544,12 +572,12 @@ end
# -------------------------------------------------------------------------
function pie_labels(sp::Subplot, series::Series)
d = series.d
if haskey(d,:x_discrete_indices)
dvals = sp.attr[:xaxis].d[:discrete_values]
[dvals[idx] for idx in d[:x_discrete_indices]]
plotattributes = series.plotattributes
if haskey(plotattributes,:x_discrete_indices)
dvals = sp.attr[:xaxis].plotattributes[:discrete_values]
[dvals[idx] for idx in plotattributes[:x_discrete_indices]]
else
d[:x]
plotattributes[:x]
end
end
@@ -562,12 +590,16 @@ function axis_drawing_info(sp::Subplot)
ymin, ymax = axis_limits(yaxis)
xticks = get_ticks(xaxis)
yticks = get_ticks(yaxis)
xminorticks = get_minor_ticks(xaxis,xticks)
yminorticks = get_minor_ticks(yaxis,yticks)
xaxis_segs = Segments(2)
yaxis_segs = Segments(2)
xtick_segs = Segments(2)
ytick_segs = Segments(2)
xgrid_segs = Segments(2)
ygrid_segs = Segments(2)
xminorgrid_segs = Segments(2)
yminorgrid_segs = Segments(2)
xborder_segs = Segments(2)
yborder_segs = Segments(2)
@@ -610,6 +642,28 @@ function axis_drawing_info(sp::Subplot)
xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end
end
if !(xaxis[:minorticks] in (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
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
if yaxis[:showaxis]
@@ -649,7 +703,28 @@ function axis_drawing_info(sp::Subplot)
yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end
end
if !(yaxis[:minorticks] in (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
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, xborder_segs, yborder_segs
xticks, yticks, xaxis_segs, yaxis_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs
end
+155 -45
View File
@@ -1,3 +1,4 @@
using Pkg
struct NoBackend <: AbstractBackend end
@@ -5,6 +6,8 @@ const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
const _default_backends = (:none, :gr, :plotly)
const _backendPackage = Dict{Symbol, Symbol}()
"Returns a list of supported backends"
backends() = _backends
@@ -12,9 +15,12 @@ backends() = _backends
"Returns the name of the current backend"
backend_name() = CURRENT_BACKEND.sym
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
backend_package(pkg::Symbol) = pkg in _default_backends ? :Plots : Symbol("Plots", _backendPackage[pkg])
backend_package_name(sym::Symbol) = sym in _default_backends ? :Plots : _backendPackage[sym]
macro init_backend(s)
str = lowercase(string(s))
package_str = string(s)
str = lowercase(package_str)
sym = Symbol(str)
T = Symbol(string(s) * "Backend")
esc(quote
@@ -22,24 +28,25 @@ macro init_backend(s)
export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
backend_name(::$T) = Symbol($str)
backend_package_name(pkg::$T) = backend_package_name(Symbol($str))
push!(_backends, Symbol($str))
_backendType[Symbol($str)] = $T
_backendSymbol[$T] = Symbol($str)
include("backends/" * $str * ".jl")
_backendPackage[Symbol($str)] = Symbol($package_str)
# include("backends/" * $str * ".jl")
end)
end
include("backends/web.jl")
# include("backends/web.jl")
# include("backends/supported.jl")
# ---------------------------------------------------------
function add_backend(pkg::Symbol)
info("To do a standard install of $pkg, copy and run this:\n\n")
@info("To do a standard install of $pkg, copy and run this:\n\n")
println(add_backend_string(_backend_instance(pkg)))
println()
end
add_backend_string(b::AbstractBackend) = warn("No custom install defined for $(backend_name(b))")
# don't do anything as a default
_create_backend_figure(plt::Plot) = nothing
@@ -134,31 +141,30 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
function pickDefaultBackend()
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
if env_default != ""
try
Pkg.installed(env_default) # this will error if not installed
sym = Symbol(lowercase(env_default))
if haskey(_backendType, sym)
sym = Symbol(lowercase(env_default))
if sym in _backends
if sym in _initialized_backends
return backend(sym)
else
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
join(sort(_backends), "\n\t"))
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
end
catch
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
else
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
join(sort(_backends), "\n\t"))
end
end
# the ordering/inclusion of this package list is my semi-arbitrary guess at
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
return backend(Symbol(lowercase(pkgstr)))
end
end
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
# if pkgstr in keys(Pkg.installed())
# return backend(Symbol(lowercase(pkgstr)))
# end
# end
# the default if nothing else is installed
backend(:plotly)
backend(:gr)
end
@@ -174,24 +180,6 @@ function backend()
pickDefaultBackend()
end
sym = CURRENT_BACKEND.sym
if !(sym in _initialized_backends)
# # initialize
# println("[Plots.jl] Initializing backend: ", sym)
inst = _backend_instance(sym)
try
_initialize_backend(inst)
catch err
warn("Couldn't initialize $sym. (might need to install it?)")
add_backend(sym)
rethrow(err)
end
push!(_initialized_backends, sym)
end
CURRENT_BACKEND.pkg
end
@@ -199,16 +187,29 @@ end
Set the plot backend.
"""
function backend(pkg::AbstractBackend)
CURRENT_BACKEND.sym = backend_name(pkg)
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
CURRENT_BACKEND.pkg = pkg
sym = backend_name(pkg)
if sym in _initialized_backends
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
else
# try
_initialize_backend(pkg)
push!(_initialized_backends, sym)
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
# catch
# add_backend(sym)
# end
end
backend()
end
function backend(modname::Symbol)
warn_on_deprecated_backend(modname)
CURRENT_BACKEND.sym = modname
CURRENT_BACKEND.pkg = _backend_instance(modname)
function backend(sym::Symbol)
if sym in _backends
backend(_backend_instance(sym))
else
@warn("`:$sym` is not a supported backend.")
end
backend()
end
@@ -216,7 +217,7 @@ const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
function warn_on_deprecated_backend(bsym::Symbol)
if bsym in _deprecated_backends
warn("Backend $bsym has been deprecated. It may not work as originally intended.")
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
end
end
@@ -308,3 +309,112 @@ end
# is_subplot_supported(::AbstractBackend) = false
# is_subplot_supported() = is_subplot_supported(backend())
################################################################################
# initialize the backends
function _initialize_backend(pkg::AbstractBackend)
sym = backend_package_name(pkg)
@eval Main begin
import $sym
export $sym
end
end
function add_backend_string(pkg::AbstractBackend)
sym = backend_package_name(pkg)
"""
using Pkg
Pkg.add("$sym")
"""
end
# ------------------------------------------------------------------------------
# glvisualize
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval Main begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
import FileIO, Images
export GLVisualize
import Reactive: Signal
import GLAbstraction: Style
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
end
end
# ------------------------------------------------------------------------------
# hdf5
function _initialize_backend(::HDF5Backend)
@eval Main begin
import HDF5
export HDF5
end
end
# ------------------------------------------------------------------------------
# PGFPLOTS
function add_backend_string(::PGFPlotsBackend)
"""
using Pkg
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
# ------------------------------------------------------------------------------
# plotlyjs
function add_backend_string(::PlotlyJSBackend)
"""
using Pkg
Pkg.add("PlotlyJS")
Pkg.add("Rsvg")
import Blink
Blink.AtomShell.install()
"""
end
# ------------------------------------------------------------------------------
# pyplot
function _initialize_backend(::PyPlotBackend)
@eval Main begin
import PyPlot, PyCall
import LaTeXStrings
export PyPlot
# we don't want every command to update the figure
PyPlot.ioff()
end
end
function add_backend_string(::PyPlotBackend)
"""
using Pkg
Pkg.add("PyPlot")
Pkg.add("PyCall")
Pkg.add("LaTeXStrings")
withenv("PYTHON" => "") do
Pkg.build("PyCall")
Pkg.build("PyPlot")
end
"""
end
# ------------------------------------------------------------------------------
# unicodeplots
function add_backend_string(::UnicodePlotsBackend)
"""
using Pkg
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
+180 -201
View File
@@ -9,10 +9,6 @@ TODO
* fix units in all visuals (e.g dotted lines, marker scale, surfaces)
=#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "glvisualize.jl"))
end
const _glvisualize_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -61,36 +57,11 @@ const _glvisualize_style = [:auto, :solid, :dash, :dot, :dashdot]
const _glvisualize_marker = _allMarkers
const _glvisualize_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
import FileIO, Images
export GLVisualize
import Reactive: Signal
import GLAbstraction: Style
import GLVisualize: visualize
import Plots.GL
import UnicodeFun
Plots.slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots
end
end
function add_backend_string(b::GLVisualizeBackend)
"""
if !Plots.is_installed("GLVisualize")
Pkg.add("GLVisualize")
end
"""
end
slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
GL = Plots
# ---------------------------------------------------------------------------
@@ -211,7 +182,7 @@ function gl_marker(shape::Symbol)
end
end
function extract_limits(sp, d, kw_args)
function extract_limits(sp, plotattributes, kw_args)
clims = sp[:clims]
if is_2tuple(clims)
if isfinite(clims[1]) && isfinite(clims[2])
@@ -229,70 +200,70 @@ to_vec(::Type{T}, vec::StaticArrays.StaticVector{2}) where {T <: StaticArrays.St
to_vec(::Type{T}, vecs::AbstractVector) where {T <: StaticArrays.StaticVector} = map(x-> to_vec(T, x), vecs)
function extract_marker(d, kw_args)
dim = Plots.is3d(d) ? 3 : 2
function extract_marker(plotattributes, kw_args)
dim = Plots.is3d(plotattributes) ? 3 : 2
scaling = dim == 3 ? 0.003 : 2
if haskey(d, :markershape)
shape = d[:markershape]
if haskey(plotattributes, :markershape)
shape = plotattributes[:markershape]
shape = gl_marker(shape)
if shape != :none
kw_args[:primitive] = shape
end
end
dim = isa(kw_args[:primitive], GLVisualize.Sprites) ? 2 : 3
if haskey(d, :markersize)
msize = d[:markersize]
if haskey(plotattributes, :markersize)
msize = plotattributes[:markersize]
kw_args[:scale] = to_vec(GeometryTypes.Vec{dim, Float32}, msize .* scaling)
end
if haskey(d, :offset)
kw_args[:offset] = d[:offset]
if haskey(plotattributes, :offset)
kw_args[:offset] = plotattributes[:offset]
end
# get the color
key = :markercolor
haskey(d, key) || return
c = gl_color(d[key])
if isa(c, AbstractVector) && d[:marker_z] != nothing
extract_colornorm(d, kw_args)
haskey(plotattributes, key) || return
c = gl_color(plotattributes[key])
if isa(c, AbstractVector) && plotattributes[:marker_z] != nothing
extract_colornorm(plotattributes, kw_args)
kw_args[:color] = nothing
kw_args[:color_map] = c
kw_args[:intensity] = convert(Vector{Float32}, d[:marker_z])
kw_args[:intensity] = convert(Vector{Float32}, plotattributes[:marker_z])
else
kw_args[:color] = c
end
key = :markerstrokecolor
haskey(d, key) || return
c = gl_color(d[key])
haskey(plotattributes, key) || return
c = gl_color(plotattributes[key])
if c != nothing
if !(isa(c, Colorant) || (isa(c, Vector) && eltype(c) <: Colorant))
error("Stroke Color not supported: $c")
end
kw_args[:stroke_color] = c
kw_args[:stroke_width] = Float32(d[:markerstrokewidth])
kw_args[:stroke_width] = Float32(plotattributes[:markerstrokewidth])
end
end
function _extract_surface(d::Plots.Surface)
d.surf
function _extract_surface(plotattributes::Plots.Surface)
plotattributes.surf
end
function _extract_surface(d::AbstractArray)
d
function _extract_surface(plotattributes::AbstractArray)
plotattributes
end
# TODO when to transpose??
function extract_surface(d)
map(_extract_surface, (d[:x], d[:y], d[:z]))
function extract_surface(plotattributes)
map(_extract_surface, (plotattributes[:x], plotattributes[:y], plotattributes[:z]))
end
function topoints(::Type{P}, array) where P
[P(x) for x in zip(array...)]
end
function extract_points(d)
dim = is3d(d) ? 3 : 2
array = if d[:seriestype] == :straightline
straightline_data(d)
elseif d[:seriestype] == :shape
shape_data(d)
function extract_points(plotattributes)
dim = is3d(plotattributes) ? 3 : 2
array = if plotattributes[:seriestype] == :straightline
straightline_data(plotattributes)
elseif plotattributes[:seriestype] == :shape
shape_data(plotattributes)
else
(d[:x], d[:y], d[:z])[1:dim]
(plotattributes[:x], plotattributes[:y], plotattributes[:z])[1:dim]
end
topoints(Point{dim, Float32}, array)
end
@@ -304,50 +275,50 @@ function make_gradient(grad::ColorGradient)
end
make_gradient(c) = make_gradient(cgrad())
function extract_any_color(d, kw_args)
if d[:marker_z] == nothing
c = scalar_color(d, :fill)
extract_c(d, kw_args, :fill)
function extract_any_color(plotattributes, kw_args)
if plotattributes[:marker_z] == nothing
c = scalar_color(plotattributes, :fill)
extract_c(plotattributes, kw_args, :fill)
if isa(c, Colorant)
kw_args[:color] = c
else
kw_args[:color] = nothing
kw_args[:color_map] = make_gradient(c)
clims = d[:subplot][:clims]
clims = plotattributes[:subplot][:clims]
if Plots.is_2tuple(clims)
if isfinite(clims[1]) && isfinite(clims[2])
kw_args[:color_norm] = Vec2f0(clims)
end
elseif clims == :auto
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(plotattributes[:y]))
end
end
else
kw_args[:color] = nothing
clims = d[:subplot][:clims]
clims = plotattributes[:subplot][:clims]
if Plots.is_2tuple(clims)
if isfinite(clims[1]) && isfinite(clims[2])
kw_args[:color_norm] = Vec2f0(clims)
end
elseif clims == :auto
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(d[:y]))
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(plotattributes[:y]))
else
error("Unsupported limits: $clims")
end
kw_args[:intensity] = convert(Vector{Float32}, d[:marker_z])
kw_args[:color_map] = gl_color_map(d, :marker)
kw_args[:intensity] = convert(Vector{Float32}, plotattributes[:marker_z])
kw_args[:color_map] = gl_color_map(plotattributes, :marker)
end
end
function extract_stroke(d, kw_args)
extract_c(d, kw_args, :line)
if haskey(d, :linewidth)
kw_args[:thickness] = Float32(d[:linewidth] * 3)
function extract_stroke(plotattributes, kw_args)
extract_c(plotattributes, kw_args, :line)
if haskey(plotattributes, :linewidth)
kw_args[:thickness] = Float32(plotattributes[:linewidth] * 3)
end
end
function extract_color(d, sym)
d[Symbol("$(sym)color")]
function extract_color(plotattributes, sym)
plotattributes[Symbol("$(sym)color")]
end
gl_color(c::PlotUtils.ColorGradient) = c.colors
@@ -364,12 +335,12 @@ function gl_color(c, a)
c = convertColor(c, a)
RGBA{Float32}(c)
end
function scalar_color(d, sym)
gl_color(extract_color(d, sym))
function scalar_color(plotattributes, sym)
gl_color(extract_color(plotattributes, sym))
end
function gl_color_map(d, sym)
colors = extract_color(d, sym)
function gl_color_map(plotattributes, sym)
colors = extract_color(plotattributes, sym)
_gl_color_map(colors)
end
function _gl_color_map(colors::PlotUtils.ColorGradient)
@@ -397,7 +368,7 @@ function gappy(x, ps)
return last(ps) - x
end
function ticks(points, resolution)
Float16[gappy(x, points) for x = linspace(first(points),last(points), resolution)]
Float16[gappy(x, points) for x = range(first(points), stop=last(points), length=resolution)]
end
@@ -406,10 +377,10 @@ function insert_pattern!(points, kw_args)
kw_args[:pattern] = tex
kw_args[:pattern_length] = Float32(last(points))
end
function extract_linestyle(d, kw_args)
haskey(d, :linestyle) || return
ls = d[:linestyle]
lw = d[:linewidth]
function extract_linestyle(plotattributes, kw_args)
haskey(plotattributes, :linestyle) || return
ls = plotattributes[:linestyle]
lw = plotattributes[:linewidth]
kw_args[:thickness] = Float32(lw)
if ls == :dash
points = [0.0, lw, 2lw, 3lw, 4lw]
@@ -429,7 +400,7 @@ function extract_linestyle(d, kw_args)
points = [0.0, dtick, dtick+dgap, dtick+dgap+ptick, dtick+dgap+ptick+pgap, dtick+dgap+ptick+pgap+ptick, dtick+dgap+ptick+pgap+ptick+pgap]
insert_pattern!(points, kw_args)
end
extract_c(d, kw_args, :line)
extract_c(plotattributes, kw_args, :line)
nothing
end
@@ -496,8 +467,8 @@ function hover(to_hover, to_display, window)
nothing
end
function extract_extrema(d, kw_args)
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
function extract_extrema(plotattributes, kw_args)
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
nothing
end
@@ -508,50 +479,50 @@ function extract_font(font, kw_args)
kw_args[:color] = gl_color(font.color)
end
function extract_colornorm(d, kw_args)
clims = d[:subplot][:clims]
function extract_colornorm(plotattributes, kw_args)
clims = plotattributes[:subplot][:clims]
if Plots.is_2tuple(clims)
if isfinite(clims[1]) && isfinite(clims[2])
kw_args[:color_norm] = Vec2f0(clims)
end
elseif clims == :auto
z = if haskey(d, :marker_z) && d[:marker_z] != nothing
d[:marker_z]
elseif haskey(d, :line_z) && d[:line_z] != nothing
d[:line_z]
elseif isa(d[:z], Plots.Surface)
d[:z].surf
z = if haskey(plotattributes, :marker_z) && plotattributes[:marker_z] != nothing
plotattributes[:marker_z]
elseif haskey(plotattributes, :line_z) && plotattributes[:line_z] != nothing
plotattributes[:line_z]
elseif isa(plotattributes[:z], Plots.Surface)
plotattributes[:z].surf
else
d[:y]
plotattributes[:y]
end
kw_args[:color_norm] = Vec2f0(ignorenan_extrema(z))
kw_args[:intensity] = map(Float32, collect(z))
end
end
function extract_gradient(d, kw_args, sym)
function extract_gradient(plotattributes, kw_args, sym)
key = Symbol("$(sym)color")
haskey(d, key) || return
c = make_gradient(d[key])
haskey(plotattributes, key) || return
c = make_gradient(plotattributes[key])
kw_args[:color] = nothing
extract_colornorm(d, kw_args)
extract_colornorm(plotattributes, kw_args)
kw_args[:color_map] = c
return
end
function extract_c(d, kw_args, sym)
function extract_c(plotattributes, kw_args, sym)
key = Symbol("$(sym)color")
haskey(d, key) || return
c = gl_color(d[key])
haskey(plotattributes, key) || return
c = gl_color(plotattributes[key])
kw_args[:color] = nothing
kw_args[:color_map] = nothing
kw_args[:color_norm] = nothing
if (
isa(c, AbstractVector) &&
((haskey(d, :marker_z) && d[:marker_z] != nothing) ||
(haskey(d, :line_z) && d[:line_z] != nothing))
((haskey(plotattributes, :marker_z) && plotattributes[:marker_z] != nothing) ||
(haskey(plotattributes, :line_z) && plotattributes[:line_z] != nothing))
)
extract_colornorm(d, kw_args)
extract_colornorm(plotattributes, kw_args)
kw_args[:color_map] = c
else
kw_args[:color] = c
@@ -559,16 +530,16 @@ function extract_c(d, kw_args, sym)
return
end
function extract_stroke(d, kw_args, sym)
function extract_stroke(plotattributes, kw_args, sym)
key = Symbol("$(sym)strokecolor")
haskey(d, key) || return
c = gl_color(d[key])
haskey(plotattributes, key) || return
c = gl_color(plotattributes[key])
if c != nothing
if !isa(c, Colorant)
error("Stroke Color not supported: $c")
end
kw_args[:stroke_color] = c
kw_args[:stroke_width] = Float32(d[Symbol("$(sym)strokewidth")]) * 2
kw_args[:stroke_width] = Float32(plotattributes[Symbol("$(sym)strokewidth")]) * 2
end
return
end
@@ -580,12 +551,12 @@ function draw_grid_lines(sp, grid_segs, thickness, style, model, color)
kw_args = Dict{Symbol, Any}(
:model => model
)
d = Dict(
plotattributes = Dict(
:linestyle => style,
:linewidth => Float32(thickness),
:linecolor => color
)
Plots.extract_linestyle(d, kw_args)
Plots.extract_linestyle(plotattributes, kw_args)
GL.gl_lines(map(Point2f0, grid_segs.pts), kw_args)
end
@@ -696,7 +667,7 @@ function text_model(font, pivot)
end
end
function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, area)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs = Plots.axis_drawing_info(sp)
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgc = Colors.color(Plots.gl_color(xaxis[:foreground_color_grid]))
@@ -710,6 +681,14 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
grid = draw_grid_lines(sp, ygrid_segs, yaxis[:gridlinewidth], yaxis[:gridstyle], model, RGBA(ygc, yaxis[:gridalpha]))
push!(axis_vis, grid)
end
if xaxis[:minorgrid]
minorgrid = draw_minorgrid_lines(sp, xminorgrid_segs, xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], model, RGBA(xgc, xaxis[:minorgridalpha]))
push!(axis_vis, minorgrid)
end
if yaxis[:minorgrid]
minorgrid = draw_minorgrid_lines(sp, yminorgrid_segs, yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], model, RGBA(ygc, yaxis[:minorgridalpha]))
push!(axis_vis, minorgrid)
end
xac = Colors.color(Plots.gl_color(xaxis[:foreground_color_axis]))
yac = Colors.color(Plots.gl_color(yaxis[:foreground_color_axis]))
@@ -829,10 +808,10 @@ function gl_draw_axes_3d(sp, model)
)
end
function gl_bar(d, kw_args)
x, y = d[:x], d[:y]
function gl_bar(plotattributes, kw_args)
x, y = plotattributes[:x], plotattributes[:y]
nx, ny = length(x), length(y)
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=x]
x = if nx == ny
cv
@@ -853,18 +832,18 @@ function gl_bar(d, kw_args)
end
# make fillto a vector... default fills to 0
fillto = d[:fillrange]
fillto = plotattributes[:fillrange]
if fillto == nothing
fillto = 0
end
# create the bar shapes by adding x/y segments
positions, scales = Array{Point2f0}(ny), Array{Vec2f0}(ny)
positions, scales = Array{Point2f0}(undef, ny), Array{Vec2f0}(undef, ny)
m = Reactive.value(kw_args[:model])
sx, sy = m[1,1], m[2,2]
for i=1:ny
center = x[i]
hwi = abs(_cycle(hw,i)); yi = y[i]; fi = _cycle(fillto,i)
if Plots.isvertical(d)
if Plots.isvertical(plotattributes)
sz = (hwi*sx, yi*sy)
else
sz = (yi*sx, hwi*2*sy)
@@ -883,10 +862,10 @@ const _box_halfwidth = 0.4
notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
function gl_boxplot(d, kw_args)
function gl_boxplot(plotattributes, kw_args)
kwbox = copy(kw_args)
range = 1.5; notch = false
x, y = d[:x], d[:y]
x, y = plotattributes[:x], plotattributes[:y]
glabels = sort(collect(unique(x)))
warning = false
outliers_x, outliers_y = zeros(0), zeros(0)
@@ -901,18 +880,18 @@ function gl_boxplot(d, kw_args)
# filter y
values = y[filter(i -> _cycle(x,i) == glabel, 1:length(y))]
# compute quantiles
q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5))
q1,q2,q3,q4,q5 = quantile(values, range(0, stop=1, length=5))
# notch
n = Plots.notch_width(q2, q4, length(values))
# warn on inverted notches?
if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) )
warn("Boxplot's notch went outside hinges. Set notch to false.")
@warn("Boxplot's notch went outside hinges. Set notch to false.")
warning = true # Show the warning only one time
end
# make the shape
center = Plots.discrete_value!(d[:subplot][:xaxis], glabel)[1]
hw = d[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(d[:bar_width], i)
center = Plots.discrete_value!(plotattributes[:subplot][:xaxis], glabel)[1]
hw = plotattributes[:bar_width] == nothing ? Plots._box_halfwidth*2 : _cycle(plotattributes[:bar_width], i)
l, m, r = center - hw/2, center, center + hw/2
# internal nodes for notches
@@ -951,17 +930,17 @@ function gl_boxplot(d, kw_args)
:model => kw_args[:model],
:offset => Vec2f0(0),
)
extract_marker(d, kw_args)
extract_marker(plotattributes, kw_args)
outlier_kw = Dict(
:model => kw_args[:model],
:color => scalar_color(d, :fill),
:stroke_width => Float32(d[:markerstrokewidth]),
:stroke_color => scalar_color(d, :markerstroke),
:color => scalar_color(plotattributes, :fill),
:stroke_width => Float32(plotattributes[:markerstrokewidth]),
:stroke_color => scalar_color(plotattributes, :markerstroke),
)
lines_kw = Dict(
:model => kw_args[:model],
:stroke_width => d[:linewidth],
:stroke_color => scalar_color(d, :fill),
:stroke_width => plotattributes[:linewidth],
:stroke_color => scalar_color(plotattributes, :fill),
)
vis1 = GLVisualize.visualize((GLVisualize.RECTANGLE, box_pos), Style(:default), kwbox)
vis2 = GLVisualize.visualize((GLVisualize.CIRCLE, outliers), Style(:default), outlier_kw)
@@ -1005,11 +984,11 @@ end
function scale_for_annotations!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
if anns != nothing && !isnull(anns.baseshape)
if anns != nothing && anns.baseshape != nothing
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw, msh = anns.scalefactor
offsets = Array{Vec2f0}(length(anns.strs))
offsets = Array{Vec2f0}(undef, length(anns.strs))
series[:markersize] = map(1:length(anns.strs)) do i
str = _cycle(anns.strs, i)
# get the width and height of the string (in mm)
@@ -1087,8 +1066,8 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
end
for series in Plots.series_list(sp)
d = series.d
st = d[:seriestype]; kw_args = KW() # exctract kw
plotattributes = series.plotattributes
st = plotattributes[:seriestype]; kw_args = KW() # exctract kw
kw_args[:model] = model_m # add transformation
if !_3d # 3D is treated differently, since we need boundingboxes for camera
@@ -1096,76 +1075,76 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
end
scale_for_annotations!(series)
if st in (:surface, :wireframe)
x, y, z = extract_surface(d)
extract_gradient(d, kw_args, :fill)
z = Plots.transpose_z(d, z, false)
x, y, z = extract_surface(plotattributes)
extract_gradient(plotattributes, kw_args, :fill)
z = Plots.transpose_z(plotattributes, z, false)
if isa(x, AbstractMatrix) && isa(y, AbstractMatrix)
x, y = Plots.transpose_z(d, x, false), Plots.transpose_z(d, y, false)
x, y = Plots.transpose_z(plotattributes, x, false), Plots.transpose_z(plotattributes, y, false)
end
if st == :wireframe
kw_args[:wireframe] = true
kw_args[:stroke_color] = d[:linecolor]
kw_args[:stroke_width] = Float32(d[:linewidth]/100f0)
kw_args[:stroke_color] = plotattributes[:linecolor]
kw_args[:stroke_width] = Float32(plotattributes[:linewidth]/100f0)
end
vis = GL.gl_surface(x, y, z, kw_args)
elseif (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
elseif (st in (:path, :path3d, :straightline)) && plotattributes[:linewidth] > 0
kw = copy(kw_args)
points = Plots.extract_points(d)
extract_linestyle(d, kw)
points = Plots.extract_points(plotattributes)
extract_linestyle(plotattributes, kw)
vis = GL.gl_lines(points, kw)
if d[:markershape] != :none
if plotattributes[:markershape] != :none
kw = copy(kw_args)
extract_stroke(d, kw)
extract_marker(d, kw)
extract_stroke(plotattributes, kw)
extract_marker(plotattributes, kw)
vis2 = GL.gl_scatter(copy(points), kw)
vis = [vis; vis2]
end
if d[:fillrange] != nothing
if plotattributes[:fillrange] != nothing
kw = copy(kw_args)
fr = d[:fillrange]
ps = if all(x-> x >= 0, diff(d[:x])) # if is monotonic
fr = plotattributes[:fillrange]
ps = if all(x-> x >= 0, diff(plotattributes[:x])) # if is monotonic
vcat(points, Point2f0[(points[i][1], _cycle(fr, i)) for i=length(points):-1:1])
else
points
end
extract_c(d, kw, :fill)
extract_c(plotattributes, kw, :fill)
vis = [GL.gl_poly(ps, kw), vis]
end
elseif st in (:scatter, :scatter3d) #|| d[:markershape] != :none
extract_marker(d, kw_args)
points = extract_points(d)
elseif st in (:scatter, :scatter3d) #|| plotattributes[:markershape] != :none
extract_marker(plotattributes, kw_args)
points = extract_points(plotattributes)
vis = GL.gl_scatter(points, kw_args)
elseif st == :shape
extract_c(d, kw_args, :fill)
vis = GL.gl_shape(d, kw_args)
extract_c(plotattributes, kw_args, :fill)
vis = GL.gl_shape(plotattributes, kw_args)
elseif st == :contour
x,y,z = extract_surface(d)
z = transpose_z(d, z, false)
extract_extrema(d, kw_args)
extract_gradient(d, kw_args, :fill)
kw_args[:fillrange] = d[:fillrange]
kw_args[:levels] = d[:levels]
x,y,z = extract_surface(plotattributes)
z = transpose_z(plotattributes, z, false)
extract_extrema(plotattributes, kw_args)
extract_gradient(plotattributes, kw_args, :fill)
kw_args[:fillrange] = plotattributes[:fillrange]
kw_args[:levels] = plotattributes[:levels]
vis = GL.gl_contour(x,y,z, kw_args)
elseif st == :heatmap
x,y,z = extract_surface(d)
extract_gradient(d, kw_args, :fill)
extract_extrema(d, kw_args)
extract_limits(sp, d, kw_args)
x,y,z = extract_surface(plotattributes)
extract_gradient(plotattributes, kw_args, :fill)
extract_extrema(plotattributes, kw_args)
extract_limits(sp, plotattributes, kw_args)
vis = GL.gl_heatmap(x,y,z, kw_args)
elseif st == :bar
extract_c(d, kw_args, :fill)
extract_stroke(d, kw_args, :marker)
vis = gl_bar(d, kw_args)
extract_c(plotattributes, kw_args, :fill)
extract_stroke(plotattributes, kw_args, :marker)
vis = gl_bar(plotattributes, kw_args)
elseif st == :image
extract_extrema(d, kw_args)
vis = GL.gl_image(d[:z].surf, kw_args)
extract_extrema(plotattributes, kw_args)
vis = GL.gl_image(plotattributes[:z].surf, kw_args)
elseif st == :boxplot
extract_c(d, kw_args, :fill)
vis = gl_boxplot(d, kw_args)
extract_c(plotattributes, kw_args, :fill)
vis = gl_boxplot(plotattributes, kw_args)
elseif st == :volume
volume = d[:y]
_d = copy(d)
volume = plotattributes[:y]
_d = copy(plotattributes)
_d[:y] = 0:1
_d[:x] = 0:1
kw_args = KW()
@@ -1178,15 +1157,15 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
isa(vis, Array) && isempty(vis) && continue # nothing to see here
GLVisualize._view(vis, sp_screen, camera=:perspective)
if haskey(d, :hover) && !(d[:hover] in (false, :none, nothing))
hover(vis, d[:hover], sp_screen)
if haskey(plotattributes, :hover) && !(plotattributes[:hover] in (false, :none, nothing))
hover(vis, plotattributes[:hover], sp_screen)
end
if isdefined(:GLPlot) && isdefined(Main.GLPlot, :(register_plot!))
del_signal = Main.GLPlot.register_plot!(vis, sp_screen, create_gizmo=false)
append!(_glplot_deletes, del_signal)
end
anns = series[:series_annotations]
for (x, y, str, font) in EachAnn(anns, d[:x], d[:y])
for (x, y, str, font) in EachAnn(anns, plotattributes[:x], plotattributes[:y])
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
x, y = Reactive.value(model_m) * GeometryTypes.Vec{4, Float32}(x, y, 0, 1)
extract_font(font, txt_args)
@@ -1262,10 +1241,10 @@ function gl_lines(points, kw_args)
return result
end
function gl_shape(d, kw_args)
points = Plots.extract_points(d)
function gl_shape(plotattributes, kw_args)
points = Plots.extract_points(plotattributes)
result = []
for rng in iter_segments(d[:x], d[:y])
for rng in iter_segments(plotattributes[:x], plotattributes[:y])
ps = points[rng]
meshes = gl_poly(ps, kw_args)
append!(result, meshes)
@@ -1321,7 +1300,7 @@ function gl_poly(points, kw_args)
if !isempty(GeometryTypes.faces(mesh)) # check if polygonation has any faces
push!(result, GLVisualize.visualize(mesh, Style(:default), kw_args))
else
warn("Couldn't draw the polygon: $points")
@warn("Couldn't draw the polygon: $points")
end
end
result
@@ -1331,7 +1310,7 @@ end
function gl_surface(x,y,z, kw_args)
if isa(x, Range) && isa(y, Range)
if isa(x, AbstractRange) && isa(y, AbstractRange)
main = z
kw_args[:ranges] = (x, y)
else
@@ -1347,7 +1326,7 @@ function gl_surface(x,y,z, kw_args)
if get(kw_args, :wireframe, false)
points = map(Point3f0, zip(vec(x), vec(y), vec(z)))
faces = Cuint[]
idx = (i,j) -> sub2ind(size(z), i, j) - 1
idx = (i,j) -> CartesianIndices(size(z), i, j) - 1
for i=1:size(z,1), j=1:size(z,2)
i < size(z,1) && push!(faces, idx(i, j), idx(i+1, j))
@@ -1419,10 +1398,10 @@ end
"""
Ugh, so much special casing (╯°□°)╯︵ ┻━┻
"""
function label_scatter(d, w, ho)
function label_scatter(plotattributes, w, ho)
kw = KW()
extract_stroke(d, kw)
extract_marker(d, kw)
extract_stroke(plotattributes, kw)
extract_marker(plotattributes, kw)
kw[:scale] = Vec2f0(w/2)
kw[:offset] = Vec2f0(-w/4)
if haskey(kw, :intensity)
@@ -1463,21 +1442,21 @@ function make_label(sp, series, i)
GL = Plots
w, gap, ho = 20f0, 5f0, 5
result = []
d = series.d
st = d[:seriestype]
plotattributes = series.plotattributes
st = plotattributes[:seriestype]
kw_args = KW()
if (st in (:path, :path3d, :straightline)) && d[:linewidth] > 0
if (st in (:path, :path3d, :straightline)) && plotattributes[:linewidth] > 0
points = Point2f0[(0, ho), (w, ho)]
kw = KW()
extract_linestyle(d, kw)
extract_linestyle(plotattributes, kw)
append!(result, GL.gl_lines(points, kw))
if d[:markershape] != :none
push!(result, label_scatter(d, w, ho))
if plotattributes[:markershape] != :none
push!(result, label_scatter(plotattributes, w, ho))
end
elseif st in (:scatter, :scatter3d) #|| d[:markershape] != :none
push!(result, label_scatter(d, w, ho))
elseif st in (:scatter, :scatter3d) #|| plotattributes[:markershape] != :none
push!(result, label_scatter(plotattributes, w, ho))
else
extract_c(d, kw_args, :fill)
extract_c(plotattributes, kw_args, :fill)
if isa(kw_args[:color], AbstractVector)
kw_args[:color] = first(kw_args[:color])
end
+80 -64
View File
@@ -3,10 +3,6 @@
# significant contributions by @jheinen
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "gr.jl"))
end
const _gr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -22,6 +18,7 @@ const _gr_attr = merge_with_base_supported([
:layout,
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:match_dimensions,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
@@ -31,7 +28,7 @@ const _gr_attr = merge_with_base_supported([
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:legend, :legendtitle, :colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
@@ -65,12 +62,8 @@ function add_backend_string(::GRBackend)
"""
end
function _initialize_backend(::GRBackend; kw...)
@eval begin
import GR
export GR
end
end
import GR
export GR
# --------------------------------------------------------------------------------------
@@ -144,7 +137,7 @@ gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(_cycle(c,1)))
gr_set_markercolor(c) = GR.setmarkercolorind(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))
function gr_set_transparency(::Void) end
function gr_set_transparency(::Nothing) end
# --------------------------------------------------------------------------------------
@@ -196,7 +189,7 @@ gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
function gr_inqtext(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.inqmathtex(x, y, s[2:end-1])
elseif search(s, '\\') != 0 || contains(s, "10^{")
elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s)
GR.inqtextext(x, y, s)
else
GR.inqtext(x, y, s)
@@ -208,7 +201,7 @@ gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
function gr_text(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.mathtex(x, y, s[2:end-1])
elseif search(s, '\\') != 0 || contains(s, "10^{")
elseif findfirst(isequal('\\'), s) != nothing || occursin("10^{", s)
GR.textext(x, y, s)
else
GR.text(x, y, s)
@@ -317,7 +310,7 @@ function normalize_zvals(zv::AVec, clims::NTuple{2, <:Real})
if vmin == vmax
zeros(length(zv))
else
clamp.((zv - vmin) ./ (vmax - vmin), 0, 1)
clamp.((zv .- vmin) ./ (vmax .- vmin), 0, 1)
end
end
@@ -346,7 +339,11 @@ end
# draw the markers, one at a time
function gr_draw_markers(series::Series, x, y, msize, mz)
function gr_draw_markers(series::Series, x, y, clims, msize = series[:markersize])
isempty(x) && return
GR.setfillintstyle(GR.INTSTYLE_SOLID)
shapes = series[:markershape]
if shapes != :none
for i=1:length(x)
@@ -363,7 +360,7 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
# draw the shape - don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
cfunc(get_markercolor(series, i))
cfunc(get_markercolor(series, clims, i))
gr_set_transparency(get_markeralpha(series, i))
gr_draw_marker(x[i], y[i], msi, shape)
end
@@ -371,13 +368,6 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
end
end
function gr_draw_markers(series::Series, x, y, clims)
isempty(x) && return
mz = normalize_zvals(series[:marker_z], clims)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_draw_markers(series, x, y, series[:markersize], mz)
end
# ---------------------------------------------------------
function gr_set_line(lw, style, c) #, a)
@@ -429,6 +419,8 @@ const viewport_plotarea = zeros(4)
# the size of the current plot in pixels
const gr_plot_size = [600.0, 400.0]
const gr_colorbar_ratio = 0.1
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
viewport = zeros(4)
viewport[1] = viewport_canvas[2] * (left(bb) / w)
@@ -444,7 +436,7 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
end
if hascolorbar(sp)
viewport[2] -= 0.1
viewport[2] -= gr_colorbar_ratio
end
viewport
end
@@ -485,12 +477,19 @@ function gr_colorbar(sp::Subplot, clims)
xmin, xmax = gr_xy_axislims(sp)[1:2]
gr_set_viewport_cmap(sp)
l = zeros(Int32, 1, 256)
l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)]
l[1,:] = Int[round(Int, _i) for _i in range(1000, stop=1255, length=256)]
GR.setscale(0)
GR.setwindow(xmin, xmax, clims[1], clims[2])
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
ztick = 0.5 * GR.tick(clims[1], clims[2])
GR.axes(0, ztick, xmax, clims[1], 0, 1, 0.005)
gr_set_font(guidefont(sp[:yaxis]))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(-1, 0)
gr_text(viewport_plotarea[2] + gr_colorbar_ratio,
gr_view_ycenter(), sp[:colorbar_title])
gr_set_viewport_plotarea()
end
@@ -502,16 +501,16 @@ function gr_legend_pos(s::Symbol,w,h)
if str == "best"
str = "topright"
end
if contains(str,"right")
if occursin("right", str)
xpos = viewport_plotarea[2] - 0.05 - w
elseif contains(str,"left")
elseif occursin("left", str)
xpos = viewport_plotarea[1] + 0.11
else
xpos = (viewport_plotarea[2]-viewport_plotarea[1])/2 - w/2 +.04
end
if contains(str,"top")
if occursin("top", str)
ypos = viewport_plotarea[4] - 0.06
elseif contains(str,"bottom")
elseif occursin("bottom", str)
ypos = viewport_plotarea[3] + h + 0.06
else
ypos = (viewport_plotarea[4]-viewport_plotarea[3])/2 + h/2
@@ -531,7 +530,7 @@ const _gr_gradient_alpha = ones(256)
function gr_set_gradient(c)
grad = isa(c, ColorGradient) ? c : cgrad()
for (i,z) in enumerate(linspace(0, 1, 256))
for (i,z) in enumerate(range(0, stop=1, length=256))
c = grad[z]
GR.setcolorrep(999+i, red(c), green(c), blue(c))
_gr_gradient_alpha[i] = alpha(c)
@@ -624,7 +623,7 @@ end
function _update_min_padding!(sp::Subplot{GRBackend})
dpi = sp.plt[:thickness_scaling]
if !haskey(ENV, "GKSwstype")
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
if isijulia()
ENV["GKSwstype"] = "svg"
end
end
@@ -665,6 +664,9 @@ function _update_min_padding!(sp::Subplot{GRBackend})
if sp[:yaxis][:guide] != ""
leftpad += 4mm
end
if sp[:colorbar_title] != ""
rightpad += 4mm
end
sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad])
end
@@ -718,7 +720,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
for ax in (sp[:xaxis], sp[:yaxis])
v = series[ax[:letter]]
if diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
warn("GR: heatmap only supported with equally spaced data.")
@warn("GR: heatmap only supported with equally spaced data.")
end
end
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
@@ -818,7 +820,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setwindow(xmin, xmax, ymin, ymax)
end
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
xticks, yticks, xspine_segs, yspine_segs, xtick_segs, ytick_segs, xgrid_segs, ygrid_segs, xminorgrid_segs, yminorgrid_segs, xborder_segs, yborder_segs = axis_drawing_info(sp)
# @show xticks yticks #spine_segs grid_segs
# draw the grid lines
@@ -834,6 +836,18 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_set_transparency(yaxis[:gridalpha])
gr_polyline(coords(ygrid_segs)...)
end
if xaxis[:minorgrid]
# gr_set_linecolor(sp[:foreground_color_grid])
# GR.grid(xtick, ytick, 0, 0, majorx, majory)
gr_set_line(xaxis[:minorgridlinewidth], xaxis[:minorgridstyle], xaxis[:foreground_color_minor_grid])
gr_set_transparency(xaxis[:minorgridalpha])
gr_polyline(coords(xminorgrid_segs)...)
end
if yaxis[:minorgrid]
gr_set_line(yaxis[:minorgridlinewidth], yaxis[:minorgridstyle], yaxis[:foreground_color_minor_grid])
gr_set_transparency(yaxis[:minorgridalpha])
gr_polyline(coords(yminorgrid_segs)...)
end
gr_set_transparency(1.0)
# axis lines
@@ -1022,7 +1036,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
for (i, rng) in enumerate(segments)
gr_set_fillcolor(get_fillcolor(series, i))
gr_set_fillcolor(get_fillcolor(series, clims, i))
fx = _cycle(x, vcat(rng, reverse(rng)))
fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
gr_set_transparency(get_fillalpha(series, i))
@@ -1033,7 +1047,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# draw the line(s)
if st in (:path, :straightline)
for (i, rng) in enumerate(segments)
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i)) #, series[:linealpha])
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i)) #, series[:linealpha])
gr_set_transparency(get_linealpha(series, i))
arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
gr_polyline(x[rng], y[rng]; arrowside = arrowside)
@@ -1051,7 +1065,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if typeof(series[:levels]) <: AbstractArray
h = series[:levels]
else
h = series[:levels] > 1 ? linspace(zmin, zmax, series[:levels]) : [(zmin + zmax) / 2]
h = series[:levels] > 1 ? range(zmin, stop=zmax, length=series[:levels]) : [(zmin + zmax) / 2]
end
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
@@ -1069,7 +1083,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if cmap
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_viewport_cmap(sp)
l = (length(h) > 1) ? round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255) : Int32[1000, 1255]
l = (length(h) > 1) ? round.(Int32, 1000 .+ (h .- ignorenan_minimum(h)) ./ (ignorenan_maximum(h) - ignorenan_minimum(h)) .* 255) : Int32[1000, 1255]
GR.setwindow(xmin, xmax, zmin, zmax)
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
ztick = 0.5 * GR.tick(zmin, zmax)
@@ -1099,10 +1113,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setspace(zmin, zmax, 0, 90)
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z]
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
round(Int, blue(c) * 255) << 16 +
round(Int, green(c) * 255) << 8 +
round(Int, red(c) * 255) ), colors)
rgba = map(c -> UInt32( round(UInt, alpha(c) * 255) << 24 +
round(UInt, blue(c) * 255) << 16 +
round(UInt, green(c) * 255) << 8 +
round(UInt, red(c) * 255) ), colors)
w, h = length(x), length(y)
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
@@ -1113,7 +1127,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
lz = series[:line_z]
segments = iter_segments(series)
for (i, rng) in enumerate(segments)
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i)) #, series[:linealpha])
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i)) #, series[:linealpha])
gr_set_transparency(get_linealpha(series, i))
GR.polyline3d(x[rng], y[rng], z[rng])
end
@@ -1185,12 +1199,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
xseg, yseg = x[rng], y[rng]
# draw the interior
gr_set_fill(get_fillcolor(series, i))
gr_set_fill(get_fillcolor(series, clims, i))
gr_set_transparency(get_fillalpha(series, i))
GR.fillarea(xseg, yseg)
# draw the shapes
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, i))
gr_set_line(get_linewidth(series, i), get_linestyle(series, i), get_linecolor(series, clims, i))
gr_set_transparency(get_linealpha(series, i))
GR.polyline(xseg, yseg)
end
@@ -1206,12 +1220,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
if eltype(z) <: Colors.AbstractGray
grey = round.(UInt8, float(z) * 255)
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
rgba = map(c -> UInt32( 0xff000000 + UInt(c)<<16 + UInt(c)<<8 + UInt(c) ), grey)
else
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
round(Int, blue(c) * 255) << 16 +
round(Int, green(c) * 255) << 8 +
round(Int, red(c) * 255) ), z)
rgba = map(c -> UInt32( round(UInt, alpha(c) * 255) << 24 +
round(UInt, blue(c) * 255) << 16 +
round(UInt, green(c) * 255) << 8 +
round(UInt, red(c) * 255) ), z)
end
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
end
@@ -1223,16 +1237,18 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_text(GR.wctondc(xi, yi)..., str)
end
# draw the colorbar
if cmap && st != :contour # special colorbar with steps is drawn for contours
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_transparency(1)
gr_colorbar(sp, clims)
end
GR.restorestate()
end
# draw the colorbar
GR.savestate()
# special colorbar with steps is drawn for contours
if cmap && any(series[:seriestype] != :contour for series in series_list(sp))
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_transparency(1)
gr_colorbar(sp, clims)
end
GR.restorestate()
# add the legend
if sp[:legend] != :none
@@ -1280,10 +1296,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
for series in series_list(sp)
should_add_to_legend(series) || continue
st = series[:seriestype]
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series)) #, series[:linealpha])
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series, clims)) #, series[:linealpha])
if (st == :shape || series[:fillrange] != nothing) && series[:ribbon] == nothing
gr_set_fill(get_fillcolor(series)) #, series[:fillalpha])
gr_set_fill(get_fillcolor(series, clims)) #, series[:fillalpha])
l, r = xpos-0.07, xpos-0.01
b, t = ypos-0.4dy, ypos+0.4dy
x = [l, r, r, l, l]
@@ -1291,7 +1307,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_set_transparency(get_fillalpha(series))
gr_polyline(x, y, GR.fillarea)
gr_set_transparency(get_linealpha(series))
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series))
gr_set_line(get_linewidth(series), get_linestyle(series), get_linecolor(series, clims))
st == :shape && gr_polyline(x, y)
end
@@ -1305,7 +1321,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if series[:markershape] != :none
gr_draw_markers(series, xpos - .035, ypos, 6, nothing)
gr_draw_markers(series, xpos - .035, ypos, clims, 6)
end
if typeof(series[:label]) <: Array
@@ -1358,10 +1374,10 @@ const _gr_mimeformats = Dict(
"image/svg+xml" => "svg",
)
const _gr_wstype_default = @static if is_linux()
const _gr_wstype_default = @static if Sys.islinux()
"x11"
# "cairox11"
elseif is_apple()
elseif Sys.isapple()
"quartz"
else
"use_default"
@@ -1379,7 +1395,7 @@ for (mime, fmt) in _gr_mimeformats
ENV["GKS_FILEPATH"] = filepath
gr_display(plt, $fmt)
GR.emergencyclosegks()
write(io, readstring(filepath))
write(io, read(filepath, String))
rm(filepath)
if env != "0"
ENV["GKSwstype"] = env
+65 -81
View File
@@ -28,10 +28,6 @@ Read from .hdf5 file using:
- Should be reliable for archival purposes.
==#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
end
import FixedPointNumbers: N0f8 #In core Julia
#Dispatch types:
@@ -39,12 +35,13 @@ struct HDF5PlotNative; end #Indentifies a data element that can natively be hand
struct HDF5CTuple; end #Identifies a "complex" tuple structure
mutable struct HDF5Plot_PlotRef
ref::Union{Plot, Void}
ref::Union{Plot, Nothing}
end
#==Useful constants
===============================================================================#
const _hdf5_nullable{T} = Union{T, Nothing}
const _hdf5_plotroot = "plot"
const _hdf5_dataroot = "data" #TODO: Eventually move data to different root (easier to locate)?
const _hdf5plot_datatypeid = "TYPE" #Attribute identifying type
@@ -108,12 +105,35 @@ const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::HDF5Backend, shape::Shape) = true
function add_backend_string(::HDF5Backend)
"""
if !Plots.is_installed("HDF5")
Pkg.add("HDF5")
end
"""
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Nothing,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
"RGBA" => ARGB{N0f8},
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
#Sub-structure types:
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
"SUBPLOT" => Subplot,
"NULLABLE" => _hdf5_nullable,
)
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
@@ -128,7 +148,7 @@ _hdf5_map_str2telem(v::Vector) = HDF5PLOT_MAP_STR2TELEM[v[1]]
function _hdf5_merge!(dest::Dict, src::Dict)
for (k, v) in src
if isa(v, Axis)
_hdf5_merge!(dest[k].d, v.d)
_hdf5_merge!(dest[k].plotattributes, v.plotattributes)
else
dest[k] = v
end
@@ -140,44 +160,6 @@ end
#==
===============================================================================#
function _initialize_backend(::HDF5Backend)
@eval begin
import HDF5
export HDF5
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
const telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Void,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
"RGBA" => ARGB{N0f8},
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
#Sub-structure types:
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
"SUBPLOT" => Subplot,
"NULLABLE" => Nullable,
)
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
end
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{HDF5Backend})
@@ -233,7 +215,7 @@ end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
function _update_plot_object(plt::Plot{HDF5Backend})
#Do nothing
end
@@ -244,7 +226,7 @@ end
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
warn(msg)
@warn(msg)
return
end
@@ -289,7 +271,7 @@ function _hdf5plot_writecount(grp, n::Int) #Write directly to group
end
function _hdf5plot_gwritefields(grp, k::String, v)
grp = HDF5.g_create(grp, k)
for _k in fieldnames(v)
for _k in fieldnames(typeof(v))
_v = getfield(v, _k)
kstr = string(_k)
_hdf5plot_gwrite(grp, kstr, _v)
@@ -312,12 +294,12 @@ end
#=
function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
# @show grp, k
warn("Cannot write Array: $k=$v")
@warn("Cannot write Array: $k=$v")
end
=#
function _hdf5plot_gwrite(grp, k::String, v::Void)
function _hdf5plot_gwrite(grp, k::String, v::Nothing)
grp[k] = 0
_hdf5plot_writetype(grp, k, Void)
_hdf5plot_writetype(grp, k, Nothing)
end
function _hdf5plot_gwrite(grp, k::String, v::Bool)
grp[k] = Int(v)
@@ -341,10 +323,10 @@ function _hdf5plot_gwrite(grp, k::String, v::Tuple)
end
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
end
function _hdf5plot_gwrite(grp, k::String, d::Dict)
# warn("Cannot write dict: $k=$d")
function _hdf5plot_gwrite(grp, k::String, plotattributes::Dict)
# @warn("Cannot write dict: $k=$plotattributes")
end
function _hdf5plot_gwrite(grp, k::String, v::Range)
function _hdf5plot_gwrite(grp, k::String, v::AbstractRange)
_hdf5plot_gwrite(grp, k, collect(v)) #For now
end
function _hdf5plot_gwrite(grp, k::String, v::ARGB{N0f8})
@@ -363,9 +345,10 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
vgrp = HDF5.g_create(grp, k)
_hdf5plot_writetype(vgrp, Array) #ANY
sz = size(v)
lidx = LinearIndices(sz)
for iter in eachindex(v)
coord = ind2sub(sz, iter)
coord = lidx[iter]
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
@@ -397,7 +380,7 @@ function _hdf5plot_gwrite(grp, k::String, v::HDF5PLOT_SIMPLESUBSTRUCT)
end
function _hdf5plot_gwrite(grp, k::String, v::Axis)
grp = HDF5.g_create(grp, k)
for (_k, _v) in v.d
for (_k, _v) in v.plotattributes
kstr = string(_k)
_hdf5plot_gwrite(grp, kstr, _v)
end
@@ -409,15 +392,15 @@ function _hdf5plot_gwrite(grp, k::String, v::Surface)
_hdf5plot_gwrite(grp, "data2d", v.surf)
_hdf5plot_writetype(grp, Surface)
end
#TODO: "Properly" support Nullable using _hdf5plot_writetype?
function _hdf5plot_gwrite(grp, k::String, v::Nullable)
if isnull(v)
_hdf5plot_gwrite(grp, k, nothing)
else
_hdf5plot_gwrite(grp, k, v.value)
end
return
end
# #TODO: "Properly" support Nullable using _hdf5plot_writetype?
# function _hdf5plot_gwrite(grp, k::String, v::_hdf5_nullable)
# if isnull(v)
# _hdf5plot_gwrite(grp, k, nothing)
# else
# _hdf5plot_gwrite(grp, k, v.value)
# end
# return
# end
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
#Currently no support for SeriesAnnotations
@@ -429,8 +412,8 @@ function _hdf5plot_gwrite(grp, k::String, v::Subplot)
_hdf5plot_writetype(grp, Subplot)
return
end
function _hdf5plot_write(grp, d::Dict)
for (k, v) in d
function _hdf5plot_write(grp, plotattributes::Dict)
for (k, v) in plotattributes
kstr = string(k)
_hdf5plot_gwrite(grp, kstr, v)
end
@@ -448,7 +431,7 @@ function _hdf5plot_write(sp::Subplot{HDF5Backend}, subpath::String, f)
_hdf5plot_writecount(grp, length(sp.series_list))
for (i, series) in enumerate(sp.series_list)
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/series_list/series$i"))
_hdf5plot_write(grp, series.d)
_hdf5plot_write(grp, series.plotattributes)
end
return
@@ -485,7 +468,7 @@ function _hdf5plot_readcount(grp) #Read directly from group
end
_hdf5plot_convert(T::Type{HDF5PlotNative}, v) = v
_hdf5plot_convert(T::Type{Void}, v) = nothing
_hdf5plot_convert(T::Type{Nothing}, v) = nothing
_hdf5plot_convert(T::Type{Bool}, v) = (v!=0)
_hdf5plot_convert(T::Type{Symbol}, v) = Symbol(v)
_hdf5plot_convert(T::Type{Tuple}, v) = tuple(v...) #With Vector{T<:Number}
@@ -527,10 +510,11 @@ function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
sz = _hdf5plot_read(grp, "dim")
if [0] == sz; return []; end
sz = tuple(sz...)
result = Array{Any}(sz)
result = Array{Any}(undef, sz)
lidx = LinearIndices(sz)
for iter in eachindex(result)
coord = ind2sub(sz, iter)
coord = lidx[iter]
idxstr = join(coord, "_")
result[iter] = _hdf5plot_read(grp, "v$idxstr")
end
@@ -595,17 +579,17 @@ function _hdf5plot_read(grp, k::String)
return _hdf5plot_read(grp, k, T, dtid)
end
#Read in values in group to populate d:
function _hdf5plot_read(grp, d::Dict)
#Read in values in group to populate plotattributes:
function _hdf5plot_read(grp, plotattributes::Dict)
gnames = names(grp)
for k in gnames
try
v = _hdf5plot_read(grp, k)
d[Symbol(k)] = v
plotattributes[Symbol(k)] = v
catch e
@show e
@show grp
warn("Could not read field $k")
@warn("Could not read field $k")
end
end
return
@@ -630,7 +614,7 @@ function _hdf5plot_read(sp::Subplot, subpath::String, f)
kwlist = KW()
_hdf5plot_read(grp, kwlist)
plot!(sp, kwlist[:x], kwlist[:y]) #Add data & create data structures
_hdf5_merge!(sp.series_list[end].d, kwlist)
_hdf5_merge!(sp.series_list[end].plotattributes, kwlist)
end
return
+23 -41
View File
@@ -13,10 +13,6 @@ Add in functionality to Plots.jl:
:aspect_ratio,
=#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
end
# ---------------------------------------------------------------------------
#TODO: remove features
const _inspectdr_attr = merge_with_base_supported([
@@ -90,24 +86,24 @@ end
# py_marker(markers::AVec) = map(py_marker, markers)
function _inspectdr_mapglyph(markers::AVec)
warn("Vectors of markers are currently unsupported in InspectDR.")
@warn("Vectors of markers are currently unsupported in InspectDR.")
_inspectdr_mapglyph(markers[1])
end
_inspectdr_mapglyphsize(v::Real) = v
function _inspectdr_mapglyphsize(v::Vector)
warn("Vectors of marker sizes are currently unsupported in InspectDR.")
@warn("Vectors of marker sizes are currently unsupported in InspectDR.")
_inspectdr_mapglyphsize(v[1])
end
_inspectdr_mapcolor(v::Colorant) = v
function _inspectdr_mapcolor(g::PlotUtils.ColorGradient)
warn("Color gradients are currently unsupported in InspectDR.")
@warn("Color gradients are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(g.colors[div(1+end,2)])
end
function _inspectdr_mapcolor(v::AVec)
warn("Vectors of colors are currently unsupported in InspectDR.")
@warn("Vectors of colors are currently unsupported in InspectDR.")
#Pick middle color:
_inspectdr_mapcolor(v[div(1+end,2)])
end
@@ -152,37 +148,23 @@ end
# ---------------------------------------------------------------------------
function add_backend_string(::InspectDRBackend)
"""
if !Plots.is_installed("InspectDR")
Pkg.add("InspectDR")
end
"""
#Glyph used when plotting "Shape"s:
INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
mutable struct InspecDRPlotRef
mplot::Union{Nothing, InspectDR.Multiplot}
gui::Union{Nothing, InspectDR.GtkPlot}
end
function _initialize_backend(::InspectDRBackend; kw...)
@eval begin
import InspectDR
export InspectDR
_inspectdr_getmplot(::Any) = nothing
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
#Glyph used when plotting "Shape"s:
const INSPECTDR_GLYPH_SHAPE = InspectDR.GlyphPolyline(
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
)
mutable struct InspecDRPlotRef
mplot::Union{Void, InspectDR.Multiplot}
gui::Union{Void, InspectDR.GtkPlot}
end
_inspectdr_getmplot(::Any) = nothing
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
end
end
_inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
push!(_initialized_backends, :inspectdr)
# ---------------------------------------------------------------------------
@@ -347,8 +329,8 @@ end
# ---------------------------------------------------------------------------
function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
const plot = sp.o
const strip = plot.strips[1] #Only 1 strip supported with Plots.jl
plot = sp.o
strip = plot.strips[1] #Only 1 strip supported with Plots.jl
xaxis = sp[:xaxis]; yaxis = sp[:yaxis]
xgrid_show = xaxis[:grid]
@@ -406,7 +388,7 @@ end
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{InspectDRBackend})
const mplot = _inspectdr_getmplot(plt.o)
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot; return; end
mplot.title = plt[:plot_title]
@@ -475,7 +457,7 @@ end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
function _update_plot_object(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot; return; end
@@ -506,7 +488,7 @@ const _inspectdr_mimeformats_nodpi = Dict(
# "application/postscript" => "ps", #TODO: support once Cairo supports PSSurface
"application/pdf" => "pdf"
)
_inspectdr_show(io::IO, mime::MIME, ::Void, w, h) =
_inspectdr_show(io::IO, mime::MIME, ::Nothing, w, h) =
throw(ErrorException("Cannot show(::IO, ...) plot - not yet generated"))
function _inspectdr_show(io::IO, mime::MIME, mplot, w, h)
InspectDR._show(io, mime, mplot, Float64(w), Float64(h))
+48 -67
View File
@@ -2,10 +2,6 @@
# significant contributions by: @pkofod
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
:background_color_legend,
@@ -27,7 +23,7 @@ const _pgfplots_attr = merge_with_base_supported([
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar,
:colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
@@ -47,23 +43,6 @@ const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :d
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
function add_backend_string(::PGFPlotsBackend)
"""
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
end
end
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
@@ -124,7 +103,7 @@ function pgf_framestyle(style::Symbol)
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
@warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
default_style
end
end
@@ -154,9 +133,9 @@ pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
function pgf_fillstyle(d, i = 1)
cstr,a = pgf_color(get_fillcolor(d, i))
fa = get_fillalpha(d, i)
function pgf_fillstyle(plotattributes, i = 1)
cstr,a = pgf_color(get_fillcolor(plotattributes, i))
fa = get_fillalpha(plotattributes, i)
if fa != nothing
a = fa
end
@@ -172,11 +151,11 @@ function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
end
function pgf_linestyle(d, i = 1)
lw = pgf_thickness_scaling(d) * get_linewidth(d, i)
lc = get_linecolor(d, i)
la = get_linealpha(d, i)
ls = get_linestyle(d, i)
function pgf_linestyle(plotattributes, i = 1)
lw = pgf_thickness_scaling(plotattributes) * get_linewidth(plotattributes, i)
lc = get_linecolor(plotattributes, i)
la = get_linealpha(plotattributes, i)
ls = get_linestyle(plotattributes, i)
return pgf_linestyle(lw, lc, la, ls)
end
@@ -185,19 +164,19 @@ function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
end
function pgf_marker(d, i = 1)
shape = _cycle(d[:markershape], i)
cstr, a = pgf_color(plot_color(get_markercolor(d, i), get_markeralpha(d, i)))
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(d, i), get_markerstrokealpha(d, i)))
function pgf_marker(plotattributes, i = 1)
shape = _cycle(plotattributes[:markershape], i)
cstr, a = pgf_color(plot_color(get_markercolor(plotattributes, i), get_markeralpha(plotattributes, i)))
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(plotattributes, i), get_markerstrokealpha(plotattributes, i)))
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(pgf_thickness_scaling(d) * 0.5 * _cycle(d[:markersize], i)),
mark size = $(pgf_thickness_scaling(plotattributes) * 0.5 * _cycle(plotattributes[:markersize], i)),
mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
line width = $(pgf_thickness_scaling(plotattributes) * _cycle(plotattributes[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, _cycle(d[:markerstrokestyle], i), "solid"))
$(get(_pgfplots_linestyles, _cycle(plotattributes[:markerstrokestyle], i), "solid"))
}"""
end
@@ -218,24 +197,24 @@ end
# --------------------------------------------------------------------------------------
function pgf_series(sp::Subplot, series::Series)
d = series.d
st = d[:seriestype]
plotattributes = series.plotattributes
st = plotattributes[:seriestype]
series_collection = PGFPlots.Plot[]
# function args
args = if st == :contour
d[:z].surf, d[:x], d[:y]
plotattributes[:z].surf, plotattributes[:x], plotattributes[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
plotattributes[:x], plotattributes[:y], plotattributes[:z]
elseif st == :straightline
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
theta, r = filter_radial_data(plotattributes[:x], plotattributes[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
else
d[:x], d[:y]
plotattributes[:x], plotattributes[:y]
end
# PGFPlots can't handle non-Vector?
@@ -248,8 +227,8 @@ function pgf_series(sp::Subplot, series::Series)
if st in (:contour, :histogram2d)
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
push!(style, pgf_linestyle(plotattributes))
push!(style, pgf_marker(plotattributes))
push!(style, "forget plot")
kw[:style] = join(style, ',')
@@ -268,21 +247,21 @@ function pgf_series(sp::Subplot, series::Series)
for (i, rng) in enumerate(segments)
style = []
kw = KW()
push!(style, pgf_linestyle(d, i))
push!(style, pgf_marker(d, i))
push!(style, pgf_linestyle(plotattributes, i))
push!(style, pgf_marker(plotattributes, i))
if st == :shape
push!(style, pgf_fillstyle(d, i))
push!(style, pgf_fillstyle(plotattributes, i))
end
# add to legend?
if i == 1 && sp[:legend] != :none && should_add_to_legend(series)
if d[:fillrange] != nothing
if plotattributes[:fillrange] != nothing
push!(style, "forget plot")
push!(series_collection, pgf_fill_legend_hack(d, args))
push!(series_collection, pgf_fill_legend_hack(plotattributes, args))
else
kw[:legendentry] = d[:label]
if st == :shape # || d[:fillrange] != nothing
kw[:legendentry] = plotattributes[:label]
if st == :shape # || plotattributes[:fillrange] != nothing
push!(style, "area legend")
end
end
@@ -349,16 +328,16 @@ function pgf_fillrange_args(fillrange, x, y, z)
return x_fill, y_fill, z_fill
end
function pgf_fill_legend_hack(d, args)
function pgf_fill_legend_hack(plotattributes, args)
style = []
kw = KW()
push!(style, pgf_linestyle(d, 1))
push!(style, pgf_marker(d, 1))
push!(style, pgf_fillstyle(d, 1))
push!(style, pgf_linestyle(plotattributes, 1))
push!(style, pgf_marker(plotattributes, 1))
push!(style, pgf_fillstyle(plotattributes, 1))
push!(style, "area legend")
kw[:legendentry] = d[:label]
kw[:legendentry] = plotattributes[:label]
kw[:style] = join(style, ',')
st = d[:seriestype]
st = plotattributes[:seriestype]
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
@@ -426,11 +405,12 @@ function pgf_axis(sp::Subplot, letter)
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = String[begin
tick_labels = Vector{String}(length(ticks[2]))
for (i, label) in enumerate(ticks[2])
base, power = split(label, "^")
power = string("{", power, "}")
string(base, "^", power)
end for label in ticks[2]]
tick_labels[i] = string(base, "^", power)
end
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
@@ -504,7 +484,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
bb = bbox(sp)
push!(style, """
xshift = $(left(bb).value)mm,
yshift = $(round((total_height - (bottom(bb))).value,2))mm,
yshift = $(round((total_height - (bottom(bb))).value, digits=2))mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""")
kw[:width] = "$(width(bb).value)mm"
@@ -555,8 +535,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# colormap this should not cause any problem.
for series in series_list(sp)
for col in (:markercolor, :fillcolor, :linecolor)
if typeof(series.d[col]) == ColorGradient
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
if typeof(series.plotattributes[col]) == ColorGradient
push!(style,"colormap={plots}{$(pgf_colormap(series.plotattributes[col]))}")
if sp[:colorbar] == :none
kw[:colorbar] = "false"
@@ -570,6 +550,7 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
end
@label colorbar_end
push!(style, "colorbar style={title=$(sp[:colorbar_title])}")
o = axisf(; style = join(style, ","), kw...)
# add the series object to the PGFPlots.Axis
@@ -607,7 +588,7 @@ function _show(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
write(io, readstring(open(fn)))
write(io, read(open(fn), String))
# cleanup
PGFPlots.cleanup(plt.o)
@@ -616,7 +597,7 @@ end
function _show(io::IO, mime::MIME"application/x-tex", plt::Plot{PGFPlotsBackend})
fn = tempname()*".tex"
PGFPlots.save(fn, backend_object(plt), include_preamble=false)
write(io, readstring(open(fn)))
write(io, read(open(fn), String))
end
function _display(plt::Plot{PGFPlotsBackend})
+166 -177
View File
@@ -1,10 +1,6 @@
# https://plot.ly/javascript/getting-started
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotly.jl"))
end
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -68,7 +64,7 @@ function _plotly_framestyle(style::Symbol)
return style
else
default_style = get(_plotly_framestyle_defaults, style, :axes)
warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
@warn("Framestyle :$style is not supported by Plotly and PlotlyJS. :$default_style was cosen instead.")
default_style
end
end
@@ -76,46 +72,37 @@ end
# --------------------------------------------------------------------------------------
function add_backend_string(::PlotlyBackend)
"""
Pkg.build("Plots")
"""
end
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
function _initialize_backend(::PlotlyBackend; kw...)
@eval begin
_js_code = open(readstring, _plotly_js_path, "r")
_js_code = open(read, _plotly_js_path, "r")
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
# end
end
# TODO: other initialization
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
# end
using UUIDs
push!(_initialized_backends, :plotly)
# ----------------------------------------------------------------
@@ -162,7 +149,7 @@ function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper"
))
end
# function get_annotation_dict_for_arrow(d::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
# function get_annotation_dict_for_arrow(plotattributes::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
# xdiff = xyprev[1] - xy[1]
# ydiff = xyprev[2] - xy[2]
# dist = sqrt(xdiff^2 + ydiff^2)
@@ -176,7 +163,7 @@ end
# # :ay => -40,
# :ax => 10xdiff / dist,
# :ay => -10ydiff / dist,
# :arrowcolor => rgba_string(d[:linecolor]),
# :arrowcolor => rgba_string(plotattributes[:linecolor]),
# :xref => "x",
# :yref => "y",
# :arrowsize => 10a.headwidth,
@@ -319,14 +306,14 @@ function plotly_polaraxis(axis::Axis)
end
function plotly_layout(plt::Plot)
d_out = KW()
plotattributes_out = KW()
w, h = plt[:size]
d_out[:width], d_out[:height] = w, h
d_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
d_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
plotattributes_out[:width], plotattributes_out[:height] = w, h
plotattributes_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
plotattributes_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
d_out[:annotations] = KW[]
plotattributes_out[:annotations] = KW[]
multiple_subplots = length(plt.subplots) > 1
@@ -347,10 +334,10 @@ function plotly_layout(plt::Plot)
end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
title_font = font(titlefont(sp), :top)
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
push!(plotattributes_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
end
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
plotattributes_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
# set to supported framestyle
sp[:framestyle] = _plotly_framestyle(sp[:framestyle])
@@ -359,7 +346,7 @@ function plotly_layout(plt::Plot)
if is3d(sp)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
d_out[:scene] = KW(
plotattributes_out[:scene] = KW(
Symbol("xaxis$(spidx)") => plotly_axis(plt, sp[:xaxis], sp),
Symbol("yaxis$(spidx)") => plotly_axis(plt, sp[:yaxis], sp),
Symbol("zaxis$(spidx)") => plotly_axis(plt, sp[:zaxis], sp),
@@ -374,19 +361,19 @@ function plotly_layout(plt::Plot)
),
)
elseif ispolar(sp)
d_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
plotattributes_out[Symbol("angularaxis$(spidx)")] = plotly_polaraxis(sp[:xaxis])
plotattributes_out[Symbol("radialaxis$(spidx)")] = plotly_polaraxis(sp[:yaxis])
else
d_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
plotattributes_out[Symbol("xaxis$(x_idx)")] = plotly_axis(plt, sp[:xaxis], sp)
# don't allow yaxis to be reupdated/reanchored in a linked subplot
spidx == y_idx ? d_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
spidx == y_idx ? plotattributes_out[Symbol("yaxis$(y_idx)")] = plotly_axis(plt, sp[:yaxis], sp) : nothing
end
# legend
d_out[:showlegend] = sp[:legend] != :none
plotattributes_out[:showlegend] = sp[:legend] != :none
xpos,ypos = plotly_legend_pos(sp[:legend])
if sp[:legend] != :none
d_out[:legend] = KW(
plotattributes_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
@@ -398,13 +385,13 @@ function plotly_layout(plt::Plot)
# annotations
for ann in sp[:annotations]
append!(d_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
append!(plotattributes_out[:annotations], KW[plotly_annotation_dict(locate_annotation(sp, ann...)...; xref = "x$(x_idx)", yref = "y$(y_idx)")])
end
# series_annotations
for series in series_list(sp)
anns = series[:series_annotations]
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
push!(d_out[:annotations], plotly_annotation_dict(
push!(plotattributes_out[:annotations], plotly_annotation_dict(
xi,
yi,
PlotText(str,fnt); xref = "x$(x_idx)", yref = "y$(y_idx)")
@@ -417,24 +404,24 @@ function plotly_layout(plt::Plot)
# a = sargs[:arrow]
# if sargs[:seriestype] in (:path, :line) && typeof(a) <: Arrow
# add_arrows(sargs[:x], sargs[:y]) do xyprev, xy
# push!(d_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
# push!(plotattributes_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
# end
# end
# end
if ispolar(sp)
d_out[:direction] = "counterclockwise"
plotattributes_out[:direction] = "counterclockwise"
end
d_out
plotattributes_out
end
# turn off hover if nothing's using it
if all(series -> series.d[:hover] in (false,:none), plt.series_list)
d_out[:hovermode] = "none"
if all(series -> series.plotattributes[:hover] in (false,:none), plt.series_list)
plotattributes_out[:hovermode] = "none"
end
d_out
plotattributes_out
end
function plotly_layout_json(plt::Plot)
@@ -450,7 +437,7 @@ function plotly_colorscale(c::AbstractVector{<:RGBA}, α)
if length(c) == 1
return [[0.0, rgba_string(plot_color(c[1], α))], [1.0, rgba_string(plot_color(c[1], α))]]
else
vals = linspace(0.0, 1.0, length(c))
vals = range(0.0, stop=1.0, length=length(c))
return [[vals[i], rgba_string(plot_color(c[i], α))] for i in eachindex(c)]
end
end
@@ -540,21 +527,24 @@ end
as_gradient(grad::ColorGradient, α) = grad
as_gradient(grad, α) = cgrad(alpha = α)
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
# get a dictionary representing the series params (plotattributes is the Plots-dict, plotattributes_out is the Plotly-dict)
function plotly_series(plt::Plot, series::Series)
st = series[:seriestype]
if st == :shape
return plotly_series_shapes(plt, series)
end
sp = series[:subplot]
d_out = KW()
clims = get_clims(sp)
if st == :shape
return plotly_series_shapes(plt, series, clims)
end
plotattributes_out = KW()
# these are the axes that the series should be mapped to
x_idx, y_idx = plotly_link_indicies(plt, sp)
d_out[:xaxis] = "x$(x_idx)"
d_out[:yaxis] = "y$(y_idx)"
d_out[:showlegend] = should_add_to_legend(series)
plotattributes_out[:xaxis] = "x$(x_idx)"
plotattributes_out[:yaxis] = "y$(y_idx)"
plotattributes_out[:showlegend] = should_add_to_legend(series)
if st == :straightline
x, y = straightline_data(series)
@@ -567,7 +557,7 @@ function plotly_series(plt::Plot, series::Series)
for (letter, data) in zip((:x, :y, :z), (x, y, z))
)
d_out[:name] = series[:label]
plotattributes_out[:name] = series[:label]
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
@@ -575,70 +565,69 @@ function plotly_series(plt::Plot, series::Series)
hasfillrange = st in (:path, :scatter, :scattergl, :straightline) &&
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
plotattributes_out[:colorbar] = KW(:title => sp[:colorbar_title])
clims = sp[:clims]
if is_2tuple(clims)
d_out[:zmin], d_out[:zmax] = clims
plotattributes_out[:zmin], plotattributes_out[:zmax] = clims
end
# set the "type"
if st in (:path, :scatter, :scattergl, :straightline, :path3d, :scatter3d)
return plotly_series_segments(series, d_out, x, y, z)
return plotly_series_segments(series, plotattributes, x, y, z, clims)
elseif st == :heatmap
x = heatmap_edges(x, sp[:xaxis][:scale])
y = heatmap_edges(y, sp[:yaxis][:scale])
d_out[:type] = "heatmap"
d_out[:x], d_out[:y], d_out[:z] = x, y, z
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = hascolorbar(sp)
plotattributes_out[:type] = "heatmap"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:showscale] = hascolorbar(sp)
elseif st == :contour
d_out[:type] = "contour"
d_out[:x], d_out[:y], d_out[:z] = x, y, z
# d_out[:showscale] = series[:colorbar] != :none
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = hascolorbar(sp)
plotattributes_out[:type] = "contour"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
# plotattributes_out[:showscale] = series[:colorbar] != :none
plotattributes_out[:ncontours] = series[:levels]
plotattributes_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines", :showlabels => series[:contour_labels] == true)
plotattributes_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
plotattributes_out[:showscale] = hascolorbar(sp)
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
d_out[:x], d_out[:y], d_out[:z] = x, y, z
plotattributes_out[:type] = "surface"
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x, y, z
if st == :wireframe
d_out[:hidesurface] = true
plotattributes_out[:hidesurface] = true
wirelines = KW(
:show => true,
:color => rgba_string(plot_color(series[:linecolor], series[:linealpha])),
:highlightwidth => series[:linewidth],
)
d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
d_out[:showscale] = false
plotattributes_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines)
plotattributes_out[:showscale] = false
else
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:opacity] = series[:fillalpha]
plotattributes_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
plotattributes_out[:opacity] = series[:fillalpha]
if series[:fill_z] != nothing
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
plotattributes_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end
d_out[:showscale] = hascolorbar(sp)
plotattributes_out[:showscale] = hascolorbar(sp)
end
elseif st == :pie
d_out[:type] = "pie"
d_out[:labels] = pie_labels(sp, series)
d_out[:values] = y
d_out[:hoverinfo] = "label+percent+name"
plotattributes_out[:type] = "pie"
plotattributes_out[:labels] = pie_labels(sp, series)
plotattributes_out[:values] = y
plotattributes_out[:hoverinfo] = "label+percent+name"
else
warn("Plotly: seriestype $st isn't supported.")
@warn("Plotly: seriestype $st isn't supported.")
return KW()
end
# add "marker"
if hasmarker
inds = eachindex(x)
d_out[:marker] = KW(
plotattributes_out[:marker] = KW(
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
# :opacity => series[:markeralpha],
:size => 2 * _cycle(series[:markersize], inds),
@@ -650,22 +639,22 @@ function plotly_series(plt::Plot, series::Series)
)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
plotly_polar!(plotattributes_out, series)
plotly_hover!(plotattributes_out, series[:hover])
return [d_out]
return [plotattributes_out]
end
function plotly_series_shapes(plt::Plot, series::Series)
function plotly_series_shapes(plt::Plot, series::Series, clims)
segments = iter_segments(series)
d_outs = Vector{KW}(length(segments))
plotattributes_outs = Vector{KW}(undef, length(segments))
# TODO: create a d_out for each polygon
# TODO: create a plotattributes_out for each polygon
# x, y = series[:x], series[:y]
# these are the axes that the series should be mapped to
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
d_base = KW(
plotattributes_base = KW(
:xaxis => "x$(x_idx)",
:yaxis => "y$(y_idx)",
:name => series[:label],
@@ -680,37 +669,37 @@ function plotly_series_shapes(plt::Plot, series::Series)
length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill
d_out = merge(d_base, KW(
plotattributes_out = merge(plotattributes_base, KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i))),
:fillcolor => rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i))),
))
if series[:markerstrokewidth] > 0
d_out[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
plotattributes[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:dash => string(get_linestyle(series, i)),
)
end
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(d_out, series)
plotly_hover!(d_out, _cycle(series[:hover], i))
d_outs[i] = d_out
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(plotattributes_out, series)
plotly_hover!(plotattributes_out, _cycle(series[:hover], i))
plotattributes_outs[i] = plotattributes_out
end
if series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
elseif series[:line_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
end
d_outs
plotattributes_outs
end
function plotly_series_segments(series::Series, d_base::KW, x, y, z)
function plotly_series_segments(series::Series, ploattributes_base::KW, x, y, z, clims)
st = series[:seriestype]
sp = series[:subplot]
isscatter = st in (:scatter, :scatter3d, :scattergl)
@@ -720,51 +709,51 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
(isa(series[:fillrange], AbstractVector) || isa(series[:fillrange], Tuple))
segments = iter_segments(series)
d_outs = Vector{KW}((hasfillrange ? 2 : 1 ) * length(segments))
plotattributes_outs = Vector{KW}(undef, (hasfillrange ? 2 : 1 ) * length(segments))
for (i,rng) in enumerate(segments)
!isscatter && length(rng) < 2 && continue
d_out = deepcopy(d_base)
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
d_out[:legendgroup] = series[:label]
plotattributes_out = deepcopy(plotattributes_base)
plotattributes_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotattributes_out[:legendgroup] = series[:label]
# set the type
if st in (:path, :scatter, :scattergl, :straightline)
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
d_out[:mode] = if hasmarker
plotattributes_out[:type] = st==:scattergl ? "scattergl" : "scatter"
plotattributes_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if series[:fillrange] == true || series[:fillrange] == 0 || isa(series[:fillrange], Tuple)
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
plotattributes[:fill] = "tozeroy"
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
elseif typeof(series[:fillrange]) <: Union{AbstractVector{<:Real}, Real}
d_out[:fill] = "tonexty"
d_out[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, i), get_fillalpha(series, i)))
plotattributes[:fill] = "tonexty"
plotattributes[:fillcolor] = rgba_string(plot_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)))
elseif !(series[:fillrange] in (false, nothing))
warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
@warn("fillrange ignored... plotly only supports filling to zero and to a vector of values. fillrange: $(series[:fillrange])")
end
d_out[:x], d_out[:y] = x[rng], y[rng]
plotattributes_out[:x], plotattributes_out[:y] = x[rng], y[rng]
elseif st in (:path3d, :scatter3d)
d_out[:type] = "scatter3d"
d_out[:mode] = if hasmarker
plotattributes_out[:type] = "scatter3d"
plotattributes_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y], d_out[:z] = x[rng], y[rng], z[rng]
plotattributes_out[:x], plotattributes_out[:y], plotattributes_out[:z] = x[rng], y[rng], z[rng]
end
# add "marker"
if hasmarker
d_out[:marker] = KW(
plotattributes_out[:marker] = KW(
:symbol => get(_plotly_markers, _cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => series[:markeralpha],
:size => 2 * _cycle(series[:markersize], i),
:color => rgba_string(plot_color(get_markercolor(series, i), get_markeralpha(series, i))),
:color => rgba_string(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))),
:line => KW(
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))),
:width => _cycle(series[:markerstrokewidth], i),
@@ -774,8 +763,8 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
# add "line"
if hasline
d_out[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, i), get_linealpha(series, i))),
plotattributes[:line] = KW(
:color => rgba_string(plot_color(get_linecolor(series, clims, i), get_linealpha(series, i))),
:width => get_linewidth(series, i),
:shape => if st == :steppre
"vh"
@@ -788,14 +777,14 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, _cycle(series[:hover], rng))
plotly_polar!(plotattributes_out, series)
plotly_hover!(plotattributes_out, _cycle(series[:hover], rng))
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
# series, one for series being filled to) instead of one
d_out_fillrange = deepcopy(d_out)
d_out_fillrange[:showlegend] = false
plotattributes_out_fillrange = deepcopy(plotattributes_out)
plotattributes_out_fillrange[:showlegend] = false
# if fillrange is provided as real or tuple of real, expand to array
if typeof(series[:fillrange]) <: Real
series[:fillrange] = fill(series[:fillrange], length(rng))
@@ -805,49 +794,49 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
d_out_fillrange[:y] = series[:fillrange][rng]
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
plotattributes_out_fillrange[:y] = series[:fillrange][rng]
delete!(plotattributes_out_fillrange, :fill)
delete!(plotattributes_out_fillrange, :fillcolor)
else
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
# if fillrange is a tuple with upper and lower limit, plotattributes_out_fillrange
# is the series that will do the filling
fillrng = Tuple(series[:fillrange][i][rng] for i in 1:2)
d_out_fillrange[:x], d_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
d_out_fillrange[:line][:width] = 0
delete!(d_out, :fill)
delete!(d_out, :fillcolor)
plotattributes_out_fillrange[:x], plotattributes_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
plotattributes_out_fillrange[:line][:width] = 0
delete!(plotattributes_out, :fill)
delete!(plotattributes_out, :fillcolor)
end
d_outs[(2 * i - 1):(2 * i)] = [d_out_fillrange, d_out]
plotattributes_outs[(2 * i - 1):(2 * i)] = [plotattributes_out_fillrange, plotattributes_out]
else
d_outs[i] = d_out
plotattributes_outs[i] = plotattributes_out
end
end
if series[:line_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :line))
elseif series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :fill))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
push!(plotattributes_outs, plotly_colorbar_hack(series, plotattributes_base, :marker))
end
d_outs
plotattributes_outs
end
function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
d_out = deepcopy(d_base)
function plotly_colorbar_hack(series::Series, plotattributes_base::KW, sym::Symbol)
plotattributes_out = deepcopy(plotattributes_base)
cmin, cmax = get_clims(series[:subplot])
d_out[:showlegend] = false
d_out[:type] = is3d(series) ? :scatter3d : :scatter
d_out[:hoverinfo] = :none
d_out[:mode] = :markers
d_out[:x], d_out[:y] = [series[:x][1]], [series[:y][1]]
plotattributes_out[:showlegend] = false
plotattributes_out[:type] = is3d(series) ? :scatter3d : :scatter
plotattributes_out[:hoverinfo] = :none
plotattributes_out[:mode] = :markers
plotattributes_out[:x], plotattributes_out[:y] = [series[:x][1]], [series[:y][1]]
if is3d(series)
d_out[:z] = [series[:z][1]]
plotattributes_out[:z] = [series[:z][1]]
end
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
d_out[:marker] = KW(
plotattributes_out[:marker] = KW(
:size => 0,
:opacity => 0,
:color => [0.5],
@@ -856,26 +845,26 @@ function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
:colorscale => plotly_colorscale(series[Symbol("$(sym)color")], 1),
:showscale => hascolorbar(series[:subplot]),
)
return d_out
return plotattributes_out
end
function plotly_polar!(d_out::KW, series::Series)
function plotly_polar!(plotattributes_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
d_out[:t] = rad2deg.(theta)
d_out[:r] = r
theta, r = filter_radial_data(pop!(plotattributes_out, :x), pop!(plotattributes_out, :y), axis_limits(series[:subplot][:yaxis]))
plotattributes_out[:t] = rad2deg.(theta)
plotattributes_out[:r] = r
end
end
function plotly_hover!(d_out::KW, hover)
function plotly_hover!(plotattributes_out::KW, hover)
# hover text
if hover in (:none, false)
d_out[:hoverinfo] = "none"
plotattributes_out[:hoverinfo] = "none"
elseif hover != nothing
d_out[:hoverinfo] = "text"
d_out[:text] = hover
plotattributes_out[:hoverinfo] = "text"
plotattributes_out[:text] = hover
end
end
@@ -906,7 +895,7 @@ function html_body(plt::Plot{PlotlyBackend}, style = nothing)
w, h = plt[:size]
style = "width:$(w)px;height:$(h)px;"
end
uuid = Base.Random.uuid4()
uuid = UUIDs.uuid4()
html = """
<div id=\"$(uuid)\" style=\"$(style)\"></div>
<script>
+3 -35
View File
@@ -1,6 +1,3 @@
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
end
# https://github.com/spencerlyon2/PlotlyJS.jl
@@ -13,35 +10,6 @@ const _plotlyjs_scale = _plotly_scale
# --------------------------------------------------------------------------------------
function add_backend_string(::PlotlyJSBackend)
"""
if !Plots.is_installed("PlotlyJS")
Pkg.add("PlotlyJS")
end
if !Plots.is_installed("Rsvg")
Pkg.add("Rsvg")
end
import Blink
Blink.AtomShell.install()
"""
end
function _initialize_backend(::PlotlyJSBackend; kw...)
@eval begin
import PlotlyJS
export PlotlyJS
end
# # override IJulia inline display
# if isijulia()
# IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
# end
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
@@ -63,14 +31,14 @@ end
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y))
kw = KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
kw = KW(xsym => (series.plotattributes[:x],), ysym => (series.plotattributes[:y],))
z = series[:z]
if z != nothing
kw[:z] = (isa(z,Surface) ? transpose_z(series, series[:z].surf, false) : z,)
end
PlotlyJS.restyle!(
plt.o,
findfirst(plt.series_list, series),
findfirst(isequal(series), plt.series_list),
kw
)
end
@@ -120,7 +88,7 @@ function _display(plt::Plot{PlotlyJSBackend})
end
end
@require WebIO begin
@require WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" begin
function WebIO.render(plt::Plot{PlotlyJSBackend})
prepare_output(plt)
WebIO.render(plt.o)
+68 -100
View File
@@ -1,10 +1,6 @@
# https://github.com/stevengj/PyPlot.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pyplot.jl"))
end
const _pyplot_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
@@ -59,57 +55,31 @@ is_marker_supported(::PyPlotBackend, shape::Shape) = true
# --------------------------------------------------------------------------------------
function add_backend_string(::PyPlotBackend)
"""
if !Plots.is_installed("PyPlot")
Pkg.add("PyPlot")
end
withenv("PYTHON" => "") do
Pkg.build("PyPlot")
end
# problem: https://github.com/tbreloff/Plots.jl/issues/308
# solution: hack from @stevengj: https://github.com/stevengj/PyPlot.jl/pull/223#issuecomment-229747768
otherdisplays = splice!(Base.Multimedia.displays, 2:length(Base.Multimedia.displays))
append!(Base.Multimedia.displays, otherdisplays)
pycolors = PyPlot.pyimport("matplotlib.colors")
pypath = PyPlot.pyimport("matplotlib.path")
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
pypatches = PyPlot.pyimport("matplotlib.patches")
pyfont = PyPlot.pyimport("matplotlib.font_manager")
pyticker = PyPlot.pyimport("matplotlib.ticker")
pycmap = PyPlot.pyimport("matplotlib.cm")
pynp = PyPlot.pyimport("numpy")
pynp["seterr"](invalid="ignore")
pytransforms = PyPlot.pyimport("matplotlib.transforms")
pycollections = PyPlot.pyimport("matplotlib.collections")
pyart3d = PyPlot.art3D
# now restart julia!
"""
# "support" matplotlib v1.5
set_facecolor_sym = if PyPlot.version < v"2"
@warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
:set_axis_bgcolor
else
:set_facecolor
end
function _initialize_backend(::PyPlotBackend)
@eval begin
# problem: https://github.com/tbreloff/Plots.jl/issues/308
# solution: hack from @stevengj: https://github.com/stevengj/PyPlot.jl/pull/223#issuecomment-229747768
otherdisplays = splice!(Base.Multimedia.displays, 2:length(Base.Multimedia.displays))
import PyPlot, PyCall
import LaTeXStrings: latexstring
append!(Base.Multimedia.displays, otherdisplays)
export PyPlot
const pycolors = PyPlot.pyimport("matplotlib.colors")
const pypath = PyPlot.pyimport("matplotlib.path")
const mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
const pypatches = PyPlot.pyimport("matplotlib.patches")
const pyfont = PyPlot.pyimport("matplotlib.font_manager")
const pyticker = PyPlot.pyimport("matplotlib.ticker")
const pycmap = PyPlot.pyimport("matplotlib.cm")
const pynp = PyPlot.pyimport("numpy")
pynp["seterr"](invalid="ignore")
const pytransforms = PyPlot.pyimport("matplotlib.transforms")
const pycollections = PyPlot.pyimport("matplotlib.collections")
const pyart3d = PyPlot.art3D
# "support" matplotlib v1.5
const set_facecolor_sym = if PyPlot.version < v"2"
warn("You are using Matplotlib $(PyPlot.version), which is no longer officialy supported by the Plots community. To ensure smooth Plots.jl integration update your Matplotlib library to a version >= 2.0.0")
:set_axis_bgcolor
else
:set_facecolor
end
# we don't want every command to update the figure
PyPlot.ioff()
end
end
# --------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------
# # convert colorant to 4-tuple RGBA
# py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
@@ -160,7 +130,7 @@ function py_linestyle(seriestype::Symbol, linestyle::Symbol)
linestyle == :dash && return "--"
linestyle == :dot && return ":"
linestyle == :dashdot && return "-."
warn("Unknown linestyle $linestyle")
@warn("Unknown linestyle $linestyle")
return "-"
end
@@ -221,13 +191,13 @@ function py_marker(marker::Symbol)
marker == :vline && return "|"
haskey(_shapes, marker) && return py_marker(_shapes[marker])
warn("Unknown marker $marker")
@warn("Unknown marker $marker")
return "o"
end
# py_marker(markers::AVec) = map(py_marker, markers)
function py_marker(markers::AVec)
warn("Vectors of markers are currently unsupported in PyPlot: $markers")
@warn("Vectors of markers are currently unsupported in PyPlot: $markers")
py_marker(markers[1])
end
@@ -266,23 +236,26 @@ function add_pyfixedformatter(cbar, vals::AVec)
cbar[:update_ticks]()
end
function labelfunc(scale::Symbol, backend::PyPlotBackend)
if scale == :log10
x -> latexstring("10^{$x}")
elseif scale == :log2
x -> latexstring("2^{$x}")
elseif scale == :ln
x -> latexstring("e^{$x}")
else
string
@require LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" begin
function labelfunc(scale::Symbol, backend::PyPlotBackend)
if scale == :log10
x -> LaTeXStrings.latexstring("10^{$x}")
elseif scale == :log2
x -> LaTeXStrings.latexstring("2^{$x}")
elseif scale == :ln
x -> LaTeXStrings.latexstring("e^{$x}")
else
string
end
end
end
function py_mask_nans(z)
# pynp["ma"][:masked_invalid](z)))
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
@require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" begin
function py_mask_nans(z)
# pynp["ma"][:masked_invalid](z)))
PyCall.pycall(pynp["ma"][:masked_invalid], Any, z)
# pynp["ma"][:masked_where](pynp["isnan"](z),z)
end
end
# ---------------------------------------------------------------------------
@@ -290,7 +263,7 @@ end
function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
x, y = series[:x], series[:y]
nx, ny = length(x), length(y)
if !isa(get(series.d, :z, nothing), Surface) && nx != ny
if !isa(get(series.plotattributes, :z, nothing), Surface) && nx != ny
if nx < ny
series[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
else
@@ -326,7 +299,7 @@ py_fillcolormap(series::Series) = py_colormap(series[:fillcolor])
# getAxis(sp::Subplot) = sp.o
# function getAxis(plt::Plot{PyPlotBackend}, series::Series)
# sp = get_subplot(plt, get(series.d, :subplot, 1))
# sp = get_subplot(plt, get(series.plotattributes, :subplot, 1))
# getAxis(sp)
# end
@@ -439,12 +412,12 @@ end
# ---------------------------------------------------------------------------
# function _series_added(pkg::PyPlotBackend, plt::Plot, d::KW)
# function _series_added(pkg::PyPlotBackend, plt::Plot, plotattributes::KW)
# TODO: change this to accept Subplot??
# function _series_added(plt::Plot{PyPlotBackend}, series::Series)
function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# d = series.d
# plotattributes = series.plotattributes
st = series[:seriestype]
sp = series[:subplot]
ax = sp.o
@@ -463,12 +436,10 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# handle zcolor and get c/cmap
needs_colorbar = hascolorbar(sp)
extrakw = if needs_colorbar || is_2tuple(sp[:clims])
vmin, vmax = get_clims(sp)
KW(:vmin => vmin, :vmax => vmax)
else
KW()
end
vmin, vmax = clims = get_clims(sp)
# Dict to store extra kwargs
extrakw = KW(:vmin => vmin, :vmax => vmax)
# holds references to any python object representing the matplotlib series
handles = []
@@ -529,7 +500,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
handle = ax[:plot]((arg[rng] for arg in xyargs)...;
label = i == 1 ? series[:label] : "",
zorder = series[:series_plotindex],
color = py_color(get_linecolor(series, i), get_linealpha(series, i)),
color = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
linestyle = py_linestyle(st, get_linestyle(series, i)),
solid_capstyle = "round",
@@ -542,7 +513,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
a = series[:arrow]
if a != nothing && !is3d(st) # TODO: handle 3d later
if typeof(a) != Arrow
warn("Unexpected type for arrow: $(typeof(a))")
@warn("Unexpected type for arrow: $(typeof(a))")
else
arrowprops = KW(
:arrowstyle => "simple,head_length=$(a.headlength),head_width=$(a.headwidth)",
@@ -571,7 +542,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
:scatter3d, :steppre, :steppost,
:bar)
markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] != nothing
py_color(plot_color.(get_markercolor.(series, eachindex(x)), get_markeralpha.(series, eachindex(x))))
# py_color(plot_color.(get_markercolor.(series, clims, eachindex(x)), get_markeralpha.(series, eachindex(x))))
[py_color(plot_color(get_markercolor(series, clims, i), get_markeralpha(series, i))) for i in eachindex(x)]
else
py_color(plot_color(series[:markercolor], series[:markeralpha]))
end
@@ -679,8 +651,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if typeof(z) <: AbstractMatrix || typeof(z) <: Surface
x, y, z = map(Array, (x,y,z))
if !ismatrix(x) || !ismatrix(y)
x = repmat(x', length(y), 1)
y = repmat(y, 1, length(series[:x]))
x = repeat(x', length(y), 1)
y = repeat(y, 1, length(series[:x]))
end
z = transpose_z(series, z)
if st == :surface
@@ -719,11 +691,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
elseif typeof(z) <: AbstractVector
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
handle = ax[:plot_trisurf](x, y, z;
label = series[:label],
zorder = series[:series_plotindex],
@@ -794,8 +761,8 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
path;
label = series[:label],
zorder = series[:series_plotindex],
edgecolor = py_color(get_linecolor(series, i), get_linealpha(series, i)),
facecolor = py_color(get_fillcolor(series, i), get_fillalpha(series, i)),
edgecolor = py_color(get_linecolor(series, clims, i), get_linealpha(series, i)),
facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
linewidth = py_thickness_scale(plt, get_linewidth(series, i)),
linestyle = py_linestyle(st, get_linestyle(series, i)),
fill = true
@@ -844,7 +811,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
zorder = series[:series_plotindex],
facecolor = py_color(get_fillcolor(series, i), get_fillalpha(series, i)),
facecolor = py_color(get_fillcolor(series, clims, i), get_fillalpha(series, i)),
linewidths = 0
)
push!(handles, handle)
@@ -895,7 +862,7 @@ function py_compute_axis_minval(axis::Axis)
sps = axis.sps
for sp in sps
for series in series_list(sp)
v = series.d[axis[:letter]]
v = series.plotattributes[axis[:letter]]
if !isempty(v)
minval = NaNMath.min(minval, ignorenan_minimum(abs.(v)))
end
@@ -912,14 +879,14 @@ end
function py_set_scale(ax, axis::Axis)
scale = axis[:scale]
letter = axis[:letter]
scale in supported_scales() || return warn("Unhandled scale value in pyplot: $scale")
scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale")
func = ax[Symbol("set_", letter, "scale")]
kw = KW()
arg = if scale == :identity
"linear"
else
kw[Symbol(:base,letter)] = if scale == :ln
e
elseif scale == :log2
2
elseif scale == :log10
@@ -1099,7 +1066,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
ax[Symbol("set_", letter, "label")](axis[:guide])
if get(axis.d, :flip, false)
if get(axis.plotattributes, :flip, false)
ax[Symbol("invert_", letter, "axis")]()
end
pyaxis[:label][:set_fontsize](py_thickness_scale(plt, axis[:guidefontsize]))
@@ -1254,6 +1221,7 @@ const _pyplot_legend_pos = KW(
function py_add_legend(plt::Plot, sp::Subplot, ax)
leg = sp[:legend]
clims = get_clims(sp)
if leg != :none
# gotta do this to ensure both axes are included
labels = []
@@ -1263,19 +1231,19 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
# add a line/marker and a label
push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing
pypatches[:Patch](
edgecolor = py_color(get_linecolor(series), get_linealpha(series)),
facecolor = py_color(get_fillcolor(series), get_fillalpha(series)),
edgecolor = py_color(get_linecolor(series, clims), get_linealpha(series)),
facecolor = py_color(get_fillcolor(series, clims), get_fillalpha(series)),
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
linestyle = py_linestyle(series[:seriestype], get_linestyle(series))
)
elseif series[:seriestype] in (:path, :straightline)
PyPlot.plt[:Line2D]((0,1),(0,0),
color = py_color(get_linecolor(series), get_linealpha(series)),
color = py_color(get_linecolor(series, clims), get_linealpha(series)),
linewidth = py_thickness_scale(plt, clamp(get_linewidth(series), 0, 5)),
linestyle = py_linestyle(:path, get_linestyle(series)),
marker = py_marker(series[:markershape]),
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series, clims), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
)
else
series[:serieshandle][1]
+4 -9
View File
@@ -3,14 +3,9 @@
# [ADD BACKEND WEBSITE]
function _initialize_backend(::[PkgName]Backend; kw...)
@eval begin
import [PkgName]
export [PkgName]
# todo: other initialization that needs to be eval-ed
end
# todo: other initialization
end
import [PkgName]
export [PkgName]
push!(_initialized_backends, [pgkname]::Symbol)
# ---------------------------------------------------------------------------
@@ -54,7 +49,7 @@ end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
# Override this to update plot items (title, xlabel, etc), and add annotations (plotattributes[:annotations])
function _update_plot_object(plt::Plot{[PkgName]Backend})
end
+11 -31
View File
@@ -1,10 +1,6 @@
# https://github.com/Evizero/UnicodePlots.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
end
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
@@ -29,26 +25,10 @@ const _unicodeplots_scale = [:identity]
# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupported_args(::UnicodePlotsBackend, d::KW) = nothing
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
# --------------------------------------------------------------------------------------
function add_backend_string(::UnicodePlotsBackend)
"""
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
const _canvas_type = Ref(:auto)
function _canvas_map()
@@ -124,7 +104,7 @@ function rebuildUnicodePlot!(plt::Plot, width, height)
# now use the ! functions to add to the plot
for series in series_list(sp)
addUnicodeSeries!(o, series.d, sp[:legend] != :none, xlim, ylim)
addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
end
# save the object
@@ -134,17 +114,17 @@ end
# add a single series
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = d[:seriestype]
st = plotattributes[:seriestype]
if st == :histogram2d
UnicodePlots.densityplot!(o, d[:x], d[:y])
UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
return
end
if st in (:path, :straightline)
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
elseif st == :scatter || plotattributes[:markershape] != :none
func = UnicodePlots.scatterplot!
# elseif st == :bar
# func = UnicodePlots.barplot!
@@ -156,16 +136,16 @@ function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
# get the series data and label
x, y = if st == :straightline
straightline_data(d)
straightline_data(plotattributes)
elseif st == :shape
shape_data(series)
else
[collect(float(d[s])) for s in (:x, :y)]
[collect(float(plotattributes[s])) for s in (:x, :y)]
end
label = addlegend ? d[:label] : ""
label = addlegend ? plotattributes[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto
# add the series
x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
@@ -183,7 +163,7 @@ function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
gui(plt)
# @osx_only begin
@static if is_apple()
@static if Sys.isapple()
# BEGIN HACK
# wait while the plot gets drawn
+4 -7
View File
@@ -2,9 +2,6 @@
# NOTE: backend should implement `html_body` and `html_head`
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
end
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
"""
@@ -23,16 +20,16 @@ function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr
end
function open_browser_window(filename::AbstractString)
@static if is_apple()
@static if Sys.isapple()
return run(`open $(filename)`)
end
@static if is_linux() || is_bsd() # is_bsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
@static if Sys.islinux() || Sys.isbsd() # Sys.isbsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
return run(`xdg-open $(filename)`)
end
@static if is_windows()
@static if Sys.iswindows()
return run(`$(ENV["COMSPEC"]) /c start "" "$(filename)"`)
end
warn("Unknown OS... cannot open browser window.")
@warn("Unknown OS... cannot open browser window.")
end
function write_temp_html(plt::AbstractPlot)
+28 -21
View File
@@ -7,7 +7,7 @@ nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
compute_angle(v::P2) = (angle = atan(v[2], v[1]); angle < 0 ? 2π - angle : angle)
# -------------------------------------------------------------
@@ -58,7 +58,7 @@ end
"get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1)
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
Tuple{Float64,Float64}[(r*cos(u),r*sin(u)) for u in range(start_θ, stop=end_θ, length=n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
@@ -68,7 +68,8 @@ function weave(x,y; ordering = Vector[x,y])
while !done
for o in ordering
try
push!(ret, shift!(o))
push!(ret, popfirst!(o))
catch
end
end
done = isempty(x) && isempty(y)
@@ -296,7 +297,7 @@ function font(args...)
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
warn("Unused font arg: $arg ($(typeof(arg)))")
@warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
@@ -388,13 +389,14 @@ function stroke(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
width = arg
else
warn("Unused stroke arg: $arg ($(typeof(arg)))")
@warn("Unused stroke arg: $arg ($(typeof(arg)))")
end
end
@@ -420,13 +422,14 @@ function brush(args...; alpha = nothing)
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
catch
end
elseif allAlphas(arg)
alpha = arg
elseif allReals(arg)
size = arg
else
warn("Unused brush arg: $arg ($(typeof(arg)))")
@warn("Unused brush arg: $arg ($(typeof(arg)))")
end
end
@@ -438,16 +441,16 @@ end
mutable struct SeriesAnnotations
strs::AbstractVector # the labels/names
font::Font
baseshape::Nullable
baseshape::Union{Shape, AbstractVector{Shape}, Nothing}
scalefactor::Tuple
end
function series_annotations(strs::AbstractVector, args...)
fnt = font()
shp = Nullable{Any}()
shp = nothing
scalefactor = (1,1)
for arg in args
if isa(arg, Shape) || (isa(arg, AbstractVector) && eltype(arg) == Shape)
shp = Nullable(arg)
shp = arg
elseif isa(arg, Font)
fnt = arg
elseif isa(arg, Symbol) && haskey(_shapes, arg)
@@ -457,7 +460,7 @@ function series_annotations(strs::AbstractVector, args...)
elseif is_2tuple(arg)
scalefactor = arg
else
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
@warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
end
end
# if scalefactor != 1
@@ -468,7 +471,7 @@ function series_annotations(strs::AbstractVector, args...)
SeriesAnnotations(strs, fnt, shp, scalefactor)
end
series_annotations(anns::SeriesAnnotations) = anns
series_annotations(::Void) = nothing
series_annotations(::Nothing) = nothing
function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
anns = series[:series_annotations]
@@ -483,12 +486,13 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# end
# @show msw msh
if anns != nothing && !isnull(anns.baseshape)
if anns != nothing && anns.baseshape != nothing
# we use baseshape to overwrite the markershape attribute
# with a list of custom shapes for each
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Shape[begin
shapes = Vector{Shape}(length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs,i)
# get the width and height of the string (in mm)
@@ -506,8 +510,8 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(get(anns.baseshape),i)
shape = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end for i=1:length(anns.strs)]
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end
series[:markershape] = shapes
series[:markersize] = msize
end
@@ -519,9 +523,12 @@ mutable struct EachAnn
x
y
end
Base.start(ea::EachAnn) = 1
Base.done(ea::EachAnn, i) = ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
function Base.next(ea::EachAnn, i)
function Base.iterate(ea::EachAnn, i = 1)
if ea.anns == nothing || isempty(ea.anns.strs) || i > length(ea.y)
return nothing
end
tmp = _cycle(ea.anns.strs,i)
str,fnt = if isa(tmp, PlotText)
tmp.str, tmp.font
@@ -531,7 +538,7 @@ function Base.next(ea::EachAnn, i)
((_cycle(ea.x,i), _cycle(ea.y,i), str, fnt), i+1)
end
annotations(::Void) = []
annotations(::Nothing) = []
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
annotations(sa::SeriesAnnotations) = sa
@@ -697,7 +704,7 @@ function arrow(args...)
elseif T <: Tuple && length(arg) == 2
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
else
warn("Skipped arrow arg $arg")
@warn("Skipped arrow arg $arg")
end
end
Arrow(style, side, headlength, headwidth)
@@ -747,7 +754,7 @@ end
@deprecate curve_points coords
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
coords(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, range(range..., stop=n, length=50))
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
# may create a loop if necessary. Assumes the view is [0,1]
+17 -17
View File
@@ -72,7 +72,7 @@ is_subplot_supported(::BokehBackend) = false
function _initialize_backend(::BokehBackend; kw...)
@eval begin
warn("Bokeh is no longer supported... many features will likely be broken.")
@warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
@@ -95,9 +95,9 @@ const _glyphtypes = KW(
)
function bokeh_glyph_type(d::KW)
st = d[:seriestype]
mt = d[:markershape]
function bokeh_glyph_type(plotattributes::KW)
st = plotattributes[:seriestype]
mt = plotattributes[:markershape]
if st == :scatter && mt == :none
mt = :circle
end
@@ -125,7 +125,7 @@ end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::BokehBackend, d::KW)
# function _create_plot(pkg::BokehBackend, plotattributes::KW)
function _create_backend_figure(plt::Plot{BokehBackend})
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
@@ -142,34 +142,34 @@ function _create_backend_figure(plt::Plot{BokehBackend})
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
# Plot(bplt, pkg, 0, d, KW[])
# Plot(bplt, pkg, 0, plotattributes, KW[])
end
# function _series_added(::BokehBackend, plt::Plot, d::KW)
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{BokehBackend}, series::Series)
bdata = Dict{Symbol, Vector}(:x => collect(series.d[:x]), :y => collect(series.d[:y]))
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
glyph = Bokeh.Bokehjs.Glyph(
glyphtype = bokeh_glyph_type(d),
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
linewidth = d[:linewidth], # shape's stroke width or line width
fillcolor = webcolor(d[:markercolor]),
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
dash = get_stroke_vector(d[:linestyle])
glyphtype = bokeh_glyph_type(plotattributes),
linecolor = webcolor(plotattributes[:linecolor]), # shape's stroke or line color
linewidth = plotattributes[:linewidth], # shape's stroke width or line width
fillcolor = webcolor(plotattributes[:markercolor]),
size = ceil(Int, plotattributes[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
dash = get_stroke_vector(plotattributes[:linestyle])
)
legend = nothing # TODO
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
# push!(plt.seriesargs, d)
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot_object(plt::Plot{BokehBackend}, d::KW)
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
end
# ----------------------------------------------------------------
@@ -196,7 +196,7 @@ end
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
warn("mime png not implemented")
@warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
+110 -110
View File
@@ -51,32 +51,32 @@ end
# Base.size(v::MissingVec) = (1,)
# Base.getindex(v::MissingVec, i::Integer) = 0.0
function createGadflyPlotObject(d::KW)
function createGadflyPlotObject(plotattributes::KW)
gplt = Gadfly.Plot()
gplt.mapping = Dict()
gplt.data_source = Gadfly.DataFrames.DataFrame()
# gplt.layers = gplt.layers[1:0]
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]),
Gadfly.Guide.ylabel(d[:yguide]),
Gadfly.Guide.title(d[:title])]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(plotattributes[:xguide]),
Gadfly.Guide.ylabel(plotattributes[:yguide]),
Gadfly.Guide.title(plotattributes[:title])]
gplt
end
# ---------------------------------------------------------------------------
function getLineGeom(d::KW)
st = d[:seriestype]
xbins, ybins = maketuple(d[:bins])
function getLineGeom(plotattributes::KW)
st = plotattributes[:seriestype]
xbins, ybins = maketuple(plotattributes[:bins])
if st == :hexb
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
elseif st == :histogram2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif st == :histogram
Gadfly.Geom.histogram(bincount = xbins,
orientation = isvertical(d) ? :vertical : :horizontal,
position = d[:bar_position] == :stack ? :stack : :dodge)
orientation = isvertical(plotattributes) ? :vertical : :horizontal,
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
elseif st == :path
Gadfly.Geom.path
elseif st in (:bar, :sticks)
@@ -90,7 +90,7 @@ function getLineGeom(d::KW)
elseif st == :vline
Gadfly.Geom.vline
elseif st == :contour
Gadfly.Geom.contour(levels = d[:levels])
Gadfly.Geom.contour(levels = plotattributes[:levels])
# elseif st == :shape
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
@@ -98,11 +98,11 @@ function getLineGeom(d::KW)
end
end
function get_extra_theme_args(d::KW, k::Symbol)
function get_extra_theme_args(plotattributes::KW, k::Symbol)
# gracefully handles old Gadfly versions
extra_theme_args = KW()
try
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k])
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(plotattributes[k])
catch err
if string(err) == "UndefVarError(:get_stroke_vector)"
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
@@ -113,53 +113,53 @@ function get_extra_theme_args(d::KW, k::Symbol)
extra_theme_args
end
function getGadflyLineTheme(d::KW)
st = d[:seriestype]
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
function getGadflyLineTheme(plotattributes::KW)
st = plotattributes[:seriestype]
lc = convertColor(getColor(plotattributes[:linecolor]), plotattributes[:linealpha])
fc = convertColor(getColor(plotattributes[:fillcolor]), plotattributes[:fillalpha])
Gadfly.Theme(;
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
line_width = (st == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
line_width = (st == :sticks ? 1 : plotattributes[:linewidth]) * Gadfly.px,
# line_style = Gadfly.get_stroke_vector(plotattributes[:linestyle]),
lowlight_color = x->RGB(fc), # fill/ribbon
lowlight_opacity = alpha(fc), # fill/ribbon
bar_highlight = RGB(lc), # bars
get_extra_theme_args(d, :linestyle)...
get_extra_theme_args(plotattributes, :linestyle)...
)
end
# add a line as a new layer
function addGadflyLine!(plt::Plot, numlayers::Int, d::KW, geoms...)
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms..., getGadflyLineTheme(d))
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
kwargs = KW()
st = d[:seriestype]
st = plotattributes[:seriestype]
# add a fill?
if d[:fillrange] != nothing && st != :contour
fillmin, fillmax = map(makevec, maketuple(d[:fillrange]))
if plotattributes[:fillrange] != nothing && st != :contour
fillmin, fillmax = map(makevec, maketuple(plotattributes[:fillrange]))
nmin, nmax = length(fillmin), length(fillmax)
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
push!(gfargs, Gadfly.Geom.ribbon)
end
if st in (:hline, :vline)
kwargs[st == :hline ? :yintercept : :xintercept] = d[:y]
kwargs[st == :hline ? :yintercept : :xintercept] = plotattributes[:y]
else
if st == :sticks
w = 0.01 * mean(diff(d[:x]))
kwargs[:xmin] = d[:x] - w
kwargs[:xmax] = d[:x] + w
w = 0.01 * mean(diff(plotattributes[:x]))
kwargs[:xmin] = plotattributes[:x] - w
kwargs[:xmax] = plotattributes[:x] + w
elseif st == :contour
kwargs[:z] = d[:z].surf
addGadflyContColorScale(plt, d[:linecolor])
kwargs[:z] = plotattributes[:z].surf
addGadflyContColorScale(plt, plotattributes[:linecolor])
end
kwargs[:x] = d[st == :histogram ? :y : :x]
kwargs[:y] = d[:y]
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
kwargs[:y] = plotattributes[:y]
end
@@ -180,24 +180,24 @@ getMarkerGeom(other) = gadflyshape(get_shape(other))
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
function getMarkerGeom(d::KW)
if d[:seriestype] == :shape
function getMarkerGeom(plotattributes::KW)
if plotattributes[:seriestype] == :shape
Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
getMarkerGeom(d[:markershape])
getMarkerGeom(plotattributes[:markershape])
end
end
function getGadflyMarkerTheme(d::KW, attr::KW)
c = getColor(d[:markercolor])
α = d[:markeralpha]
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
c = getColor(plotattributes[:markercolor])
α = plotattributes[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
ms = d[:markersize]
ms = plotattributes[:markersize]
ms = if typeof(ms) <: AVec
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
mean(ms) * Gadfly.px
else
ms * Gadfly.px
@@ -206,10 +206,10 @@ function getGadflyMarkerTheme(d::KW, attr::KW)
Gadfly.Theme(;
default_color = c,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
highlight_width = d[:markerstrokewidth] * Gadfly.px,
line_width = d[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(d, :markerstrokestyle)...
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
)
end
@@ -221,30 +221,30 @@ function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d))
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
kwargs = KW()
# handle continuous color scales for the markers
zcolor = d[:marker_z]
zcolor = plotattributes[:marker_z]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, d[:markercolor])
addGadflyContColorScale(plt, plotattributes[:markercolor])
end
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
function addToGadflyLegend(plt::Plot, d::KW)
if plt.attr[:legend] != :none && d[:label] != ""
function addToGadflyLegend(plt::Plot, plotattributes::KW)
if plt.attr[:legend] != :none && plotattributes[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
end
# now add the series to the legend
@@ -254,20 +254,20 @@ function addToGadflyLegend(plt::Plot, d::KW)
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
c = getColor(plotattributes[plotattributes[:markershape] == :none ? :linecolor : :markercolor])
foundit = false
# extend the label if we found this color
for i in 1:length(guide.colors)
if RGB(c) == guide.colors[i]
guide.labels[i] *= ", " * d[:label]
guide.labels[i] *= ", " * plotattributes[:label]
foundit = true
end
end
# didn't find the color, so add a new entry into the legend
if !foundit
push!(guide.labels, d[:label])
push!(guide.labels, plotattributes[:label])
push!(guide.colors, c)
end
end
@@ -279,40 +279,40 @@ getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : A
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
function addGadflySeries!(plt::Plot, d::KW)
function addGadflySeries!(plt::Plot, plotattributes::KW)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
smooth = getGadflySmoothing(d[:smooth])
smooth = getGadflySmoothing(plotattributes[:smooth])
# lines
geom = getLineGeom(d)
geom = getLineGeom(plotattributes)
if geom != nothing
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), plotattributes, geom, smooth...))
smooth = Any[] # don't add a regression for markers too
end
# special handling for ohlc and scatter
st = d[:seriestype]
st = plotattributes[:seriestype]
# if st == :ohlc
# error("Haven't re-implemented after refactoring")
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
elseif st == :scatter && d[:markershape] == :none
d[:markershape] = :circle
if st in (:histogram2d, :hexbin) && (isa(plotattributes[:fillcolor], ColorGradient) || isa(plotattributes[:fillcolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(plotattributes[:fillcolor], p))))
elseif st == :scatter && plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
# markers
if d[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...))
if plotattributes[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
end
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
# now save the layers that apply to this series
d[:gadflylayers] = layers
plotattributes[:gadflylayers] = layers
prepend!(gplt.layers, layers)
end
@@ -322,10 +322,10 @@ end
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
# # colorgroup
# z = d[:z]
# z = plotattributes[:z]
# # handle line segments of different colors
# cscheme = d[:linecolor]
# cscheme = plotattributes[:linecolor]
# if isa(cscheme, ColorVector)
# # create a color scale, and set the color group to the index of the color
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
@@ -333,10 +333,10 @@ end
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(plotattributes[:y])]
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
# grp = collect(repeat((1:length(plotattributes[:y]))', 2, 1))[1:end-1]
# plotattributes[:x], plotattributes[:y] = map(createSegments, (plotattributes[:x], plotattributes[:y]))
# colorgroup = [(:linecolor, cs), (:group, grp)]
@@ -388,11 +388,11 @@ continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScal
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
function getGadflyScaleFunction(d::KW, isx::Bool)
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
scalekey = isx ? :xscale : :yscale
hasScaleKey = haskey(d, scalekey)
hasScaleKey = haskey(plotattributes, scalekey)
if hasScaleKey
scale = d[scalekey]
scale = plotattributes[scalekey]
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
@@ -403,15 +403,15 @@ function getGadflyScaleFunction(d::KW, isx::Bool)
end
function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
gfunc, hasScaleKey, func = getGadflyScaleFunction(d, isx)
function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
gfunc, hasScaleKey, func = getGadflyScaleFunction(plotattributes, isx)
# do we want to add min/max limits for the axis?
limsym = isx ? :xlims : :ylims
limargs = Any[]
# map :auto to nothing, otherwise add to limargs
lims = get(d, limsym, :auto)
lims = get(plotattributes, limsym, :auto)
if lims == :auto
lims = nothing
else
@@ -432,7 +432,7 @@ function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
lims, func
end
function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
if isa(gplt.coord, Gadfly.Coord.Cartesian)
gplt.coord = Gadfly.Coord.cartesian(
gplt.coord.xvars,
@@ -441,16 +441,16 @@ function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
xflip = get(d, :xflip, gplt.coord.xflip),
yflip = get(d, :yflip, gplt.coord.yflip),
xflip = get(plotattributes, :xflip, gplt.coord.xflip),
yflip = get(plotattributes, :yflip, gplt.coord.yflip),
fixed = gplt.coord.fixed,
aspect_ratio = gplt.coord.aspect_ratio,
raster = gplt.coord.raster
)
else
gplt.coord = Gadfly.Coord.Cartesian(
xflip = get(d, :xflip, false),
yflip = get(d, :yflip, false)
xflip = get(plotattributes, :xflip, false),
yflip = get(plotattributes, :yflip, false)
)
end
end
@@ -464,37 +464,37 @@ function findGuideAndSet(gplt, t::DataType, args...; kw...)
end
end
function updateGadflyGuides(plt::Plot, d::KW)
function updateGadflyGuides(plt::Plot, plotattributes::KW)
gplt = getGadflyContext(plt)
haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title]))
haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide]))
haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide]))
haskey(plotattributes, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(plotattributes[:title]))
haskey(plotattributes, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(plotattributes[:xguide]))
haskey(plotattributes, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(plotattributes[:yguide]))
xlims, xfunc = addGadflyLimitsScale(gplt, d, true)
ylims, yfunc = addGadflyLimitsScale(gplt, d, false)
xlims, xfunc = addGadflyLimitsScale(gplt, plotattributes, true)
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
ticks = get(d, :xticks, :auto)
ticks = get(plotattributes, :xticks, :auto)
if ticks == :none
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(d, :yticks, :auto)
ticks = get(plotattributes, :yticks, :auto)
if ticks == :none
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
updateGadflyAxisFlips(gplt, d, xlims, ylims, xfunc, yfunc)
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
end
function updateGadflyPlotTheme(plt::Plot, d::KW)
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
kwargs = KW()
# colors
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
map(s -> getColor(d[s]), (
map(s -> getColor(plotattributes[s]), (
:background_color_inside,
:foreground_color_grid,
:foreground_color_text,
@@ -503,17 +503,17 @@ function updateGadflyPlotTheme(plt::Plot, d::KW)
))
# # hide the legend?
leg = d[d[:legend] == :none ? :colorbar : :legend]
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(d, :grid, true)
if !get(plotattributes, :grid, true)
kwargs[:grid_color] = gridcolor
end
# fonts
tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont]
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
getGadflyContext(plt).theme = Gadfly.Theme(;
background_color = insidecolor,
@@ -568,9 +568,9 @@ end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::GadflyBackend, d::KW)
# gplt = createGadflyPlotObject(d)
# Plot(gplt, pkg, 0, d, KW[])
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
# gplt = createGadflyPlotObject(plotattributes)
# Plot(gplt, pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{GadflyBackend})
createGadflyPlotObject(plt.attr)
@@ -578,7 +578,7 @@ end
# plot one data series
# function _series_added(::GadflyBackend, plt::Plot, d::KW)
# function _series_added(::GadflyBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{GadflyBackend}, series::Series)
# first clear out the temporary layer
gplt = getGadflyContext(plt)
@@ -586,16 +586,16 @@ function _series_added(plt::Plot{GadflyBackend}, series::Series)
gplt.layers = gplt.layers[2:end]
end
addGadflySeries!(plt, series.d)
# push!(plt.seriesargs, d)
addGadflySeries!(plt, series.plotattributes)
# push!(plt.seriesargs, plotattributes)
# plt
end
function _update_plot_object(plt::Plot{GadflyBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
+16 -16
View File
@@ -18,9 +18,9 @@ function _initialize_backend(::ImmerseBackend; kw...)
end
end
function createImmerseFigure(d::KW)
w,h = d[:size]
figidx = Immerse.figure(; name = d[:window_title], width = w, height = h)
function createImmerseFigure(plotattributes::KW)
w,h = plotattributes[:size]
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
Immerse.Figure(figidx)
end
@@ -28,12 +28,12 @@ end
# create a blank Gadfly.Plot object
# function _create_plot(pkg::ImmerseBackend, d::KW)
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
# # create the underlying Gadfly.Plot object
# gplt = createGadflyPlotObject(d)
# gplt = createGadflyPlotObject(plotattributes)
#
# # save both the Immerse.Figure and the Gadfly.Plot
# Plot((nothing,gplt), pkg, 0, d, KW[])
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{ImmerseBackend})
(nothing, createGadflyPlotObject(plt.attr))
@@ -41,20 +41,20 @@ end
# # plot one data series
# function _series_added(::ImmerseBackend, plt::Plot, d::KW)
# addGadflySeries!(plt, d)
# push!(plt.seriesargs, d)
# function _series_added(::ImmerseBackend, plt::Plot, plotattributes::KW)
# addGadflySeries!(plt, plotattributes)
# push!(plt.seriesargs, plotattributes)
# plt
# end
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
addGadflySeries!(plt, series.d)
addGadflySeries!(plt, series.plotattributes)
end
function _update_plot_object(plt::Plot{ImmerseBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
@@ -94,10 +94,10 @@ end
#
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
# # create the Gtk window with vertical box vsep
# d = getattr(subplt,1)
# w,h = d[:size]
# plotattributes = getattr(subplt,1)
# w,h = plotattributes[:size]
# vsep = Gtk.GtkBoxLeaf(:v)
# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h)
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
#
# figindices = []
# row = Gtk.GtkBoxLeaf(:h)
+57 -57
View File
@@ -31,7 +31,7 @@ is_subplot_supported(::QwtBackend) = true
function _initialize_backend(::QwtBackend; kw...)
@eval begin
warn("Qwt is no longer supported... many features will likely be broken.")
@warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
@@ -52,84 +52,84 @@ const _qwtAliases = KW(
:star8 => :star2,
)
function fixcolors(d::KW)
for (k,v) in d
function fixcolors(plotattributes::KW)
for (k,v) in plotattributes
if typeof(v) <: ColorScheme
d[k] = getColor(v)
plotattributes[k] = getColor(v)
end
end
end
function replaceQwtAliases(d, s)
if haskey(_qwtAliases, d[s])
d[s] = _qwtAliases[d[s]]
function replaceQwtAliases(plotattributes, s)
if haskey(_qwtAliases, plotattributes[s])
plotattributes[s] = _qwtAliases[plotattributes[s]]
end
end
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
d = KW(kw)
st = d[:seriestype]
plotattributes = KW(kw)
st = plotattributes[:seriestype]
if st == :scatter
d[:seriestype] = :none
if d[:markershape] == :none
d[:markershape] = :circle
plotattributes[:seriestype] = :none
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
elseif st in (:hline, :vline)
addLineMarker(plt, d)
d[:seriestype] = :none
d[:markershape] = :circle
d[:markersize] = 1
addLineMarker(plt, plotattributes)
plotattributes[:seriestype] = :none
plotattributes[:markershape] = :circle
plotattributes[:markersize] = 1
if st == :vline
d[:x], d[:y] = d[:y], d[:x]
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
end
elseif !iscreating && st == :bar
d = barHack(; kw...)
plotattributes = barHack(; kw...)
elseif !iscreating && st == :histogram
d = barHack(; histogramHack(; kw...)...)
plotattributes = barHack(; histogramHack(; kw...)...)
end
replaceQwtAliases(d, :seriestype)
replaceQwtAliases(d, :markershape)
replaceQwtAliases(plotattributes, :seriestype)
replaceQwtAliases(plotattributes, :markershape)
for k in keys(d)
for k in keys(plotattributes)
if haskey(_qwtAliases, k)
d[_qwtAliases[k]] = d[k]
plotattributes[_qwtAliases[k]] = plotattributes[k]
end
end
d[:x] = collect(d[:x])
d[:y] = collect(d[:y])
plotattributes[:x] = collect(plotattributes[:x])
plotattributes[:y] = collect(plotattributes[:y])
d
plotattributes
end
# function _create_plot(pkg::QwtBackend, d::KW)
# function _create_plot(pkg::QwtBackend, plotattributes::KW)
function _create_backend_figure(plt::Plot{QwtBackend})
fixcolors(plt.attr)
dumpdict(plt.attr,"\n\n!!! plot")
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
# plt = Plot(o, pkg, 0, d, KW[])
# plt = Plot(o, pkg, 0, plotattributes, KW[])
# plt
end
# function _series_added(::QwtBackend, plt::Plot, d::KW)
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{QwtBackend}, series::Series)
d = adjustQwtKeywords(plt, false; series.d...)
fixcolors(d)
dumpdict(d,"\n\n!!! plot!")
Qwt.oplot(plt.o; d...)
# push!(plt.seriesargs, d)
plotattributes = adjustQwtKeywords(plt, false; series.plotattributes...)
fixcolors(plotattributes)
dumpdict(plotattributes,"\n\n!!! plot!")
Qwt.oplot(plt.o; plotattributes...)
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
lims = get(d, isx ? :xlims : :ylims, nothing)
ticks = get(d, isx ? :xticks : :yticks, nothing)
function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool)
lims = get(plotattributes, isx ? :xlims : :ylims, nothing)
ticks = get(plotattributes, isx ? :xticks : :yticks, nothing)
w = plt.o.widget
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
@@ -142,7 +142,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: Range
if typeof(ticks) <: AbstractRange
if isx
plt.o.autoscale_x = false
else
@@ -150,49 +150,49 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
scalesym = isx ? :xscale : :yscale
if haskey(d, scalesym)
scaletype = d[scalesym]
if haskey(plotattributes, scalesym)
scaletype = plotattributes[scalesym]
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
end
end
function _update_plot_object(plt::Plot{QwtBackend}, d::KW)
haskey(d, :title) && Qwt.title(plt.o, d[:title])
haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide])
haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide])
updateLimsAndTicks(plt, d, true)
updateLimsAndTicks(plt, d, false)
function _update_plot_object(plt::Plot{QwtBackend}, plotattributes::KW)
haskey(plotattributes, :title) && Qwt.title(plt.o, plotattributes[:title])
haskey(plotattributes, :xguide) && Qwt.xlabel(plt.o, plotattributes[:xguide])
haskey(plotattributes, :yguide) && Qwt.ylabel(plt.o, plotattributes[:yguide])
updateLimsAndTicks(plt, plotattributes, true)
updateLimsAndTicks(plt, plotattributes, false)
end
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, plotattributes::KW)
haskey(plotattributes, :size) && Qwt.resizewidget(plt.o, plotattributes[:size]...)
haskey(plotattributes, :pos) && Qwt.movewidget(plt.o, plotattributes[:pos]...)
end
# ----------------------------------------------------------------
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
for yi in d[:y]
function addLineMarker(plt::Plot{QwtBackend}, plotattributes::KW)
for yi in plotattributes[:y]
marker = Qwt.QWT.QwtPlotMarker()
ishorizontal = (d[:seriestype] == :hline)
ishorizontal = (plotattributes[:seriestype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
qcolor = Qwt.convertRGBToQColor(getColor(plotattributes[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(plotattributes[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, plotattributes[:linewidth], linestyle))
marker[:attach](plt.o.widget)
end
+41 -41
View File
@@ -34,7 +34,7 @@ is_subplot_supported(::WinstonBackend) = false
function _initialize_backend(::WinstonBackend; kw...)
@eval begin
# ENV["WINSTON_OUTPUT"] = "gtk"
warn("Winston is no longer supported... many features will likely be broken.")
@warn("Winston is no longer supported... many features will likely be broken.")
import Winston, Gtk
export Winston, Gtk
end
@@ -75,10 +75,10 @@ function _create_backend_figure(plt::Plot{WinstonBackend})
)
end
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
function addRegressionLineWinston(d::KW, wplt)
xs, ys = regressionXY(d[:x], d[:y])
function addRegressionLineWinston(plotattributes::KW, wplt)
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
end
@@ -93,22 +93,22 @@ function getWinstonItems(plt::Plot)
end
function _series_added(plt::Plot{WinstonBackend}, series::Series)
d = series.d
plotattributes = series.plotattributes
window, canvas, wplt = getWinstonItems(plt)
# until we call it normally, do the hack
if d[:seriestype] == :bar
d = barHack(;d...)
if plotattributes[:seriestype] == :bar
plotattributes = barHack(;plotattributes...)
end
e = KW()
e[:color] = getColor(d[:linecolor])
e[:linewidth] = d[:linewidth]
e[:kind] = winston_linestyle[d[:linestyle]]
e[:symbolkind] = winston_marker[d[:markershape]]
e[:color] = getColor(plotattributes[:linecolor])
e[:linewidth] = plotattributes[:linewidth]
e[:kind] = winston_linestyle[plotattributes[:linestyle]]
e[:symbolkind] = winston_marker[plotattributes[:markershape]]
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
e[:symbolsize] = d[:markersize] / 5
e[:symbolsize] = plotattributes[:markersize] / 5
# pos # (Int,Int), move the enclosing window to this position
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
@@ -116,69 +116,69 @@ function _series_added(plt::Plot{WinstonBackend}, series::Series)
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
if d[:seriestype] == :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
if plotattributes[:seriestype] == :none
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
elseif d[:seriestype] == :path
x, y = d[:x], d[:y]
elseif plotattributes[:seriestype] == :path
x, y = plotattributes[:x], plotattributes[:y]
Winston.add(wplt, Winston.Curve(x, y; e...))
fillrange = d[:fillrange]
fillrange = plotattributes[:fillrange]
if fillrange != nothing
if isa(fillrange, AbstractVector)
y2 = fillrange
else
y2 = Float64[fillrange for yi in y]
end
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(d[:fillcolor])))
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(plotattributes[:fillcolor])))
end
elseif d[:seriestype] == :scatter
if d[:markershape] == :none
d[:markershape] = :circle
elseif plotattributes[:seriestype] == :scatter
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
# elseif d[:seriestype] == :step
# elseif plotattributes[:seriestype] == :step
# fn = Winston.XXX
# elseif d[:seriestype] == :stepinverted
# elseif plotattributes[:seriestype] == :stepinverted
# fn = Winston.XXX
elseif d[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(d[:x], d[:y]; e...))
elseif plotattributes[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
# elseif d[:seriestype] == :dots
# elseif plotattributes[:seriestype] == :dots
# fn = Winston.XXX
# elseif d[:seriestype] == :histogram2d
# elseif plotattributes[:seriestype] == :histogram2d
# fn = Winston.XXX
# elseif d[:seriestype] == :hexbin
# elseif plotattributes[:seriestype] == :hexbin
# fn = Winston.XXX
elseif d[:seriestype] == :histogram
hst = hist(d[:y], d[:bins])
elseif plotattributes[:seriestype] == :histogram
hst = hist(plotattributes[:y], plotattributes[:bins])
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
# elseif d[:seriestype] == :bar
# elseif plotattributes[:seriestype] == :bar
# # fn = Winston.XXX
else
error("seriestype $(d[:seriestype]) not supported by Winston.")
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
end
# markershape
if d[:markershape] != :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
if plotattributes[:markershape] != :none
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
end
# optionally add a regression line
d[:smooth] && d[:seriestype] != :histogram && addRegressionLineWinston(d, wplt)
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
# push!(plt.seriesargs, d)
# push!(plt.seriesargs, plotattributes)
# plt
end
@@ -192,17 +192,17 @@ const _winstonNames = KW(
:yscale => :ylog,
)
function _update_plot_object(plt::Plot{WinstonBackend}, d::KW)
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xguide, :yguide, :title, :xlims, :ylims)
if haskey(d, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k])
if haskey(plotattributes, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
end
end
for k in (:xscale, :yscale)
if haskey(d, k)
islogscale = d[k] == :log10
if haskey(plotattributes, k)
islogscale = plotattributes[k] == :log10
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
end
end
+1 -1
View File
@@ -19,7 +19,7 @@
# work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
function sample_evenly(v::AVec, n::Integer = length(v))
idx = Int[round(Int, x) for x in linspace(1, length(v), n)]
idx = Int[round(Int, x) for x in range(1, stop=length(v), length=n)]
v[idx]
end
+15 -15
View File
@@ -13,15 +13,15 @@ function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(linspace(1,10,30))
log10(range(1, stop=10, length=30))
elseif scale == :log2
log2(linspace(1,2,30))
log2(range(1, stop=2, length=30))
elseif scale == :ln
log(linspace(1,pi,30))
log(range(1, stop=pi, length=30))
elseif scale in (:exp, :exp10)
(exp10(linspace(0,1,30)) - 1) / 9
(exp10(range(0, stop=1, length=30)) - 1) / 9
else
linspace(0, 1, length(colors))
range(0, stop=1, length=length(colors))
end
ColorGradient(colors, values)
end
@@ -51,7 +51,7 @@ convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
convertColor(v::Void) = RGBA(0,0,0,0)
convertColor(v::Nothing) = RGBA(0,0,0,0)
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
function convertColor(c, α::Real)
@@ -59,7 +59,7 @@ function convertColor(c, α::Real)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::Void) = convertColor(c)
convertColor(c, α::Nothing) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
@@ -113,20 +113,20 @@ struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) where S<:Real
function ColorGradient(cs::AVec, vals::AVec{S} = range(0, stop=1, length=length(cs)); alpha = nothing) where S<:Real
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
# # otherwise interpolate evenly between the minval and maxval
# minval, maxval = minimum(vals), maximum(vals)
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(linspace(0, 1, length(cs)), vals)
vals = merge(range(0, stop=1, length=length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
new(convertColor(cs, alpha), vals)
end
end
@@ -142,12 +142,12 @@ function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s]
if vals == 0:0
vals = linspace(0, 1, length(cs))
vals = range(0, stop=1, length=length(cs))
end
ColorGradient(cs, vals; kw...)
end
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
@@ -247,7 +247,7 @@ ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Color
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Void) = c.c
convertColor(c::ColorWrapper, α::Nothing) = c.c
# --------------------------------------------------------------
@@ -332,7 +332,7 @@ function generate_colorgradient(bgcolor = colorant"white";
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=linspace(0, 340, 20)
hchoices=range(0, stop=340, length=20)
)[2:end]
gradient_from_list(colors)
end
+21 -21
View File
@@ -7,22 +7,22 @@
const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
# missing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
function convertToAnyVector(v::AMat, plotattributes::KW)
if all3D(plotattributes)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
@@ -30,30 +30,30 @@ function convertToAnyVector(v::AMat, d::KW)
end
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
# dates
convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
function convertToAnyVector(v::AVec, plotattributes::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
function convertToAnyVector(args...)
@@ -65,19 +65,19 @@ end
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
compute_x(x::Nothing, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
@@ -92,8 +92,8 @@ nobigs(v) = v
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
compute_xyz(x::Nothing, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
+31 -28
View File
@@ -29,7 +29,7 @@ animation.
[:(begin
p = plot([sin,cos], zeros(0), leg=false)
anim = Animation()
for x in linspace(0, 10π, 100)
for x in range(0, stop=10π, length=100)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
@@ -52,7 +52,7 @@ the `z` argument to turn on series gradients.
[:(begin
y = rand(100)
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=0, α=0.6)
scatter!(y, zcolor=abs.(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs.(y-0.5)+4,
scatter!(y, zcolor=abs.(y.-0.5), m=(:heat,0.8,Plots.stroke(1,:green)), ms=10*abs.(y.-0.5).+4,
lab="grad")
end)]
),
@@ -66,10 +66,11 @@ the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`
`yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`
""",
[:(begin
using Statistics
y = rand(20,3)
plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2),
leg=false)
hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
hline!(mean(y, dims = 1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))
vline!([5,10])
title!("TITLE")
yaxis!("YLABEL", :log10)
@@ -85,8 +86,8 @@ yaxis!("YLABEL", :log10)
PlotExample("Images",
"Plot an image. y-axis is set to flipped",
[:(begin
import FileIO
img = FileIO.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
import FileIO, PlotReferenceImages
img = FileIO.load(joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots","pyplot","0.7.0","ref1.png"))
plot(img)
end)]
),
@@ -102,7 +103,7 @@ series.
""",
[:(begin
ys = Vector[rand(10), rand(20)]
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,stroke(3,:gray)))
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,Plots.stroke(3,:gray)))
end)]
),
@@ -145,7 +146,7 @@ styles = filter(s -> s in Plots.supported_styles(),
[:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
n = length(styles)
y = cumsum(randn(20,n),1)
y = cumsum(randn(20,n), dims = 1)
plot(y, line = (5, styles), label = map(string,styles), legendtitle = "linestyle")
end)]
),
@@ -156,8 +157,8 @@ PlotExample("Marker types",
markers = filter(m -> m in Plots.supported_markers(), Plots._shape_keys)
markers = reshape(markers, 1, length(markers))
n = length(markers)
x = linspace(0,10,n+2)[2:end-1]
y = repmat(reshape(reverse(x),1,:), n, 1)
x = range(0, stop=10, length=n+2)[2:end-1]
y = repeat(reshape(reverse(x),1,:), n, 1)
scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen, xlim=(0,10), ylim=(0,10))
end)]
),
@@ -202,7 +203,8 @@ plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbo
PlotExample("",
"",
[:(begin
srand(111)
using Random
Random.seed!(111)
plot!(Plots.fakedata(100,10))
end)]
),
@@ -215,7 +217,7 @@ subsequently create a :path series with the appropriate line segments.
""",
[:(begin
n=20
hgt=rand(n)+1
hgt=rand(n).+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
@@ -238,7 +240,7 @@ y = rand(10)
plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false)
annotate!([(5, y[5], text("this is #5",16,:red,:center)),
(10, y[10], text("this is #10",:right,20,"courier"))])
scatter!(linspace(2,8,6), rand(6), marker=(50,0.2,:orange),
scatter!(range(2, stop=8, length=6), rand(6), marker=(50,0.2,:orange),
series_annotations = ["series","annotations","map","to","series",
text("data",:green)])
end)]
@@ -254,7 +256,7 @@ verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)]
x = 0.1:0.2:0.9
y = 0.7rand(5)+0.15
y = 0.7rand(5).+0.15
plot(x, y, line = (3,:dash,:lightblue), marker = (Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue, xlim = (0,1), ylim=(0,1), leg=false)
end)]
@@ -269,8 +271,8 @@ unfilled contour from a matrix.
x = 1:0.5:20
y = 1:0.5:10
f(x,y) = (3x+y^2)*abs(sin(x)+cos(y))
X = repmat(reshape(x,1,:), length(y), 1)
Y = repmat(y, 1, length(x))
X = repeat(reshape(x,1,:), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
p1 = contour(x, y, f, fill=true)
p2 = contour(x, y, Z)
@@ -291,11 +293,11 @@ PlotExample("3D",
"",
[:(begin
n = 100
ts = linspace(0,8π,n)
ts = range(0, stop=8π, length=n)
x = ts .* map(cos,ts)
y = 0.1ts .* map(sin,ts)
z = 1:n
plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,stroke(0)), leg=false, cbar=true, w=5)
plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,Plots.stroke(0)), leg=false, cbar=true, w=5)
plot!(zeros(n),zeros(n),1:n, w=10)
end)]
),
@@ -323,7 +325,7 @@ PlotExample("Groups and Subplots",
PlotExample("Polar Plots",
"",
[:(begin
Θ = linspace(0,1.5π,100)
Θ = range(0, stop=1.5π, length=100)
r = abs.(0.1randn(100)+sin.(3Θ))
plot(Θ, r, proj=:polar, m=2)
end)]
@@ -368,7 +370,7 @@ PlotExample("Animation with subplots",
plot(log,1,xlims=(1,10π),ylims=(0,5),leg=false),layout=l)
anim = Animation()
for x = linspace(1,10π,100)
for x = range(1, stop=10π, length=100)
plot(push!(p,x,Float64[sin(x),cos(x),atan(x),cos(x),log(x)]))
frame(anim)
end
@@ -377,13 +379,14 @@ PlotExample("Animation with subplots",
PlotExample("Spy",
"""
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
various different nonzero values, a colorbar is added. The colorbar can be disabled with
`legend = nothing`.
""",
[:(begin
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
using SparseArrays
a = spdiagm(0 => ones(50), 1 => ones(49), -1 => ones(49), 10 => ones(40), -10 => ones(40))
b = spdiagm(0 => 1:50, 1 => 1:49, -1 => 1:49, 10 => 1:40, -10 => 1:40)
plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
end)]
),
@@ -411,7 +414,7 @@ attribute. The default framestyle is `:axes`.
scatter(fill(randn(10), 6), fill(randn(10), 6),
framestyle = [:box :semi :origin :zerolines :grid :none],
title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = RowVector(1:6), layout = 6, label = "", markerstrokewidth = 0,
color = permutedims(1:6), layout = 6, label = "", markerstrokewidth = 0,
ticks = -2:2)
end)]
),
@@ -419,15 +422,15 @@ attribute. The default framestyle is `:axes`.
PlotExample("Lines and markers with varying colors",
"""
You can use the `line_z` and `marker_z` properties to associate a color with
each line segment or marker in the plot.
each line segment or marker in the plot.
""",
[:(begin
t = linspace(0, 1, 100)
t = range(0, stop=1, length=100)
θ = 6π .* t
x = t .* cos.(θ)
y = t .* sin.(θ)
p1 = plot(x, y, line_z=t, linewidth=3, legend=false)
p2 = scatter(x, y, marker_z=t, color=:bluesreds, legend=false)
p2 = scatter(x, y, marker_z=(x,y)->x+y, color=:bluesreds, legend=false)
plot(p1, p2)
end)]
),
@@ -439,7 +442,7 @@ each line segment or marker in the plot.
# make and display one plot
function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
Plots._debugMode.on = debug
info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
@info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
backend(pkgname)
backend()
map(eval, _examples[idx].exprs)
+87
View File
@@ -0,0 +1,87 @@
function __init__()
if isdefined(Main, :PLOTS_DEFAULTS)
if haskey(Main.PLOTS_DEFAULTS, :theme)
theme(Main.PLOTS_DEFAULTS[:theme])
end
for (k,v) in Main.PLOTS_DEFAULTS
k == :theme || default(k, v)
end
end
pushdisplay(PlotsDisplay())
atreplinit(i -> begin
if PlotDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
pushdisplay(PlotsDisplay())
end)
include(joinpath(@__DIR__, "backends", "plotly.jl"))
include(joinpath(@__DIR__, "backends", "gr.jl"))
include(joinpath(@__DIR__, "backends", "web.jl"))
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "glvisualize.jl"))
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
@require PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" include(joinpath(@__DIR__, "backends", "plotlyjs.jl"))
@require PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" include(joinpath(@__DIR__, "backends", "pyplot.jl"))
@require UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" include(joinpath(@__DIR__, "backends", "unicodeplots.jl"))
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
@require IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
if IJulia.inited
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_extra_mime_info!(plt::Plot, out::Dict) = out
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function IJulia.display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_extra_mime_info!(plt, out)
out
end
ENV["MPLBACKEND"] = "Agg"
end
end
end
+13 -13
View File
@@ -5,8 +5,8 @@ to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm
Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
#Base.broadcast(::typeof(Base.:.*), m::Measure, n::Number) = m * n
#Base.broadcast(::typeof(Base.:.*), m::Number, n::Measure) = m * n
Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
Base.zero(::Type{typeof(mm)}) = 0mm
@@ -147,7 +147,7 @@ function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
elseif oarg in (:top, :bottom, :vcenter)
origver = oarg
else
warn("Unused origin arg in bbox construction: $oarg")
@warn("Unused origin arg in bbox construction: $oarg")
end
end
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
@@ -268,7 +268,7 @@ function GridLayout(dims...;
widths = zeros(dims[2]),
heights = zeros(dims[1]),
kw...)
grid = Matrix{AbstractLayout}(dims...)
grid = Matrix{AbstractLayout}(undef, dims...)
layout = GridLayout(
parent,
(20mm, 5mm, 2mm, 10mm),
@@ -357,10 +357,10 @@ function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0
# get the max horizontal (left and right) padding over columns,
# and max vertical (bottom and top) padding over rows
# TODO: add extra padding here
pad_left = maximum(minpad_left, 1)
pad_top = maximum(minpad_top, 2)
pad_right = maximum(minpad_right, 1)
pad_bottom = maximum(minpad_bottom, 2)
pad_left = maximum(minpad_left, dims = 1)
pad_top = maximum(minpad_top, dims = 2)
pad_right = maximum(minpad_right, dims = 1)
pad_bottom = maximum(minpad_bottom, dims = 2)
# make sure the perimeter match the parent
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
@@ -464,12 +464,12 @@ end
# constructors
# pass the layout arg through
function layout_args(d::KW)
layout_args(get(d, :layout, default(:layout)))
function layout_args(plotattributes::KW)
layout_args(get(plotattributes, :layout, default(:layout)))
end
function layout_args(d::KW, n_override::Integer)
layout, n = layout_args(get(d, :layout, n_override))
function layout_args(plotattributes::KW, n_override::Integer)
layout, n = layout_args(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
@@ -566,7 +566,7 @@ function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
plt = shift!(plts) # grab the first plot out of the list
plt = popfirst!(plts) # grab the first plot out of the list
layout[r,c] = plt.layout
append!(subplots, plt.subplots)
merge!(spmap, plt.spmap)
+27 -113
View File
@@ -145,10 +145,6 @@ function Base.display(::PlotsDisplay, plt::Plot)
_display(plt)
end
# override the REPL display to open a gui window
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
function _do_plot_show(plt, showval::Symbol)
showval == :gui && gui(plt)
@@ -172,10 +168,10 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
if output_type == :png
# info("writing png to html output")
# @info("writing png to html output")
print(io, "<img src=\"data:image/png;base64,", base64encode(show, MIME("image/png"), plt), "\" />")
elseif output_type == :svg
# info("writing svg to html output")
# @info("writing svg to html output")
show(io, MIME("image/svg+xml"), plt)
elseif output_type == :txt
show(io, MIME("text/plain"), plt)
@@ -184,13 +180,13 @@ function _show(io::IO, ::MIME"text/html", plt::Plot)
end
end
# delegate mimewritable (showable on julia 0.7) to _show instead
function Base.mimewritable(m::M, plt::P) where {M<:MIME, P<:Plot}
return method_exists(_show, Tuple{IO, M, P})
# delegate showable to _show instead
function Base.showable(m::M, plt::P) where {M<:MIME, P<:Plot}
return hasmethod(_show, Tuple{IO, M, P})
end
function _display(plt::Plot)
warn("_display is not defined for this backend.")
@warn("_display is not defined for this backend.")
end
# for writing to io streams... first prepare, then callback
@@ -198,8 +194,12 @@ for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml
"application/eps", "application/pdf", "application/postscript",
"application/x-tex")
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
prepare_output(plt)
_show(io, m, plt)
if haskey(io, :juno_plotsize)
showjuno(io, m, plt)
else
prepare_output(plt)
_show(io, m, plt)
end
end
end
@@ -230,7 +230,7 @@ if is_installed("FileIO")
FileIO.save(pngfn, s)
# now write from the file
write(io, readstring(open(pngfn)))
write(io, read(open(pngfn), String))
end
end
@@ -250,112 +250,26 @@ end
#
# html_output_format("svg")
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
@require IJulia begin
if IJulia.inited
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_extra_mime_info!(plt::Plot, out::Dict) = out
function _extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function IJulia.display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_extra_mime_info!(plt, out)
out
end
ENV["MPLBACKEND"] = "Agg"
end
end
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
@require Juno begin
import Hiccup, Media
function showjuno(io::IO, m, plt)
sz = plt[:size]
dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
if Juno.isactive()
Media.media(Plot, Media.Plot)
jsize = get(io, :juno_plotsize, [400, 500])
function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing)
end
scale = minimum(jsize[i] / sz[i] for i in 1:2)
plt[:size] = (s * scale for s in sz)
plt[:dpi] = Plots.DPI
plt[:thickness_scaling] *= scale
if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes")
function Juno.render(pane::Juno.PlotPane, plt::Plot)
# temporarily overwrite size to be Atom.plotsize
sz = plt[:size]
dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
jsize = Juno.plotsize()
jsize[1] == 0 && (jsize[1] = 400)
jsize[2] == 0 && (jsize[2] = 500)
prepare_output(plt)
_show(io, m, plt)
scale = minimum(jsize[i] / sz[i] for i in 1:2)
plt[:size] = (s * scale for s in sz)
plt[:dpi] = Plots.DPI
plt[:thickness_scaling] *= scale
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
# special handling for PlotlyJS
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})
display(Plots.PlotsDisplay(), plt)
end
else
function Juno.render(pane::Juno.PlotPane, plt::Plot)
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. Unset ENV[\"PLOTS_USE_ATOM_PLOTPANE\"] and restart Julia to enable it."
Juno.render(pane, HTML(s))
end
end
# special handling for plotly... use PlotsDisplay
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyBackend})
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
Juno.render(pane, HTML(s))
end
end
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
+72 -70
View File
@@ -7,42 +7,44 @@ function command_idx(kw_list::AVec{KW}, kw::KW)
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
end
function _expand_seriestype_array(d::KW, args)
sts = get(d, :seriestype, :path)
function _expand_seriestype_array(plotattributes::KW, args)
sts = get(plotattributes, :seriestype, :path)
if typeof(sts) <: AbstractArray
delete!(d, :seriestype)
RecipeData[begin
dc = copy(d)
delete!(plotattributes, :seriestype)
rd = Vector{RecipeData}(undef, size(sts, 1))
for r in 1:size(sts, 1)
dc = copy(plotattributes)
dc[:seriestype] = sts[r:r,:]
RecipeData(dc, args)
end for r=1:size(sts,1)]
rd[r] = RecipeData(dc, args)
end
rd
else
RecipeData[RecipeData(copy(d), args)]
RecipeData[RecipeData(copy(plotattributes), args)]
end
end
function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
function _preprocess_args(plotattributes::KW, args, still_to_process::Vector{RecipeData})
# the grouping mechanism is a recipe on a GroupBy object
# we simply add the GroupBy object to the front of the args list to allow
# the recipe to be applied
if haskey(d, :group)
args = (extractGroupArgs(d[:group], args...), args...)
if haskey(plotattributes, :group)
args = (extractGroupArgs(plotattributes[:group], args...), args...)
end
# if we were passed a vector/matrix of seriestypes and there's more than one row,
# we want to duplicate the inputs, once for each seriestype row.
if !isempty(args)
append!(still_to_process, _expand_seriestype_array(d, args))
append!(still_to_process, _expand_seriestype_array(plotattributes, args))
end
# remove subplot and axis args from d... they will be passed through in the kw_list
# remove subplot and axis args from plotattributes... they will be passed through in the kw_list
if !isempty(args)
for (k,v) in d
for (k,v) in plotattributes
for defdict in (_subplot_defaults,
_axis_defaults,
_axis_defaults_byletter)
if haskey(defdict, k)
delete!(d, k)
delete!(plotattributes, k)
end
end
end
@@ -55,9 +57,9 @@ end
# user recipes
function _process_userrecipes(plt::Plot, d::KW, args)
function _process_userrecipes(plt::Plot, plotattributes::KW, args)
still_to_process = RecipeData[]
args = _preprocess_args(d, args, still_to_process)
args = _preprocess_args(plotattributes, args, still_to_process)
# for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a stack of series that still need to be processed.
@@ -70,7 +72,7 @@ function _process_userrecipes(plt::Plot, d::KW, args)
# grab the first in line to be processed and either add it to the kw_list or
# pass it through apply_recipe to generate a list of RecipeData objects (data + attributes)
# for further processing.
next_series = shift!(still_to_process)
next_series = popfirst!(still_to_process)
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(next_series) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $next_series")
@@ -78,20 +80,20 @@ function _process_userrecipes(plt::Plot, d::KW, args)
if isempty(next_series.args)
_process_userrecipe(plt, kw_list, next_series)
else
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
rd_list = RecipesBase.apply_recipe(next_series.plotattributes, next_series.args...)
prepend!(still_to_process,rd_list)
end
end
# don't allow something else to handle it
d[:smooth] = false
plotattributes[:smooth] = false
kw_list
end
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
# when the arg tuple is empty, that means there's nothing left to recursively
# process... finish up and add to the kw_list
kw = recipedata.d
kw = recipedata.plotattributes
preprocessArgs!(kw)
_preprocess_userrecipe(kw)
warnOnUnsupported_scales(plt.backend, kw)
@@ -115,12 +117,12 @@ function _preprocess_userrecipe(kw::KW)
# map marker_z if it's a Function
if isa(get(kw, :marker_z, nothing), Function)
# TODO: should this take y and/or z as arguments?
kw[:marker_z] = map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
kw[:marker_z] = isa(kw[:z], Nothing) ? map(kw[:marker_z], kw[:x], kw[:y]) : map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
end
# map line_z if it's a Function
if isa(get(kw, :line_z, nothing), Function)
kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
kw[:line_z] = isa(kw[:z], Nothing) ? map(kw[:line_z], kw[:x], kw[:y]) : map(kw[:line_z], kw[:x], kw[:y], kw[:z])
end
# convert a ribbon into a fillrange
@@ -151,7 +153,7 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
x, y = kw[:x], kw[:y]
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
sx = [ignorenan_minimum(x), ignorenan_maximum(x)]
sy = β * sx + α
sy = β .* sx .+ α
push!(kw_list, merge(copy(kw), KW(
:seriestype => :path,
:x => sx,
@@ -181,11 +183,11 @@ function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_pr
st = kw[:seriestype] = get(_typeAliases, st, st)
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
for data in datalist
preprocessArgs!(data.d)
if data.d[:seriestype] == st
error("Plot recipe $st returned the same seriestype: $(data.d)")
preprocessArgs!(data.plotattributes)
if data.plotattributes[:seriestype] == st
error("Plot recipe $st returned the same seriestype: $(data.plotattributes)")
end
push!(still_to_process, data.d)
push!(still_to_process, data.plotattributes)
end
catch err
if isa(err, MethodError)
@@ -201,14 +203,14 @@ end
# ------------------------------------------------------------------
# setup plot and subplot
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
function _plot_setup(plt::Plot, plotattributes::KW, kw_list::Vector{KW})
# merge in anything meant for the Plot
for kw in kw_list, (k,v) in kw
haskey(_plot_defaults, k) && (d[k] = pop!(kw, k))
haskey(_plot_defaults, k) && (plotattributes[k] = pop!(kw, k))
end
# TODO: init subplots here
_update_plot_args(plt, d)
_update_plot_args(plt, plotattributes)
if !plt.init
plt.o = Base.invokelatest(_create_backend_figure, plt)
@@ -250,7 +252,7 @@ function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
plt[:inset_subplots] = nothing
end
function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
function _subplot_setup(plt::Plot, plotattributes::KW, 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.
@@ -287,8 +289,8 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# override subplot/axis args. `sp_attrs` take precendence
for (idx,sp) in enumerate(plt.subplots)
attr = if !haskey(d, :subplot) || d[:subplot] == idx
merge(d, get(sp_attrs, sp, KW()))
attr = if !haskey(plotattributes, :subplot) || plotattributes[:subplot] == idx
merge(plotattributes, get(sp_attrs, sp, KW()))
else
get(sp_attrs, sp, KW())
end
@@ -301,13 +303,13 @@ 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}, d::KW) where T
st::Symbol = d[:seriestype]
sp::Subplot{T} = d[:subplot]
function _prepare_subplot(plt::Plot{T}, plotattributes::KW) where T
st::Symbol = plotattributes[:seriestype]
sp::Subplot{T} = plotattributes[:subplot]
sp_idx = get_subplot_index(plt, sp)
_update_subplot_args(plt, sp, d, sp_idx, true)
_update_subplot_args(plt, sp, plotattributes, sp_idx, true)
st = _override_seriestype_check(d, st)
st = _override_seriestype_check(plotattributes, st)
# change to a 3d projection for this subplot?
if is3d(st)
@@ -325,28 +327,28 @@ end
# ------------------------------------------------------------------
# series types
function _override_seriestype_check(d::KW, st::Symbol)
function _override_seriestype_check(plotattributes::KW, st::Symbol)
# do we want to override the series type?
if !is3d(st) && !(st in (:contour,:contour3d))
z = d[:z]
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
z = plotattributes[:z]
if !isa(z, Nothing) && (size(plotattributes[:x]) == size(plotattributes[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d)
d[:seriestype] = st
plotattributes[:seriestype] = st
end
end
st
end
function _prepare_annotations(sp::Subplot, d::KW)
function _prepare_annotations(sp::Subplot, plotattributes::KW)
# 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])
# series_anns = annotations(pop!(d, :series_annotations, []))
# series_anns = annotations(pop!(plotattributes, :series_annotations, []))
# if isa(series_anns, SeriesAnnotations)
# series_anns.x = d[:x]
# series_anns.y = d[:y]
# series_anns.x = plotattributes[:x]
# series_anns.y = plotattributes[:y]
# elseif length(series_anns) > 0
# x, y = d[:x], d[:y]
# x, y = plotattributes[:x], plotattributes[:y]
# nx, ny, na = map(length, (x,y,series_anns))
# n = max(nx, ny, na)
# series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
@@ -354,14 +356,14 @@ function _prepare_annotations(sp::Subplot, d::KW)
# sp.attr[:annotations] = vcat(sp_anns, series_anns)
end
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
function _expand_subplot_extrema(sp::Subplot, plotattributes::KW, st::Symbol)
# adjust extrema and discrete info
if st == :image
xmin, xmax = ignorenan_extrema(d[:x]); ymin, ymax = ignorenan_extrema(d[:y])
xmin, xmax = ignorenan_extrema(plotattributes[:x]); ymin, ymax = ignorenan_extrema(plotattributes[:y])
expand_extrema!(sp[:xaxis], (xmin, xmax))
expand_extrema!(sp[:yaxis], (ymin, ymax))
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
expand_extrema!(sp, d)
expand_extrema!(sp, plotattributes)
end
# expand for zerolines (axes through origin)
if sp[:framestyle] in (:origin, :zerolines)
@@ -370,10 +372,10 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
end
end
function _add_the_series(plt, sp, d)
warnOnUnsupported_args(plt.backend, d)
warnOnUnsupported(plt.backend, d)
series = Series(d)
function _add_the_series(plt, sp, plotattributes)
warnOnUnsupported_args(plt.backend, plotattributes)
warnOnUnsupported(plt.backend, plotattributes)
series = Series(plotattributes)
push!(plt.series_list, series)
push!(sp.series_list, series)
_series_added(plt, series)
@@ -383,38 +385,38 @@ end
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
function _process_seriesrecipe(plt::Plot, d::KW)
function _process_seriesrecipe(plt::Plot, plotattributes::KW)
# replace seriestype aliases
st = Symbol(d[:seriestype])
st = d[:seriestype] = get(_typeAliases, st, st)
st = Symbol(plotattributes[:seriestype])
st = plotattributes[:seriestype] = get(_typeAliases, st, st)
# shapes shouldn't have fillrange set
if d[:seriestype] == :shape
d[:fillrange] = nothing
if plotattributes[:seriestype] == :shape
plotattributes[:fillrange] = nothing
end
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
if is_seriestype_supported(st)
sp = _prepare_subplot(plt, d)
_prepare_annotations(sp, d)
_expand_subplot_extrema(sp, d, st)
_update_series_attributes!(d, plt, sp)
_add_the_series(plt, sp, d)
sp = _prepare_subplot(plt, plotattributes)
_prepare_annotations(sp, plotattributes)
_expand_subplot_extrema(sp, plotattributes, st)
_update_series_attributes!(plotattributes, plt, sp)
_add_the_series(plt, sp, plotattributes)
else
# get a sub list of series for this seriestype
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
datalist = RecipesBase.apply_recipe(plotattributes, Val{st}, plotattributes[:x], plotattributes[:y], plotattributes[:z])
# assuming there was no error, recursively apply the series recipes
for data in datalist
if isa(data, RecipeData)
preprocessArgs!(data.d)
if data.d[:seriestype] == st
preprocessArgs!(data.plotattributes)
if data.plotattributes[:seriestype] == st
error("The seriestype didn't change in series recipe $st. This will cause a StackOverflow.")
end
_process_seriesrecipe(plt, data.d)
_process_seriesrecipe(plt, data.plotattributes)
else
warn("Unhandled recipe: $(data)")
@warn("Unhandled recipe: $(data)")
break
end
end
+38 -39
View File
@@ -1,10 +1,10 @@
mutable struct CurrentPlot
nullableplot::Nullable{AbstractPlot}
nullableplot::Union{AbstractPlot, Nothing}
end
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
const CURRENT_PLOT = CurrentPlot(nothing)
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
isplotnull() = CURRENT_PLOT.nullableplot == nothing
"""
current()
@@ -14,9 +14,9 @@ function current()
if isplotnull()
error("No current plot/subplot")
end
get(CURRENT_PLOT.nullableplot)
CURRENT_PLOT.nullableplot
end
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(plot))
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = plot)
# ---------------------------------------------------------
@@ -46,34 +46,33 @@ When you pass in matrices, it splits by columns. To see the list of available at
function, where `attr` is the symbol `:Series:`, `:Subplot:`, `:Plot` or `:Axis`. Pass any attribute to `plotattr`
as a String to look up its docstring; e.g. `plotattr("seriestype")`.
"""
# this creates a new plot with args/kw and sets it to be the current plot
function plot(args...; kw...)
d = KW(kw)
preprocessArgs!(d)
# this creates a new plot with args/kw and sets it to be the current plot
plotattributes = KW(kw)
preprocessArgs!(plotattributes)
# create an empty Plot then process
plt = Plot()
# plt.user_attr = d
_plot!(plt, d, args)
# plt.user_attr = plotattributes
_plot!(plt, plotattributes, args)
end
# build a new plot from existing plots
# note: we split into plt1 and plts_tail so we can dispatch correctly
function plot(plt1::Plot, plts_tail::Plot...; kw...)
d = KW(kw)
preprocessArgs!(d)
plotattributes = KW(kw)
preprocessArgs!(plotattributes)
# build our plot vector from the args
n = length(plts_tail) + 1
plts = Array{Plot}(n)
plts = Array{Plot}(undef, n)
plts[1] = plt1
for (i,plt) in enumerate(plts_tail)
plts[i+1] = plt
end
# compute the layout
layout = layout_args(d, n)[1]
layout = layout_args(plotattributes, n)[1]
num_sp = sum([length(p.subplots) for p in plts])
# create a new plot object, with subplot list/map made of existing subplots.
@@ -84,21 +83,21 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot
# TODO: replace this with proper processing from a merged user_attr KW
# update plot args, first with existing plots, then override with d
# update plot args, first with existing plots, then override with plotattributes
for p in plts
_update_plot_args(plt, copy(p.attr))
plt.n += p.n
end
_update_plot_args(plt, d)
_update_plot_args(plt, plotattributes)
# pass new plot to the backend
plt.o = _create_backend_figure(plt)
plt.init = true
series_attr = KW()
for (k,v) in d
for (k,v) in plotattributes
if haskey(_series_defaults, k)
series_attr[k] = pop!(d,k)
series_attr[k] = pop!(plotattributes,k)
end
end
@@ -119,8 +118,8 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
sp.plt = plt
sp.attr[:subplot_index] = idx
for series in serieslist
merge!(series.d, series_attr)
_add_defaults!(series.d, plt, sp, cmdidx)
merge!(series.plotattributes, series_attr)
_add_defaults!(series.plotattributes, plt, sp, cmdidx)
push!(plt.series_list, series)
_series_added(plt, series)
cmdidx += 1
@@ -129,12 +128,12 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# first apply any args for the subplots
for (idx,sp) in enumerate(plt.subplots)
_update_subplot_args(plt, sp, d, idx, false)
_update_subplot_args(plt, sp, plotattributes, idx, false)
end
# finish up
current(plt)
_do_plot_show(plt, get(d, :show, default(:show)))
_do_plot_show(plt, get(plotattributes, :show, default(:show)))
plt
end
@@ -153,10 +152,10 @@ end
# this adds to a specific plot... most plot commands will flow through here
function plot!(plt::Plot, args...; kw...)
d = KW(kw)
preprocessArgs!(d)
# merge!(plt.user_attr, d)
_plot!(plt, d, args)
plotattributes = KW(kw)
preprocessArgs!(plotattributes)
# merge!(plt.user_attr, plotattributes)
_plot!(plt, plotattributes, args)
end
# -------------------------------------------------------------------------------
@@ -164,21 +163,21 @@ 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, d::KW, args::Tuple)
d[:plot_object] = plt
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
plotattributes[:plot_object] = plt
if !isempty(args) && !isdefined(Main, :StatPlots) &&
first(split(string(typeof(args[1])), ".")) == "DataFrames"
warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
@warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots")
end
# --------------------------------
# "USER RECIPES"
# --------------------------------
kw_list = _process_userrecipes(plt, d, args)
kw_list = _process_userrecipes(plt, plotattributes, args)
# info(1)
# @info(1)
# map(DD, kw_list)
@@ -193,18 +192,18 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
still_to_process = kw_list
kw_list = KW[]
while !isempty(still_to_process)
next_kw = shift!(still_to_process)
next_kw = popfirst!(still_to_process)
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
end
# info(2)
# @info(2)
# map(DD, kw_list)
# --------------------------------
# Plot/Subplot/Layout setup
# --------------------------------
_plot_setup(plt, d, kw_list)
_subplot_setup(plt, d, kw_list)
_plot_setup(plt, plotattributes, kw_list)
_subplot_setup(plt, plotattributes, kw_list)
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
@@ -213,7 +212,7 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
# "SERIES RECIPES"
# --------------------------------
# info(3)
# @info(3)
# map(DD, kw_list)
for kw in kw_list
@@ -284,11 +283,11 @@ end
function plot(sp::Subplot, args...; kw...)
plt = sp.plt
plot(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
plot(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end
function plot!(sp::Subplot, args...; kw...)
plt = sp.plt
plot!(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
plot!(plt, args...; kw..., subplot = findfirst(isequal(sp), plt.subplots))
end
# --------------------------------------------------------------------
+9 -6
View File
@@ -40,23 +40,26 @@ function plotattr(attribute::AbstractString)
error("There is no attribute named $attribute")
end
printnothing(x) = x
printnothing(x::Nothing) = "nothing"
function plotattr(attrtype::Symbol, attribute::AbstractString)
in(attrtype, keys(_attribute_defaults)) || ArgumentError("`attrtype` must match one of $(attrtypes())")
attribute = Symbol(lookup_aliases(attrtype, attribute))
desc = get(_arg_desc, attribute, "")
first_period_idx = findfirst(desc, '.')
first_period_idx = findfirst(isequal('.'), desc)
typedesc = desc[1:first_period_idx-1]
desc = strip(desc[first_period_idx+1:end])
als = keys(filter((_,v)->v==attribute, _keyAliases)) |> collect |> sort
als = keys(filter(x->x[2]==attribute, _keyAliases)) |> collect |> sort
als = join(map(string,als), ", ")
def = _attribute_defaults[attrtype][attribute]
# Looks up the different elements and plots them
println("$attribute ", typedesc == "" ? "" : "{$typedesc}", "\n",
als == "" ? "" : "$als\n",
"\n$desc\n",
"$(attrtype) attribute, ", def == "" ? "" : " default: $def")
println("$(printnothing(attribute)) ", typedesc == "" ? "" : "{$(printnothing(typedesc))}", "\n",
als == "" ? "" : "$(printnothing(als))\n",
"\n$(printnothing(desc))\n",
"$(printnothing(attrtype)) attribute, ", def == "" ? "" : " default: $(printnothing(def))")
end
+58 -51
View File
@@ -47,7 +47,7 @@ end
num_series(x::AMat) = size(x,2)
num_series(x) = 1
RecipesBase.apply_recipe(d::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
RecipesBase.apply_recipe(plotattributes::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
# ---------------------------------------------------------------------------
@@ -80,7 +80,7 @@ end
@recipe function f(::Type{Val{:hline}}, x, y, z)
n = length(y)
newx = repmat(Float64[-1, 1, NaN], n)
newx = repeat(Float64[-1, 1, NaN], n)
newy = vec(Float64[yi for i=1:3,yi=y])
x := newx
y := newy
@@ -92,7 +92,7 @@ end
@recipe function f(::Type{Val{:vline}}, x, y, z)
n = length(y)
newx = vec(Float64[yi for i=1:3,yi=y])
newy = repmat(Float64[-1, 1, NaN], n)
newy = repeat(Float64[-1, 1, NaN], n)
x := newx
y := newy
seriestype := :straightline
@@ -277,14 +277,14 @@ end
fr = plotattributes[:fillrange]
newfr = fr != nothing ? zeros(0) : nothing
newz = z != nothing ? zeros(0) : nothing
# lz = d[:line_z]
# lz = plotattributes[:line_z]
# newlz = lz != nothing ? zeros(0) : nothing
# for each line segment (point series with no NaNs), convert it into a bezier curve
# where the points are the control points of the curve
for rng in iter_segments(args...)
length(rng) < 2 && continue
ts = linspace(0, 1, npoints)
ts = range(0, stop = 1, length = npoints)
nanappend!(newx, map(t -> bezier_value(_cycle(x,rng), t), ts))
nanappend!(newy, map(t -> bezier_value(_cycle(y,rng), t), ts))
if z != nothing
@@ -313,9 +313,9 @@ end
end
# if lz != nothing
# # line_z := newlz
# linecolor := (isa(d[:linecolor], ColorGradient) ? d[:linecolor] : cgrad())
# linecolor := (isa(plotattributes[:linecolor], ColorGradient) ? plotattributes[:linecolor] : cgrad())
# end
# Plots.DD(d)
# Plots.DD(plotattributes)
()
end
@deps curves path
@@ -453,16 +453,16 @@ function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:A
w_adj, baseline
end
function _preprocess_barlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
function _preprocess_barlike(plotattributes, x, y)
xscale = get(plotattributes, :xscale, :identity)
yscale = get(plotattributes, :yscale, :identity)
weights, baseline = _preprocess_binbarlike_weights(float(eltype(y)), y, yscale)
x, weights, xscale, yscale, baseline
end
function _preprocess_binlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
function _preprocess_binlike(plotattributes, x, y)
xscale = get(plotattributes, :xscale, :identity)
yscale = get(plotattributes, :yscale, :identity)
T = float(promote_type(eltype(x), eltype(y)))
edge = T.(x)
weights, baseline = _preprocess_binbarlike_weights(T, y, yscale)
@@ -498,21 +498,25 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
log_scale_x = xscale in _logScales
log_scale_y = yscale in _logScales
nbins = length(linearindices(weights))
if length(linearindices(edge)) != nbins + 1
nbins = length(eachindex(weights))
if length(eachindex(edge)) != nbins + 1
error("Edge vector must be 1 longer than weight vector")
end
x = eltype(edge)[]
y = eltype(weights)[]
it_e, it_w = start(edge), start(weights)
a, it_e = next(edge, it_e)
it_tuple_e = iterate(edge)
a, it_state_e = it_tuple_e
it_tuple_e = iterate(edge, it_state_e)
it_tuple_w = iterate(weights)
last_w = eltype(weights)(NaN)
i = 1
while (!done(edge, it_e) && !done(edge, it_e))
b, it_e = next(edge, it_e)
w, it_w = next(weights, it_w)
while it_tuple_e != nothing && it_tuple_w != nothing
b, it_state_e = it_tuple_e
w, it_state_w = it_tuple_w
if (log_scale_x && a 0)
a = b/_logScaleBases[xscale]^3
@@ -536,6 +540,9 @@ function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::S
a = b
last_w = w
it_tuple_e = iterate(edge, it_state_e)
it_tuple_w = iterate(weights, it_state_w)
end
if (last_w != baseline)
push!(x, a)
@@ -579,14 +586,14 @@ end
end
Plots.@deps stepbins path
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
wand_edges(x...) = (@warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
n_samples = length(linearindices(first(vs)))
n_samples = length(LinearIndices(first(vs)))
# The nd estimator is the key to most automatic binning methods, and is modified for twodimensional histograms to include correlation
nd = n_samples^(1/(2+N))
@@ -619,11 +626,11 @@ _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N, Any}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...,))
_hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
map(dim -> _hist_edge(vs, dim, binning), (1:N...))
map(dim -> _hist_edge(vs, dim, binning), (1:N...,))
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
@@ -774,11 +781,11 @@ end
# ---------------------------------------------------------------------------
# Error Bars
function error_style!(d::KW)
d[:seriestype] = :path
d[:linecolor] = d[:markerstrokecolor]
d[:linewidth] = d[:markerstrokewidth]
d[:label] = ""
function error_style!(plotattributes::KW)
plotattributes[:seriestype] = :path
plotattributes[:linecolor] = plotattributes[:markerstrokecolor]
plotattributes[:linewidth] = plotattributes[:markerstrokewidth]
plotattributes[:label] = ""
end
# if we're passed a tuple of vectors, convert to a vector of tuples
@@ -792,7 +799,7 @@ end
function error_coords(xorig, yorig, ebar)
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
x, y = Array{float_extended_type(xorig)}(0), Array{Float64}(0)
x, y = Array{float_extended_type(xorig)}(undef, 0), Array{Float64}(undef, 0)
# for each point, create a line segment from the bottom to the top of the errorbar
for i = 1:max(length(xorig), length(yorig))
xi = _cycle(xorig, i)
@@ -835,16 +842,16 @@ end
# ---------------------------------------------------------------------------
# quiver
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
function quiver_using_arrows(d::KW)
d[:label] = ""
d[:seriestype] = :path
if !isa(d[:arrow], Arrow)
d[:arrow] = arrow()
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
function quiver_using_arrows(plotattributes::KW)
plotattributes[:label] = ""
plotattributes[:seriestype] = :path
if !isa(plotattributes[:arrow], Arrow)
plotattributes[:arrow] = arrow()
end
velocity = error_zipit(d[:quiver])
xorig, yorig = d[:x], d[:y]
velocity = error_zipit(plotattributes[:quiver])
xorig, yorig = plotattributes[:x], plotattributes[:y]
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
x, y = zeros(0), zeros(0)
@@ -870,17 +877,17 @@ function quiver_using_arrows(d::KW)
nanappend!(y, [yi, yi+vy, NaN])
end
d[:x], d[:y] = x, y
# KW[d]
plotattributes[:x], plotattributes[:y] = x, y
# KW[plotattributes]
end
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
function quiver_using_hack(d::KW)
d[:label] = ""
d[:seriestype] = :shape
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
function quiver_using_hack(plotattributes::KW)
plotattributes[:label] = ""
plotattributes[:seriestype] = :shape
velocity = error_zipit(d[:quiver])
xorig, yorig = d[:x], d[:y]
velocity = error_zipit(plotattributes[:quiver])
xorig, yorig = plotattributes[:x], plotattributes[:y]
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
pts = P2[]
@@ -916,11 +923,11 @@ function quiver_using_hack(d::KW)
nanappend!(pts, P2[p, ppv-U1, ppv-U1+U2, ppv, ppv-U1-U2, ppv-U1])
end
d[:x], d[:y] = Plots.unzip(pts[2:end])
# KW[d]
plotattributes[:x], plotattributes[:y] = Plots.unzip(pts[2:end])
# KW[plotattributes]
end
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
# function apply_series_recipe(plotattributes::KW, ::Type{Val{:quiver}})
@recipe function f(::Type{Val{:quiver}}, x, y, z)
if :arrow in supported_attrs()
quiver_using_arrows(plotattributes)
+43 -43
View File
@@ -8,25 +8,25 @@
const FuncOrFuncs{F} = Union{F, Vector{F}, Matrix{F}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(d, :seriestype, :none))
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image, :plots_heatmap), get(plotattributes, :seriestype, :none))
# unknown
convertToAnyVector(x, d::KW) = error("No user recipe defined for $(typeof(x))")
convertToAnyVector(x, plotattributes::KW) = error("No user recipe defined for $(typeof(x))")
# missing
convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
function convertToAnyVector(v::AMat, plotattributes::KW)
if all3D(plotattributes)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
@@ -34,33 +34,33 @@ function convertToAnyVector(v::AMat, d::KW)
end
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
# volume
convertToAnyVector(v::Volume, d::KW) = Any[v], nothing
convertToAnyVector(v::Volume, plotattributes::KW) = Any[v], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
# # dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
function convertToAnyVector(v::AVec, plotattributes::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
vcat(Any[convertToAnyVector(vi, plotattributes)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
function convertToAnyVector(args...)
@@ -72,19 +72,19 @@ end
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Nothing, y::Nothing, z) = 1:size(z,1)
compute_x(x::Nothing, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x::Nothing, y::Nothing, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
@@ -99,9 +99,9 @@ nobigs(v) = v
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
compute_xyz(x::Nothing, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
@@ -180,14 +180,14 @@ end
# this should catch unhandled "series recipes" and error with a nice message
@recipe f(::Type{V}, x, y, z) where {V<:Val} = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
_apply_type_recipe(plotattributes, v) = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1]
# Handle type recipes when the recipe is defined on the elements.
# This sort of recipe should return a pair of functions... one to convert to number,
# and one to format tick values.
function _apply_type_recipe(d, v::AbstractArray)
function _apply_type_recipe(plotattributes, v::AbstractArray)
isempty(v) && return Float64[]
args = RecipesBase.apply_recipe(d, typeof(v[1]), v[1])[1].args
args = RecipesBase.apply_recipe(plotattributes, typeof(v[1]), v[1])[1].args
if length(args) == 2 && typeof(args[1]) <: Function && typeof(args[2]) <: Function
numfunc, formatter = args
Formatted(map(numfunc, v), formatter)
@@ -197,13 +197,13 @@ function _apply_type_recipe(d, v::AbstractArray)
end
# # special handling for Surface... need to properly unwrap and re-wrap
# function _apply_type_recipe(d, v::Surface)
# function _apply_type_recipe(plotattributes, v::Surface)
# T = eltype(v.surf)
# @show T
# if T <: Integer || T <: AbstractFloat
# v
# else
# ret = _apply_type_recipe(d, v.surf)
# ret = _apply_type_recipe(plotattributes, v.surf)
# if typeof(ret) <: Formatted
# Formatted(Surface(ret.data), ret.formatter)
# else
@@ -213,7 +213,7 @@ end
# end
# don't do anything for ints or floats
_apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
_apply_type_recipe(plotattributes, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
@@ -274,11 +274,11 @@ end
# # --------------------------------------------------------------------
# helper function to ensure relevant attributes are wrapped by Surface
function wrap_surfaces(d::KW)
if haskey(d, :fill_z)
v = d[:fill_z]
function wrap_surfaces(plotattributes::KW)
if haskey(plotattributes, :fill_z)
v = plotattributes[:fill_z]
if !isa(v, Surface)
d[:fill_z] = Surface(v)
plotattributes[:fill_z] = Surface(v)
end
end
end
@@ -428,17 +428,17 @@ end
# # 3d line or scatter
@recipe function f(x::AVec, y::AVec, z::AVec)
# st = get(d, :seriestype, :none)
# st = get(plotattributes, :seriestype, :none)
# if st == :scatter
# d[:seriestype] = :scatter3d
# plotattributes[:seriestype] = :scatter3d
# elseif !is3d(st)
# d[:seriestype] = :path3d
# plotattributes[:seriestype] = :path3d
# end
SliceIt, x, y, z
end
@recipe function f(x::AMat, y::AMat, z::AMat)
# st = get(d, :seriestype, :none)
# st = get(plotattributes, :seriestype, :none)
# if size(x) == size(y) == size(z)
# if !is3d(st)
# seriestype := :path3d
@@ -518,7 +518,7 @@ end
xs, fs
end
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, linspace(umin, umax, n)
@recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, range(umin, stop = umax, length = n)
#
# # special handling... 3D parametric function(s)
@@ -526,7 +526,7 @@ end
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
fx, fy, fz, linspace(umin, umax, numPoints)
fx, fy, fz, range(umin, stop = umax, length = numPoints)
end
#
@@ -573,7 +573,7 @@ end
# # create a new series, with the label of the group, and an idxfilter (to be applied in slice_and_dice)
# # TODO: use @series instead
# @show i, glab, groupby.groupIds[i]
# di = copy(d)
# di = copy(plotattributes)
# get!(di, :label, string(glab))
# get!(di, :idxfilter, groupby.groupIds[i])
# push!(series_list, RecipeData(di, args))
@@ -594,12 +594,12 @@ function split_kw(key, val::SeriesAnnotations, indices)
end
function groupedvec2mat(x_ind, x, y::AbstractArray, groupby, def_val = y[1])
y_mat = Array{promote_type(eltype(y), typeof(def_val))}(length(keys(x_ind)), length(groupby.groupLabels))
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)
xi = x[groupby.groupIds[i]]
yi = y[groupby.groupIds[i]]
y_mat[getindex.(x_ind, xi), i] = yi
y_mat[getindex.(Ref(x_ind), xi), i] = yi
end
return y_mat
end
@@ -636,7 +636,7 @@ group_as_matrix(t) = false
x = g.args[1]
last_args = g.args[2:end]
end
x_u = unique(x)
x_u = unique(sort(x))
x_ind = Dict(zip(x_u, 1:length(x_u)))
for (key,val) in plotattributes
if splittable_kw(key, val, lengthGroup)
+4 -4
View File
@@ -34,16 +34,16 @@ bottompad(sp::Subplot) = sp.minpad[4]
get_subplot(plt::Plot, sp::Subplot) = sp
get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
get_subplot(plt::Plot, k) = plt.spmap[k]
get_subplot(series::Series) = series.d[:subplot]
get_subplot(series::Series) = series.plotattributes[:subplot]
get_subplot_index(plt::Plot, idx::Integer) = Int(idx)
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(x -> x === sp, plt.subplots)
series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
series_list(sp::Subplot) = sp.series_list # filter(series -> series.plotattributes[:subplot] === sp, sp.plt.series_list)
function should_add_to_legend(series::Series)
series.d[:primary] && series.d[:label] != "" &&
!(series.d[:seriestype] in (
series.plotattributes[:primary] && series.plotattributes[:label] != "" &&
!(series.plotattributes[:seriestype] in (
:hexbin,:bins2d,:histogram2d,:hline,:vline,
:contour,:contourf,:contour3d,:surface,:wireframe,
:heatmap, :pie, :image
+4 -4
View File
@@ -10,7 +10,7 @@ end
function _get_defaults(s::Symbol)
thm = PlotThemes._themes[s]
if :defaults in fieldnames(thm)
if :defaults in fieldnames(typeof(thm))
return thm.defaults
else # old PlotTheme type
defaults = KW(
@@ -93,7 +93,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
cfunc(RGB(def))
elseif eltype(def) <: Colorant
cfunc.(RGB.(def))
elseif contains(string(arg), "color")
elseif occursin("color", string(arg))
cfunc.(RGB.(plot_color.(def)))
else
def
@@ -132,7 +132,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
f(r) = sin(r) / r
_norm(x, y) = norm([x, y])
x = y = linspace(-3π, 3π, 30)
x = y = range(-3π, stop = 3π, length = 30)
z = f.(_norm.(x, y'))
wi = 2:3:30
@@ -152,7 +152,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
end
n = 100
ts = linspace(0, 10π, n)
ts = range(0, stop = 10π, length = n)
x = ts .* cos.(ts)
y = (0.1ts) .* sin.(ts)
z = 1:n
+8 -7
View File
@@ -5,8 +5,9 @@
const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
const TicksArgs = Union{AVec{T}, Tuple{AVec{T}, AVec{S}}, Symbol} where {T<:Real, S<:AbstractString}
struct PlotsDisplay <: Display end
struct PlotsDisplay <: AbstractDisplay end
# -----------------------------------------------------------
@@ -20,11 +21,11 @@ Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
mutable struct Series
d::KW
plotattributes::KW
end
attr(series::Series, k::Symbol) = series.d[k]
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
attr(series::Series, k::Symbol) = series.plotattributes[k]
attr!(series::Series, v, k::Symbol) = (series.plotattributes[k] = v)
# -----------------------------------------------------------
@@ -47,7 +48,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}
d::KW
plotattributes::KW
end
mutable struct Extrema
@@ -87,7 +88,7 @@ end
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
Base.length(plt::Plot) = length(plt.subplots)
Base.endof(plt::Plot) = length(plt)
Base.lastindex(plt::Plot) = length(plt)
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
Base.size(plt::Plot) = size(plt.layout)
@@ -98,6 +99,6 @@ Base.ndims(plt::Plot) = 2
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
Base.endof(sp::Subplot) = length(series_list(sp))
Base.lastindex(sp::Subplot) = length(series_list(sp))
# -----------------------------------------------------------------------
+118 -132
View File
@@ -4,7 +4,7 @@ calcMidpoints(edges::AbstractVector) = Float64[0.5 * (edges[i] + edges[i+1]) for
"Make histogram-like bins of data"
function binData(data, nbins)
lo, hi = ignorenan_extrema(data)
edges = collect(linspace(lo, hi, nbins+1))
edges = collect(range(lo, stop=hi, length=nbins+1))
midpoints = calcMidpoints(edges)
buckets = Int[max(2, min(searchsortedfirst(edges, x), length(edges)))-1 for x in data]
counts = zeros(Int, length(midpoints))
@@ -19,15 +19,15 @@ A hacky replacement for a histogram when the backend doesn't support histograms
Convert it into a bar chart with the appropriate x/y values.
"""
function histogramHack(; kw...)
d = KW(kw)
plotattributes = KW(kw)
# we assume that the y kwarg is set with the data to be binned, and nbins is also defined
edges, midpoints, buckets, counts = binData(d[:y], d[:bins])
d[:x] = midpoints
d[:y] = float(counts)
d[:seriestype] = :bar
d[:fillrange] = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
d
edges, midpoints, buckets, counts = binData(plotattributes[:y], plotattributes[:bins])
plotattributes[:x] = midpoints
plotattributes[:y] = float(counts)
plotattributes[:seriestype] = :bar
plotattributes[:fillrange] = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange]
plotattributes
end
"""
@@ -35,10 +35,10 @@ A hacky replacement for a bar graph when the backend doesn't support bars direct
Convert it into a line chart with fillrange set.
"""
function barHack(; kw...)
d = KW(kw)
midpoints = d[:x]
heights = d[:y]
fillrange = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
plotattributes = KW(kw)
midpoints = plotattributes[:x]
heights = plotattributes[:y]
fillrange = plotattributes[:fillrange] == nothing ? 0.0 : plotattributes[:fillrange]
# estimate the edges
dists = diff(midpoints) * 0.5
@@ -62,11 +62,11 @@ function barHack(; kw...)
append!(y, [fillrange, heights[i], heights[i], fillrange])
end
d[:x] = x
d[:y] = y
d[:seriestype] = :path
d[:fillrange] = fillrange
d
plotattributes[:x] = x
plotattributes[:y] = y
plotattributes[:seriestype] = :path
plotattributes[:fillrange] = fillrange
plotattributes
end
@@ -75,33 +75,33 @@ A hacky replacement for a sticks graph when the backend doesn't support sticks d
Convert it into a line chart that traces the sticks, and a scatter that sets markers at the points.
"""
function sticksHack(; kw...)
dLine = KW(kw)
dScatter = copy(dLine)
plotattributesLine = KW(kw)
plotattributesScatter = copy(plotattributesLine)
# these are the line vertices
x = Float64[]
y = Float64[]
fillrange = dLine[:fillrange] == nothing ? 0.0 : dLine[:fillrange]
fillrange = plotattributesLine[:fillrange] == nothing ? 0.0 : plotattributesLine[:fillrange]
# calculate the vertices
yScatter = dScatter[:y]
for (i,xi) in enumerate(dScatter[:x])
yScatter = plotattributesScatter[:y]
for (i,xi) in enumerate(plotattributesScatter[:x])
yi = yScatter[i]
for j in 1:3 push!(x, xi) end
append!(y, [fillrange, yScatter[i], fillrange])
end
# change the line args
dLine[:x] = x
dLine[:y] = y
dLine[:seriestype] = :path
dLine[:markershape] = :none
dLine[:fillrange] = nothing
plotattributesLine[:x] = x
plotattributesLine[:y] = y
plotattributesLine[:seriestype] = :path
plotattributesLine[:markershape] = :none
plotattributesLine[:fillrange] = nothing
# change the scatter args
dScatter[:seriestype] = :none
plotattributesScatter[:seriestype] = :none
dLine, dScatter
plotattributesLine, plotattributesScatter
end
function regressionXY(x, y)
@@ -119,7 +119,7 @@ function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
n, m = size(z)
# idx = 0
colors = ColorGradient(vec(z))
newz = reshape(linspace(0, 1, n*m), n, m)
newz = reshape(range(0, stop=1, length=n*m), n, m)
newz, colors
# newz = zeros(n, m)
# for i=1:n, j=1:m
@@ -130,10 +130,10 @@ function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
# newz, ColorGradient(colors)
end
function imageHack(d::KW)
function imageHack(plotattributes::KW)
is_seriestype_supported(:heatmap) || error("Neither :image or :heatmap are supported!")
d[:seriestype] = :heatmap
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
plotattributes[:seriestype] = :heatmap
plotattributes[:z], plotattributes[:fillcolor] = replace_image_with_heatmap(plotattributes[:z].surf)
end
# ---------------------------------------------------------------
@@ -215,15 +215,12 @@ anynan(i::Int, args::Tuple) = any(a -> try isnan(_cycle(a,i)) catch MethodError
anynan(istart::Int, iend::Int, args::Tuple) = any(i -> anynan(i, args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(i -> anynan(i, args), istart:iend)
function Base.start(itr::SegmentsIterator)
nextidx = 1
if !any(isempty,itr.args) && anynan(1, itr.args)
_, nextidx = next(itr, 1)
function Base.iterate(itr::SegmentsIterator, nextidx::Int = 1)
nextidx > itr.n && return nothing
if nextidx == 1 && !any(isempty,itr.args) && anynan(1, itr.args)
nextidx = 2
end
nextidx
end
Base.done(itr::SegmentsIterator, nextidx::Int) = nextidx > itr.n
function Base.next(itr::SegmentsIterator, nextidx::Int)
i = istart = iend = nextidx
# find the next NaN, and iend is the one before
@@ -259,7 +256,7 @@ float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64
nop() = nothing
notimpl() = error("This has not been implemented yet")
isnothing(x::Void) = true
isnothing(x::Nothing) = true
isnothing(x) = false
_cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
@@ -306,7 +303,8 @@ function _expand_limits(lims, x)
lims[1] = NaNMath.min(lims[1], e1)
lims[2] = NaNMath.max(lims[2], e2)
# catch err
# warn(err)
# @warn(err)
catch
end
nothing
end
@@ -330,32 +328,32 @@ function replaceType(vec, val)
push!(vec, val)
end
function replaceAlias!(d::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
function replaceAlias!(plotattributes::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
if haskey(aliases, k)
d[aliases[k]] = pop!(d, k)
plotattributes[aliases[k]] = pop!(plotattributes, k)
end
end
function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
ks = collect(keys(d))
function replaceAliases!(plotattributes::KW, aliases::Dict{Symbol,Symbol})
ks = collect(keys(plotattributes))
for k in ks
replaceAlias!(d, k, aliases)
replaceAlias!(plotattributes, k, aliases)
end
end
createSegments(z) = collect(repmat(reshape(z,1,:),2,1))[2:end]
createSegments(z) = collect(repeat(reshape(z,1,:),2,1))[2:end]
Base.first(c::Colorant) = c
Base.first(x::Symbol) = x
sortedkeys(d::Dict) = sort(collect(keys(d)))
sortedkeys(plotattributes::Dict) = sort(collect(keys(plotattributes)))
const _scale_base = Dict{Symbol, Real}(
:log10 => 10,
:log2 => 2,
:ln => e,
:ln => ,
)
function _heatmap_edges(v::AVec)
@@ -381,7 +379,7 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
theta, r = filter_radial_data(x, y, r_extrema)
r = (r - rmin) / (rmax - rmin)
r = (r .- rmin) ./ (rmax .- rmin)
x = r.*cos.(theta)
y = r.*sin.(theta)
x, y
@@ -411,8 +409,8 @@ function fakedata(sz...)
y
end
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
function is_installed(pkgstr::AbstractString)
try
@@ -434,8 +432,8 @@ isscalar(::Any) = false
is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2
isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.d)
isvertical(plotattributes::KW) = get(plotattributes, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.plotattributes)
ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
@@ -450,8 +448,8 @@ limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert(::Type{Vector{T}}, rng::Range{T}) where {T<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::Range{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::AbstractRange{T}) where {T<:Real} = T[x for x in rng]
Base.convert(::Type{Vector{T}}, rng::AbstractRange{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
@@ -494,8 +492,8 @@ end
# this is a helper function to determine whether we need to transpose a surface matrix.
# it depends on whether the backend matches rows to x (transpose_on_match == true) or vice versa
# for example: PyPlot sends rows to y, so transpose_on_match should be true
function transpose_z(d, z, transpose_on_match::Bool = true)
if d[:match_dimensions] == transpose_on_match
function transpose_z(plotattributes, z, transpose_on_match::Bool = true)
if plotattributes[:match_dimensions] == transpose_on_match
# z'
permutedims(z, [2,1])
else
@@ -619,20 +617,40 @@ function hascolorbar(sp::Subplot)
hascbar
end
function get_linecolor(series, i::Int = 1)
lc = series[:linecolor]
lz = series[:line_z]
if lz == nothing
isa(lc, ColorGradient) ? lc : plot_color(_cycle(lc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(lc, ColorGradient) ? lc : cgrad()
grad[clamp((_cycle(lz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
for comp in (:line, :fill, :marker)
function get_linealpha(series, i::Int = 1)
_cycle(series[:linealpha], i)
compcolor = string(comp, :color)
get_compcolor = Symbol(:get_, compcolor)
comp_z = string(comp, :_z)
compalpha = string(comp, :alpha)
get_compalpha = Symbol(:get_, compalpha)
@eval begin
function $get_compcolor(series, cmin::Real, cmax::Real, i::Int = 1)
c = series[$Symbol($compcolor)]
z = series[$Symbol($comp_z)]
if z == nothing
isa(c, ColorGradient) ? c : plot_color(_cycle(c, i))
else
grad = isa(c, ColorGradient) ? c : cgrad()
grad[clamp((_cycle(z, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
$get_compcolor(series, clims, i::Int = 1) = $get_compcolor(series, clims[1], clims[2], i)
function $get_compcolor(series, i::Int = 1)
if series[$Symbol($comp_z)] == nothing
$get_compcolor(series, 0, 1, i)
else
$get_compcolor(series, get_clims(series[:subplot]), i)
end
end
$get_compalpha(series, i::Int = 1) = _cycle(series[$Symbol($compalpha)], i)
end
end
function get_linewidth(series, i::Int = 1)
@@ -643,38 +661,6 @@ function get_linestyle(series, i::Int = 1)
_cycle(series[:linestyle], i)
end
function get_fillcolor(series, i::Int = 1)
fc = series[:fillcolor]
fz = series[:fill_z]
if fz == nothing
isa(fc, ColorGradient) ? fc : plot_color(_cycle(fc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(fc, ColorGradient) ? fc : cgrad()
grad[clamp((_cycle(fz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_fillalpha(series, i::Int = 1)
_cycle(series[:fillalpha], i)
end
function get_markercolor(series, i::Int = 1)
mc = series[:markercolor]
mz = series[:marker_z]
if mz == nothing
isa(mc, ColorGradient) ? mc : plot_color(_cycle(mc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(mc, ColorGradient) ? mc : cgrad()
grad[clamp((_cycle(mz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_markeralpha(series, i::Int = 1)
_cycle(series[:markeralpha], i)
end
function get_markerstrokecolor(series, i::Int = 1)
msc = series[:markerstrokecolor]
isa(msc, ColorGradient) ? msc : _cycle(msc, i)
@@ -820,20 +806,20 @@ end
debugshow(x) = show(x)
debugshow(x::AbstractArray) = print(summary(x))
function dumpdict(d::KW, prefix = "", alwaysshow = false)
function dumpdict(plotattributes::KW, prefix = "", alwaysshow = false)
_debugMode.on || alwaysshow || return
println()
if prefix != ""
println(prefix, ":")
end
for k in sort(collect(keys(d)))
for k in sort(collect(keys(plotattributes)))
@printf("%14s: ", k)
debugshow(d[k])
debugshow(plotattributes[k])
println()
end
println()
end
DD(d::KW, prefix = "") = dumpdict(d, prefix, true)
DD(plotattributes::KW, prefix = "") = dumpdict(plotattributes, prefix, true)
function dumpcallstack()
@@ -846,8 +832,8 @@ end
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + ignorenan_maximum(v))
extendSeriesData(v::Range{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::Range{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AbstractRange{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AbstractRange{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData(v::AVec{T}, z::Real) where {T} = (push!(v, convert(T, z)); v)
extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Vector{T}, z)); v)
@@ -856,28 +842,28 @@ extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Ve
# NOTE: backends should implement the following methods to get/set the x/y/z data objects
tovec(v::AbstractVector) = v
tovec(v::Void) = zeros(0)
tovec(v::Nothing) = zeros(0)
function getxy(plt::Plot, i::Integer)
d = plt.series_list[i].d
tovec(d[:x]), tovec(d[:y])
plotattributes = plt.series_list[i].plotattributes
tovec(plotattributes[:x]), tovec(plotattributes[:y])
end
function getxyz(plt::Plot, i::Integer)
d = plt.series_list[i].d
tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
plotattributes = plt.series_list[i].plotattributes
tovec(plotattributes[:x]), tovec(plotattributes[:y]), tovec(plotattributes[:z])
end
function setxy!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.series_list[i]
series.d[:x], series.d[:y] = xy
sp = series.d[:subplot]
series.plotattributes[:x], series.plotattributes[:y] = xy
sp = series.plotattributes[:subplot]
reset_extrema!(sp)
_series_updated(plt, series)
end
function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z}
series = plt.series_list[i]
series.d[:x], series.d[:y], series.d[:z] = xyz
sp = series.d[:subplot]
series.plotattributes[:x], series.plotattributes[:y], series.plotattributes[:z] = xyz
sp = series.plotattributes[:subplot]
reset_extrema!(sp)
_series_updated(plt, series)
end
@@ -926,13 +912,13 @@ Base.push!(series::Series, xi, yi, zi) = (push_x!(series,xi); push_y!(series,yi)
# -------------------------------------------------------
function attr!(series::Series; kw...)
d = KW(kw)
preprocessArgs!(d)
for (k,v) in d
plotattributes = KW(kw)
preprocessArgs!(plotattributes)
for (k,v) in plotattributes
if haskey(_series_defaults, k)
series[k] = v
else
warn("unused key $k in series attr")
@warn("unused key $k in series attr")
end
end
_series_updated(series[:subplot].plt, series)
@@ -940,13 +926,13 @@ function attr!(series::Series; kw...)
end
function attr!(sp::Subplot; kw...)
d = KW(kw)
preprocessArgs!(d)
for (k,v) in d
plotattributes = KW(kw)
preprocessArgs!(plotattributes)
for (k,v) in plotattributes
if haskey(_subplot_defaults, k)
sp[k] = v
else
warn("unused key $k in subplot attr")
@warn("unused key $k in subplot attr")
end
end
sp
@@ -1071,9 +1057,9 @@ mm2px(mm::Real) = float(px / MM_PER_PX)
"Smallest x in plot"
xmin(plt::Plot) = ignorenan_minimum([ignorenan_minimum(series.d[:x]) for series in plt.series_list])
xmin(plt::Plot) = ignorenan_minimum([ignorenan_minimum(series.plotattributes[:x]) for series in plt.series_list])
"Largest x in plot"
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series in plt.series_list])
xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.plotattributes[:x]) for series in plt.series_list])
"Extrema of x-values in plot"
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
@@ -1138,9 +1124,9 @@ function convert_sci_unicode(label::AbstractString)
"×10" => "×10^{",
)
for key in keys(unicode_dict)
label = replace(label, key, unicode_dict[key])
label = replace(label, key => unicode_dict[key])
end
if contains(label, "10^{")
if occursin("10^{", label)
label = string(label, "}")
end
label
+2
View File
@@ -2,7 +2,9 @@ StatPlots
Images
ImageMagick
@osx QuartzImageIO
FileIO
GR 0.31.0
RDatasets
VisualRegressionTests
UnicodePlots
LaTeXStrings
+35
View File
@@ -0,0 +1,35 @@
using Pkg
# need this to use Conda
# ENV["PYTHON"] = ""
to_add = [
PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"),
# PackageSpec(url="https://github.com/JuliaStats/KernelDensity.jl.git"),
PackageSpec(name="PlotUtils", rev="master"),
PackageSpec(name="RecipesBase", rev="master"),
# PackageSpec(name="Blink", rev="master"),
# PackageSpec(name="Rsvg", rev="master"),
# PackageSpec(name="PlotlyJS", rev="master"),
# PackageSpec(name="VisualRegressionTests", rev="master"),
# PackageSpec("PyPlot"),
# PackageSpec("InspectDR"),
]
if isinteractive()
append!(to_add, [
PackageSpec(name="FileIO"),
PackageSpec(name="ImageMagick"),
PackageSpec(name="UnicodePlots"),
PackageSpec(name="VisualRegressionTests"),
])
end
Pkg.add(to_add)
Pkg.build("ImageMagick")
# Pkg.build("GR")
# Pkg.build("Blink")
# import Blink
# Blink.AtomShell.install()
# Pkg.build("PyPlot")
+21 -15
View File
@@ -2,20 +2,26 @@
using VisualRegressionTests
# using ExamplePlots
import DataFrames, RDatasets
if isinteractive()
@eval Main import Gtk
end
# import DataFrames, RDatasets
# don't let pyplot use a gui... it'll crash
# note: Agg will set gui -> :none in PyPlot
ENV["MPLBACKEND"] = "Agg"
try
@eval import PyPlot
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
end
# ENV["MPLBACKEND"] = "Agg"
# try
# @eval import PyPlot
# @info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
# end
using Plots
using StatPlots
using Base.Test
# using StatPlots
import PlotReferenceImages
using Random
using Test
default(size=(500,300))
@@ -26,19 +32,19 @@ default(size=(500,300))
const _current_plots_version = v"0.17.4"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
Plots._debugMode.on = debug
example = Plots._examples[idx]
info("Testing plot: $pkg:$idx:$(example.header)")
@info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg)
backend()
# ensure consistent results
srand(1234)
Random.seed!(1234)
# reference image directory setup
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
refdir = Pkg.dir("PlotReferenceImages", "Plots", string(pkg))
refdir = joinpath(dirname(pathof(PlotReferenceImages)), "..", "Plots", string(pkg))
fn = "ref$idx.png"
# firgure out version info
@@ -83,7 +89,7 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
# the test
vtest = VisualTest(func, reffn, idx)
test_images(vtest, popup=popup, sigma=sigma, eps=eps, newfn = newfn)
test_images(vtest, popup=popup, sigma=sigma, tol=tol, newfn = newfn)
end
function image_comparison_facts(pkg::Symbol;
@@ -91,11 +97,11 @@ function image_comparison_facts(pkg::Symbol;
only = nothing, # limit to these examples (int index)
debug = false, # print debug information?
sigma = [1,1], # number of pixels to "blur"
eps = 1e-2) # acceptable error (percent)
tol = 1e-2) # acceptable error (percent)
for i in 1:length(Plots._examples)
i in skip && continue
if only == nothing || i in only
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success == true
@test image_comparison_tests(pkg, i, debug=debug, sigma=sigma, tol=tol) |> success == true
end
end
end
+12 -11
View File
@@ -1,11 +1,12 @@
module PlotsTests
include("add_packages.jl")
include("imgcomp.jl")
# don't actually show the plots
srand(1234)
Random.seed!(1234)
default(show=false, reuse=true)
img_eps = isinteractive() ? 1e-2 : 10e-2
img_tol = isinteractive() ? 1e-2 : 10e-2
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
@@ -13,7 +14,7 @@ img_eps = isinteractive() ? 1e-2 : 10e-2
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
image_comparison_facts(:gr, eps=img_eps)
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
end
@@ -21,7 +22,7 @@ end
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
#
# image_comparison_facts(:pyplot, eps=img_eps)
# image_comparison_facts(:pyplot, tol=img_tol)
#end
@testset "UnicodePlots" begin
@@ -39,14 +40,14 @@ end
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if is_linux() && isinteractive()
# if Sys.islinux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
# 27, # (polar plots) takes very long / not working
# 31, # animation (skipped for speed)
# ],
# eps=img_eps)
# tol=img_tol)
# end
# end
@@ -70,7 +71,7 @@ end
# 28, # heatmap not defined
# 31, # animation
# ],
# eps=img_eps)
# tol=img_tol)
# end
@@ -79,7 +80,7 @@ end
# @test backend() == Plots.PlotlyBackend()
#
# # # until png generation is reliable on OSX, just test on linux
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
# end
@@ -88,7 +89,7 @@ end
# @test backend() == Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
# image_comparison_facts(:immerse, only=[1], tol=img_tol)
# end
@@ -97,7 +98,7 @@ end
# @test backend() == Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
# image_comparison_facts(:plotlyjs, only=[1], tol=img_tol)
# end
@@ -110,7 +111,7 @@ end
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], tol=img_tol)
# end
-31
View File
@@ -1,31 +0,0 @@
Pkg.add("ImageMagick")
Pkg.build("ImageMagick")
# Pkg.clone("GR")
# Pkg.build("GR")
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
# Pkg.clone("https://github.com/JuliaStats/KernelDensity.jl.git")
Pkg.clone("StatPlots")
# Pkg.checkout("PlotUtils")
# Pkg.clone("Blink")
# Pkg.build("Blink")
# import Blink
# Blink.AtomShell.install()
# Pkg.add("Rsvg")
# Pkg.add("PlotlyJS")
# Pkg.checkout("RecipesBase")
# Pkg.clone("VisualRegressionTests")
# need this to use Conda
ENV["PYTHON"] = ""
Pkg.add("PyPlot")
Pkg.build("PyPlot")
# Pkg.add("InspectDR")
Pkg.test("Plots"; coverage=false)