Compare commits

..

156 Commits

Author SHA1 Message Date
SimonDanisch 5b6d7d10d4 use correct revision 2019-01-31 18:50:20 +01:00
SimonDanisch 71cf37cc16 use name 2019-01-31 18:27:54 +01:00
Michael Krabbe Borregaard f905cb9577 Merge pull request #1829 from oschulz/faster-load
Reduce load time for Plots and GR backend
2019-01-28 14:24:23 +01:00
Oliver Schulz b9b6439f47 Clean up backend default handling 2019-01-25 17:18:44 +01:00
Oliver Schulz ffcdf986a3 Set explicit return type for function _backend_instance
Inferred return type is Any, otherwise, not AbstractBackend.
2019-01-25 17:18:44 +01:00
Oliver Schulz 43245b5eb5 Clean up backend-related global vars and related functions 2019-01-25 17:18:44 +01:00
Oliver Schulz 420228c67b Remove function add_backend
No longer in use.
2019-01-25 17:18:44 +01:00
Oliver Schulz f1719d6e91 Improve implementation of backend(pkg::AbstractBackend) 2019-01-25 17:05:43 +01:00
Oliver Schulz 9aa1fd5c00 macro init_backend can call backend() with backend instance 2019-01-25 17:05:43 +01:00
Oliver Schulz 141845aa40 _initialize_backend doesn't need to do anything for PlotlyBackend 2019-01-25 17:05:43 +01:00
Oliver Schulz 7867df6079 _initialize_backend doesn't need to do anything for GRBackend 2019-01-25 17:05:43 +01:00
Oliver Schulz 182b937143 Refactor __init__() to make Plots load faster 2019-01-25 17:05:43 +01:00
Michael Krabbe Borregaard 399a9b16f6 StatPlots --> StatsPlots 2019-01-24 23:24:17 +01:00
Michael Krabbe Borregaard 42aa7d8d55 Merge pull request #1901 from mkborregaard/clamp
Inplace clamp
2019-01-23 22:36:00 +01:00
Michael Krabbe Borregaard 8778119792 Inplace clamp 2019-01-23 22:35:13 +01:00
Michael Krabbe Borregaard 10e3f2c990 Merge pull request #1900 from mkborregaard/clamp
WIP clamp greyscale images to (0,1)
2019-01-23 21:05:09 +01:00
Michael Krabbe Borregaard 5e25989366 copy and clamp for greyscale images if outside (0,1) 2019-01-23 21:04:27 +01:00
Michael Krabbe Borregaard f12d328cf7 clamp image for backends not supporting image
Does not work for GR or PyPlot which are supposed to support images natively
2019-01-23 21:04:27 +01:00
Daniel Schwabeneder efc4917724 Merge pull request #1769 from djsegal/djsegal/scatter
Allow vectors of markers for pyplot scatter
2019-01-23 19:21:05 +01:00
Daniel Schwabeneder c2bf145ff5 Merge pull request #1895 from sswatson/fontargs
Support keyword arguments for font options
2019-01-23 19:05:39 +01:00
djsegal c8c82811b3 Fix bug where pyplot marker vec added blank legend 2019-01-22 15:07:21 -05:00
Daniel Schwabeneder c21e133e69 Merge pull request #1899 from daschw/pyplot-image
fix grayscale image in pyplot
2019-01-22 13:55:43 +01:00
Daniel Schwabeneder 789a7fbb88 fix grayscale image in pyplot 2019-01-22 13:00:56 +01:00
Samuel S. Watson 888ed9f0ae Support keyword arguments for font attributes 2019-01-16 13:04:31 -05:00
Michael Krabbe Borregaard 57da253fa8 Merge pull request #1894 from sswatson/fontrotationfix
Fix annotation font rotation in PyPlot backend
2019-01-16 19:02:54 +01:00
Samuel S. Watson 44a6707397 Fix annotation font rotation 2019-01-16 10:28:46 -05:00
Samuel S. Watson f0a3ca4314 Merge remote-tracking branch 'upstream/master' 2019-01-16 09:44:03 -05:00
Michael Krabbe Borregaard 9bbd52dcc2 Merge pull request #1893 from JuliaPlots/doc_pr
rebased docpr from sswatson
2019-01-16 15:08:37 +01:00
Samuel S. Watson f50862ac51 Remove blank lines 2019-01-16 15:04:01 +01:00
Samuel S. Watson 017bed1a07 Remove xydoc and xyzdoc 2019-01-16 15:04:01 +01:00
Iblis Lin 3765d5f549 change contour example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-16 15:04:01 +01:00
Iblis Lin dd28159564 remove rand from example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-16 15:04:01 +01:00
Samuel S. Watson 63cdf9f8e7 Add shorthands.jl 2019-01-16 15:04:01 +01:00
Samuel S. Watson e30889aa12 document @shorthands functions 2019-01-16 15:04:01 +01:00
Samuel S. Watson b7caec1bfe Remove blank lines 2019-01-16 08:43:43 -05:00
Samuel S. Watson 660786b99c Merge branch 'master' of https://github.com/sswatson/Plots.jl 2019-01-16 08:41:02 -05:00
Samuel S. Watson b060576209 Remove xydoc and xyzdoc 2019-01-16 08:40:25 -05:00
Michael Krabbe Borregaard 7b3826c2d5 Merge pull request #1448 from OliverEvans96/gif_cache
Remove cache-busting from gif animation. Should be done by the frontend.
2019-01-16 09:30:39 +01:00
Michael Krabbe Borregaard 51d4416b00 Merge pull request #1891 from mkborregaard/master
filter infinite values in histograms too
2019-01-14 23:09:59 +01:00
Michael Krabbe Borregaard cfe6103f48 filter infinite values in histograms too 2019-01-14 23:08:50 +01:00
Michael Krabbe Borregaard bee8230079 Merge pull request #1889 from mkborregaard/master
fix histograms with NaN; close #1212
2019-01-14 11:45:04 +01:00
Michael Krabbe Borregaard 3d77c59c92 don't rebind vs 2019-01-14 11:44:42 +01:00
Michael Krabbe Borregaard 667ed161c0 move filtering to makebins 2019-01-14 10:36:08 +01:00
Michael Krabbe Borregaard 979f9495f1 add faster method for 1-d histogram 2019-01-14 00:04:01 +01:00
Michael Krabbe Borregaard d29a44efa7 fix histograms with NaN 2019-01-13 12:45:24 +01:00
Michael Krabbe Borregaard 7750003033 Merge pull request #1885 from sglyon/sl/plotlyjs-fix
Sl/plotlyjs fix
2019-01-11 19:52:02 +01:00
Iblis Lin e673339dc4 change contour example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-10 08:46:38 -05:00
Iblis Lin b20b47f8eb remove rand from example
Co-Authored-By: sswatson <samuel.s.watson@gmail.com>
2019-01-10 08:44:41 -05:00
Samuel S. Watson 689e437bac Add shorthands.jl 2019-01-08 18:10:48 -05:00
Samuel S. Watson e6bb17dc86 document @shorthands functions 2019-01-08 17:55:52 -05:00
Spencer Lyon 80a97b0f26 ENH: use PlotlyJS.savefig(::IO, ...) methods instead of former plotlyjs_save_hack hack 2019-01-08 14:04:33 -05:00
Spencer Lyon ffea050bc2 ENH: don't special case html display for jupyter 2019-01-08 14:04:03 -05:00
Josef Heinen 8951526d0d Set minimum GR version 2019-01-07 13:26:08 +01:00
Michael Krabbe Borregaard 3e799fbe21 Merge pull request #1880 from jheinen/master
Added support for discrete contour plots
2019-01-06 11:30:33 +01:00
Josef Heinen 53e27dbc38 Added support for discrete contour plots 2019-01-06 11:24:45 +01:00
Michael Krabbe Borregaard 9985d303ce Merge pull request #1879 from wfrgra/round_axis_limits
stop default axis widen behaviour overriding axis limit rounding
2019-01-06 08:11:43 +01:00
Michael Krabbe Borregaard ba46299088 Fix stray srand in showtheme 2019-01-05 17:59:18 +01:00
wfrgra 9679eae662 stop default widen behaviour overriding axis limit rounding 2019-01-05 13:46:53 +11:00
Michael Krabbe Borregaard 7acb5a4bdb allow annotations to take a tuple and pass it to text 2019-01-02 17:39:28 +01:00
Michael Krabbe Borregaard d1428b8221 update news.md 2018-12-29 10:05:02 +01:00
Michael Krabbe Borregaard c59a361ab3 Merge pull request #1875 from pfitzseb/sp/fixtypo
PlotDisplay -> PlotsDisplay
2018-12-29 09:46:54 +01:00
Sebastian Pfitzner 8935728daa PlotDisplay -> PlotsDisplay 2018-12-29 09:34:53 +01:00
Michael Krabbe Borregaard 155ac91385 Merge pull request #1874 from pfitzseb/sp/displayfixagain
insert PlotDisplay directly after REPLDisplay
2018-12-27 11:22:12 +01:00
Sebastian Pfitzner 4403ed3860 insert PlotDisplay directly after REPLDisplay 2018-12-27 10:57:10 +01:00
Michael Krabbe Borregaard 712b567752 update news for release 2018-12-10 11:02:34 +01:00
Michael Krabbe Borregaard 75be945359 Revert "MethodError -> ArgumentError"
This reverts commit 6f821e5344.
2018-12-07 09:42:44 +01:00
Michael Krabbe Borregaard fe50a457cd Merge pull request #1862 from mkborregaard/master
Fix MethodError to ArgumentError; fix #1861
2018-12-07 08:13:38 +01:00
Michael Krabbe Borregaard 6f821e5344 MethodError -> ArgumentError 2018-12-07 08:12:41 +01:00
Michael Krabbe Borregaard 14cbfb5706 fix warn -> @warn 2018-12-07 08:11:30 +01:00
Michael Krabbe Borregaard a882685169 Merge pull request #1857 from BoundaryValueProblems/master
vmin, vmax in KW were suppressed for :wireframe
2018-12-03 08:09:34 +01:00
Naoki Saito b9b7edc72d vmin, vmax in KW were suppressed for :wireframe 2018-12-02 15:37:25 -08:00
Michael Krabbe Borregaard d0b939da4a Merge pull request #1854 from mauro3/patch-1
Fix #1799
2018-11-28 17:22:55 +01:00
Mauro 2643d493a3 Fix #1799
This may fix #1799.  Although, note, I have no deeper understanding of this code...
2018-11-28 17:07:38 +01:00
Michael Krabbe Borregaard c26689fcb1 Merge pull request #1850 from greimel/gre/pgf-axes
Use :foreground_color_border for axis color in pgfplot
2018-11-19 22:37:48 +01:00
Fabian Greimel a2365f2c14 Use :foreground_color_border for axis color in pgfplot 2018-11-19 22:21:21 +01:00
Daniel Schwabeneder 435ff795ca Merge pull request #1841 from daschw/docs-formatter
add :plain formatter option in arg_desc (fix #1840)
2018-11-11 21:57:35 +01:00
Daniel Schwabeneder af34fdc45a add :plain formatter option in arg_desc 2018-11-11 21:25:41 +01:00
Michael Krabbe Borregaard 3bfedd844e Merge pull request #1838 from tkf/smuggle
Smuggle PyCall and LaTeXStrings through PyPlot
2018-11-09 08:20:55 +01:00
Takafumi Arakaki f726151e6e Smuggle PyCall and LaTeXStrings through PyPlot
fix #1672
fix https://github.com/JuliaPy/PyPlot.jl/issues/389
fix https://github.com/JuliaPy/PyPlot.jl/issues/408
2018-11-08 19:23:32 -08:00
Daniel Schwabeneder c6c4becf7d Merge pull request #1808 from JonathanAnderson/patch-1
Fallback to non gr3 surface call
2018-11-02 13:05:36 +01:00
Michael Krabbe Borregaard e2deb71988 Merge pull request #1828 from harryscholes/#1827
Fixes #1827
2018-10-31 14:00:09 +01:00
Harry a717bf4f34 Fixes #1827 2018-10-31 12:24:04 +00:00
Daniel Schwabeneder 2fef7a5b84 Merge pull request #1822 from JuliaPlots/revert-1821-revert-1819-mkb/plotrecipes
Revert "Revert "Transfer portfoliocomposition recipe from PlotRecipes""
2018-10-30 16:26:58 +01:00
Daniel Schwabeneder 12309c281b Revert "Revert "Transfer portfoliocomposition recipe from PlotRecipes"" 2018-10-30 16:26:19 +01:00
Daniel Schwabeneder a2a4e5b350 Merge pull request #1821 from JuliaPlots/revert-1819-mkb/plotrecipes
Revert "Transfer portfoliocomposition recipe from PlotRecipes"
2018-10-30 16:07:11 +01:00
Daniel Schwabeneder 6741287ef1 Revert "Transfer portfoliocomposition recipe from PlotRecipes" 2018-10-30 16:06:51 +01:00
Daniel Schwabeneder 6940f5a982 Merge pull request #1819 from JuliaPlots/mkb/plotrecipes
Transfer portfoliocomposition recipe from PlotRecipes
2018-10-30 15:51:46 +01:00
Michael Krabbe Borregaard b0bd5c13a0 Merge pull request #1820 from diegozea/patch-1
It solves Shape bugs
2018-10-30 15:17:11 +01:00
Diego Javier Zea af119a0248 It solves Shape bugs
unneeded get and missing undef
2018-10-30 15:15:03 +01:00
Michael Krabbe Borregaard 759cd7b3f2 add seed! 2018-10-30 14:05:31 +01:00
Michael Krabbe Borregaard 5e06e0d2d2 fix example 2018-10-30 14:05:31 +01:00
Michael Krabbe Borregaard 85b83e1745 add portfoliocomposition 2018-10-30 14:05:31 +01:00
Simon 441954be35 Merge pull request #1818 from JuliaPlots/mkb/dev2
Deprecate glivisualize backend - replaces #1816
2018-10-30 12:52:27 +01:00
Daniel Schwabeneder 11c1a23dfe Merge pull request #1815 from daschw/heatmap
allow heatmap of nx1 or 1xn matrices
2018-10-30 11:54:57 +01:00
Michael Krabbe Borregaard 1386435b17 Completely deprecate glvisualize 2018-10-30 11:41:37 +01:00
Michael Krabbe Borregaard f33d135182 More completely remove deprecated backends 2018-10-30 11:41:27 +01:00
Daniel Schwabeneder 5396477082 alow heatmap of nx1 or 1xn matrices 2018-10-30 09:02:58 +01:00
Jonathan Anderson 5ea77cc4b6 Fallback to non gr3 surface call
Taking an idea from @FlorianRhiem in this issue https://github.com/jheinen/GR.jl/issues/159, I figured I would fall back to GR if GR3 had an error. With this change, I was able to solve my issue in https://github.com/JuliaPlots/Plots.jl/issues/1781
2018-10-24 16:45:23 -05:00
Daniel Schwabeneder 45b5b33929 Merge pull request #1805 from yha/function-recipe-scale
function recipe: taking axis scales into account
2018-10-24 09:19:38 +02:00
Daniel Schwabeneder 9213b09c57 Merge pull request #1803 from daschw/staticarrays
remove FixedSizeArrays fix #1802
2018-10-23 19:45:30 +02:00
Daniel Schwabeneder 113e616d25 remove FixedSizeArrays 2018-10-23 17:53:25 +02:00
Daniel Schwabeneder 8861c553da Merge pull request #1801 from PhilipVinc/philipvinc-labels_mirror_fix
Fix Mirroring of Labels
2018-10-23 17:35:02 +02:00
Filippo Vicentini 6be7995500 Add paddings to the side where the axis label is 2018-10-23 15:58:10 +02:00
Filippo Vicentini 89d08606ad Mirror guides if :guide_position == :auto and :mirror == true
Before, guides where mirrored only if guide_position was set.
2018-10-23 14:05:05 +02:00
Michael Krabbe Borregaard e709560319 Merge pull request #1800 from jheinen/master
up GR version
2018-10-23 10:00:35 +02:00
Josef Heinen 9eda7548d0 Merge remote-tracking branch 'upstream/master'
t push
2018-10-23 08:51:04 +02:00
Josef Heinen 6e0522308a up GR version 2018-10-23 08:50:25 +02:00
Josef Heinen 7062e8864b up GR version 2018-10-23 08:46:07 +02:00
yharel 957cea2638 function recipe: taking axis scales into account 2018-10-22 03:11:26 +03:00
Daniel Schwabeneder 532710e6bf Merge pull request #1791 from daschw/release
prepare release
2018-10-14 19:12:42 +02:00
Daniel Schwabeneder 24e46e4c01 Merge pull request #1790 from daschw/appveyor
don't test for julia 0.7 on appveyor
2018-10-14 19:11:52 +02:00
Daniel Schwabeneder cb3cdbf6e7 prepare release 2018-10-14 19:10:12 +02:00
Daniel Schwabeneder dcceef2e52 Merge pull request #1782 from ma-laforge/hdf5
Add support for annotations and "Shape"s.
2018-10-14 18:40:44 +02:00
Daniel Schwabeneder cbc965dc53 Merge pull request #1787 from greimel/gre/gr-axis-color
GR: use correct attribute for axis color
2018-10-14 18:39:39 +02:00
Daniel Schwabeneder f5b793f80c Merge pull request #1777 from JuliaPlots/sd-remote
use remote urls plotly
2018-10-14 18:36:10 +02:00
Daniel Schwabeneder d3b51703f2 don't test for julia 0.7 on appveyor 2018-10-14 18:27:36 +02:00
Daniel Schwabeneder 0ecee70af2 Merge branch 'master' into sd-remote 2018-10-14 18:11:21 +02:00
Daniel Schwabeneder 061704ac6e Merge pull request #1789 from daschw/docs2
Prepare for PlotDocs.
2018-10-14 16:12:46 +02:00
Daniel Schwabeneder 3e1ce8c2fa really fix conflicts 2018-10-14 15:51:02 +02:00
Daniel Schwabeneder 1cc84672e7 fix conflicts 2018-10-14 15:50:10 +02:00
Daniel Schwabeneder 04f502df8a select pgfplots examples for docs 2018-10-14 15:38:50 +02:00
Daniel Schwabeneder 22c3afd8a0 remove is_installed 2018-10-14 14:11:16 +02:00
Daniel Schwabeneder d9be97fc45 fix pgfplots saving with FileIO 2018-10-14 14:09:43 +02:00
Fabian Greimel b04e6ff699 GR: use correct attribute for axis color 2018-10-13 14:07:19 +02:00
Daniel Schwabeneder 9c1a5548e1 small PGFPlots fix in backends.jl 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder b73d7f03a7 don't add PyPlot and PlotlyJS in tests 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 106ed6b953 one more fix for plotlyjs 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder cccbaa0bdc skip visual regression tests on windows 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 874dacd2c8 fix plotlyjs (fix #1728) 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder a72a23b548 move supported backend attr to backends.jl 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 31004e8c12 move _current_plots_version from PlotDocs to Plots 2018-10-09 20:56:02 +02:00
Daniel Schwabeneder 87c471c0f5 plotlyjs, pyplot and test fixes 2018-10-09 20:56:02 +02:00
Michael Krabbe Borregaard d3e1a423fd update news for release 2018-10-08 16:17:01 +02:00
MA Laforge 16cc743d26 Add support for annotations and "Shape"s.
Also build plot attributes list after series are read in
to avoid having the internal mechanisms overwrite data.
2018-10-08 06:54:01 -07:00
SimonDanisch 9ccb699fca improve comments 2018-10-05 12:33:13 +02:00
SimonDanisch 7e0960e7a0 fix IJulia 2018-10-05 12:27:09 +02:00
SimonDanisch ee4fc2803b dont download by default 2018-10-05 12:27:01 +02:00
djsegal 268c2861c9 Fix off-by-one error in pyplot scatter building 2018-10-04 17:29:37 -04:00
djsegal 15739bc0ee Allow vectors of markers for pyplot scatter 2018-10-04 17:20:14 -04:00
Michael Krabbe Borregaard e84de56f2e Merge pull request #1779 from JackDunnNZ/patch-1
Minor formatting fix
2018-10-04 16:42:35 +02:00
Jack Dunn 6b46e81fbd Update backends.jl 2018-10-04 09:50:43 -04:00
SimonDanisch f5de5f58ce make ijulia plotly integration precompile save 2018-10-04 15:39:59 +02:00
SimonDanisch 3c2cfa333c allow to not host plotly from local file 2018-10-04 15:20:21 +02:00
Daniel Schwabeneder 63bc3a2b88 Merge pull request #1772 from daschw/incremental-compilation
Fix incremental compilation warnings (fix #1692, fix #1734)
2018-09-30 20:20:14 +02:00
Daniel Schwabeneder 1e83bc05ee move including of default backends out of __init__() 2018-09-30 18:03:22 +02:00
Daniel Schwabeneder fc51c355a5 don't add PyPlot and PlotlyJS in tests 2018-09-06 22:53:32 +02:00
Daniel Schwabeneder 59e7213c96 one more fix for plotlyjs 2018-09-06 22:30:42 +02:00
Daniel Schwabeneder 192020a93a skip visual regression tests on windows 2018-09-06 22:08:32 +02:00
Daniel Schwabeneder 5f5019d310 fix plotlyjs (fix #1728) 2018-09-06 22:04:44 +02:00
Daniel Schwabeneder f0f90d87af move supported backend attr to backends.jl 2018-09-04 19:08:48 +02:00
Daniel Schwabeneder 1bbe800dcd move _current_plots_version from PlotDocs to Plots 2018-09-03 17:30:50 +02:00
Daniel Schwabeneder a731ef6e2d plotlyjs, pyplot and test fixes 2018-09-02 22:28:34 +02:00
Daniel Schwabeneder c2e8b5a1fa Merge pull request #1611 from daschw/pyplot-thickness
Fix pyplot thickness and 0.6 backports release
2018-07-26 17:03:48 +02:00
Oliver Evans 1a67ca897c Remove cache-busting from gif animation. Should be done by the frontend. 2018-03-21 12:25:06 -04:00
Michael Krabbe Borregaard d1980ef978 Merge pull request #775 from JonathanAnderson/julia0.6
Update gr.jl in v0.6 so inline plots work
2017-05-08 10:07:40 +02:00
Jonathan Anderson b3db49b4ae Update gr.jl in v0.6 so inline plots work
I wanted to switch from using GR directly to using Plots, but the inline plots were not working for me. The following change is sufficient to generate inline plots in iterm for me.

See the method in GR.jl:
https://github.com/jheinen/GR.jl/blob/0f167b2be921a0014c405f760a1e1bc22b222751/src/GR.jl#L3014

julia> versioninfo()
Julia Version 0.6.0-pre.beta.187
Commit 55c97fb* (2017-04-17 23:06 UTC)
Platform Info:
OS: Linux (x86_64-redhat-linux)
CPU: Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.9.1 (ORCJIT, haswell)


julia> using TerminalExtensions
julia> using Plots
julia> gr(display_type=:inline);
julia> z=[sin(sqrt(x^2+y^2)) for x in linspace(-2π,2π,50), y in linspace(-2π,2π,50)];
julia> contour(z)
2017-04-18 10:39:50 -05:00
48 changed files with 1492 additions and 5868 deletions
+1
View File
@@ -6,3 +6,4 @@ examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
deps/build.log
deps/deps.jl
+34 -5
View File
@@ -10,7 +10,36 @@
---
## (current master)
- All new development should target Julia 1.x!
## 0.22.1
- push PlotsDisplay just after REPLDisplay
## 0.22.0
- deprecate GLVisualize
- allow 1-row and 1-column heatmaps
- add portfoliodecomposition recipe from PlotRecipes
- solve Shape bug
- simplify PyPlot backend installation
- fix wireframe bug in PyPlot
- fix color bug in PyPlot
- minor bug fixes in gr and pyplot
## 0.21.0
- Compatibility with StaticArrays 0.9.0
- Up GR min version to 0.35
- fix :mirror
## 0.20.6
- fixes for PlotDocs.jl
- fix gr axis color argument
- Shapes for inspectdr
- don't load plotly js file by default
## 0.20.5
- fix precompilation issue when depending on Plots
## 0.20.4
- honour `html_output_format` in Juno
## 0.20.3
- implement guide position in gr, pyplot and pgfplots
@@ -153,7 +182,7 @@ Many updates, min julia 1.0
- add `reset_defaults()` function to reset plot defaults
- update syntax to 0.6
- make `fill = true` fill to 0 rather than to 1
- use new `@df` syntax in StatPlots examples
- use new `@df` syntax in StatsPlots examples
- allow changing the color of legend box
- implement `title_location` for gr
- add `hline` marker to pgfplots - fixes errorbars
@@ -305,7 +334,7 @@ Many updates, min julia 1.0
- added dependency on PlotThemes
- set_theme --> theme
- remove Compat from REQUIRE
- warning for DataFrames without StatPlots
- warning for DataFrames without StatsPlots
- closeall exported and implemented for gr/pyplot
- fix DateTime recipe
- reset theme with theme(:none)
@@ -427,8 +456,8 @@ Many updates, min julia 1.0
#### 0.8.0
- added dependency on PlotUtils
- BREAKING: removed DataFrames support (now in StatPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
- BREAKING: removed DataFrames support (now in StatsPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatsPlots.jl)
- GR:
- inline iterm2 support
- trisurface support
+1 -1
View File
@@ -13,4 +13,4 @@ JSON
NaNMath
Requires
Contour
GR 0.34.0
GR 0.37.0
+1 -1
View File
@@ -1,6 +1,6 @@
environment:
matrix:
- julia_version: 0.7
# - julia_version: 0.7
- julia_version: 1
- julia_version: nightly
+15 -5
View File
@@ -1,8 +1,18 @@
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
file_path = ""
if get(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL", "false") == "true"
global file_path
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
@info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
isfile(local_fn) && (file_path = local_fn)
else
file_path = local_fn
end
end
open("deps.jl", "w") do io
println(io, "const plotly_local_file_path = $(repr(file_path))")
end
+20 -93
View File
@@ -1,10 +1,11 @@
module Plots
_current_plots_version = v"0.20.6"
using Reexport
import StaticArrays
using StaticArrays.FixedSizeArrays
using Dates, Printf, Statistics, Base64, LinearAlgebra
using Dates, Printf, Statistics, Base64, LinearAlgebra, Random
import SparseArrays: findnz
@reexport using RecipesBase
@@ -18,6 +19,17 @@ import JSON
using Requires
if isfile(joinpath(@__DIR__, "..", "deps", "deps.jl"))
include(joinpath(@__DIR__, "..", "deps", "deps.jl"))
else
# This is a bit dirty, but I don't really see why anyone should be forced
# to build Plots, while it will just include exactly the below line
# as long as `ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] = "true"` is not set.
# If the above env is set + `plotly_local_file_path == ""``,
# it will warn in the __init__ function to run build
const plotly_local_file_path = ""
end
export
grid,
bbox,
@@ -72,7 +84,6 @@ export
backends,
backend_name,
backend_object,
add_backend,
aliases,
Shape,
@@ -168,99 +179,15 @@ include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
include("output.jl")
include("ijulia.jl")
include("fileio.jl")
include("init.jl")
# ---------------------------------------------------------
include("backends/plotly.jl")
include("backends/gr.jl")
include("backends/web.jl")
@shorthands scatter
@shorthands bar
@shorthands barh
@shorthands histogram
@shorthands barhist
@shorthands stephist
@shorthands scatterhist
@shorthands histogram2d
@shorthands density
@shorthands heatmap
@shorthands plots_heatmap
@shorthands hexbin
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands hspan
@shorthands vspan
@shorthands ohlc
@shorthands contour
@shorthands contourf
@shorthands contour3d
@shorthands surface
@shorthands wireframe
@shorthands path3d
@shorthands scatter3d
@shorthands boxplot
@shorthands violin
@shorthands quiver
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
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...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
include("shorthands.jl")
let PlotOrSubplot = Union{Plot, Subplot}
global title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
+3 -3
View File
@@ -93,13 +93,13 @@ end
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
# write out html to view the gif
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
ext = file_extension(agif.filename)
write(io, if ext == "gif"
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
"<img src=\"$(relpath(agif.filename))\" />"
elseif ext in ("mov", "mp4")
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
"<video controls><source src=\"$(relpath(agif.filename)) type=\"video/$ext\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end)
+24 -24
View File
@@ -2,7 +2,7 @@
const _arg_desc = KW(
# series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
@@ -10,7 +10,7 @@ const _arg_desc = KW(
:linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area from this to y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
@@ -21,7 +21,7 @@ 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. `range(min(x), stop = extrema(x), length = 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(minimum(x), stop = maximum(x), length = 25)`",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
@@ -29,13 +29,13 @@ const _arg_desc = KW(
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
@@ -43,12 +43,12 @@ const _arg_desc = KW(
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?",
:contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
@@ -63,11 +63,11 @@ const _arg_desc = KW(
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
# subplot args
@@ -98,7 +98,7 @@ const _arg_desc = KW(
:legendfont => "Font. Font of legend items.",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.",
:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units.",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
@@ -110,14 +110,14 @@ const _arg_desc = KW(
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args
:guide => "String. Axis guide (label).",
:guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
+2 -2
View File
@@ -1050,8 +1050,8 @@ function preprocessArgs!(plotattributes::KW)
# warnings for moved recipes
st = get(plotattributes, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
@warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatsPlots)
@warn("seriestype $st has been moved to StatsPlots. To use: \`Pkg.add(\"StatsPlots\"); using StatsPlots\`")
end
return
+1 -1
View File
@@ -459,7 +459,7 @@ const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter
function default_should_widen(axis::Axis)
should_widen = false
if !is_2tuple(axis[:lims])
if !(is_2tuple(axis[:lims]) || axis[:lims] == :round)
for sp in axis.sps
for series in series_list(sp)
if series.plotattributes[:seriestype] in _widen_seriestypes
+367 -120
View File
@@ -7,16 +7,20 @@ 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}()
const _backend_packages = Dict{Symbol, Symbol}()
"Returns a list of supported backends"
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]
function _backend_instance(sym::Symbol)::AbstractBackend
haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
end
backend_package_name(sym::Symbol) = _backend_packages[sym]
macro init_backend(s)
package_str = string(s)
@@ -26,13 +30,13 @@ macro init_backend(s)
esc(quote
struct $T <: AbstractBackend end
export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str)))
$sym(; kw...) = (default(; kw...); backend($T()))
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)
_backendPackage[Symbol($str)] = Symbol($package_str)
_backend_packages[Symbol($str)] = Symbol($package_str)
# include("backends/" * $str * ".jl")
end)
end
@@ -42,12 +46,6 @@ end
# ---------------------------------------------------------
function add_backend(pkg::Symbol)
@info("To do a standard install of $pkg, copy and run this:\n\n")
println(add_backend_string(_backend_instance(pkg)))
println()
end
# don't do anything as a default
_create_backend_figure(plt::Plot) = nothing
_prepare_plot_object(plt::Plot) = nothing
@@ -138,33 +136,27 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
_fallback_default_backend() = backend(GRBackend())
function _pick_default_backend()
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
if env_default != ""
sym = Symbol(lowercase(env_default))
if sym in _backends
if sym in _initialized_backends
return backend(sym)
backend(sym)
else
@warn("You have set `PLOTS_DEFAULT_BACKEND=$env_default` but `$(backend_package_name(sym))` is not loaded.")
_fallback_default_backend()
end
else
@warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
@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"))
_fallback_default_backend()
end
else
_fallback_default_backend()
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 pkgstr in keys(Pkg.installed())
# return backend(Symbol(lowercase(pkgstr)))
# end
# end
# the default if nothing else is installed
backend(:gr)
end
@@ -174,13 +166,11 @@ end
Returns the current plotting package name. Initializes package on first call.
"""
function backend()
if CURRENT_BACKEND.sym == :none
_pick_default_backend()
end
global CURRENT_BACKEND
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
end
CURRENT_BACKEND.pkg
CURRENT_BACKEND.pkg
end
"""
@@ -188,20 +178,13 @@ Set the plot backend.
"""
function backend(pkg::AbstractBackend)
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
if !(sym in _initialized_backends)
_initialize_backend(pkg)
push!(_initialized_backends, sym)
end
backend()
CURRENT_BACKEND.sym = sym
CURRENT_BACKEND.pkg = pkg
pkg
end
function backend(sym::Symbol)
@@ -209,15 +192,15 @@ function backend(sym::Symbol)
backend(_backend_instance(sym))
else
@warn("`:$sym` is not a supported backend.")
backend()
end
backend()
end
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize]
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.")
end
end
@@ -268,17 +251,11 @@ end
# @init_backend Immerse
# @init_backend Gadfly
@init_backend PyPlot
# @init_backend Qwt
@init_backend UnicodePlots
# @init_backend Winston
# @init_backend Bokeh
@init_backend Plotly
@init_backend PlotlyJS
@init_backend GR
@init_backend GLVisualize
@init_backend PGFPlots
@init_backend InspectDR
@init_backend HDF5
@@ -322,72 +299,189 @@ function _initialize_backend(pkg::AbstractBackend)
end
end
function add_backend_string(pkg::AbstractBackend)
sym = backend_package_name(pkg)
"""
using Pkg
Pkg.add("$sym")
"""
end
_initialize_backend(pkg::GRBackend) = nothing
_initialize_backend(pkg::PlotlyBackend) = nothing
# ------------------------------------------------------------------------------
# glvisualize
# gr
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
const _gr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins,
:layout,
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:match_dimensions,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
:legendfontrotation, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
:tickfontrotation, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
:overwrite_figure,
:polar,
:aspect_ratio,
:normalize, :weights,
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _gr_seriestype = [
:path, :scatter, :straightline,
:heatmap, :pie, :image,
:contour, :path3d, :scatter3d, :surface, :wireframe,
:shape
]
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _gr_marker = _allMarkers
const _gr_scale = [:identity, :log10]
is_marker_supported(::GRBackend, shape::Shape) = true
# ------------------------------------------------------------------------------
# hdf5
# plotly
function _initialize_backend(::HDF5Backend)
@eval Main begin
import HDF5
export HDF5
end
end
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :line_z, :levels,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
:normalize, :weights,
# :contours,
:aspect_ratio,
:hover,
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
]
const _plotly_scale = [:identity, :log10]
# ------------------------------------------------------------------------------
# PGFPLOTS
# pgfplots
function add_backend_string(::PGFPlotsBackend)
"""
using Pkg
Pkg.add("PGFPlots")
Pkg.build("PGFPlots")
"""
end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
:title,
# :window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# plotlyjs
function add_backend_string(::PlotlyJSBackend)
"""
using Pkg
Pkg.add("PlotlyJS")
Pkg.add("Rsvg")
import Blink
Blink.AtomShell.install()
"""
function _initialize_backend(pkg::PlotlyJSBackend)
@eval Main begin
import PlotlyJS, ORCA
export PlotlyJS
end
end
const _plotlyjs_attr = _plotly_attr
const _plotlyjs_seriestype = _plotly_seriestype
const _plotlyjs_style = _plotly_style
const _plotlyjs_marker = _plotly_marker
const _plotlyjs_scale = _plotly_scale
# ------------------------------------------------------------------------------
# pyplot
function _initialize_backend(::PyPlotBackend)
@eval Main begin
import PyPlot, PyCall
import LaTeXStrings
import PyPlot
export PyPlot
@@ -396,25 +490,178 @@ function _initialize_backend(::PyPlotBackend)
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
const _pyplot_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
:stride,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
const _pyplot_marker = vcat(_allMarkers, :pixel)
const _pyplot_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# unicodeplots
function add_backend_string(::UnicodePlotsBackend)
"""
using Pkg
Pkg.add("UnicodePlots")
Pkg.build("UnicodePlots")
"""
end
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
:seriescolor,
:seriesalpha,
:linestyle,
:markershape,
:bins,
:title,
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
:spy
]
const _unicodeplots_style = [:auto, :solid]
const _unicodeplots_marker = [:none, :auto, :circle]
const _unicodeplots_scale = [:identity]
# ------------------------------------------------------------------------------
# hdf5
const _hdf5_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
# ------------------------------------------------------------------------------
# inspectdr
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar,
# :marker_z,
# :line_z,
# :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
:overwrite_figure,
:polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
:match_dimensions,
# :clims,
# :inset_subplots,
:dpi,
# :colorbar_title,
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
:none, :auto,
:circle, :rect, :diamond,
:cross, :xcross,
:utriangle, :dtriangle, :rtriangle, :ltriangle,
:pentagon, :hexagon, :heptagon, :octagon,
:star4, :star5, :star6, :star7, :star8,
:vline, :hline, :+, :x,
]
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
File diff suppressed because it is too large Load Diff
+26 -75
View File
@@ -3,68 +3,10 @@
# significant contributions by @jheinen
const _gr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins,
:layout,
:title, :window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip,
:match_dimensions,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
:legendfontrotation, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
:tickfontrotation, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
:ribbon, :quiver,
:orientation,
:overwrite_figure,
:polar,
:aspect_ratio,
:normalize, :weights,
:inset_subplots,
:bar_width,
:arrow,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _gr_seriestype = [
:path, :scatter, :straightline,
:heatmap, :pie, :image,
:contour, :path3d, :scatter3d, :surface, :wireframe,
:shape
]
const _gr_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _gr_marker = _allMarkers
const _gr_scale = [:identity, :log10]
is_marker_supported(::GRBackend, shape::Shape) = true
function add_backend_string(::GRBackend)
"""
Pkg.add("GR")
Pkg.build("GR")
"""
end
import GR
export GR
# --------------------------------------------------------------------------------------
const gr_linetype = KW(
@@ -661,11 +603,19 @@ function _update_min_padding!(sp::Subplot{GRBackend})
end
# Add margin for x label
if sp[:xaxis][:guide] != ""
bottompad += 4mm
if sp[:xaxis][:guide_position] == :top || (sp[:xaxis][:guide_position] == :auto && sp[:xaxis][:mirror] == true)
toppad += 4mm
else
bottompad += 4mm
end
end
# Add margin for y label
if sp[:yaxis][:guide] != ""
leftpad += 4mm
if sp[:yaxis][:guide_position] == :right || (sp[:yaxis][:guide_position] == :auto && sp[:yaxis][:mirror] == true)
rightpad += 4mm
else
leftpad += 4mm
end
end
if sp[:colorbar_title] != ""
rightpad += 4mm
@@ -722,7 +672,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
outside_ticks = true
for ax in (sp[:xaxis], sp[:yaxis])
v = series[ax[:letter]]
if diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
if length(v) > 1 && diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
@warn("GR: heatmap only supported with equally spaced data.")
end
end
@@ -855,12 +805,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# axis lines
if xaxis[:showaxis]
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
gr_set_line(1, :solid, xaxis[:foreground_color_border])
GR.setclip(0)
gr_polyline(coords(xspine_segs)...)
end
if yaxis[:showaxis]
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_line(1, :solid, yaxis[:foreground_color_border])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
end
@@ -962,7 +912,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if xaxis[:guide] != ""
gr_set_font(guidefont(xaxis))
if xaxis[:guide_position] == :top
if xaxis[:guide_position] == :top || (xaxis[:guide_position] == :auto && xaxis[:mirror] == true)
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
gr_text(gr_view_xcenter(), viewport_subplot[4], xaxis[:guide])
else
@@ -974,7 +924,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if yaxis[:guide] != ""
gr_set_font(guidefont(yaxis))
GR.setcharup(-1, 0)
if yaxis[:guide_position] == :left
if yaxis[:guide_position] == :right || (yaxis[:guide_position] == :auto && yaxis[:mirror] == true)
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
gr_text(viewport_subplot[2], gr_view_ycenter(), yaxis[:guide])
else
@@ -1080,16 +1030,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
else
h = series[:levels] > 1 ? range(zmin, stop=zmax, length=series[:levels]) : [(zmin + zmax) / 2]
end
GR.setlinetype(gr_linetype[get_linestyle(series)])
GR.setlinewidth(max(0, get_linewidth(series) / (sum(gr_plot_size) * 0.001)))
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
GR.contourf(x, y, h, z, series[:contour_labels] == true ? 1 : 0)
else
GR.setlinetype(gr_linetype[get_linestyle(series)])
GR.setlinewidth(max(0, get_linewidth(series) / (sum(gr_plot_size) * 0.001)))
if plot_color(series[:linecolor]) == [plot_color(:black)]
GR.contour(x, y, h, z, 0 + (series[:contour_labels] == true ? 1 : 0))
else
GR.contour(x, y, h, z, 1000 + (series[:contour_labels] == true ? 1 : 0))
end
coff = plot_color(series[:linecolor]) == [plot_color(:black)] ? 0 : 1000
GR.contour(x, y, h, z, coff + (series[:contour_labels] == true ? 1 : 0))
end
# create the colorbar of contour levels
@@ -1109,7 +1056,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if length(x) == length(y) == length(z)
GR.trisurface(x, y, z)
else
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
try
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
catch
GR.surface(x, y, z, GR.OPTION_COLORED_MESH)
end
end
else
GR.setfillcolorind(0)
+50 -62
View File
@@ -16,16 +16,19 @@ Read from .hdf5 file using:
#==TODO
===============================================================================
1. Support more features
- SeriesAnnotations & GridLayout known to be missing.
3. Improve error handling.
1. Support more features.
- GridLayout known not to be working.
2. Improve error handling.
- Will likely crash if file format is off.
2. Save data in a folder parallel to "plot".
3. Save data in a folder parallel to "plot".
- Will make it easier for users to locate data.
- Use HDF5 reference to link data?
3. Develop an actual versioned file format.
4. Develop an actual versioned file format.
- Should have some form of backward compatibility.
- Should be reliable for archival purposes.
5. Fix construction of plot object with hdf5plot_read.
- Not building object correctly when backends do not natively support
a certain feature (ex: :steppre)
==#
import FixedPointNumbers: N0f8 #In core Julia
@@ -56,53 +59,13 @@ const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText,
Shape,
}
#==
===============================================================================#
const _hdf5_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::HDF5Backend, shape::Shape) = true
if length(HDF5PLOT_MAP_TELEM2STR) < 1
@@ -125,7 +88,8 @@ if length(HDF5PLOT_MAP_TELEM2STR) < 1
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"PLOTTEXT" => PlotText,
"SHAPE" => Shape,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SURFACE" => Surface,
@@ -284,6 +248,14 @@ end
# ----------------------------------------------------------------
function _hdf5plot_gwrite(grp, k::String, v) #Default
T = typeof(v)
if !(T <: Number || T <: String)
tstr = string(T)
path = HDF5.name(grp) * "/" * k
@info("Type not supported: $tstr\npath: $path")
# @show v
return
end
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
@@ -338,10 +310,6 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
end
#Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
if "annotations" == k;
return #Hack. Does not yet support annotations.
end
vgrp = HDF5.g_create(grp, k)
_hdf5plot_writetype(vgrp, Array) #ANY
sz = size(v)
@@ -351,7 +319,7 @@ function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
coord = lidx[iter]
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
_hdf5plot_gwrite(vgrp, "v$idxstr", elem)
end
_hdf5plot_gwrite(vgrp, "dim", [sz...])
@@ -402,10 +370,6 @@ end
# return
# end
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
#Currently no support for SeriesAnnotations
return
end
function _hdf5plot_gwrite(grp, k::String, v::Subplot)
grp = HDF5.g_create(grp, k)
_hdf5plot_gwrite(grp, "index", v[:subplot_index])
@@ -528,6 +492,29 @@ function _hdf5plot_read(grp, k::String, T::Type{HDF5CTuple}, dtid)
v = _hdf5plot_read(grp, k, Array, dtid)
return tuple(v...)
end
function _hdf5plot_read(grp, k::String, T::Type{PlotText}, dtid)
grp = HDF5.g_open(grp, k)
str = _hdf5plot_read(grp, "str")
font = _hdf5plot_read(grp, "font")
return PlotText(str, font)
end
function _hdf5plot_read(grp, k::String, T::Type{SeriesAnnotations}, dtid)
grp = HDF5.g_open(grp, k)
strs = _hdf5plot_read(grp, "strs")
font = _hdf5plot_read(grp, "font")
baseshape = _hdf5plot_read(grp, "baseshape")
scalefactor = _hdf5plot_read(grp, "scalefactor")
return SeriesAnnotations(strs, font, baseshape, scalefactor)
end
function _hdf5plot_read(grp, k::String, T::Type{Shape}, dtid)
grp = HDF5.g_open(grp, k)
x = _hdf5plot_read(grp, "x")
y = _hdf5plot_read(grp, "y")
return Shape(x, y)
end
function _hdf5plot_read(grp, k::String, T::Type{ColorGradient}, dtid)
grp = HDF5.g_open(grp, k)
@@ -601,11 +588,6 @@ end
function _hdf5plot_read(sp::Subplot, subpath::String, f)
f = f::HDF5.HDF5File #Assert
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
_hdf5_merge!(sp.attr, kwlist)
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list"))
nseries = _hdf5plot_readcount(grp)
@@ -617,6 +599,12 @@ function _hdf5plot_read(sp::Subplot, subpath::String, f)
_hdf5_merge!(sp.series_list[end].plotattributes, kwlist)
end
#Perform after adding series... otherwise values get overwritten:
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
_hdf5_merge!(sp.attr, kwlist)
return
end
-55
View File
@@ -14,61 +14,6 @@ Add in functionality to Plots.jl:
=#
# ---------------------------------------------------------------------------
#TODO: remove features
const _inspectdr_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid,
:foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location,
:window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, #:gridalpha, :gridstyle, :gridlinewidth, #alhpa & linewidth are per plot - not per subplot
:legend, #:legendtitle, :colorbar,
# :marker_z,
# :line_z,
# :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
:overwrite_figure,
:polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
:match_dimensions,
# :clims,
# :inset_subplots,
:dpi,
# :colorbar_title,
])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost
]
#see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[
:none, :auto,
:circle, :rect, :diamond,
:cross, :xcross,
:utriangle, :dtriangle, :rtriangle, :ltriangle,
:pentagon, :hexagon, :heptagon, :octagon,
:star4, :star5, :star6, :star7, :star8,
:vline, :hline, :+, :x,
]
const _inspectdr_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::InspectDRBackend, shape::Shape) = true
+2 -43
View File
@@ -2,47 +2,6 @@
# significant contributions by: @pkofod
const _pgfplots_attr = merge_with_base_supported([
:annotations,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
:title,
# :window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar, :colorbar_title,
:fill_z, :line_z, :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
:tick_direction,
:framestyle,
:camera,
:contour_labels,
])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape, :straightline,]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10]
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
@@ -446,7 +405,7 @@ function pgf_axis(sp::Subplot, letter)
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}}"))
end
if !axis[:showaxis]
@@ -455,7 +414,7 @@ function pgf_axis(sp::Subplot, letter)
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
else
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}"))
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_border], 1.0), "}"))
end
# return the style list and KW args
+23 -85
View File
@@ -1,60 +1,6 @@
# https://plot.ly/javascript/getting-started
const _plotly_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha,
:bins,
:title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :gridalpha, :gridlinewidth,
:legend, :colorbar, :colorbar_title,
:marker_z, :fill_z, :line_z, :levels,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
:normalize, :weights,
# :contours,
:aspect_ratio,
:hover,
:inset_subplots,
:bar_width,
:clims,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _plotly_seriestype = [
:path, :scatter, :pie, :heatmap,
:contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl,
:straightline
]
const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot]
const _plotly_marker = [
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
]
const _plotly_scale = [:identity, :log10]
is_subplot_supported(::PlotlyBackend) = true
# is_string_supported(::PlotlyBackend) = true
const _plotly_framestyles = [:box, :axes, :zerolines, :grid, :none]
@@ -71,30 +17,9 @@ end
# --------------------------------------------------------------------------------------
const plotly_remote_file_path = "https://cdn.plot.ly/plotly-latest.min.js"
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"
_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>
"""
# 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)
@@ -102,8 +27,6 @@ end
using UUIDs
push!(_initialized_backends, :plotly)
# ----------------------------------------------------------------
const _plotly_legend_pos = KW(
@@ -115,7 +38,7 @@ const _plotly_legend_pos = KW(
:bottomright => [1., 0.],
:topright => [1., 1.],
:topleft => [0., 1.]
)
)
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
@@ -882,12 +805,27 @@ plotly_series_json(plt::Plot) = JSON.json(plotly_series(plt))
# ----------------------------------------------------------------
const _use_remote = Ref(false)
const ijulia_initialized = Ref(false)
function html_head(plt::Plot{PlotlyBackend})
jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
"<script src=\"$jsfilename\"></script>"
local_file = ("file://" * plotly_local_file_path)
plotly = use_local_dependencies[] ? local_file : plotly_remote_file_path
if isijulia() && !ijulia_initialized[]
# using requirejs seems to be key to load a js depency in IJulia!
# https://requirejs.org/docs/start.html
# https://github.com/JuliaLang/IJulia.jl/issues/345
display("text/html", """
<script type="text/javascript">
requirejs([$(repr(plotly))], function(p) {
window.Plotly = p
});
</script>
""")
ijulia_initialized[] = true
end
# IJulia just needs one initialization
isijulia() && return ""
return "<script src=$(repr(plotly))></script>"
end
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
@@ -908,8 +846,8 @@ end
function js_body(plt::Plot{PlotlyBackend}, uuid)
js = """
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
"""
end
+7 -26
View File
@@ -1,18 +1,11 @@
# https://github.com/spencerlyon2/PlotlyJS.jl
const _plotlyjs_attr = _plotly_attr
const _plotlyjs_seriestype = _plotly_seriestype
const _plotlyjs_style = _plotly_style
const _plotlyjs_marker = _plotly_marker
const _plotlyjs_scale = _plotly_scale
# https://github.com/sglyon/PlotlyJS.jl
# --------------------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
if !isplotnull() && plt[:overwrite_figure] && isa(current().o, PlotlyJS.SyncPlot)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), current().o.view)
PlotlyJS.SyncPlot(PlotlyJS.Plot(), options = current().o.options)
else
PlotlyJS.plot()
end
@@ -56,23 +49,11 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
show(io, MIME("text/html"), plt.o)
end
end
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
tmpfn = tempname() * "." * ext
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")
_show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend}) = show(io, MIME("text/html"), plt.o)
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = PlotlyJS.savefig(io, plt.o, format="eps")
function write_temp_html(plt::Plot{PlotlyJSBackend})
filename = string(tempname(), ".html")
+99 -88
View File
@@ -1,55 +1,9 @@
# Do "using PyPlot: PyCall, LaTeXStrings" without dependency warning:
const PyCall = PyPlot.PyCall
const LaTeXStrings = PyPlot.LaTeXStrings
# https://github.com/stevengj/PyPlot.jl
const _pyplot_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :guide_position, :lims, :ticks, :scale, :flip, :rotation,
:titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
:stride,
:framestyle,
:tick_direction,
:camera,
:contour_labels,
])
const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape, :straightline,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _pyplot_style = [:auto, :solid, :dash, :dot, :dashdot]
const _pyplot_marker = vcat(_allMarkers, :pixel)
const _pyplot_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::PyPlotBackend, shape::Shape) = true
@@ -236,26 +190,22 @@ function add_pyfixedformatter(cbar, vals::AVec)
cbar[:update_ticks]()
end
@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
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
@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
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
# ---------------------------------------------------------------------------
@@ -272,17 +222,6 @@ function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series)
end
end
# total hack due to PyPlot bug (see issue #145).
# hack: duplicate the color vector when the total rgba fields is the same as the series length
function py_color_fix(c, x)
if (typeof(c) <: AbstractArray && length(c)*4 == length(x)) ||
(typeof(c) <: Tuple && length(x) == 4)
vcat(c, c)
else
c
end
end
py_linecolor(series::Series) = py_color(series[:linecolor])
py_markercolor(series::Series) = py_color(series[:markercolor])
py_markerstrokecolor(series::Series) = py_color(series[:markerstrokecolor])
@@ -439,7 +378,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
vmin, vmax = clims = get_clims(sp)
# Dict to store extra kwargs
extrakw = KW(:vmin => vmin, :vmax => vmax)
if st == :wireframe
extrakw = KW() # vmin, vmax cause an error for wireframe plot
else
extrakw = KW(:vmin => vmin, :vmax => vmax)
end
# holds references to any python object representing the matplotlib series
handles = []
@@ -547,7 +490,13 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
else
py_color(plot_color(series[:markercolor], series[:markeralpha]))
end
extrakw[:c] = py_color_fix(markercolor, x)
extrakw[:c] = if markercolor isa Array
permutedims(hcat([[m...] for m in markercolor]...),[2,1])
elseif markercolor isa Tuple
reshape([markercolor...], 1, length(markercolor))
else
error("This case is not handled. Please file an issue.")
end
xyargs = if st == :bar && !isvertical(series)
(y, x)
else
@@ -555,7 +504,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
if isa(series[:markershape], AbstractVector{Shape})
# this section will create one scatter per data point to accomodate the
# this section will create one scatter per data point to accommodate the
# vector of shapes
handle = []
x,y = xyargs
@@ -575,6 +524,68 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
extrakw...
))
end
push!(handles, handle)
elseif isa(series[:markershape], AbstractVector{Symbol})
handle = []
x,y = xyargs
shapes = series[:markershape]
prev_marker = py_marker(_cycle(shapes,1))
cur_x_list = []
cur_y_list = []
cur_color_list = []
cur_scale_list = []
delete!(extrakw, :c)
for i=1:length(y)
cur_marker = py_marker(_cycle(shapes,i))
if ( cur_marker == prev_marker )
push!(cur_x_list, _cycle(x,i))
push!(cur_y_list, _cycle(y,i))
push!(cur_color_list, _cycle(markercolor, i))
push!(cur_scale_list, py_thickness_scale(plt, _cycle(series[:markersize],i) .^ 2))
continue
end
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = prev_marker,
s = cur_scale_list,
edgecolors = py_markerstrokecolor(series),
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
facecolors = cur_color_list,
extrakw...
))
cur_x_list = [_cycle(x,i)]
cur_y_list = [_cycle(y,i)]
cur_color_list = [_cycle(markercolor, i)]
cur_scale_list = [py_thickness_scale(plt, _cycle(series[:markersize],i) .^ 2)]
prev_marker = cur_marker
end
if !isempty(cur_color_list)
push!(handle, ax[:scatter](cur_x_list, cur_y_list;
label = series[:label],
zorder = series[:series_plotindex] + 0.5,
marker = prev_marker,
s = cur_scale_list,
edgecolors = py_markerstrokecolor(series),
linewidths = py_thickness_scale(plt, series[:markerstrokewidth]),
facecolors = cur_color_list,
extrakw...
))
end
push!(handles, handle)
else
# do a normal scatter plot
@@ -718,7 +729,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
handle = ax[:imshow](z;
zorder = series[:series_plotindex],
cmap = py_colormap([:black, :white]),
cmap = py_colormap(cgrad([:black, :white])),
vmin = 0.0,
vmax = 1.0,
extent = (xmin, xmax, ymax, ymin)
@@ -839,7 +850,7 @@ function py_set_ticks(ax, ticks, letter)
if ticks == :none || ticks == nothing || ticks == false
kw = KW()
for dir in (:top,:bottom,:left,:right)
kw[dir] = kw[Symbol(:label,dir)] = "off"
kw[dir] = kw[Symbol(:label,dir)] = false
end
axis[:set_tick_params](;which="both", kw...)
return
@@ -1064,7 +1075,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(ticks) > 1
ticks[2][ticks[1] .== 0] = ""
ticks[2][ticks[1] .== 0] .= ""
end
axis[:ticks] != :native ? py_set_ticks(ax, ticks, letter) : nothing
pyaxis[:set_tick_params](direction = axis[:tick_direction] == :out ? "out" : "in")
@@ -1102,7 +1113,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
else
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
kw[dir] = kw[Symbol(:label,dir)] = false
end
ax[:xaxis][:set_tick_params](; which="both", kw...)
end
@@ -1112,7 +1123,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if !ispolar(sp)
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
kw[dir] = kw[Symbol(:label,dir)] = false
end
ax[:yaxis][:set_tick_params](; which="both", kw...)
end
@@ -1203,7 +1214,7 @@ function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
color = py_color(val.font.color),
horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign),
verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign),
rotation = val.font.rotation * 180 / π,
rotation = val.font.rotation,
size = py_thickness_scale(sp.plt, val.font.pointsize),
zorder = 999
)
@@ -1239,12 +1250,12 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
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)
elseif series[:seriestype] in (:path, :straightline, :scatter)
PyPlot.plt[:Line2D]((0,1),(0,0),
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]),
marker = py_marker(first(series[:markershape])),
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series, clims), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
)
-22
View File
@@ -1,28 +1,6 @@
# https://github.com/Evizero/UnicodePlots.jl
const _unicodeplots_attr = merge_with_base_supported([
:label,
:legend,
:seriescolor,
:seriesalpha,
:linestyle,
:markershape,
:bins,
:title,
:guide, :lims,
])
const _unicodeplots_seriestype = [
:path, :scatter, :straightline,
# :bar,
:shape,
:histogram2d,
:spy
]
const _unicodeplots_style = [:auto, :solid]
const _unicodeplots_marker = [:none, :auto, :circle]
const _unicodeplots_scale = [:identity]
# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
+6
View File
@@ -42,8 +42,14 @@ function write_temp_html(plt::AbstractPlot)
end
function standalone_html_window(plt::AbstractPlot)
old = use_local_dependencies[] # save state to restore afterwards
# if we open a browser ourself, we can host local files, so
# when we have a local plotly downloaded this is the way to go!
use_local_dependencies[] = isfile(plotly_local_file_path)
filename = write_temp_html(plt)
open_browser_window(filename)
# restore for other backends
use_local_dependencies[] = old
end
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
+57 -14
View File
@@ -1,7 +1,7 @@
const P2 = FixedSizeArrays.Vec{2,Float64}
const P3 = FixedSizeArrays.Vec{3,Float64}
const P2 = StaticArrays.SVector{2,Float64}
const P3 = StaticArrays.SVector{3,Float64}
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))
@@ -256,8 +256,24 @@ mutable struct Font
color::Colorant
end
"Create a Font from a list of unordered features"
function font(args...)
"""
font(args...)
Create a Font from a list of features. Values may be specified either as
arguments (which are distinguished by type/value) or as keyword arguments.
# Arguments
- `family`: AbstractString. "serif" or "sans-serif" or "monospace"
- `pointsize`: Integer. Size of font in points
- `halign`: Symbol. Horizontal alignment (:hcenter, :left, or :right)
- `valign`: Symbol. Vertical aligment (:vcenter, :top, or :bottom)
- `rotation`: Real. Angle of rotation for text in degrees (use a non-integer type)
- `color`: Colorant or Symbol
# Examples
```julia-repl
julia> font(8)
julia> font(family="serif",halign=:center,rotation=45.0)
```
"""
function font(args...;kw...)
# defaults
family = "sans-serif"
@@ -301,6 +317,32 @@ function font(args...)
end
end
for symbol in keys(kw)
if symbol == :family
family = kw[:family]
elseif symbol == :pointsize
pointsize = kw[:pointsize]
elseif symbol == :halign
halign = kw[:halign]
if halign == :center
halign = :hcenter
end
@assert halign in (:hcenter, :left, :right)
elseif symbol == :valign
valign = kw[:valign]
if valign == :center
valign = :vcenter
end
@assert valign in (:vcenter, :top, :bottom)
elseif symbol == :rotation
rotation = kw[:rotation]
elseif symbol == :color
color = parse(Colorant, kw[:color])
else
@warn("Unused font kwarg: $symbol")
end
end
Font(family, pointsize, halign, valign, rotation, color)
end
@@ -344,15 +386,16 @@ end
PlotText(str) = PlotText(string(str), font())
"""
text(string, args...)
text(string, args...; kw...)
Create a PlotText object wrapping a string with font info, for plot annotations
Create a PlotText object wrapping a string with font info, for plot annotations.
`args` and `kw` are passed to `font`.
"""
text(t::PlotText) = t
text(t::PlotText, font::Font) = PlotText(t.str, font)
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
PlotText(string(str), font(args...))
function text(str, args...;kw...)
PlotText(string(str), font(args...;kw...))
end
Base.length(t::PlotText) = length(t.str)
@@ -491,7 +534,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# with a list of custom shapes for each
msw,msh = anns.scalefactor
msize = Float64[]
shapes = Vector{Shape}(length(anns.strs))
shapes = Vector{Shape}(undef, length(anns.strs))
for i in eachindex(anns.strs)
str = _cycle(anns.strs,i)
@@ -509,7 +552,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
# and then re-scale a copy of baseshape to match the w/h ratio
maxscale = max(xscale, yscale)
push!(msize, maxscale)
baseshape = _cycle(get(anns.baseshape),i)
baseshape = _cycle(anns.baseshape, i)
shapes[i] = scale(baseshape, msw*xscale/maxscale, msh*yscale/maxscale, (0,0))
end
series[:markershape] = shapes
@@ -554,7 +597,7 @@ function process_annotation(sp::Subplot, xs, ys, labs, font = font())
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (x, y, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (x, y, isa(lab, PlotText) ? lab : text(lab, font)))
push!(anns, (x, y, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
@@ -569,7 +612,7 @@ function process_annotation(sp::Subplot, positions::Union{AVec{Symbol},Symbol},
alphabet = "abcdefghijklmnopqrstuvwxyz"
push!(anns, (pos, text(string("(", alphabet[sp[:subplot_index]], ")"), font)))
else
push!(anns, (pos, isa(lab, PlotText) ? lab : text(lab, font)))
push!(anns, (pos, isa(lab, PlotText) ? lab : isa(lab, Tuple) ? text(lab...) : text(lab, font)))
end
end
anns
@@ -736,7 +779,7 @@ end
# -----------------------------------------------------------------------
"create a BezierCurve for plotting"
mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
mutable struct BezierCurve{T <: StaticArrays.SVector}
control_points::Vector{T}
end
@@ -750,7 +793,7 @@ function (bc::BezierCurve)(t::Real)
end
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
# mean{N,T<:Real}(ps::StaticArrays.SVector{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
@deprecate curve_points coords
-208
View File
@@ -1,208 +0,0 @@
# https://github.com/bokeh/Bokeh.jl
supported_attrs(::BokehBackend) = merge_with_base_supported([
# :annotations,
# :axis,
# :background_color,
:linecolor,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
:group,
# :label,
# :layout,
# :legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
# :linealpha,
:markershape,
:markercolor,
:markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :bins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
:size,
:title,
# :window_title,
:x,
# :xguide,
# :xlims,
# :xticks,
:y,
# :yguide,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface,
# :levels,
])
supported_types(::BokehBackend) = [:path, :scatter]
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::BokehBackend) = [:identity, :ln]
is_subplot_supported(::BokehBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::BokehBackend; kw...)
@eval begin
@warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
end
const _glyphtypes = KW(
:circle => :Circle,
:rect => :Square,
:diamond => :Diamond,
:utriangle => :Triangle,
:dtriangle => :InvertedTriangle,
# :pentagon =>
# :hexagon =>
# :heptagon =>
# :octagon =>
:cross => :Cross,
:xcross => :X,
:star5 => :Asterisk,
)
function bokeh_glyph_type(plotattributes::KW)
st = plotattributes[:seriestype]
mt = plotattributes[:markershape]
if st == :scatter && mt == :none
mt = :circle
end
# if we have a marker, use that
if st == :scatter || mt != :none
return _glyphtypes[mt]
end
# otherwise return a line
return :Line
end
function get_stroke_vector(linestyle::Symbol)
dash = 12
dot = 3
gap = 2
linestyle == :solid && return Int[]
linestyle == :dash && return Int[dash, gap]
linestyle == :dot && return Int[dot, gap]
linestyle == :dashdot && return Int[dash, gap, dot, gap]
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
error("unsupported linestyle: ", linestyle)
end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::BokehBackend, 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
datacolumns = Bokeh.BokehDataSet[]
tools = Bokeh.tools()
filename = tempname() * ".html"
title = plt.attr[:title]
w, h = plt.attr[:size]
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
# legend = plt.attr[:legend] ? xxxx : nothing
legend = nothing
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
# Plot(bplt, pkg, 0, plotattributes, KW[])
end
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{BokehBackend}, series::Series)
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
glyph = Bokeh.Bokehjs.Glyph(
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, plotattributes)
# plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{BokehBackend}, i::Int)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y]
# end
#
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y] = xy
# plt
# end
# ----------------------------------------------------------------
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
@warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
Bokeh.showplot(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
# # TODO: display/show the subplot
# end
-744
View File
@@ -1,744 +0,0 @@
# https://github.com/dcjones/Gadfly.jl
supported_attrs(::GadflyBackend) = merge_with_base_supported([
:annotations,
:background_color, :foreground_color, :color_palette,
:group, :label, :seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :n, :nc, :nr, :layout, :smooth,
:title, :window_title, :show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
:z,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
])
supported_types(::GadflyBackend) = [
:path,
:scatter, :hexbin,
:bar,
:contour, :shape
]
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
is_subplot_supported(::GadflyBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GadflyBackend; kw...)
@eval begin
import Gadfly, Compose
export Gadfly, Compose
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
end
end
# ---------------------------------------------------------------------------
# immutable MissingVec <: AbstractVector{Float64} end
# Base.size(v::MissingVec) = (1,)
# Base.getindex(v::MissingVec, i::Integer) = 0.0
function createGadflyPlotObject(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(plotattributes[:xguide]),
Gadfly.Guide.ylabel(plotattributes[:yguide]),
Gadfly.Guide.title(plotattributes[:title])]
gplt
end
# ---------------------------------------------------------------------------
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(plotattributes) ? :vertical : :horizontal,
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
elseif st == :path
Gadfly.Geom.path
elseif st in (:bar, :sticks)
Gadfly.Geom.bar
elseif st == :steppost
Gadfly.Geom.step
elseif st == :steppre
Gadfly.Geom.step(direction = :vh)
elseif st == :hline
Gadfly.Geom.hline
elseif st == :vline
Gadfly.Geom.vline
elseif st == :contour
Gadfly.Geom.contour(levels = plotattributes[:levels])
# elseif st == :shape
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
nothing
end
end
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(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?")
else
rethrow()
end
end
extra_theme_args
end
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 : 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(plotattributes, :linestyle)...
)
end
# add a line as a new layer
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
kwargs = KW()
st = plotattributes[:seriestype]
# add a fill?
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(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] = plotattributes[:y]
else
if st == :sticks
w = 0.01 * mean(diff(plotattributes[:x]))
kwargs[:xmin] = plotattributes[:x] - w
kwargs[:xmax] = plotattributes[:x] + w
elseif st == :contour
kwargs[:z] = plotattributes[:z].surf
addGadflyContColorScale(plt, plotattributes[:linecolor])
end
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
kwargs[:y] = plotattributes[:y]
end
# # add the layer
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
get_shape(sym::Symbol) = _shapes[sym]
get_shape(shape::Shape) = shape
# extract the underlying ShapeGeometry object(s)
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
getMarkerGeom(other) = gadflyshape(get_shape(other))
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
function getMarkerGeom(plotattributes::KW)
if plotattributes[:seriestype] == :shape
Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
getMarkerGeom(plotattributes[:markershape])
end
end
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
c = getColor(plotattributes[:markercolor])
α = plotattributes[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
ms = plotattributes[:markersize]
ms = if typeof(ms) <: AVec
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
mean(ms) * Gadfly.px
else
ms * Gadfly.px
end
Gadfly.Theme(;
default_color = c,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
)
end
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
plt.attr[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = default_gradient()
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
kwargs = KW()
# handle continuous color scales for the markers
zcolor = plotattributes[:marker_z]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, plotattributes[:markercolor])
end
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
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)
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
end
# now add the series to the legend
for guide in gplt.guides
if isa(guide, Gadfly.Guide.ManualColorKey)
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(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] *= ", " * plotattributes[:label]
foundit = true
end
end
# didn't find the color, so add a new entry into the legend
if !foundit
push!(guide.labels, plotattributes[:label])
push!(guide.colors, c)
end
end
end
end
end
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
function addGadflySeries!(plt::Plot, plotattributes::KW)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
smooth = getGadflySmoothing(plotattributes[:smooth])
# lines
geom = getLineGeom(plotattributes)
if geom != nothing
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 = plotattributes[:seriestype]
# if st == :ohlc
# error("Haven't re-implemented after refactoring")
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 plotattributes[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
end
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
# now save the layers that apply to this series
plotattributes[:gadflylayers] = layers
prepend!(gplt.layers, layers)
end
# ---------------------------------------------------------------------------
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
# # colorgroup
# z = plotattributes[:z]
# # handle line segments of different colors
# 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...))
# # 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(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)]
# ---------------------------------------------------------------------------
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
ticks == :auto && return
# remove the ticks?
if ticks in (:none, false, nothing)
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
end
ttype = ticksType(ticks)
# just the values... put ticks here, but use standard labels
if ttype == :ticks
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
# set the ticks and the labels
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
elseif ttype == :ticks_and_labels
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
# # TODO add xtick_label function (given tick, return label??)
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
# filterGadflyScale(gplt, isx)
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
# labelmap = Dict(zip(ticks...))
# labelfunc = val -> labelmap[val]
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
filterGadflyScale(gplt, isx)
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
push!(gplt.scales, gfunc(labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
end
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
scalekey = isx ? :xscale : :yscale
hasScaleKey = haskey(plotattributes, scalekey)
if hasScaleKey
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
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
end
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
end
function addGadflyLimitsScale(gplt, 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(plotattributes, limsym, :auto)
if lims == :auto
lims = nothing
else
if limsType(lims) == :limits
push!(limargs, (:minvalue, min(lims...)))
push!(limargs, (:maxvalue, max(lims...)))
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
end
# replace any current scales with this one
if hasScaleKey || !isempty(limargs)
filterGadflyScale(gplt, isx)
push!(gplt.scales, gfunc(; limargs...))
end
lims, func
end
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
if isa(gplt.coord, Gadfly.Coord.Cartesian)
gplt.coord = Gadfly.Coord.cartesian(
gplt.coord.xvars,
gplt.coord.yvars;
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
xflip = get(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(plotattributes, :xflip, false),
yflip = get(plotattributes, :yflip, false)
)
end
end
function findGuideAndSet(gplt, t::DataType, args...; kw...)
for (i,guide) in enumerate(gplt.guides)
if isa(guide, t)
gplt.guides[i] = t(args...; kw...)
end
end
end
function updateGadflyGuides(plt::Plot, plotattributes::KW)
gplt = getGadflyContext(plt)
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, plotattributes, true)
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
ticks = get(plotattributes, :xticks, :auto)
if ticks == :none
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(plotattributes, :yticks, :auto)
if ticks == :none
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
end
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
kwargs = KW()
# colors
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
map(s -> getColor(plotattributes[s]), (
:background_color_inside,
:foreground_color_grid,
:foreground_color_text,
:foreground_color_guide,
:foreground_color_legend
))
# # hide the legend?
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(plotattributes, :grid, true)
kwargs[:grid_color] = gridcolor
end
# fonts
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
getGadflyContext(plt).theme = Gadfly.Theme(;
background_color = insidecolor,
minor_label_color = textcolor,
minor_label_font = tfont.family,
minor_label_font_size = tfont.pointsize * Gadfly.pt,
major_label_color = guidecolor,
major_label_font = gfont.family,
major_label_font_size = gfont.pointsize * Gadfly.pt,
key_title_color = guidecolor,
key_title_font = gfont.family,
key_title_font_size = gfont.pointsize * Gadfly.pt,
key_label_color = legendcolor,
key_label_font = lfont.family,
key_label_font_size = lfont.pointsize * Gadfly.pt,
plot_padding = 1 * Gadfly.mm,
kwargs...
)
end
# ----------------------------------------------------------------
function createGadflyAnnotationObject(x, y, val::AbstractString)
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, val)
))
end
function createGadflyAnnotationObject(x, y, txt::PlotText)
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, txt.str, halign, valign, rotations...),
Compose.font(string(txt.font.family)),
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
Compose.stroke(txt.font.color),
Compose.fill(txt.font.color)
))
end
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
# gplt = createGadflyPlotObject(plotattributes)
# Plot(gplt, pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{GadflyBackend})
createGadflyPlotObject(plt.attr)
end
# plot one data series
# 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)
if gplt.layers[1].geom.tag == :remove
gplt.layers = gplt.layers[2:end]
end
addGadflySeries!(plt, series.plotattributes)
# push!(plt.seriesargs, plotattributes)
# plt
end
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
# ----------------------------------------------------------------
# accessors for x/y data
# TODO: need to save all the layer indices which apply to this series
function getGadflyMappings(plt::Plot, i::Integer)
@assert i > 0 && i <= plt.n
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
end
function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
# isbefore && return false # wait until after plotting to create the subplots
# subplt.o = nothing
# true
# end
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
# function buildGadflySubplotContext(subplt::Subplot)
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
#
# # add the Plot object to the row
# push!(row, getGadflyContext(subplt.plts[i]))
#
# # add the row
# if c == ncols(subplt.layout, r)
# push!(rows, Gadfly.hstack(row...))
# row = Any[]
# end
# end
#
# # stack the rows
# Gadfly.vstack(rows...)
# end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
# -------------------------------------------------------------------------
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
func = getGadflyWriteFunc($mime())
doshow(io, func, plt)
end
end
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
setGadflyDisplaySize(plt.attr[:size]...)
display(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
# ctx = buildGadflySubplotContext(subplt)
#
# # taken from Gadfly since I couldn't figure out how to do it directly
#
# filename = string(Gadfly.tempname(), ".html")
# output = open(filename, "w")
#
# plot_output = IOBuffer()
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
# Compose.default_graphic_height, false), ctx)
# plotsvg = takebuf_string(plot_output)
#
# write(output,
# """
# <!DOCTYPE html>
# <html>
# <head>
# <title>Gadfly Plot</title>
# <meta charset="utf-8">
# </head>
# <body>
# <script charset="utf-8">
# $(readall(Compose.snapsvgjs))
# </script>
# <script charset="utf-8">
# $(readall(Gadfly.gadflyjs))
# </script>
# $(plotsvg)
# </body>
# </html>
# """)
# close(output)
# Gadfly.open_file(filename)
# end
-93
View File
@@ -1,93 +0,0 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
struct ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
new(shape, tag)
end
end
# TODO: add for PR
# const shape = ShapeGeometry
function Gadfly.element_aesthetics(::ShapeGeometry)
[:x, :y, :size, :color]
end
# Generate a form for a shape geometry.
#
# Args:
# geom: shape geometry.
# theme: the plot's theme.
# aes: aesthetics.
#
# Returns:
# A compose Form.
#
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
# TODO: add for PR
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
# element_aesthetics(geom)...)
default_aes = Gadfly.Aesthetics()
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
default_aes.size = Compose.Measure[theme.default_point_size]
aes = Gadfly.inherit(aes, default_aes)
lw_hover_scale = 10
lw_ratio = theme.line_width / aes.size[1]
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
ctx = Compose.compose!(
Compose.context(),
make_polygon(geom, aes.x, aes.y, aes.size),
Compose.fill(aes.color),
Compose.linewidth(theme.highlight_width))
if aes.color_key_continuous != nothing && aes.color_key_continuous
Compose.compose!(ctx,
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
else
Compose.compose!(ctx,
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
for c in aes.color]))
end
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
end
function gadflyshape(sv::Shape)
ShapeGeometry(Any[vertices(sv)])
end
function gadflyshape(sv::AVec{Shape})
ShapeGeometry(Any[vertices(s) for s in sv])
end
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs))
T = Tuple{Compose.Measure, Compose.Measure}
polys = Array(Vector{T}, n)
for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
# ---------------------------------------------------------------------------------------------
-186
View File
@@ -1,186 +0,0 @@
# https://github.com/JuliaGraphics/Immerse.jl
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
is_subplot_supported(::ImmerseBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::ImmerseBackend; kw...)
@eval begin
import Immerse, Gadfly, Compose, Gtk
export Immerse, Gadfly, Compose, Gtk
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
end
end
function createImmerseFigure(plotattributes::KW)
w,h = plotattributes[:size]
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
Immerse.Figure(figidx)
end
# ----------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
# # create the underlying Gadfly.Plot object
# gplt = createGadflyPlotObject(plotattributes)
#
# # save both the Immerse.Figure and the Gadfly.Plot
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
# end
function _create_backend_figure(plt::Plot{ImmerseBackend})
(nothing, createGadflyPlotObject(plt.attr))
end
# # plot one data series
# 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.plotattributes)
end
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
updateGadflyGuides(plt, plotattributes)
updateGadflyPlotTheme(plt, plotattributes)
end
# ----------------------------------------------------------------
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
# return false
# # isbefore && return false
# end
#
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
# # create the Gtk window with vertical box vsep
# plotattributes = getattr(subplt,1)
# w,h = plotattributes[:size]
# vsep = Gtk.GtkBoxLeaf(:v)
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
#
# figindices = []
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# for (i,(r,c)) in enumerate(subplt.layout)
# plt = subplt.plts[i]
#
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
#
# # add the plot's box to the row
# push!(row, box)
#
# # create the figure and store the index returned for destruction later
# figidx = Immerse.figure(canvas)
# push!(figindices, figidx)
#
# fig = Immerse.figure(figidx)
# plt.o = (fig, plt.o[2])
#
# # add the row
# if c == ncols(subplt.layout, r)
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# end
#
# end
#
# # destructor... clean up plots
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
#
# subplt.o = win
# true
# end
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
fig, gplt = plt.o
if fig == nothing
fig = createImmerseFigure(plt.attr)
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
plt.o = (fig, gplt)
end
Immerse.figure(fig.figno; displayfig = false)
display(gplt)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
#
# # if we haven't created the window yet, do it
# if subplt.o == nothing
# showSubplotObject(subplt)
# end
#
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
# for plt in subplt.plts
# fig, gplt = plt.o
# Immerse.figure(fig.figno; displayfig = false)
# display(gplt)
# end
#
# # o is the window... show it
# showall(subplt.o)
# end
-308
View File
@@ -1,308 +0,0 @@
# https://github.com/tbreloff/Qwt.jl
supported_attrs(::QwtBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:pos,
:title,
:window_title,
:guide, :lims, :ticks, :scale,
])
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supported_scales(::QwtBackend) = [:identity, :log10]
is_subplot_supported(::QwtBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::QwtBackend; kw...)
@eval begin
@warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
end
# -------------------------------
const _qwtAliases = KW(
:bins => :heatmap_n,
:fillrange => :fillto,
:linewidth => :width,
:markershape => :marker,
:hexbin => :heatmap,
:path => :line,
:steppost => :step,
:steppre => :stepinverted,
:star5 => :star1,
:star8 => :star2,
)
function fixcolors(plotattributes::KW)
for (k,v) in plotattributes
if typeof(v) <: ColorScheme
plotattributes[k] = getColor(v)
end
end
end
function replaceQwtAliases(plotattributes, s)
if haskey(_qwtAliases, plotattributes[s])
plotattributes[s] = _qwtAliases[plotattributes[s]]
end
end
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
plotattributes = KW(kw)
st = plotattributes[:seriestype]
if st == :scatter
plotattributes[:seriestype] = :none
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
elseif st in (:hline, :vline)
addLineMarker(plt, plotattributes)
plotattributes[:seriestype] = :none
plotattributes[:markershape] = :circle
plotattributes[:markersize] = 1
if st == :vline
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
end
elseif !iscreating && st == :bar
plotattributes = barHack(; kw...)
elseif !iscreating && st == :histogram
plotattributes = barHack(; histogramHack(; kw...)...)
end
replaceQwtAliases(plotattributes, :seriestype)
replaceQwtAliases(plotattributes, :markershape)
for k in keys(plotattributes)
if haskey(_qwtAliases, k)
plotattributes[_qwtAliases[k]] = plotattributes[k]
end
end
plotattributes[:x] = collect(plotattributes[:x])
plotattributes[:y] = collect(plotattributes[:y])
plotattributes
end
# 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, plotattributes, KW[])
# plt
end
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
function _series_added(plt::Plot{QwtBackend}, series::Series)
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}, 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]
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: AbstractRange
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
scalesym = isx ? :xscale : :yscale
if haskey(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)
end
end
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}, 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}, plotattributes::KW)
for yi in plotattributes[:y]
marker = Qwt.QWT.QwtPlotMarker()
ishorizontal = (plotattributes[:seriestype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
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
# marker[:setValue](x, y)
# marker[:setLabel](Qwt.QWT.QwtText(val))
# marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
qwttext = Qwt.QWT.QwtText(val.str)
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
marker[:setLabel](qwttext)
marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
marker[:setLabel](Qwt.QWT.QwtText(val))
marker[:attach](plt.o.widget)
end
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createQwtAnnotation(plt, ann...)
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{QwtBackend}, i::Int)
series = plt.o.lines[i]
series.x, series.y
end
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.o.lines[i]
series.x, series.y = xy
plt
end
# -------------------------------
# -------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
# isbefore && return false
# i = 0
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
# push!(row, subplt.plts[i].o)
# if c == ncols(subplt.layout, r)
# push!(rows, Qwt.hsplitter(row...))
# row = Any[]
# end
# end
# # for rowcnt in subplt.layout.rowcounts
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
# # i += rowcnt
# # end
# subplt.o = Qwt.vsplitter(rows...)
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
# true
# end
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
for series in plt.o.lines
_expand_limits(lims, isx ? series.x : series.y)
end
end
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
end
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
write(io, readall("/tmp/dfskjdhfkh.png"))
end
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
# write(io, readall("/tmp/dfskjdhfkh.png"))
# end
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.showwidget(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.showwidget(subplt.o)
# end
-272
View File
@@ -1,272 +0,0 @@
# https://github.com/nolta/Winston.jl
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
supported_attrs(::WinstonBackend) = merge_with_base_supported([
:annotations,
:linecolor,
:fillrange,
:fillcolor,
:label,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:linewidth,
:markershape,
:markercolor,
:markersize,
:bins,
:title,
:window_title,
:guide, :lims, :scale,
])
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::WinstonBackend) = [:identity, :log10]
is_subplot_supported(::WinstonBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::WinstonBackend; kw...)
@eval begin
# ENV["WINSTON_OUTPUT"] = "gtk"
@warn("Winston is no longer supported... many features will likely be broken.")
import Winston, Gtk
export Winston, Gtk
end
end
# ---------------------------------------------------------------------------
## dictionaries for conversion of Plots.jl names to Winston ones.
const winston_linestyle = KW(:solid=>"solid",
:dash=>"dash",
:dot=>"dotted",
:dashdot=>"dotdashed"
)
const winston_marker = KW(:none=>".",
:rect => "square",
:circle=>"circle",
:diamond=>"diamond",
:utriangle=>"triangle",
:dtriangle=>"down-triangle",
:cross => "plus",
:xcross => "cross",
:star5 => "asterisk"
)
function _before_update(plt::Plot{WinstonBackend})
Winston.ghf(plt.o)
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{WinstonBackend})
Winston.FramedPlot(
title = plt.attr[:title],
xlabel = plt.attr[:xguide],
ylabel = plt.attr[:yguide]
)
end
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
function addRegressionLineWinston(plotattributes::KW, wplt)
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
end
function getWinstonItems(plt::Plot)
if isa(plt.o, Winston.FramedPlot)
wplt = plt.o
window, canvas = nothing, nothing
else
window, canvas, wplt = plt.o
end
window, canvas, wplt
end
function _series_added(plt::Plot{WinstonBackend}, series::Series)
plotattributes = series.plotattributes
window, canvas, wplt = getWinstonItems(plt)
# until we call it normally, do the hack
if plotattributes[:seriestype] == :bar
plotattributes = barHack(;plotattributes...)
end
e = KW()
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] = 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)
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
if plotattributes[:seriestype] == :none
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
elseif plotattributes[:seriestype] == :path
x, y = plotattributes[:x], plotattributes[:y]
Winston.add(wplt, Winston.Curve(x, y; e...))
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(plotattributes[:fillcolor])))
end
elseif plotattributes[:seriestype] == :scatter
if plotattributes[:markershape] == :none
plotattributes[:markershape] = :circle
end
# elseif plotattributes[:seriestype] == :step
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :stepinverted
# fn = Winston.XXX
elseif plotattributes[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
# elseif plotattributes[:seriestype] == :dots
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :histogram2d
# fn = Winston.XXX
# elseif plotattributes[:seriestype] == :hexbin
# fn = Winston.XXX
elseif plotattributes[:seriestype] == :histogram
hst = hist(plotattributes[:y], plotattributes[:bins])
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
# elseif plotattributes[:seriestype] == :bar
# # fn = Winston.XXX
else
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
end
# markershape
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
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
# push!(plt.seriesargs, plotattributes)
# plt
end
# ----------------------------------------------------------------
const _winstonNames = KW(
:xlims => :xrange,
:ylims => :yrange,
:xscale => :xlog,
:yscale => :ylog,
)
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xguide, :yguide, :title, :xlims, :ylims)
if haskey(plotattributes, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
end
end
for k in (:xscale, :yscale)
if haskey(plotattributes, k)
islogscale = plotattributes[k] == :log10
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
end
end
end
# ----------------------------------------------------------------
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
Winston.text(x, y, val)
end
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
# end
# ----------------------------------------------------------------
function addWinstonLegend(plt::Plot, wplt)
if plt.attr[:legend] != :none
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
end
end
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
addWinstonLegend(plt, wplt)
show(io, "image/png", wplt)
end
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
if window == nothing
if Winston.output_surface != :gtk
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
end
# initialize window
w,h = plt.attr[:size]
canvas = Gtk.GtkCanvasLeaf()
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
plt.o = (window, canvas, wplt)
end
addWinstonLegend(plt, wplt)
Winston.display(canvas, wplt)
Gtk.showall(window)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
# # TODO: display/show the Subplot object
# end
File diff suppressed because it is too large Load Diff
-415
View File
@@ -1,415 +0,0 @@
abstract type ColorScheme end
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
export
cgrad
cgrad() = default_gradient()
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
colors = ColorGradient(arg, alpha=alpha).colors
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(range(1, stop=10, length=30))
elseif scale == :log2
log2(range(1, stop=2, length=30))
elseif scale == :ln
log(range(1, stop=pi, length=30))
elseif scale in (:exp, :exp10)
(exp10(range(0, stop=1, length=30)) - 1) / 9
else
range(0, stop=1, length=length(colors))
end
ColorGradient(colors, values)
end
# --------------------------------------------------------------
getColor(scheme::ColorScheme) = getColor(scheme, 1)
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
# --------------------------------------------------------------
convertColor(c::AbstractString) = parse(Colorant, c)
convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
convertColor(v::Nothing) = RGBA(0,0,0,0)
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
function convertColor(c, α::Real)
c = convertColor(c)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::Nothing) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
# --------------------------------------------------------------
function darken(c, v=0.1)
rgba = convert(RGBA, c)
r = max(0, min(rgba.r - v, 1))
g = max(0, min(rgba.g - v, 1))
b = max(0, min(rgba.b - v, 1))
RGBA(r,g,b,rgba.alpha)
end
function lighten(c, v=0.3)
darken(c, -v)
end
# --------------------------------------------------------------
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
const _gradients = KW(
:blues => [colorant"lightblue", colorant"darkblue"],
:reds => [colorant"lightpink", colorant"darkred"],
:greens => [colorant"lightgreen", colorant"darkgreen"],
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
:rainbow => _rainbowColors,
:lightrainbow => map(lighten, _rainbowColors),
:darkrainbow => map(darken, _rainbowColors),
:darktest => _testColors,
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
_gradients[name] = colors
end
include("color_gradients.jl")
default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
struct ColorGradient <: ColorScheme
colors::Vector
values::Vector
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 range(0, stop = 1, length = length(cs))]
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(range(0, stop=1, length=length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
new(convertColor(cs, alpha), vals)
end
end
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient(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 = range(0, stop=1, length=length(cs))
end
ColorGradient(cs, vals; kw...)
end
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
function ColorGradient(grad::ColorGradient; alpha = nothing)
ColorGradient(convertColor(grad.colors, alpha), grad.values)
end
# anything else just gets the default gradient
function ColorGradient(cw; alpha=nothing)
ColorGradient(default_gradient(), alpha=alpha)
end
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
function getColorZ(gradient::ColorGradient, z::Real)
cs = gradient.colors
vs = gradient.values
n = length(cs)
@assert n > 0 && n == length(vs)
# can we just return the first color?
if z <= vs[1] || n == 1
return cs[1]
end
# find the bounding colors and interpolate
for i in 2:n
if z <= vs[i]
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
end
end
# if we get here, return the last color
cs[end]
end
getColorVector(gradient::ColorGradient) = gradient.colors
# for 0.3
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
rgb1 = RGBA(c1)
rgb2 = RGBA(c2)
r = interpolate(rgb1.r, rgb2.r, w)
g = interpolate(rgb1.g, rgb2.g, w)
b = interpolate(rgb1.b, rgb2.b, w)
a = interpolate(rgb1.alpha, rgb2.alpha, w)
RGBA(r, g, b, a)
end
function interpolate(v1::Real, v2::Real, w::Real)
(1-w) * v1 + w * v2
end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
struct ColorFunction <: ColorScheme
f::Function
end
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
struct ColorZFunction <: ColorScheme
f::Function
end
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
struct ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
struct ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Nothing) = c.c
# --------------------------------------------------------------
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
# move closer to lighter/darker depending on background value
function adjustAway(val, bgval, vmin=0., vmax=100.)
if bgval < 0.5 * (vmax+vmin)
tmp = max(val, bgval)
return 0.5 * (tmp + max(tmp, vmax))
else
tmp = min(val, bgval)
return 0.5 * (tmp + min(tmp, vmin))
end
end
# borrowed from http://stackoverflow.com/a/1855903:
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
isdark(c::Colorant) = lightnessLevel(c) < 0.5
islight(c::Colorant) = !isdark(c)
function convertHexToRGB(h::Unsigned)
mask = 0x0000FF
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
end
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
const _masterColorList = [
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
]
const _allColors = map(convertHexToRGB, _masterColorList)
const _darkColors = filter(isdark, _allColors)
const _lightColors = filter(islight, _allColors)
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
const _defaultNumColors = 17
# --------------------------------------------------------------
# Methods to automatically generate gradients for color selection based on
# background color and a short list of seed colors
# here are some magic constants that could be changed if you really want
const _lightness_darkbg = [80.0]
const _lightness_lightbg = [60.0]
const _lch_c_const = [60]
function adjust_lch(color, l, c)
lch = convert(LCHab, color)
convert(RGB, LCHab(l, c, lch.h))
end
function lightness_from_background(bgcolor)
bglight = convert(LCHab, bgcolor).l
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
end
function gradient_from_list(cs)
zvalues = Plots.get_zvalues(length(cs))
indices = sortperm(zvalues)
sorted_colors = map(RGBA, cs[indices])
sorted_zvalues = zvalues[indices]
ColorGradient(sorted_colors, sorted_zvalues)
end
function generate_colorgradient(bgcolor = colorant"white";
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
lightness = lightness_from_background(bgcolor),
chroma = _lch_c_const[1],
n = _defaultNumColors)
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
colors = distinguishable_colors(n,
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=range(0, stop=340, length=20)
)[2:end]
gradient_from_list(colors)
end
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
grad = if palette == :auto
generate_colorgradient(bgcolor)
else
ColorGradient(palette)
end
zrng = get_zvalues(numcolors)
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
palette
end
# ----------------------------------------------------------------------------------
function getpctrange(n::Int)
n > 0 || error()
n == 1 && return zeros(1)
zs = [0.0, 1.0]
for i in 3:n
sorted = sort(zs)
diffs = diff(sorted)
widestj = 0
widest = 0.0
for (j,d) in enumerate(diffs)
if d > widest
widest = d
widestj = j
end
end
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
end
zs
end
function get_zvalues(n::Int)
offsets = getpctrange(ceil(Int,n/4)+1)/4
offsets = vcat(offsets[1], offsets[3:end])
zvalues = Float64[]
for offset in offsets
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
end
vcat(zvalues[1], 1.0, zvalues[2:n-1])
end
# ----------------------------------------------------------------------------------
make255(x) = round(Int, 255 * x)
function webcolor(c::Color)
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
end
function webcolor(c::TransparentColor)
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
end
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
webcolor(c) = webcolor(convertColor(c))
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
# ----------------------------------------------------------------------------------
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, sp::Subplot, n::Int)
if c == :auto
c = autopick(sp[:color_palette], n)
end
# c should now be a subtype of ColorScheme
colorscheme(c)
end
-63
View File
@@ -1,63 +0,0 @@
# TODO:
"""
- load Contours.jl similar to DataFrames
- method to build grid from x/y/z vectors
- method to wrap contours creation
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
"""
# # ----------------------------------------------------------
# # ----------------------------------------------------------
# immutable Vertex
# x::Float64
# y::Float64
# z::Float64
# end
# immutable Edge
# v::Vertex
# u::Vertex
# end
# # ----------------------------------------------------------
# # one rectangle's z-values and the center vertex
# # z is ordered: topleft, topright, bottomright, bottomleft
# immutable GridRect
# z::Vector{Float64}
# center::Vertex
# data::Vector{Vertex}
# end
# type Grid
# xs::Vector{Float64}
# ys::Vector{Float64}
# rects::Matrix{GridRect}
# end
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
# vs = sort(v)
# end
# # the goal here is to create the vertical and horizontal partitions
# # which define the grid, so that the data is somewhat evenly split
# function bucketData(x, y, z)
# end
# function buildGrid(x, y, z)
# # create
# end
-99
View File
@@ -1,99 +0,0 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
# missing
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
# string vector
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, plotattributes::KW)
if all3D(plotattributes)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# function
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
# dates
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, 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, plotattributes)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, plotattributes::KW) = Any[t], nothing
function convertToAnyVector(args...)
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
end
# --------------------------------------------------------------------
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::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::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::Nothing) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
nobigs(v::AVec{BigInt}) = map(Int64, v)
nobigs(v) = v
@noinline function compute_xyz(x, y, z)
x = compute_x(x,y,z)
y = compute_y(x,y,z)
z = compute_z(x,y,z)
nobigs(x), nobigs(y), nobigs(z)
end
# not allowed
compute_xyz(x::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!")
# --------------------------------------------------------------------
+30 -1
View File
@@ -435,8 +435,37 @@ each line segment or marker in the plot.
end)]
),
PlotExample("Portfolio Composition maps",
"""
see: http://stackoverflow.com/a/37732384/5075246
""",
[:(begin
using Random
Random.seed!(111)
tickers = ["IBM", "Google", "Apple", "Intel"]
N = 10
D = length(tickers)
weights = rand(N,D)
weights ./= sum(weights, dims = 2)
returns = sort!((1:N) + D*randn(N))
portfoliocomposition(weights, returns, labels = permutedims(tickers))
end)]
),
]
# Some constants for PlotDocs and PlotReferenceImages
_animation_examples = [2, 30]
_backend_skips = Dict(
:gr => [25, 30],
:pyplot => [25, 30],
:plotlyjs => [2, 21, 25, 30, 31],
:pgfplots => [2, 5, 6, 10, 16, 20, 22, 23, 25, 28, 30],
)
# ---------------------------------------------------------------------------------
# make and display one plot
@@ -473,7 +502,7 @@ function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = noth
plts[i] = plt
catch ex
# TODO: put error info into markdown?
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
@warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
end
if sleep != nothing
Base.sleep(sleep)
+24
View File
@@ -0,0 +1,24 @@
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
_fileio_load(@nospecialize(filename::AbstractString)) = FileIO.load(filename::AbstractString)
_fileio_save(@nospecialize(filename::AbstractString), @nospecialize(x)) = FileIO.save(filename::AbstractString, x)
function _show_pdfbackends(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = _fileio_load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
_fileio_save(pngfn, s)
# now write from the file
write(io, read(open(pngfn), String))
end
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
+59
View File
@@ -0,0 +1,59 @@
const use_local_dependencies = Ref(false)
const use_local_plotlyjs = Ref(false)
function _init_ijulia_plotting()
# IJulia is more stable with local file
use_local_plotlyjs[] = isfile(plotly_local_file_path)
ENV["MPLBACKEND"] = "Agg"
end
"""
Add extra jupyter mimetypes to display_dict based on the plot backed.
The default is nothing, except for plotly based backends, where it
adds data for `application/vnd.plotly.v1+json` that is used in
frontends like jupyterlab and nteract.
"""
_ijulia__extra_mime_info!(plt::Plot, out::Dict) = out
function _ijulia__extra_mime_info!(plt::Plot{PlotlyJSBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = JSON.lower(plt.o)
out
end
function _ijulia__extra_mime_info!(plt::Plot{PlotlyBackend}, out::Dict)
out["application/vnd.plotly.v1+json"] = Dict(
:data => plotly_series(plt),
:layout => plotly_layout(plt)
)
out
end
function _ijulia_display_dict(plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
mime = "image/svg+xml"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :html
mime = "text/html"
out[mime] = sprint(show, MIME(mime), plt)
else
error("Unsupported output type $output_type")
end
_ijulia__extra_mime_info!(plt, out)
out
end
+39 -66
View File
@@ -1,26 +1,33 @@
function __init__()
using REPL
function _plots_defaults()
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
Main.PLOTS_DEFAULTS::Dict{Symbol,Any}
else
Dict{Symbol,Any}()
end
pushdisplay(PlotsDisplay())
end
function __init__()
user_defaults = _plots_defaults()
if haskey(user_defaults, :theme)
theme(user_defaults[:theme])
end
for (k,v) in user_defaults
k == :theme || default(k, v)
end
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, PlotsDisplay())
atreplinit(i -> begin
if PlotDisplay() in Base.Multimedia.displays
while PlotsDisplay() in Base.Multimedia.displays
popdisplay(PlotsDisplay())
end
pushdisplay(PlotsDisplay())
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, 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"))
@@ -28,60 +35,26 @@ function __init__()
@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
_init_ijulia_plotting()
"""
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"
IJulia.display_dict(plt::Plot) = _ijulia_display_dict(plt)
end
end
if haskey(ENV, "PLOTS_HOST_DEPENDENCY_LOCAL")
use_local_plotlyjs[] = ENV["PLOTS_HOST_DEPENDENCY_LOCAL"] == "true"
use_local_dependencies[] = isfile(plotly_local_file_path) && use_local_plotlyjs[]
if use_local_plotlyjs[] && !isfile(plotly_local_file_path)
@warn("PLOTS_HOST_DEPENDENCY_LOCAL is set to true, but no local plotly file found. run Pkg.build(\"Plots\") and make sure PLOTS_HOST_DEPENDENCY_LOCAL is set to true")
end
else
use_local_dependencies[] = use_local_plotlyjs[]
end
@require FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" begin
_show(io::IO, mime::MIME"image/png", plt::Plot{<:PDFBackends}) = _show_pdfbackends(io, mime, plt)
end
end
-25
View File
@@ -156,7 +156,6 @@ end
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
:glvisualize => :png,
:plotlyjs => :html,
:plotly => :html
)
@@ -210,30 +209,6 @@ _show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
closeall() = closeall(backend())
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
if is_installed("FileIO")
@eval import FileIO
function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends})
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = FileIO.load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
FileIO.save(pngfn, s)
# now write from the file
write(io, read(open(pngfn), String))
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.show(io::IO, ::MIME"text/html", plt::Plot)
+2 -2
View File
@@ -166,9 +166,9 @@ end
function _plot!(plt::Plot, plotattributes::KW, args::Tuple)
plotattributes[:plot_object] = plt
if !isempty(args) && !isdefined(Main, :StatPlots) &&
if !isempty(args) && !isdefined(Main, :StatsPlots) &&
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 StatsPlots")
end
# --------------------------------
+1 -1
View File
@@ -18,7 +18,7 @@ end
plotattr([attr])
Look up the properties of a Plots attribute, or specify an attribute type. Call `plotattr()` for options.
The information is the same as that given on https://juliaplots.github.io/attributes/.
The information is the same as that given on https://docs.juliaplots.org/latest/attributes/.
"""
function plotattr()
println("Specify an attribute type to get a list of supported attributes. Options are $(attrtypes())")
+36 -6
View File
@@ -586,12 +586,12 @@ 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 StatsPlots 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)))
_cl(x) = ceil(Int, 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)
_span(v) = maximum(v) - minimum(v)
n_samples = length(LinearIndices(first(vs)))
@@ -635,11 +635,19 @@ _hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, Abstra
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
_filternans(vs::NTuple{1,AbstractVector}) = filter!.(isfinite, vs)
function _filternans(vs::NTuple{N,AbstractVector}) where N
_invertedindex(v, not) = [j for (i,j) in enumerate(v) if !(i not)]
nots = union(Set.(findall.(!isfinite, vs))...)
_invertedindex.(vs, Ref(nots))
end
function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
edges = _hist_edges(vs, binning)
localvs = _filternans(vs)
edges = _hist_edges(localvs, binning)
h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
StatsBase.fit(StatsBase.Histogram, localvs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, localvs, StatsBase.Weights(weights), edges, closed = :left)
)
normalize!(h, mode = _hist_norm_mode(normed))
end
@@ -1131,3 +1139,25 @@ end
title := string(grad.args[1])
z
end
# Moved in from PlotRecipes - see: http://stackoverflow.com/a/37732384/5075246
@userplot PortfolioComposition
# this shows the shifting composition of a basket of something over a variable
# - "returns" are the dependent variable
# - "weights" are a matrix where the ith column is the composition for returns[i]
# - since each polygon is its own series, you can assign labels easily
@recipe function f(pc::PortfolioComposition)
weights, returns = pc.args
n = length(returns)
weights = cumsum(weights, dims = 2)
seriestype := :shape
# create a filled polygon for each item
for c=1:size(weights,2)
sx = vcat(weights[:,c], c==1 ? zeros(n) : reverse(weights[:,c-1]))
sy = vcat(returns, reverse(returns))
@series Plots.isvertical(plotattributes) ? (sx, sy) : (sy, sx)
end
end
+28 -13
View File
@@ -323,19 +323,26 @@ end
# # images - grays
function clamp_greys!(mat::AMat{T}) where T<:Gray
for i in eachindex(mat)
mat[i].val < 0 && (mat[i] = Gray(0))
mat[i].val > 1 && (mat[i] = Gray(1))
end
mat
end
@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
SliceIt, 1:m, 1:n, Surface(clamp_greys!(mat))
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
SliceIt, 1:m, 1:n, Surface(clamp!(convert(Matrix{Float64}, mat), 0., 1.))
end
end
@@ -386,8 +393,9 @@ end
xmin, xmax = try
axis_limits(plt[1][:xaxis])
catch
xm = tryrange(f, [-5,-1,0,0.01])
xm, tryrange(f, filter(x->x>xm, [5,1,0.99, 0, -0.01]))
xinv = invscalefunc(get(plotattributes, :xscale, :identity))
xm = tryrange(f, xinv.([-5,-1,0,0.01]))
xm, tryrange(f, filter(x->x>xm, xinv.([5,1,0.99, 0, -0.01])))
end
f, xmin, xmax
@@ -517,16 +525,23 @@ end
#
# # special handling... xmin/xmax with parametric function(s)
@recipe function f(f::Function, xmin::Number, xmax::Number)
xs = adapted_grid(f, (xmin, xmax))
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
xs = _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
xs, f
end
@recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
xscale, yscale = [get(plotattributes, sym, :identity) for sym=(:xscale,:yscale)]
xs = Any[_scaled_adapted_grid(f, xscale, yscale, xmin, xmax) for f in fs]
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, range(umin, stop = umax, length = n)
function _scaled_adapted_grid(f, xscale, yscale, xmin, xmax)
(xf, xinv), (yf, yinv) = ((scalefunc(s),invscalefunc(s)) for s in (xscale,yscale))
xinv.(adapted_grid(yf∘f∘xinv, xf.((xmin, xmax))))
end
#
# # special handling... 3D parametric function(s)
@recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
@@ -539,7 +554,7 @@ end
#
#
# # --------------------------------------------------------------------
# # Lists of tuples and FixedSizeArrays
# # Lists of tuples and StaticArrays
# # --------------------------------------------------------------------
#
# # if we get an unhandled tuple, just splat it in
@@ -561,14 +576,14 @@ end
#
# # 2D FixedSizeArrays
@recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
@recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
# # 2D StaticArrays
@recipe f(xy::AVec{StaticArrays.SVector{2,T}}) where {T<:Number} = unzip(xy)
@recipe f(xy::StaticArrays.SVector{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# # 3D StaticArrays
@recipe f(xyz::AVec{StaticArrays.SVector{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f(xyz::StaticArrays.SVector{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
#
# # --------------------------------------------------------------------
+455
View File
@@ -0,0 +1,455 @@
"""
scatter(x,y)
scatter!(x,y)
Make a scatter plot of y vs x.
# Examples
```julia-repl
julia> scatter([1,2,3],[4,5,6],markersize=[3,4,5],markercolor=[:red,:green,:blue])
julia> scatter([(1,4),(2,5),(3,6)])
```
"""
@shorthands scatter
"""
bar(x,y)
bar!(x,y)
Make a bar plot of y vs x.
# Arguments
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Examples
```julia-repl
julia> bar([1,2,3],[4,5,6],fillcolor=[:red,:green,:blue],fillalpha=[0.2,0.4,0.6])
julia> bar([(1,4),(2,5),(3,6)])
```
"""
@shorthands bar
@shorthands barh
"""
histogram(x)
histogram!(x)
Plot a histogram.
# Arguments
- `x`: AbstractVector of values to be binned
- $(_document_argument("bins"))
- `weights`: Vector of weights for the values in `x`, for weighted bin counts
- $(_document_argument("normalize"))
- $(_document_argument("bar_position"))
- $(_document_argument("bar_width"))
- $(_document_argument("bar_edges"))
- $(_document_argument("orientation"))
# Example
```julia-repl
julia> histogram([1,2,1,1,4,3,8],bins=0:8)
```
"""
@shorthands histogram
"""
barhist(x)
barhist!(x)
Make a histogram bar plot. See `histogram`.
"""
@shorthands barhist
"""
stephist(x)
stephist(x)
Make a histogram step plot (bin counts are represented using horizontal lines
instead of bars). See `histogram`.
"""
@shorthands stephist
"""
scatterhist(x)
scatterhist!(x)
Make a histogram scatter plot (bin counts are represented using points
instead of bars). See `histogram`.
"""
@shorthands scatterhist
"""
histogram2d(x,y)
histogram2d!(x,y)
Plot a two-dimensional histogram.
# Arguments
- `bins`: Number of bins (if an `Integer`) or bin edges (if an `AbtractVector`)
- `weights`: Vector of weights for the values in `x`. Each entry of x contributes
its weight to the height of its bin.
# Example
```julia-repl
julia> histogram2d(randn(10_000),randn(10_000))
```
"""
@shorthands histogram2d
"""
density(x)
density!(x)
Make a line plot of a kernel density estimate of x.
# Arguments
- `x`: AbstractVector of samples for probability density estimation
# Example
```julia-repl
julia> using StatsPlots
julia> density(randn(100_000))
```
"""
@shorthands density
"""
heatmap(x,y,z)
heatmap!(x,y,z)
Plot a heatmap of the rectangular array `z`.
# Example
```julia-repl
julia> heatmap(randn(10,10))
```
"""
@shorthands heatmap
@shorthands plots_heatmap
"""
hexbin(x,y)
hexbin!(x,y)
Make a hexagonal binning plot (a histogram of the observations `(x[i],y[i])`
with hexagonal bins)
# Example
```julia-repl
julia> hexbin(randn(10_000), randn(10_000))
```
"""
@shorthands hexbin
"""
sticks(x,y)
sticks!(x,y)
Draw a stick plot of y vs x.
# Example
```julia-repl
julia> sticks(1:10)
```
"""
@shorthands sticks
"""
hline(y)
hline!(y)
Draw horizontal lines at positions specified by the values in
the AbstractVector `y`
# Example
```julia-repl
julia> hline([-1,0,2])
```
"""
@shorthands hline
"""
vline(x)
vline!(x)
Draw vertical lines at positions specified by the values in
the AbstractVector `x`
# Example
```julia-repl
julia> vline([-1,0,2])
```
"""
@shorthands vline
"""
hspan(y)
Draw a rectangle between the horizontal line at position `y[1]`
and the horizontal line at position `y[2]`. If `length(y) ≥ 4`,
then further rectangles are drawn between `y[3]` and `y[4]`,
`y[5]` and `y[6]`, and so on. If `length(y)` is odd, then the
last entry of `y` is ignored.
# Example
```julia-repl
julia> hspan(1:6)
```
"""
@shorthands hspan
"""
vspan(x)
Draw a rectangle between the vertical line at position `x[1]`
and the vertical line at position `x[2]`. If `length(x) ≥ 4`,
then further rectangles are drawn between `x[3]` and `x[4]`,
`x[5]` and `x[6]`, and so on. If `length(x)` is odd, then the
last entry of `x` is ignored.
# Example
```julia-repl
julia> vspan(1:6)
```
"""
@shorthands vspan
"""
ohlc(x,y::Vector{OHLC})
ohlc!(x,y::Vector{OHLC})
Make open-high-low-close plot. Each entry of y is represented by a vertical
segment extending from the low value to the high value, with short horizontal
segments on the left and right indicating the open and close values, respectively.
# Example
```julia-repl
julia> meanprices = cumsum(randn(100))
julia> y = OHLC[(p+rand(),p+1,p-1,p+rand()) for p in meanprices]
julia> ohlc(y)
```
"""
@shorthands ohlc
"""
contour(x,y,z)
contour!(x,y,z)
Draw contour lines of the `Surface` z.
# Arguments
- `levels`: Contour levels (if `AbstractVector`) or number of levels (if `Integer`)
- `fill`: Bool. Fill area between contours or draw contours only (false by default)
# Example
```julia-repl
julia> x = y = range(-20, 20, length = 100)
julia> contour(x, y, (x, y) -> x^2 + y^2)
```
"""
@shorthands contour
"An alias for `contour` with fill = true."
@shorthands contourf
@shorthands contour3d
"""
surface(x,y,z)
surface!(x,y,z)
Draw a 3D surface plot.
# Example
```julia-repl
julia> x = y = range(-3, 3, length = 100)
julia> surface(x, y, (x, y) -> sinc(norm([x, y])))
```
"""
@shorthands surface
"""
wireframe(x,y,z)
wireframe!(x,y,z)
Draw a 3D wireframe plot.
# Example
```julia-repl
julia> wireframe(1:10,1:10,randn(10,10))
```
"""
@shorthands wireframe
"""
path3d(x,y,z)
path3d!(x,y,z)
Plot a 3D path from `(x[1],y[1],z[1])` to `(x[2],y[2],z[2])`,
..., to `(x[end],y[end],z[end])`.
# Example
```julia-repl
julia> path3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@shorthands path3d
"""
scatter3d(x,y,z)
scatter3d!(x,y,z)
Make a 3D scatter plot.
# Example
```julia-repl
julia> scatter3d([0,1,2,3],[0,1,4,9],[0,1,8,27])
```
"""
@shorthands scatter3d
"""
boxplot(x, y)
boxplot!(x, y)
Make a box and whisker plot.
# Keyword arguments
- `notch`: Bool. Notch the box plot? (false)
- `range`: Real. Values more than range*IQR below the first quartile
or above the third quartile are shown as outliers (1.5)
- `outliers`: Bool. Show outliers? (true)
- `whisker_width`: Real or Symbol. Length of whiskers (:match)
# Example
```julia-repl
julia> using StatsPlots
julia> boxplot(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands boxplot
"""
violin(x,y,z)
violin!(x,y,z)
Make a violin plot.
# Example
```julia-repl
julia> violin(repeat([1,2,3],outer=100),randn(300))
```
"""
@shorthands violin
"""
quiver(x,y,quiver=(u,v))
quiver!(x,y,quiver=(u,v))
Make a quiver (vector field) plot. The `i`th vector extends
from `(x[i],y[i])` to `(x[i] + u[i], y[i] + v[i])`.
# Example
```julia-repl
julia> quiver([1,2,3],[3,2,1],quiver=([1,1,1],[1,2,3]))
```
"""
@shorthands quiver
"""
curves(x,y)
curves!(x,y)
Draw a Bezier curve from `(x[1],y[1])` to `(x[end],y[end])`
with control points `(x[2],y[2]), ..., (x[end-1],y[end]-1)`
# Example
```julia-repl
julia> curves([1,2,3,4],[1,1,2,4])
```
"""
@shorthands curves
"Plot a pie diagram"
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
"Plot with seriestype :path3d"
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
"Add title to an existing plot"
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
"Add xlabel to an existing plot"
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
"Add ylabel to an existing plot"
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot"
xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot"
ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot"
zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
"Set xticks for an existing plot"
xticks!(v::TicksArgs; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot"
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...)
yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"""
annotate!(anns...)
Add annotations to an existing plot.
# Arguments
- `anns`: An `AbstractVector` of tuples of the form (x,y,text). The text object
can be an String or PlotText
# Example
```julia-repl
julia> plot(1:10)
julia> annotate!([(7,3,"(7,3)"),(3,7,text("hey", 14, :left, :top, :green))])
```
"""
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
"Flip the current plots' y axis"
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
"Specify x axis attributes for an existing plot"
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
"Specify x axis attributes for an existing plot"
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
xgrid!(args...; kw...) = plot!(; xgrid = args, kw...)
ygrid!(args...; kw...) = plot!(; ygrid = args, kw...)
+1 -1
View File
@@ -100,7 +100,7 @@ _get_showtheme_args(thm::Symbol, func::Symbol) = thm, get(_color_functions, func
end
end
srand(1)
Random.seed!(1)
label := ""
colorbar := false
+43 -16
View File
@@ -287,14 +287,14 @@ unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2]
unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip(xy::AVec{StaticArrays.SVector{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip(xy::StaticArrays.SVector{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip(xyz::AVec{StaticArrays.SVector{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip(xyz::StaticArrays.SVector{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
unzip(xyuv::AVec{StaticArrays.SVector{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip(xyuv::StaticArrays.SVector{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
@@ -357,6 +357,7 @@ const _scale_base = Dict{Symbol, Real}(
)
function _heatmap_edges(v::AVec)
length(v) == 1 && return v[1] .+ [-0.5, 0.5]
vmin, vmax = ignorenan_extrema(v)
extra_min = (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2
@@ -412,14 +413,6 @@ end
isijulia() = :IJulia in nameof.(collect(values(Base.loaded_modules)))
isatom() = :Atom in nameof.(collect(values(Base.loaded_modules)))
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false : true
catch
false
end
end
istuple(::Tuple) = true
istuple(::Any) = false
isvector(::AVec) = true
@@ -733,7 +726,7 @@ function with(f::Function, args...; kw...)
# save the backend
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
_pick_default_backend()
end
oldbackend = CURRENT_BACKEND.sym
@@ -745,7 +738,7 @@ function with(f::Function, args...; kw...)
end
# # TODO: generalize this strategy to allow args as much as possible
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
# # as in: with(:gr, :scatter, :legend, :grid) do; ...; end
# # TODO: can we generalize this enough to also do something similar in the plot commands??
# k = :seriestype
@@ -1206,3 +1199,37 @@ end
function construct_categorical_data(x::AbstractArray, axis::Axis)
map(xi -> axis[:discrete_values][searchsortedfirst(axis[:continuous_values], xi)], x)
end
_fmt_paragraph(paragraph::AbstractString;kwargs...) = _fmt_paragraph(IOBuffer(),paragraph,0;kwargs...)
function _fmt_paragraph(io::IOBuffer,
remaining_text::AbstractString,
column_count::Integer;
fillwidth=60,
leadingspaces=0)
kwargs = (fillwidth = fillwidth, leadingspaces = leadingspaces)
m = match(r"(.*?) (.*)",remaining_text)
if isa(m,Nothing)
if column_count + length(remaining_text) fillwidth
print(io,remaining_text)
String(take!(io))
else
print(io,"\n"*" "^leadingspaces*remaining_text)
String(take!(io))
end
else
if column_count + length(m[1]) fillwidth
print(io,"$(m[1]) ")
_fmt_paragraph(io,m[2],column_count + length(m[1]) + 1;kwargs...)
else
print(io,"\n"*" "^leadingspaces*"$(m[1]) ")
_fmt_paragraph(io,m[2],leadingspaces;kwargs...)
end
end
end
function _document_argument(S::AbstractString)
_fmt_paragraph("`$S`: "*_arg_desc[Symbol(S)],leadingspaces = 6 + length(S))
end
+1 -1
View File
@@ -1,4 +1,4 @@
StatPlots
StatsPlots
Images
ImageMagick
@osx QuartzImageIO
+16 -1
View File
@@ -4,7 +4,6 @@ using Pkg
# 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"),
@@ -17,12 +16,28 @@ to_add = [
]
if isinteractive()
Pkg.develop(PackageSpec(url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git"))
append!(to_add, [
PackageSpec(name="FileIO"),
PackageSpec(name="ImageMagick"),
PackageSpec(name="UnicodePlots"),
PackageSpec(name="VisualRegressionTests"),
PackageSpec(name="Gtk"),
# PlotlyJS:
# PackageSpec(name="PlotlyJS"),
# PackageSpec(name="Blink"),
# PackageSpec(name="ORCA"),
# PyPlot:
# PackageSpec(name="PyPlot"),
# PackageSpec(name="PyCall"),
# PackageSpec(name="LaTeXStrings"),
])
else
push!(to_add, PackageSpec(
name="PlotReferenceImages",
url="https://github.com/JuliaPlots/PlotReferenceImages.jl.git",
rev = "sd-tomls"
))
end
Pkg.add(to_add)
+2 -2
View File
@@ -18,7 +18,7 @@ end
using Plots
# using StatPlots
# using StatsPlots
import PlotReferenceImages
using Random
using Test
@@ -29,7 +29,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.20.3"
import Plots._current_plots_version
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], tol = 1e-2)
+16 -35
View File
@@ -14,16 +14,19 @@ img_tol = isinteractive() ? 1e-2 : 10e-2
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
@static if Sys.islinux()
image_comparison_facts(:gr, tol=img_tol, skip = [25, 30])
end
end
#@testset "PyPlot" begin
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
# @static if isinteractive()
# @testset "PyPlot" begin
# @test pyplot() == Plots.PyPlotBackend()
# @test backend() == Plots.PyPlotBackend()
#
# image_comparison_facts(:pyplot, tol=img_tol)
#end
# image_comparison_facts(:pyplot, tol=img_tol, skip = [2, 25, 30, 31])
# end
# end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@@ -36,22 +39,23 @@ end
# The plotlyjs testimages return a connection error on travis:
# connect: connection refused (ECONNREFUSED)
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
# @static if isinteractive()
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
#
# if Sys.islinux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
# 25,
# 27, # (polar plots) takes very long / not working
# 30,
# 31, # animation (skipped for speed)
# ],
# tol=img_tol)
# end
# end
# InspectDR returns that error on travis:
# ERROR: LoadError: InitError: Cannot open display:
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
@@ -83,16 +87,6 @@ end
# # @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
# @testset "Immerse" begin
# @test immerse() == Plots.ImmerseBackend()
# @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], tol=img_tol)
# end
# @testset "PlotlyJS" begin
# @test plotlyjs() == Plots.PlotlyJSBackend()
# @test backend() == Plots.PlotlyJSBackend()
@@ -102,19 +96,6 @@ end
# end
# @testset "Gadfly" begin
# @test gadfly() == Plots.GadflyBackend()
# @test backend() == Plots.GadflyBackend()
#
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
# @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], tol=img_tol)
# end
@testset "Axes" begin