Compare commits

..

203 Commits

Author SHA1 Message Date
Thomas Breloff fd4dd13270 added svg in pyplot; deprecate qwt; writemime backup for html 2016-03-09 13:36:21 -05:00
Thomas Breloff ded9f332f6 plotlyjs fix 2016-03-09 11:13:31 -05:00
Thomas Breloff d09ca46141 plotlyjs fix 2016-03-09 10:59:33 -05:00
Thomas Breloff b28cd7f8bd plotlyjs fix 2016-03-09 10:23:14 -05:00
Tom Breloff a4054aa500 Merge pull request #159 from jheinen/dev
Fixed some TODOs (Issue $108)
2016-03-09 09:40:06 -05:00
Josef Heinen 3332bfcee1 Fixed some TODOs (Issue $108)
- support the grid keyword
- support handling of NaN (gaps in line segments)
- support xlims/ylims
- removed gr_state macro

The GR.savestate / GR.restorestate problem (caused by exceptions) will be solved
in GR - probably by something like GR.rewind() => to unwind the attribute stack.
2016-03-09 10:34:19 +01:00
Thomas Breloff cc798a0c0a working on plotlyjs 2016-03-09 00:16:16 -05:00
Thomas Breloff fe2030b7e3 working on plotlyjs 2016-03-08 17:52:39 -05:00
Thomas Breloff ed1cce86ef ijulia, plotly, and gr display fixes 2016-03-08 15:07:51 -05:00
Thomas Breloff 9a544b0ff3 warn about Bokeh; 3D parametric plots 2016-03-08 14:18:39 -05:00
Thomas Breloff 82f7b29836 aliases 2016-03-08 13:21:54 -05:00
Thomas Breloff 076acfb242 allow one-sided limits for pyplot 2016-03-07 21:58:01 -05:00
Thomas Breloff ed336bc0ff cleaned up magic args; fixed alphas 2016-03-07 21:38:31 -05:00
Thomas Breloff 5699446d69 winston warning 2016-03-07 20:36:19 -05:00
Thomas Breloff a43d32949e better handling of 3d matrix input 2016-03-07 16:49:13 -05:00
Thomas Breloff 02a1e648bc added gr test; refactored pyplot figure generation, added overwrite_figure arg, closes #144 2016-03-07 15:17:29 -05:00
Thomas Breloff 9d3e0651e2 GR fix handling of Shape; PyPlot marker colors fix (hack), closes #145 2016-03-07 12:57:46 -05:00
Thomas Breloff cdff5a9039 gr_state macro 2016-03-07 12:17:33 -05:00
Tom Breloff ba0b5500ca Merge pull request #149 from jheinen/dev
merging GR updates
2016-03-07 11:21:09 -05:00
Josef Heinen 1439a7e289 Added support for pie charts 2016-03-07 16:36:26 +01:00
Josef Heinen 9761ede5c4 Removed support for hline, vline markers
(not yet implemented)
2016-03-07 16:36:26 +01:00
Josef Heinen e342805752 Added missing marker shapes 2016-03-07 16:36:26 +01:00
Josef Heinen d08672aa71 Improved grid plotting logic 2016-03-07 16:36:26 +01:00
Josef Heinen a3d4e05b0e Improved background color handling 2016-03-07 16:36:26 +01:00
Josef Heinen 51eeed3d50 Improved subplot layout 2016-03-07 16:36:26 +01:00
Josef Heinen 51c45456c3 Disable alpha channel when converting PNGs 2016-03-07 16:36:26 +01:00
Josef Heinen 074ba63bf5 Fill workstation background instead of viewport 2016-03-07 16:36:25 +01:00
Josef Heinen f3d552d8a0 Temporary workaround for multiple mime output 2016-03-07 16:36:25 +01:00
Josef Heinen c5fb4a9228 Added some sanity checks 2016-03-07 16:36:25 +01:00
Josef Heinen 55d7e910e4 Added workaround for multiple mime output 2016-03-07 16:36:25 +01:00
Josef Heinen ea29af8d3d Removed 'private' keyword argument :scale 2016-03-07 16:36:25 +01:00
Thomas Breloff 88b9d71bd7 fixed default PyPlot gradient 2016-03-07 09:55:05 -05:00
Thomas Breloff 165c84c246 pyplot minmax fix; convertToAnyVector fix 2016-03-04 12:46:33 -05:00
Thomas Breloff 347820867d pyplot lim fixes 2016-03-03 21:43:08 -05:00
Thomas Breloff 26d0dfbf3d Merge branch 'dev' of github.com:tbreloff/Plots.jl into dev 2016-03-03 16:06:03 -05:00
Thomas Breloff 6aa4849266 pyplot lims udpate fix 2016-03-03 16:05:27 -05:00
Thomas Breloff 335b3802b8 added FixedSizeArrays requirement 2016-03-02 22:48:27 -05:00
Thomas Breloff 73bd3fa60c curves 2016-02-22 22:53:31 -05:00
Thomas Breloff 6b61c5900c generalize curves 2016-02-22 10:39:03 -05:00
Thomas Breloff 9da4083096 directed_curve 2016-02-20 20:57:56 -05:00
Thomas Breloff 86fe244d95 revert pyplot changes 2016-02-19 21:59:43 -05:00
Thomas Breloff 732f2846de directed_curve; working on PyPlot fixes 2016-02-19 18:24:56 -05:00
Thomas Breloff 4f238caf5c added annotation options 2016-02-18 22:59:31 -05:00
Thomas Breloff c9388e9f56 bezier curves 2016-02-18 18:28:59 -05:00
Thomas Breloff 2a9fa9539f fixes to logic accepting arrays of values; additional fixes in gadfly and pyplot for this 2016-02-17 10:32:12 -05:00
Thomas Breloff b8d136588c gif macro and every/when syntax 2016-02-16 18:02:04 -05:00
Thomas Breloff 92c9e82dee fix refdir 2016-02-16 16:45:46 -05:00
Thomas Breloff 0fdb48bda3 fixes for ticks 2016-02-16 16:22:54 -05:00
Thomas Breloff e8d4fd7aac skip pyplot test 4 2016-02-12 15:41:00 -05:00
Thomas Breloff 6a4a78a26a skip pyplot test 13 2016-02-12 15:17:31 -05:00
Thomas Breloff 6c6769ca98 handle vector of PlotText as annotations 2016-02-10 13:09:22 -05:00
Thomas Breloff 3e49af9093 allow Function for fillrange and zcolor; fix fill kw 2016-02-09 19:22:05 -05:00
Thomas Breloff 5f8ecfa3fa deprecated plotter.jl 2016-02-08 14:24:25 -05:00
Thomas Breloff aca03d2609 replaced dataframes() with require block 2016-02-08 14:23:02 -05:00
Thomas Breloff 5db9493d2b added dependency on Requires; added support for plotting tuples/FixedSizeArrays; added animate macro; legend ignores empty labels in gadfly/pyplot 2016-02-08 13:42:23 -05:00
Thomas Breloff ac3c041d6d split plotly into 2 different backends: plotly and plotlyjs 2016-02-05 15:44:27 -05:00
Thomas Breloff a319c0c94a legend and colorbar overhaul 2016-02-05 15:10:12 -05:00
Thomas Breloff f74d619748 pgfplots supported 2016-02-04 16:05:21 -05:00
Thomas Breloff eef1981f20 travis 2016-02-04 14:20:34 -05:00
Thomas Breloff ade9d86696 deprecated a bunch of images and docs-related stuff; cleaned up travis, imgcomp, and runtests 2016-02-04 14:00:19 -05:00
Thomas Breloff 935c1cfeab readme 2016-02-04 13:01:06 -05:00
Thomas Breloff 5706770a11 readme 2016-02-04 13:00:12 -05:00
Thomas Breloff 2643417c0b readme 2016-02-04 12:59:40 -05:00
Thomas Breloff d388036601 major overhaul to backend definition and initialization; added pgfplots template; some new reference images 2016-02-04 12:29:56 -05:00
Tom Breloff 96df75cc05 Merge pull request #132 from spencerlyon2/dev
fix change in checking if plotly_blink window is active
2016-02-03 14:32:32 -05:00
Spencer Lyon c62d8d6753 fix change in checking if plotly_blink window is active 2016-02-03 14:21:43 -05:00
Tom Breloff 1562c96d4c Merge pull request #130 from joshday/dev
Add plot!(f::Function) method
2016-02-03 13:30:47 -05:00
Josh Day 94c87d436f Update plot.jl 2016-02-03 12:47:48 -05:00
Tom Breloff b9c8ffb5cf Merge pull request #127 from spencerlyon2/sl/plotly-blink
Sl/plotly blink
2016-02-03 10:08:57 -05:00
Spencer Lyon a37a23bcfc PlotlyJS blink backend working 2016-02-03 09:58:04 -05:00
Spencer Lyon 863ad22b48 added writemime methods for plotly_blink 2016-02-03 09:58:04 -05:00
Tom Breloff bce865ff9f Merge pull request #126 from pkofod/dev
Add abline! which creates a straight line according to the formula b+…
2016-02-03 08:55:46 -05:00
Patrick Kofod Mogensen 1963fe208e Added an extrema(plt) which return the tuple (xmin, xmax), and changed abline! to use extrema. 2016-02-03 10:39:32 +01:00
Patrick Kofod Mogensen 5c4526725b Remove trailing spaces. 2016-02-03 10:32:58 +01:00
Patrick Kofod Mogensen 3f42e9c5bd Add abline! which creates a straight line according to the formula b+a*x, and export abline!
Also add utility functions xmin(plt::Plot) and xmax(plt::Plot).
2016-02-02 23:16:02 +01:00
Thomas Breloff b1c9d0a0af gadfly hist in legend 2016-02-02 10:49:33 -05:00
Thomas Breloff adcbfb4b9e Merge branch 'master' into dev 2016-02-01 13:45:55 -05:00
Thomas Breloff b3ebccab36 gradient fixes 2016-01-30 10:03:19 -05:00
Thomas Breloff d5797054fb ColorGradient fixes; allow default keywords in backend calls 2016-01-29 17:21:25 -05:00
Tom Breloff aab0ec22b9 Merge pull request #120 from Evizero/master
fix unicodeplots compat
2016-01-28 20:25:12 -05:00
Christof Stocker f7babcc1d2 fix unicodeplots compat 2016-01-29 02:06:22 +01:00
Tom Breloff d077307721 Merge pull request #117 from jheinen/dev
Improved GR framework support
2016-01-28 14:04:55 -05:00
Josef Heinen 72e8e10bd6 Improved graphics state handling 2016-01-28 18:26:56 +01:00
Josef Heinen 5ea9e8a0d7 Added support for OHLC charts 2016-01-28 13:44:40 +01:00
Josef Heinen 87b050fad2 Added path3d and scatter3d functions 2016-01-27 16:26:57 +01:00
Josef Heinen 0c8cd74e28 Improved surface output 2016-01-26 20:49:10 +01:00
Josef Heinen 445d970784 Added color bars and surface plots 2016-01-26 17:33:13 +01:00
Josef Heinen 125a1eb9fc Added support for subplots and further linetypes:
- heatmaps
- contour plots
2016-01-25 17:43:13 +01:00
Josef Heinen a2a578d04d Improved representation of legends 2016-01-24 10:47:32 +01:00
Josef Heinen 11e5c0aa9d Use SVG output for inline graphics (IJulia) 2016-01-22 13:00:30 +01:00
Josef Heinen 14b856b0cf Added support for two y-axis scales 2016-01-18 17:25:59 +01:00
Josef Heinen 2e8dd73822 Added more line plots 2016-01-16 15:20:16 +01:00
Josef Heinen da9fdb356c Added support for bar plots 2016-01-16 13:53:22 +01:00
Josef Heinen 054a99ca38 Added horizontal/vertical linetype 2016-01-16 13:23:23 +01:00
Josef Heinen baf33609af Allow combination of lines and markers 2016-01-14 15:50:48 +01:00
Josef Heinen b4eb0b6b41 Added histogram output 2016-01-12 16:33:07 +01:00
Josef Heinen 3e9a47a683 Changed default colormap 2016-01-11 18:16:31 +01:00
Josef Heinen d71c3ecd86 Added support for multiple marker colors / sizes 2016-01-10 19:06:47 +01:00
Josef Heinen e5a864a760 Implemented filled backgrounds 2016-01-09 14:05:02 +01:00
Josef Heinen 81b59f9bc9 Implemented annotations 2016-01-08 17:08:34 +01:00
Josef Heinen 2c2a36ce34 Use Plots predefined colors 2016-01-08 11:56:20 +01:00
Josef Heinen cb0020c629 Fixed problem with uninitialized strings 2016-01-07 14:28:08 +01:00
Josef Heinen 003d39c8cd Added support for inline graphics (IJulia) 2016-01-07 11:37:04 +01:00
Josef Heinen ca866183f1 Print TODO messages for missing features 2016-01-06 10:11:30 +01:00
Thomas Breloff b6e627369b backend priority 2016-01-03 09:53:33 -05:00
Thomas Breloff da96cfc158 Merge remote-tracking branch 'origin/master' into dev 2016-01-03 09:40:05 -05:00
Tom Breloff 0abbd53e07 Merge pull request #107 from jheinen/dev
Initial support for GR framework (GR.jl)
2016-01-03 09:35:40 -05:00
Tom Breloff 6fc0f858c7 Merge pull request #106 from rcnlee/master
Minor changes - animations and AbstractDataFrame
2016-01-03 09:35:24 -05:00
Josef Heinen b3613b68cd Moved GR calls into display method 2016-01-03 11:54:24 +01:00
Josef Heinen 2b6619b3c4 Avoid global 'fig' object 2016-01-03 10:32:47 +01:00
Josef Heinen a33161aa9c Reset default backend to PyPlot
GR should NOT be the default backend until it is finished :-)
2016-01-02 12:15:07 +01:00
Ritchie Lee 5c3c5b999f Support for SubDataFrame by switching to AbstractDataFrame 2016-01-02 02:06:51 -08:00
Josef Heinen 7acca18313 remove superfluous compat macros 2016-01-02 10:40:45 +01:00
Ritchie Lee 7b71d9a448 Small API change to animations
Animation constructor minor fix
2016-01-02 01:36:36 -08:00
Josef Heinen 64ffa3e70f Merge remote-tracking branch 'upstream/master' 2016-01-01 19:53:34 +01:00
Josef Heinen fd88972380 Added support for legends 2016-01-01 19:33:35 +01:00
Tom Breloff dd7b09552a Merge pull request #101 from tbreloff/dev
merging dev into master
2015-12-30 12:58:01 -05:00
Thomas Breloff 0b23aa9e7e relax tests 2015-12-30 12:36:18 -05:00
Thomas Breloff 0caa31bd6b fixes 2015-12-30 12:02:43 -05:00
Thomas Breloff cafac135a0 PyPlot fixes; test fixes 2015-12-30 11:24:44 -05:00
Thomas Breloff 6ac312bd49 removed nlevels keyword, now an alias to levels; cleanup 2015-12-30 10:13:53 -05:00
Tom Breloff 489877d6bf Merge pull request #99 from dlfivefifty/pull-request/c09545de
Add support for levels keyword in PyPlot
2015-12-30 09:38:27 -05:00
Josef Heinen b0b2e695e1 Added support for logarithmic / flipped axes 2015-12-30 11:52:19 +01:00
Josef Heinen c3808c0c5b gr.jl: implemented line/scatter plots 2015-12-29 20:15:10 +01:00
Sheehan Olver c09545de64 Add support for levels keyword in PyPlot 2015-12-29 15:32:49 +11:00
Josef Heinen 7566b0159c Start experimenting with GR.jl backend 2015-12-25 20:11:05 +01:00
Thomas Breloff ed7cc9b89e pyplot surface/wireframe fix for matrix x/y; fix in with, when backend unset 2015-12-23 22:15:13 -05:00
Thomas Breloff 55501e68fb added tex output; fixes for surface inputs; commented out plotly_blink 2015-12-23 13:03:25 -05:00
Thomas Breloff eabe670ae8 working on plotlyjs integration 2015-12-18 17:33:57 -05:00
Thomas Breloff 9fffef6f53 cleanup 2015-12-18 13:19:22 -05:00
Thomas Breloff 368429b757 working on glvisualize 2015-12-18 10:14:15 -05:00
Tom Breloff 49f774eb0d Merge pull request #92 from dlfivefifty/dev
Add initial support for GLVisualize
2015-12-18 09:29:58 -05:00
Sheehan Olver 0487d7a058 merge glvisualize 2015-12-18 15:32:35 +11:00
Sheehan Olver 5943e77563 Fix backend_name 2015-12-18 15:30:07 +11:00
Sheehan Olver b10f0fb945 Started supporting GLVisualize 2015-12-18 15:30:07 +11:00
Sheehan Olver c299891fb0 Merge pull request #1 from tbreloff/dev
Dev
2015-12-18 15:27:35 +11:00
Thomas Breloff fe0f22dfc0 changed :log to map to :log10, switched :log to :ln; better support for plotly axis attributes, ticks, scale, etc; fix plotly bg/fg colors 2015-12-17 14:59:50 -05:00
Thomas Breloff 002603c388 added wireframe linetype; support for surface and wireframe in pyplot 2015-12-17 11:55:26 -05:00
Thomas Breloff 30ef8456c3 added xlims/ylims support in plotly 2015-12-17 00:14:38 -05:00
Thomas Breloff bee1ce401a moved annotation arg from series to plot; added annotation support for plotly 2015-12-16 23:22:46 -05:00
Thomas Breloff e18c4a370a added vline/hline marker shapes; plotly set/get, ticks 2015-12-16 11:14:06 -05:00
Thomas Breloff 2a60a929f1 recipe fix; plotly fixes 2015-12-15 22:53:57 -05:00
Thomas Breloff 939295ab04 _apply_recipe fix 2015-12-15 17:31:11 -05:00
Tom Breloff f6a0ef6a61 Merge pull request #90 from pkofod/patch-1
Added :line as to supportedTypes
2015-12-15 09:28:45 -05:00
Patrick Kofod Mogensen b3bce314e9 Added :line as to supportedTypes 2015-12-15 14:26:17 +01:00
Thomas Breloff e28b85d8b6 plotly support for ijulia and subplots 2015-12-08 12:01:26 -05:00
Thomas Breloff a0af2fc997 fix. closes #84 2015-12-07 23:14:10 -05:00
Tom Breloff 7f7f5c6f12 Merge pull request #85 from stevengj/patch-1
don't test for 0.4-
2015-11-28 20:13:06 -05:00
Steven G. Johnson d21fbfc9be don't test for 0.4-
Testing version > 0.4- is wrong because it incorrectly implies that all pre-releases of 0.4 work.  Either test for the specific 0.4 build you need, or test for `VERSION > v"0.4"` (i.e., the release version).

However, since you REQUIRE julia 0.4 anyway, you can omit this test entirely.
2015-11-25 17:00:57 -05:00
Thomas Breloff 366dc1cca9 travis 2015-11-24 17:43:18 -05:00
Thomas Breloff e9e3913bb7 switch tests to use ExamplePlots and VisualRegressionTests 2015-11-24 17:08:15 -05:00
Thomas Breloff 5491f6eff7 issubplot in _apply_recipe 2015-11-24 13:56:20 -05:00
Thomas Breloff 32e36ba324 added 3d example 2015-11-24 13:05:07 -05:00
Thomas Breloff 9d4c456461 plotly 3d path/scatter, surface 2015-11-24 12:39:54 -05:00
Thomas Breloff cdc7920dff added _apply_recipe 2015-11-24 10:45:49 -05:00
Thomas Breloff cdb4901d91 plotly fill, nbins, density; ref img 2015-11-23 23:05:24 -05:00
Thomas Breloff c7f3520ea8 plotly linestyle/markershape and others 2015-11-23 22:20:04 -05:00
Thomas Breloff f0e728c316 working on plotly; added contour and pie examples 2015-11-23 17:46:30 -05:00
Thomas Breloff 4b1f127eaf surface arg is now z; added orientation arg; working on plotly 2015-11-22 22:34:30 -05:00
Thomas Breloff 1db2d8d8d8 removed tests 2015-11-22 21:13:33 -05:00
Thomas Breloff 87bb45d01b added Surface, removed x/y length assert; added Surface createKWargsList; closes #82 2015-11-22 11:21:07 -05:00
Thomas Breloff 6beadcece8 fixes for contours in pyplot and gadfly 2015-11-21 13:59:26 -05:00
Thomas Breloff fc6f0f3a86 fixes in supported 2015-11-21 10:10:09 -05:00
Thomas Breloff ef7370f56d added density type 2015-11-21 09:26:35 -05:00
Thomas Breloff 52ba7cdbff working on plotly 2015-11-20 23:53:19 -05:00
Thomas Breloff b0c9dd44e9 working on plotly 2015-11-20 23:24:38 -05:00
Thomas Breloff 92ec093ed9 working on plotly 2015-11-20 18:36:50 -05:00
Thomas Breloff 6d2a1aafd2 working on plotly/web 2015-11-20 16:25:50 -05:00
Thomas Breloff f3a7734584 ref imgs 2015-11-20 14:28:26 -05:00
Thomas Breloff 9cf92f37f5 preparing for MLPlots; removed corrplot 2015-11-20 14:05:06 -05:00
Thomas Breloff 34831d42a4 subplot palette fix, added copy methods for Plot and Subplot 2015-11-20 12:55:45 -05:00
Thomas Breloff 607d5d7841 fixed empty plot() in gadfly backend 2015-11-20 10:17:31 -05:00
Thomas Breloff 75adfd2e9d new init logic; fix pyplot subplot bug 2015-11-20 09:26:43 -05:00
Thomas Breloff e92b5b2d35 fixed gadfly scales bug and new ref img; closes #74 2015-11-20 08:58:45 -05:00
Thomas Breloff a8c40a5493 started work on plotly 2015-11-18 21:26:16 -05:00
Thomas Breloff be5c3fb55c img_eps 2015-11-17 16:20:24 -05:00
Thomas Breloff e6e4a63022 added QuartzImageIO to test REQUIRE 2015-11-17 16:19:05 -05:00
Thomas Breloff 1cdc8928ba various fixes for pyplot and gadfly; new ref imgs 2015-11-17 15:59:45 -05:00
Thomas Breloff ad111a0163 added mpl version log 2015-11-17 11:48:10 -05:00
Thomas Breloff 7091a4899c imgcomp cleanup; pyplot dpi fix; new ref imgs 2015-11-17 11:19:12 -05:00
Thomas Breloff 3bd9e70fa9 moved PyPlot to first priority 2015-11-16 16:06:48 -05:00
Thomas Breloff 54bd2c620e gadfly ref imgs 2015-11-16 15:50:02 -05:00
Thomas Breloff 121640b1b3 fixed gadfly hline/vline constructors 2015-11-16 15:37:55 -05:00
Thomas Breloff 55e388513c fixes for gadfly and unicodeplots 2015-11-12 17:30:55 -05:00
Thomas Breloff b153dcbd63 reference images; gadfly markersize fix 2015-11-11 21:47:53 -05:00
Thomas Breloff 242cbe5ecb z/zcolor 2015-11-11 17:46:44 -05:00
Thomas Breloff f1cca13796 fix pyplot alpha and added stroke support 2015-11-11 16:27:21 -05:00
Thomas Breloff 918ba72107 readme 2015-11-10 16:41:26 -05:00
Thomas Breloff e596f27666 fixed numeric array without numeric type; updated readme; closes #64 2015-11-10 16:38:47 -05:00
Thomas Breloff a40d0000c5 fixed pyplot 2015-11-09 09:19:00 -05:00
Thomas Breloff fb82da74a1 gadfly layer order; fixes #63 2015-11-07 21:58:04 -05:00
Thomas Breloff b0991a0624 working on args 2015-11-06 15:58:15 -05:00
Thomas Breloff 6236acea02 working on markerstroke, name changes, and arg improvements 2015-11-06 15:49:27 -05:00
Thomas Breloff 391c7e8570 name changes; require to 0.4 2015-11-06 11:46:24 -05:00
Thomas Breloff 58041cc64e working on big renaming 2015-11-05 16:39:04 -05:00
Thomas Breloff 8c7d3a6e92 working on stroke/fill 2015-11-05 11:52:22 -05:00
Thomas Breloff ae1982369c working on bokeh 2015-11-03 15:48:04 -05:00
Thomas Breloff 5f85ac01f7 working on bokeh backend 2015-11-03 13:45:23 -05:00
Thomas Breloff cca263fb2b with method fix 2015-10-30 12:47:48 -04:00
Thomas Breloff 809ed02b85 gadfly/immerse downgrade fix 2015-10-30 10:03:10 -04:00
Thomas Breloff 9eab1083ab working on with 2015-10-29 17:18:14 -04:00
Thomas Breloff 60523bef80 working on 3d plotting 2015-10-29 15:44:07 -04:00
Thomas Breloff 46b959ff3c color reorg 2015-10-29 14:31:36 -04:00
126 changed files with 4753 additions and 1832 deletions
+6 -3
View File
@@ -11,10 +11,13 @@ notifications:
# uncomment the following lines to override the default test script
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone("https://github.com/tbreloff/Images.jl.git"); Pkg.checkout("Images","tom_imgcompare");'
- julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
# - julia -e 'Pkg.clone("https://github.com/tbreloff/Images.jl.git"); Pkg.checkout("Images","tom_imgcompare");'
# - julia -e 'Pkg.clone("Images"); Pkg.build("Images")'
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
- julia -e 'Pkg.clone("https://github.com/tbreloff/VisualRegressionTests.jl.git");'
- julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
- julia -e 'Pkg.clone("Cairo"); Pkg.build("Cairo")'
- julia -e 'ENV["PYTHON"] = ""; Pkg.clone("PyPlot"); Pkg.build("PyPlot")'
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
- julia -e 'Pkg.test("Plots"; coverage=false)'
# - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
+1 -386
View File
@@ -18,389 +18,4 @@ Plots is a plotting API and toolset. My goals with the package are:
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
Check out the [summary graphs](https://github.com/tbreloff/ExamplePlots.jl/tree/master/img/supported/supported.md) for the features that each backend supports.
Please add wishlist items, bugs, or any other comments/questions to the issues list.
## Examples for each implemented backend:
- [Gadfly.jl/Immerse.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/gadfly_examples.md)
- [PyPlot.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/pyplot_examples.md)
- [UnicodePlots.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/unicodeplots_examples.md)
- [Qwt.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/qwt_examples.md)
Also check out the many [IJulia notebooks](http://nbviewer.ipython.org/github/tbreloff/ExamplePlots.jl/tree/master/examples/) with many examples.
## Installation
First, add the package
```julia
Pkg.add("Plots")
# if you want the latest features:
Pkg.checkout("Plots")
# or for the bleeding edge:
Pkg.checkout("Plots", "dev")
```
then get any plotting packages you need (obviously, you should get at least one backend).
```julia
Pkg.add("Gadfly")
Pkg.add("Immerse")
Pkg.add("PyPlot")
Pkg.add("UnicodePlots")
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git")
```
## Use
Load it in. The underlying plotting backends are not imported until `backend()` is called (which happens
on your first call to `plot` or `subplot`). This means that you don't need any backends to be installed when you call `using Plots`.
Plots will try to figure out a good default backend for you automatically based on what backends are installed.
```julia
using Plots
```
Do a plot in Gadfly (inspired by [this example](http://gadflyjl.org/geom_point.html)), then save a png:
```julia
gadfly() # switch to Gadfly as a backend
dataframes() # turn on support for DataFrames inputs
# load some data
using RDatasets
iris = dataset("datasets", "iris");
# This will bring up a browser window with the plot. Add a semicolon at the end to skip display.
scatter(iris, :SepalLength, :SepalWidth, group=:Species, m=([:+ :d :s], 12), smooth=0.99, bg=:black)
# save a png (equivalent to png("gadfly1.png") and savefig("gadfly1.png"))
png("gadfly1")
```
![gadfly_plt](img/gadfly1.png)
## API
Call `backend(backend::Symbol)` or the shorthands (`gadfly()`, `qwt()`, `unicodeplots()`, etc) to set the current plotting backend.
Subsequent commands are converted into the relevant plotting commands for that package:
```julia
gadfly()
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
qwt()
plot(1:10) # this effectively calls `Qwt.plot(1:10)`
```
Use `plot` to create a new plot object, and `plot!` to add to an existing one:
```julia
plot(args...; kw...) # creates a new plot window, and sets it to be the `current`
plot!(args...; kw...) # adds to the `current`
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
```
Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity.
There are many ways to pass in data to the plot functions... some examples:
- Vector-like (subtypes of AbstractArray{T,1})
- Matrix-like (subtypes of AbstractArray{T,2})
- Vectors of Vectors
- Functions
- Vectors of Functions
- DataFrames with column symbols (initialize with `dataframes()`)
In general, you can pass in a `y` only, or an `x` and `y`, both of whatever type(s) you want, and Plots will slice up the data as needed.
For matrices, data is split by columns. For functions, data is mapped. For DataFrames, a Symbol/Symbols in place of x/y will map to
the relevant column(s).
Here are some example usages... remember you can always use `plot!` to update an existing plot, and that, unless specified, you will update the `current()`.
```julia
plot() # empty plot object
plot(4) # initialize with 4 empty series
plot(rand(10)) # plot 1 series... x = 1:10
plot(rand(10,5)) # plot 5 series... x = 1:10
plot(rand(10), rand(10)) # plot 1 series
plot(rand(10,5), rand(10)) # plot 5 series... y is the same for all
plot(sin, rand(10)) # y = sin(x)
plot(rand(10), sin) # same... y = sin(x)
plot([sin,cos], 0:0.1:π) # plot 2 series, sin(x) and cos(x)
plot([sin,cos], 0, π) # plot sin and cos on the range [0, π]
plot(1:10, Any[rand(10), sin]) # plot 2 series, y = rand(10) for the first, y = sin(x) for the second... x = 1:10 for both
plot(dataset("Ecdat", "Airline"), :Cost) # plot from a DataFrame (call `dataframes()` first to import DataFrames and initialize)
```
All plot methods accept a number of keyword arguments (see the tables below), which follow some rules:
- Many arguments have aliases which are replaced during preprocessing. `c` is the same as `color`, `m` is the same as `marker`, etc. You can choose how verbose you'd like to be. (see the tables below)
- There are some special arguments (`xaxis`, `yaxis`, `line`, `marker`, `fill` and the aliases `l`, `m`, `f`) which magically set many related things at once. (see the __Tip__ below)
- If the argument is a "matrix-type", then each column will map to a series, cycling through columns if there are fewer columns than series. Anything else will apply the argument value to every series.
- Many arguments accept many different types... for example the `color` (also `markercolor`, `fillcolor`, etc) argument will accept strings or symbols with a color name, or any `Colors.Colorant`, or a `ColorScheme`, or a symbol representing a `ColorGradient`, or an AbstractVector of colors/symbols/etc...
You can update certain plot settings after plot creation (not supported on all backends):
```julia
plot!(title = "New Title", xlabel = "New xlabel", ylabel = "New ylabel")
plot!(xlims = (0, 5.5), ylims = (-2.2, 6), xticks = 0:0.5:10, yticks = [0,1,5,10])
# using shorthands:
xaxis!("mylabel", :log10, :flip)
```
With `subplot`, create multiple plots at once, with flexible layout options:
```julia
y = rand(100,3)
subplot(y; n = 3) # create an automatic grid, and let it figure out the shape
subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows
subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns
subplot(y; layout = [1, 2]) # explicit layout. Lists the number of plots in each row
```
__Tip__: You can call `subplot!(args...; kw...)` to add to an existing subplot.
__Tip__: Calling `subplot!` on a `Plot` object, or `plot!` on a `Subplot` object will throw an error.
Shorthands:
```julia
scatter(args...; kw...) = plot(args...; kw..., linetype = :scatter)
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :scatter)
bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
hline!(args...; kw...) = plot!(args...; kw..., linetype = :hline)
vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
title!(s::AbstractString) = plot!(title = s)
xlabel!(s::AbstractString) = plot!(xlabel = s)
ylabel!(s::AbstractString) = plot!(ylabel = s)
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(xlims = lims)
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(ylims = lims)
xticks!{T<:Real}(v::AVec{T}) = plot!(xticks = v)
yticks!{T<:Real}(v::AVec{T}) = plot!(yticks = v)
xflip!(flip::Bool = true) = plot!(xflip = flip)
yflip!(flip::Bool = true) = plot!(yflip = flip)
xaxis!(args...) = plot!(xaxis = args)
yaxis!(args...) = plot!(yaxis = args)
annotate!(anns) = plot!(annotation = anns)
```
### Keyword arguments:
Keyword | Default | Type | Aliases
---- | ---- | ---- | ----
`:annotation` | `nothing` | Series | `:ann`, `:annotate`, `:annotations`, `:anns`
`:axis` | `left` | Series | `:axiss`
`:background_color` | `RGB{U8}(1.0,1.0,1.0)` | Plot | `:background`, `:bg`, `:bg_color`, `:bgcolor`
`:color` | `auto` | Series | `:c`, `:colors`
`:color_palette` | `auto` | Plot | `:palette`
`:fill` | `nothing` | Series | `:area`, `:f`
`:fillcolor` | `match` | Series | `:fc`, `:fcolor`, `:fillcolors`
`:fillopacity` | `nothing` | Series | `:fillopacitys`, `:fo`
`:fillrange` | `nothing` | Series | `:fillranges`, `:fillrng`
`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground`
`:grid` | `true` | Plot |
`:group` | `nothing` | Series | `:g`, `:groups`
`:guidefont` | `Plots.Font("Helvetica",11,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
`:label` | `AUTO` | Series | `:lab`, `:labels`
`:layout` | `nothing` | Plot |
`:legend` | `true` | Plot | `:leg`
`:legendfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
`:line` | `nothing` | Series | `:l`
`:lineopacity` | `nothing` | Series | `:lineopacitys`, `:lo`
`:linestyle` | `solid` | Series | `:linestyles`, `:ls`, `:s`, `:style`
`:linetype` | `path` | Series | `:linetypes`, `:lt`, `:t`, `:type`
`:linewidth` | `1` | Series | `:linewidths`, `:lw`, `:w`, `:width`
`:link` | `false` | Plot |
`:linkfunc` | `nothing` | Plot |
`:linkx` | `false` | Plot | `:xlink`
`:linky` | `false` | Plot | `:ylink`
`:marker` | `nothing` | Series | `:m`, `:mark`
`:markercolor` | `match` | Series | `:markercolors`, `:mc`, `:mcolor`
`:markeropacity` | `nothing` | Series | `:alpha`, `:markeropacitys`, `:mo`, `:opacity`
`:markershape` | `none` | Series | `:markershapes`, `:shape`
`:markersize` | `6` | Series | `:markersizes`, `:ms`, `:msize`
`:n` | `-1` | Plot |
`:nbins` | `100` | Series | `:nb`, `:nbin`, `:nbinss`
`:nc` | `-1` | Plot |
`:nr` | `-1` | Plot |
`:pos` | `(0,0)` | Plot |
`:show` | `false` | Plot | `:display`, `:gui`
`:size` | `(500,300)` | Plot | `:windowsize`, `:wsize`
`:smooth` | `false` | Series | `:reg`, `:regression`, `:smooths`
`:tickfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
`:title` | `` | Plot |
`:windowtitle` | `Plots.jl` | Plot | `:wtitle`
`:xaxis` | `nothing` | Plot |
`:xflip` | `false` | Plot |
`:xlabel` | `` | Plot | `:xlab`
`:xlims` | `auto` | Plot | `:xlim`, `:xlimit`, `:xlimits`
`:xscale` | `identity` | Plot |
`:xticks` | `auto` | Plot | `:xtick`
`:yaxis` | `nothing` | Plot |
`:yflip` | `false` | Plot |
`:ylabel` | `` | Plot | `:ylab`
`:ylims` | `auto` | Plot | `:ylim`, `:ylimit`, `:ylimits`
`:yrightlabel` | `` | Plot | `:y2lab`, `:y2label`, `:ylab2`, `:ylabel2`, `:ylabelright`, `:ylabr`, `:yrlab`
`:yscale` | `identity` | Plot |
`:yticks` | `auto` | Plot | `:ytick`
`:z` | `nothing` | Series | `:zs`
### Plot types:
Type | Desc | Aliases
---- | ---- | ----
`:none` | No line | `:n`, `:no`
`:line` | Lines with sorted x-axis | `:l`
`:path` | Lines | `:p`
`:steppre` | Step plot (vertical then horizontal) | `:stepinv`, `:stepinverted`, `:stepsinv`, `:stepsinverted`
`:steppost` | Step plot (horizontal then vertical) | `:stair`, `:stairs`, `:step`, `:steps`
`:sticks` | Vertical lines | `:stem`, `:stems`
`:scatter` | Points, no lines | `:dots`
`:heatmap` | Colored regions by density |
`:hexbin` | Similar to heatmap |
`:hist` | Histogram (doesn't use x) | `:histogram`
`:bar` | Bar plot (centered on x values) |
`:hline` | Horizontal line (doesn't use x) |
`:vline` | Vertical line (doesn't use x) |
`:ohlc` | Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC}) |
### Line styles:
Type | Aliases
---- | ----
`:auto` | `:a`
`:solid` | `:s`
`:dash` | `:d`
`:dot` |
`:dashdot` | `:dd`
`:dashdotdot` | `:ddd`
### Markers:
Type | Aliases
---- | ----
`:none` | `:n`, `:no`
`:auto` | `:a`
`:cross` | `:+`, `:plus`
`:diamond` | `:d`
`:dtriangle` | `:V`, `:downtri`, `:downtriangle`, `:dt`, `:dtri`, `:v`
`:ellipse` | `:c`, `:circle`
`:heptagon` | `:hep`
`:hexagon` | `:h`, `:hex`
`:octagon` | `:o`, `:oct`
`:pentagon` | `:p`, `:pent`
`:rect` | `:r`, `:sq`, `:square`
`:star4` |
`:star5` | `:s`, `:star`, `:star1`
`:star6` |
`:star7` |
`:star8` | `:s2`, `:star2`
`:utriangle` | `:^`, `:uptri`, `:uptriangle`, `:ut`, `:utri`
`:xcross` | `:X`, `:x`
__Tip__: With supported backends, you can pass a `Plots.Shape` object for the `marker`/`markershape` arguments. `Shape` takes a vector of 2-tuples in the constructor, defining the points of the polygon's shape in a unit-scaled coordinate space. To make a square, for example, you could do `Shape([(1,1),(1,-1),(-1,-1),(-1,1)])`
__Tip__: You can see the default value for a given argument with `default(arg::Symbol)`, and set the default value with `default(arg::Symbol, value)` or `default(; kw...)`. For example set the default window size and whether we should show a legend with `default(size=(600,400), leg=false)`.
__Tip__: There are some helper arguments you can set: `xaxis`, `yaxis`, `line`, `marker`, `fill`. These go through special preprocessing to extract values into individual arguments. The order doesn't matter, and if you pass a single value it's equivalent to wrapping it in a Tuple. Examples:
```
plot(y, xaxis = ("mylabel", :log, :flip, (-1,1))) # this sets the `xlabel`, `xscale`, `xflip`, and `xlims` arguments automatically
plot(y, line = (:bar, :blue, :dot, 10)) # this sets the `linetype`, `color`, `linestyle`, and `linewidth` arguments automatically
plot(y, marker = (:rect, :red, 10)) # this sets the `markershape`, `markercolor`, and `markersize` arguments automatically
plot(y, fill = (:green, 10)) # this sets the `fillcolor` and `fillrange` arguments automatically
# Note: `fillrange` can be:
a number (fill to horizontal line)
a vector of numbers (different for each data point)
a tuple of vectors (fill a band)
```
__Tip__: When plotting multiple lines, you can set all series to use the same value, or pass in a matrix to cycle through values. Example:
```julia
plot(rand(100,4); color = [:red RGB(0,0,1)], # (Matrix) lines 1 and 3 are red, lines 2 and 4 are blue
axis = :auto, # lines 1 and 3 are on the left axis, lines 2 and 4 are on the right
markershape = [:rect, :star] # (Vector) ALL lines are passed the vector [:rect, :star1]
width = 5) # all lines have a width of 5
```
__Tip__: Not all features are supported for each backend, but you can see what's supported by calling the functions: `supportedArgs()`, `supportedAxes()`, `supportedTypes()`, `supportedStyles()`, `supportedMarkers()`, `subplotSupported()`
__Tip__: Call `gui()` to display the plot in a window. Interactivity depends on backend. Plotting at the REPL (without semicolon) implicitly calls `gui()`.
### Animations
Animations are created in 3 steps (see example #2):
- Initialize an `Animation` object.
- Save each frame of the animation with `frame(anim)`.
- Convert the frames to an animated gif with `gif(anim, filename, fps=15)`
## TODO features:
- [x] Plot vectors/matrices/functions
- [x] Plot DataFrames
- [x] Histograms
- [x] Grouping
- [x] Annotations
- [x] Scales
- [x] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
- [x] Custom markers
- [x] Animations
- [x] Subplots
- [ ] Contours
- [ ] Boxplots
- [ ] 3D plotting
- [ ] Scenes/Drawing
- [ ] Graphs
- [ ] Interactivity (GUIs)
## TODO backends:
- [x] Gadfly.jl
- [x] Immerse.jl
- [x] PyPlot.jl
- [x] UnicodePlots.jl
- [x] Qwt.jl
- [x] Winston.jl (deprecated)
- [ ] GLPlot.jl
- [ ] Bokeh.jl
- [ ] Vega.jl
- [ ] Gaston.jl
- [ ] Plotly.jl
- [ ] GoogleCharts.jl
- [ ] PLplot.jl
- [ ] TextPlots.jl
- [ ] ASCIIPlots.jl
- [ ] Sparklines.jl
- [ ] Hinton.jl
- [ ] ImageTerm.jl
- [ ] GraphViz.jl
- [ ] TikzGraphs.jl
- [ ] GraphLayout.jl
## More information on backends (both supported and unsupported)
See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
View the [full documentation](http://plots.readthedocs.org).
+3 -1
View File
@@ -1,5 +1,7 @@
julia 0.3
julia 0.4
Colors
Reexport
Compat
Requires
FixedSizeArrays
@@ -31,7 +31,7 @@ const examples = PlotExample[
[
:(p = plot([sin,cos], zeros(0), leg=false)),
:(anim = Animation()),
:(for x in linspace(0, 10π, 200)
:(for x in linspace(0, 10π, 100)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end)
@@ -46,24 +46,28 @@ const examples = PlotExample[
[
:(y = rand(100)),
:(plot(0:10:100,rand(11,4),lab="lines",w=3, palette=:grays, fill=(0.5,:auto))),
:(scatter!(y, z=abs(y-.5), m=(10,:heat), lab="grad"))
:(scatter!(y, zcolor=abs(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs(y-0.5)+4, lab="grad"))
]),
PlotExample("Global",
"Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow you to pass a tuple or value which will be mapped to the relevant args automatically. The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`, `yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`",
[
:(plot(rand(20,3), xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2), leg=false)),
:(y = rand(20,3)),
:(plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2), leg=false)),
:(hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))),
:(vline!([5,10])),
:(title!("TITLE")),
:(yaxis!("YLABEL", :log10))
]),
PlotExample("Two-axis",
"Use the `axis` arguments.\n\nNote: Currently only supported with Qwt and PyPlot",
[
:(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT"))
:(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
]),
PlotExample("Arguments",
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (marker/markersize) with arguments unique to each series (colors). Special arguments `line`, `marker`, and `fill` will automatically figure out what arguments to set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with `line`.) Note that we pass a matrix of colors, and this applies the colors to each series.",
[
:(plot(Vector[rand(10), rand(20)], marker=(:ellipse,8), line=(:dot,3,[:black :orange])))
:(ys = Vector[rand(10), rand(20)]),
:(plot(ys, line=(:dot,4,[:black :orange]), marker=([:hex :d],12,0.8,stroke(3,:gray))))
]),
PlotExample("Build plot in pieces",
"Start with a base plot...",
@@ -78,7 +82,7 @@ const examples = PlotExample[
PlotExample("Heatmaps",
"",
[
:(heatmap(randn(10000),randn(10000), nbins=100))
:(heatmap(randn(10000),randn(10000), nbins=20))
]),
PlotExample("Line types",
"",
@@ -112,7 +116,7 @@ const examples = PlotExample[
PlotExample("Histogram",
"",
[
:(histogram(randn(1000), nbins=50))
:(histogram(randn(1000), nbins=20))
]),
PlotExample("Subplots",
"""
@@ -163,8 +167,37 @@ const examples = PlotExample[
m=(Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue,
xlim = (0,1), ylim=(0,1), leg=false))
]),
PlotExample("Contours",
"",
[
:(x = 1:0.3:20),
:(y = x),
:(f(x,y) = sin(x)+cos(y)),
:(contour(x, y, f, fill=true))
]),
PlotExample("Pie",
"",
[
:(x = ["Nerds", "Hackers", "Scientists"]),
:(y = [0.4, 0.35, 0.25]),
:(pie(x, y, title="The Julia Community", l=0.5))
]),
PlotExample("3D",
"",
[
:(n = 100),
:(ts = linspace(0,8π,n)),
:(x = ts .* map(cos,ts)),
:(y = 0.1ts .* map(sin,ts)),
:(z = 1:n),
:(plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,stroke(0)), leg=false, w=5)),
:(plot!(zeros(n),zeros(n),1:n, w=10))
])
]
@@ -301,20 +334,23 @@ end
@compat const _ltdesc = Dict(
:none => "No line",
:line => "Lines with sorted x-axis",
:path => "Lines",
:steppre => "Step plot (vertical then horizontal)",
:steppost => "Step plot (horizontal then vertical)",
:sticks => "Vertical lines",
:scatter => "Points, no lines",
:heatmap => "Colored regions by density",
:hexbin => "Similar to heatmap",
:hist => "Histogram (doesn't use x)",
:bar => "Bar plot (centered on x values)",
:hline => "Horizontal line (doesn't use x)",
:vline => "Vertical line (doesn't use x)",
:ohlc => "Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC})",
:none => "No line",
:line => "Lines with sorted x-axis",
:path => "Lines",
:steppre => "Step plot (vertical then horizontal)",
:steppost => "Step plot (horizontal then vertical)",
:sticks => "Vertical lines",
:scatter => "Points, no lines",
:heatmap => "Colored regions by density",
:hexbin => "Similar to heatmap",
:hist => "Histogram (doesn't use x)",
:bar => "Bar plot (centered on x values)",
:hline => "Horizontal line (doesn't use x)",
:vline => "Vertical line (doesn't use x)",
:ohlc => "Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC})",
:contour => "Contour lines (uses z)",
:path3d => "3D path (uses z)",
:scatter3d => "3D scatter plot (uses z)",
)
function buildReadme()
@@ -18,7 +18,7 @@ Plots is a plotting API and toolset. My goals with the package are:
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
Check out the [summary graphs](https://github.com/tbreloff/ExamplePlots.jl/tree/master/img/supported/supported.md) for the features that each backend supports.
Check out the [summary graphs](img/supported/supported.md) for the features that each backend supports.
Please add wishlist items, bugs, or any other comments/questions to the issues list.
@@ -52,7 +52,8 @@ Pkg.add("Gadfly")
Pkg.add("Immerse")
Pkg.add("PyPlot")
Pkg.add("UnicodePlots")
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git")
Pkg.add("Qwt")
Pkg.add("Bokeh")
```
## Use

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

+137 -59
View File
@@ -1,11 +1,16 @@
immutable GadflyPackage <: PlottingPackage end
immutable ImmersePackage <: PlottingPackage end
immutable PyPlotPackage <: PlottingPackage end
immutable QwtPackage <: PlottingPackage end
immutable GadflyPackage <: PlottingPackage end
immutable ImmersePackage <: PlottingPackage end
immutable PyPlotPackage <: PlottingPackage end
immutable QwtPackage <: PlottingPackage end
immutable UnicodePlotsPackage <: PlottingPackage end
immutable WinstonPackage <: PlottingPackage end
immutable WinstonPackage <: PlottingPackage end
immutable BokehPackage <: PlottingPackage end
immutable PlotlyPackage <: PlottingPackage end
immutable GRPackage <: PlottingPackage end
immutable GLVisualizePackage <: PlottingPackage end
immutable NoPackage <: PlottingPackage end
typealias GadflyOrImmerse @compat(Union{GadflyPackage, ImmersePackage})
@@ -14,21 +19,34 @@ export
immerse,
pyplot,
qwt,
unicodeplots
unicodeplots,
bokeh,
plotly,
gr,
glvisualize
# winston
gadfly() = backend(:gadfly)
immerse() = backend(:immerse)
pyplot() = backend(:pyplot)
qwt() = backend(:qwt)
unicodeplots() = backend(:unicodeplots)
# winston() = backend(:winston)
gadfly(; kw...) = (default(; kw...); backend(:gadfly))
immerse(; kw...) = (default(; kw...); backend(:immerse))
pyplot(; kw...) = (default(; kw...); backend(:pyplot))
qwt(; kw...) = (default(; kw...); backend(:qwt))
unicodeplots(; kw...) = (default(; kw...); backend(:unicodeplots))
bokeh(; kw...) = (default(; kw...); backend(:bokeh))
plotly(; kw...) = (default(; kw...); backend(:plotly))
gr(; kw...) = (default(; kw...); backend(:gr))
glvisualize(; kw...) = (default(; kw...); backend(:glvisualize))
# winston(; kw...) = (default(; kw...); backend(:winston))
backend_name(::GadflyPackage) = :gadfly
backend_name(::ImmersePackage) = :immerse
backend_name(::PyPlotPackage) = :pyplot
backend_name(::UnicodePlotsPackage) = :unicodeplots
backend_name(::QwtPackage) = :qwt
backend_name(::BokehPackage) = :bokeh
backend_name(::PlotlyPackage) = :plotly
backend_name(::GRPackage) = :gr
backend_name(::GLVisualizePackage) = :glvisualize
backend_name(::NoPackage) = :none
include("backends/supported.jl")
@@ -39,16 +57,23 @@ include("backends/pyplot.jl")
include("backends/immerse.jl")
include("backends/winston.jl")
include("backends/web.jl")
include("backends/bokeh.jl")
include("backends/plotly.jl")
include("backends/gr.jl")
include("backends/glvisualize.jl")
# ---------------------------------------------------------
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
updatePlotItems(pkg::PlottingPackage, plt::Plot, d::Dict) = error("updatePlotItems($pkg, plt, d) is not implemented")
_update_plot(pkg::PlottingPackage, plt::Plot, d::Dict) = error("_update_plot($pkg, plt, d) is not implemented")
# Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented")
updatePositionAndSize{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing #error("updatePositionAndSize(plt,d) is not implemented for $P")
_update_plot_pos_size{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing #error("_update_plot_pos_size(plt,d) is not implemented for $P")
subplot(pkg::PlottingPackage; kw...) = error("subplot($pkg; kw...) is not implemented")
subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
@@ -57,66 +82,43 @@ subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, s
# ---------------------------------------------------------
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse]
const INITIALIZED_BACKENDS = Set{Symbol}()
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly, :gr]
const _initialized_backends = Set{Symbol}()
backends() = BACKENDS
function backendInstance(sym::Symbol)
function _backend_instance(sym::Symbol)
sym == :qwt && return QwtPackage()
sym == :gadfly && return GadflyPackage()
sym == :unicodeplots && return UnicodePlotsPackage()
sym == :pyplot && return PyPlotPackage()
sym == :immerse && return ImmersePackage()
sym == :winston && return WinstonPackage()
sym == :bokeh && return BokehPackage()
sym == :plotly && return PlotlyPackage()
sym == :gr && return GRPackage()
sym == :glvisualize && return GLVisualizePackage()
sym == :none && return NoPackage()
error("Unsupported backend $sym")
end
end
type CurrentBackend
sym::Symbol
pkg::PlottingPackage
end
CurrentBackend(sym::Symbol) = CurrentBackend(sym, backendInstance(sym))
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
try
if Pkg.installed("Immerse") != nothing
return CurrentBackend(:immerse)
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
return backend(symbol(lowercase(pkgstr)))
end
end
try
if Pkg.installed("Qwt") != nothing
return CurrentBackend(:qwt)
end
end
try
if Pkg.installed("PyPlot") != nothing
return CurrentBackend(:pyplot)
end
end
try
if Pkg.installed("Gadfly") != nothing
return CurrentBackend(:gadfly)
end
end
try
if Pkg.installed("UnicodePlots") != nothing
return CurrentBackend(:unicodeplots)
end
end
try
if Pkg.installed("Winston") != nothing
return CurrentBackend(:winston)
end
end
warn("You don't have any of the supported backends installed! Chose from ", backends())
return CurrentBackend(:gadfly)
backend(:plotly)
end
# const CURRENT_BACKEND = pickDefaultBackend()
# println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
# ---------------------------------------------------------
@@ -125,10 +127,14 @@ end
Returns the current plotting package name. Initializes package on first call.
"""
function backend()
# error()
global CURRENT_BACKEND
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
end
currentBackendSymbol = CURRENT_BACKEND.sym
if !(currentBackendSymbol in INITIALIZED_BACKENDS)
if !(currentBackendSymbol in _initialized_backends)
# initialize
println("[Plots.jl] Initializing backend: ", CURRENT_BACKEND.sym)
@@ -143,8 +149,8 @@ function backend()
elseif currentBackendSymbol == :gadfly
try
@eval import Gadfly, Compose, DataFrames
@eval export Gadfly, Compose, DataFrames
@eval import Gadfly, Compose
@eval export Gadfly, Compose
@eval include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
catch err
warn("Couldn't import Gadfly. Install it with: Pkg.add(\"Gadfly\").")
@@ -166,10 +172,11 @@ function backend()
@eval export PyPlot
@eval const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
@eval const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
@eval const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
# @eval const pycolorbar = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colorbar"))
if !isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
PyPlot.ioff() # stops wierd behavior of displaying incomplete graphs in IJulia
# # TODO: how the hell can I use PyQt4??
# "pyqt4"=>:qt_pyqt4
# PyPlot.backend[1] = "pyqt4"
@@ -198,6 +205,70 @@ function backend()
rethrow(err)
end
elseif currentBackendSymbol == :bokeh
try
@eval import Bokeh
@eval export Bokeh
catch err
warn("Couldn't import Bokeh. Install it with: Pkg.add(\"Bokeh\").")
rethrow(err)
end
elseif currentBackendSymbol == :plotly
try
@eval begin
import JSON
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
############################
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
# the first script is some hack I needed to do in order for the notebook
# to not complain about Plotly being undefined
display("text/html", """
<script type="text/javascript">
require=requirejs=define=undefined;
</script>
<script type="text/javascript">
$(open(readall, _js_path, "r"))
</script>
""")
# display("text/html", "<p>Plotly javascript loaded.</p>")
end
# end borrowing (thanks :)
###########################
try
include(joinpath(Pkg.dir("Plots"), "src", "backends", "plotly_blink.jl"))
catch err
warn("Error including PlotlyJS: $err\n Note: Will fall back to built-in display.")
end
end
catch err
warn("Couldn't setup Plotly")
rethrow(err)
end
elseif currentBackendSymbol == :gr
try
@eval import GR
catch err
warn("Couldn't import GR. Install it with: Pkg.add(\"GR\").")
end
elseif currentBackendSymbol == :glvisualize
try
@eval import GLVisualize
@eval export GLVisualize
catch err
warn("Couldn't setup GLVisualize")
rethrow(err)
end
elseif currentBackendSymbol == :winston
warn("Winston support is deprecated and broken. Try another backend: $BACKENDS")
try
@@ -212,7 +283,7 @@ function backend()
else
error("Unknown backend $currentBackendSymbol. Choose from: $BACKENDS")
end
push!(INITIALIZED_BACKENDS, currentBackendSymbol)
push!(_initialized_backends, currentBackendSymbol)
end
CURRENT_BACKEND.pkg
@@ -222,13 +293,12 @@ end
Set the plot backend. Choose from: :qwt, :gadfly, :unicodeplots, :immerse, :pyplot
"""
function backend(pkg::PlottingPackage)
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
end
function backend(modname)
# set the PlottingPackage
if modname == :qwt
CURRENT_BACKEND.pkg = QwtPackage()
@@ -242,6 +312,14 @@ function backend(modname)
CURRENT_BACKEND.pkg = ImmersePackage()
elseif modname == :winston
CURRENT_BACKEND.pkg = WinstonPackage()
elseif modname == :bokeh
CURRENT_BACKEND.pkg = BokehPackage()
elseif modname == :plotly
CURRENT_BACKEND.pkg = PlotlyPackage()
elseif modname == :gr
CURRENT_BACKEND.pkg = GRPackage()
elseif modname == :glvisualize
CURRENT_BACKEND.pkg = GLVisualizePackage()
else
error("Unknown backend $modname. Choose from: $BACKENDS")
end

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Vendored Executable
+41
View File
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

+65 -38
View File
@@ -1,24 +1,31 @@
if VERSION >= v"0.4-"
__precompile__()
end
__precompile__()
module Plots
using Compat
using Reexport
@reexport using Colors
using Requires
using FixedSizeArrays
export
Plot,
Subplot,
SubplotLayout,
GridLayout,
FlexLayout,
AVec,
AMat,
plot,
plot!,
# plot_display,
# plot_display!,
subplot,
subplot!,
current,
default,
with,
scatter,
scatter!,
@@ -26,8 +33,12 @@ export
bar!,
histogram,
histogram!,
density,
density!,
heatmap,
heatmap!,
hexbin,
hexbin!,
sticks,
sticks!,
hline,
@@ -36,6 +47,21 @@ export
vline!,
ohlc,
ohlc!,
pie,
pie!,
contour,
contour!,
surface,
surface!,
wireframe,
wireframe!,
path3d,
path3d!,
plot3d,
plot3d!,
scatter3d,
scatter3d!,
abline!,
title!,
xlabel!,
@@ -56,12 +82,16 @@ export
backend,
backends,
backend_name,
aliases,
dataframes,
Shape,
text,
font,
stroke,
brush,
Surface,
OHLC,
colorscheme,
@@ -86,25 +116,23 @@ export
Animation,
frame,
gif,
@animate,
@gif,
# recipes
PlotRecipe,
EllipseRecipe,
spy,
# EllipseRecipe,
# spy,
corrplot
# ---------------------------------------------------------
const IMG_DIR = Pkg.dir("Plots") * "/img/"
# ---------------------------------------------------------
include("types.jl")
include("utils.jl")
include("colors.jl")
include("plotter.jl")
include("components.jl")
include("plotter2.jl")
include("args.jl")
include("plot.jl")
include("subplot.jl")
@@ -121,8 +149,12 @@ bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
density(args...; kw...) = plot(args...; kw..., linetype = :density)
density!(args...; kw...) = plot!(args...; kw..., linetype = :density)
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
hexbin(args...; kw...) = plot(args...; kw..., linetype = :hexbin)
hexbin!(args...; kw...) = plot!(args...; kw..., linetype = :hexbin)
sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
@@ -131,6 +163,20 @@ vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
pie(args...; kw...) = plot(args...; kw..., linetype = :pie)
pie!(args...; kw...) = plot!(args...; kw..., linetype = :pie)
contour(args...; kw...) = plot(args...; kw..., linetype = :contour)
contour!(args...; kw...) = plot!(args...; kw..., linetype = :contour)
surface(args...; kw...) = plot(args...; kw..., linetype = :surface)
surface!(args...; kw...) = plot!(args...; kw..., linetype = :surface)
wireframe(args...; kw...) = plot(args...; kw..., linetype = :wireframe)
wireframe!(args...; kw...) = plot!(args...; kw..., linetype = :wireframe)
path3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
path3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
plot3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
scatter3d(args...; kw...) = plot(args...; kw..., linetype = :scatter3d)
scatter3d!(args...; kw...) = plot!(args...; kw..., linetype = :scatter3d)
title!(s::@compat(AbstractString); kw...) = plot!(; title = s, kw...)
@@ -177,34 +223,15 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
# ---------------------------------------------------------
try
import DataFrames
dataframes()
end
# const CURRENT_BACKEND = pickDefaultBackend()
# for be in backends()
# try
# backend(be)
# backend()
# catch err
# @show err
# end
# end
const CURRENT_BACKEND = CurrentBackend(:none)
function __init__()
global const CURRENT_BACKEND = pickDefaultBackend()
# global CURRENT_BACKEND
# println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
# # auto init dataframes if the import statement doesn't error out
# try
# @eval import DataFrames
# dataframes()
# end
# override IJulia inline display
if isijulia()
@eval import IJulia
IJulia.display_dict(plt::PlottingObject) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
end
end
# ---------------------------------------------------------
+92 -10
View File
@@ -1,19 +1,18 @@
immutable Animation{P<:PlottingObject}
plt::P
immutable Animation
dir::ASCIIString
frames::Vector{ASCIIString}
end
function Animation(plt::PlottingObject)
Animation(plt, mktempdir(), ASCIIString[])
function Animation()
tmpdir = convert(ASCIIString, mktempdir())
Animation(tmpdir, ASCIIString[])
end
Animation() = Animation(current())
function frame(anim::Animation)
function frame{P<:PlottingObject}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
png(anim.plt, joinpath(anim.dir, filename))
png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename)
end
@@ -29,11 +28,11 @@ function gif(anim::Animation, fn::@compat(AbstractString) = "tmp.gif"; fps::Inte
fn = abspath(fn)
try
# high quality
speed = round(Int, 100 / fps)
run(`convert -delay $speed -loop 0 $(anim.dir)/*.png $fn`)
run(`convert -delay $speed -loop 0 $(anim.dir)/*.png -alpha off $fn`)
catch err
warn("Tried to create gif using convert (ImageMagick), but got error: $err\nWill try ffmpeg, but it's lower quality...)")
@@ -52,3 +51,86 @@ end
function Base.writemime(io::IO, ::MIME"text/html", agif::AnimatedGif)
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />")
end
# -----------------------------------------------
function _animate(forloop::Expr, args...; callgif = false)
if forloop.head != :for
error("@animate macro expects a for-block. got: $(forloop.head)")
end
# add the call to frame to the end of each iteration
animsym = gensym("anim")
countersym = gensym("counter")
block = forloop.args[2]
# create filter
n = length(args)
filterexpr = if n == 0
# no filter... every iteration gets a frame
true
elseif args[1] == :every
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
@assert isa(freq, Integer) && freq > 0
:(mod1($countersym, $freq) == 1)
elseif args[1] == :when
# filter on custom expression
@assert n == 2
args[2]
else
error("Unsupported animate filter: $args")
end
push!(block.args, :(if $filterexpr; frame($animsym); end))
push!(block.args, :($countersym += 1))
# add a final call to `gif(anim)`?
retval = callgif ? :(gif($animsym)) : animsym
# full expression:
esc(quote
$animsym = Animation() # init animation object
$countersym = 1 # init iteration counter
$forloop # for loop, saving a frame after each iteration
$retval # return the animation object, or the gif
end)
end
"""
Builds an `Animation` using one frame per loop iteration, then create an animated GIF.
Example:
```
p = plot(1)
@gif for x=0:0.1:5
push!(p, 1, sin(x))
end
```
"""
macro gif(forloop::Expr, args...)
_animate(forloop, args...; callgif = true)
end
"""
Collect one frame per for-block iteration and return an `Animation` object.
Example:
```
p = plot(1)
anim = @animate for x=0:0.1:5
push!(p, 1, sin(x))
end
gif(anim)
```
"""
macro animate(forloop::Expr, args...)
_animate(forloop, args...)
end
+299 -170
View File
@@ -2,13 +2,17 @@
const _allAxes = [:auto, :left, :right]
@compat const _axesAliases = Dict(
:a => :auto,
:l => :left,
:a => :auto,
:l => :left,
:r => :right
)
const _allTypes = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc, :contour]
const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe]
const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :hist, :density, :bar, :hline, :vline, :ohlc,
:contour, :pie
], _3dTypes)
@compat const _typeAliases = Dict(
:n => :none,
:no => :none,
@@ -26,9 +30,18 @@ const _allTypes = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
:stems => :sticks,
:dots => :scatter,
:histogram => :hist,
:contours => :contours,
:pdf => :density,
:contours => :contour,
:line3d => :path3d,
:surf => :surface,
:wire => :wireframe,
)
ishistlike(lt::Symbol) = lt in (:hist, :density)
islinelike(lt::Symbol) = lt in (:line, :path, :steppre, :steppost)
isheatmaplike(lt::Symbol) = lt in (:heatmap, :hexbin)
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
@compat const _styleAliases = Dict(
:a => :auto,
@@ -78,61 +91,56 @@ const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
:hep => :heptagon,
:o => :octagon,
:oct => :octagon,
:spike => :vline,
)
const _allScales = [:identity, :log, :log2, :log10, :asinh, :sqrt]
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
@compat const _scaleAliases = Dict(
:none => :identity,
:ln => :log,
:log => :log10,
)
supportedAxes(::PlottingPackage) = _allAxes
supportedTypes(::PlottingPackage) = _allTypes
supportedStyles(::PlottingPackage) = _allStyles
supportedMarkers(::PlottingPackage) = _allMarkers
supportedScales(::PlottingPackage) = _allScales
subplotSupported(::PlottingPackage) = true
supportedAxes() = supportedAxes(backend())
supportedTypes() = supportedTypes(backend())
supportedStyles() = supportedStyles(backend())
supportedMarkers() = supportedMarkers(backend())
supportedScales() = supportedScales(backend())
subplotSupported() = subplotSupported(backend())
# -----------------------------------------------------------------------------
const _seriesDefaults = Dict{Symbol, Any}()
# series-specific
_seriesDefaults[:axis] = :left
_seriesDefaults[:color] = :auto
_seriesDefaults[:label] = "AUTO"
_seriesDefaults[:linetype] = :path
_seriesDefaults[:linestyle] = :solid
_seriesDefaults[:linewidth] = 1
_seriesDefaults[:lineopacity] = nothing
_seriesDefaults[:markershape] = :none
_seriesDefaults[:markercolor] = :match
_seriesDefaults[:markeropacity] = nothing
_seriesDefaults[:markersize] = 6
_seriesDefaults[:fillrange] = nothing # ribbons, areas, etc
_seriesDefaults[:fillcolor] = :match
_seriesDefaults[:fillopacity] = nothing
# _seriesDefaults[:ribbon] = nothing
# _seriesDefaults[:ribboncolor] = :match
_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
# _seriesDefaults[:heatmap_c] = (0.15, 0.5) # TODO: this should be replaced with a ColorGradient
# _seriesDefaults[:fill] = nothing # fills in the area
_seriesDefaults[:smooth] = false # regression line?
_seriesDefaults[:group] = nothing # groupby vector
_seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
_seriesDefaults[:z] = nothing # depth for contour, color scale, etc
# _seriesDefaults[:args] = [] # additional args to pass to the backend
# _seriesDefaults[:kwargs] = [] # additional keyword args to pass to the backend
# # note: can be Vector{Dict} or Vector{Tuple}
_seriesDefaults[:surface] = nothing
_seriesDefaults[:nlevels] = 15
_seriesDefaults[:axis] = :left
_seriesDefaults[:label] = "AUTO"
_seriesDefaults[:linetype] = :path
_seriesDefaults[:linestyle] = :solid
_seriesDefaults[:linewidth] = 1
_seriesDefaults[:linecolor] = :auto
_seriesDefaults[:linealpha] = nothing
# _seriesDefaults[:linestroke] = Stroke(1, :auto, nothing, :solid) # linewidth, linecolor, linealpha, linestyle
# _seriesDefaults[:fillbrush] = Brush(nothing, :match, nothing) # fillrange, fillcolor, fillalpha
_seriesDefaults[:fillrange] = nothing # ribbons, areas, etc
_seriesDefaults[:fillcolor] = :match
_seriesDefaults[:fillalpha] = nothing
_seriesDefaults[:markershape] = :none
# _seriesDefaults[:markerstroke] = Stroke(1, :match_foreground, nothing, :solid)
# _seriesDefaults[:markerbrush] = Brush(6, :match, nothing)
_seriesDefaults[:markercolor] = :match
_seriesDefaults[:markeralpha] = nothing
_seriesDefaults[:markersize] = 6
_seriesDefaults[:markerstrokestyle] = :solid
_seriesDefaults[:markerstrokewidth] = 1
_seriesDefaults[:markerstrokecolor] = :match
_seriesDefaults[:markerstrokealpha] = nothing
# _seriesDefaults[:ribbon] = nothing
# _seriesDefaults[:ribboncolor] = :match
_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
_seriesDefaults[:smooth] = false # regression line?
_seriesDefaults[:group] = nothing # groupby vector
# _seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
_seriesDefaults[:x] = nothing
_seriesDefaults[:y] = nothing
_seriesDefaults[:z] = nothing # depth for contour, surface, etc
_seriesDefaults[:zcolor] = nothing # value for color scale
# _seriesDefaults[:surface] = nothing
# _seriesDefaults[:nlevels] = 15
_seriesDefaults[:levels] = 15
_seriesDefaults[:orientation] = :vertical
const _plotDefaults = Dict{Symbol, Any}()
@@ -142,7 +150,8 @@ _plotDefaults[:title] = ""
_plotDefaults[:xlabel] = ""
_plotDefaults[:ylabel] = ""
_plotDefaults[:yrightlabel] = ""
_plotDefaults[:legend] = true
_plotDefaults[:legend] = :best
_plotDefaults[:colorbar] = :legend
_plotDefaults[:background_color] = colorant"white"
_plotDefaults[:foreground_color] = :auto
_plotDefaults[:xlims] = :auto
@@ -170,22 +179,17 @@ _plotDefaults[:tickfont] = font(8)
_plotDefaults[:guidefont] = font(11)
_plotDefaults[:legendfont] = font(8)
_plotDefaults[:grid] = true
_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
_plotDefaults[:overwrite_figure] = false
# TODO: x/y scales
const _allArgs = sort(collect(union(keys(_seriesDefaults), keys(_plotDefaults))))
supportedArgs(::PlottingPackage) = _allArgs
supportedArgs(::PlottingPackage) = error("supportedArgs not defined") #_allArgs
supportedArgs() = supportedArgs(backend())
@compat const _argNotes = Dict(
:color => "Series color. To have different marker and/or fill colors, optionally set the markercolor and fillcolor args.",
:z => "Determines the depth. For color gradients, we expect 0 ≤ z ≤ 1.",
# :heatmap_c => "For Qwt heatmaps only... will be deprecated eventually.",
)
# -----------------------------------------------------------------------------
@@ -215,79 +219,103 @@ end
# Alternate args
@compat const _keyAliases = Dict(
:c => :color,
:lab => :label,
:l => :line,
:w => :linewidth,
:width => :linewidth,
:lw => :linewidth,
:lo => :lineopacity,
:type => :linetype,
:lt => :linetype,
:t => :linetype,
:style => :linestyle,
:s => :linestyle,
:ls => :linestyle,
:m => :marker,
:mark => :marker,
:shape => :markershape,
:mc => :markercolor,
:mcolor => :markercolor,
:ms => :markersize,
:msize => :markersize,
:mo => :markeropacity,
:opacity => :markeropacity,
:alpha => :markeropacity,
:f => :fill,
:area => :fill,
:fillrng => :fillrange,
:fc => :fillcolor,
:fcolor => :fillcolor,
:fo => :fillopacity,
:g => :group,
:nb => :nbins,
:nbin => :nbins,
:rib => :ribbon,
:ann => :annotation,
:anns => :annotation,
:annotate => :annotation,
:annotations => :annotation,
:xlab => :xlabel,
:ylab => :ylabel,
:yrlab => :yrightlabel,
:ylabr => :yrightlabel,
:y2lab => :yrightlabel,
:ylab2 => :yrightlabel,
:ylabelright => :yrightlabel,
:ylabel2 => :yrightlabel,
:y2label => :yrightlabel,
:leg => :legend,
:bg => :background_color,
:bgcolor => :background_color,
:bg_color => :background_color,
:background => :background_color,
:fg => :foreground_color,
:fgcolor => :foreground_color,
:fg_color => :foreground_color,
:foreground => :foreground_color,
:regression => :smooth,
:reg => :smooth,
:xlim => :xlims,
:xlimit => :xlims,
:xlimits => :xlims,
:ylim => :ylims,
:ylimit => :ylims,
:ylimits => :ylims,
:xtick => :xticks,
:ytick => :yticks,
:windowsize => :size,
:wsize => :size,
:wtitle => :windowtitle,
:gui => :show,
:display => :show,
:palette => :color_palette,
:xlink => :linkx,
:ylink => :linky,
:c => :linecolor,
:color => :linecolor,
:colour => :linecolor,
:lab => :label,
:l => :line,
:w => :linewidth,
:width => :linewidth,
:lw => :linewidth,
:la => :linealpha,
:lineopacity => :linealpha,
:type => :linetype,
:lt => :linetype,
:t => :linetype,
:seriestype => :linetype,
:style => :linestyle,
:s => :linestyle,
:ls => :linestyle,
:m => :marker,
:mark => :marker,
:shape => :markershape,
:mc => :markercolor,
:mcolor => :markercolor,
:markercolour => :markercolor,
:ms => :markersize,
:msize => :markersize,
:ma => :markeralpha,
:alpha => :markeralpha,
:opacity => :markeralpha,
:markeropacity => :markeralpha,
:f => :fill,
:area => :fill,
:fillrng => :fillrange,
:fc => :fillcolor,
:fcolor => :fillcolor,
:fillcolour => :fillcolor,
:fa => :fillalpha,
:fillopacity => :fillalpha,
:g => :group,
:nb => :nbins,
:nbin => :nbins,
:rib => :ribbon,
:ann => :annotation,
:anns => :annotation,
:annotate => :annotation,
:annotations => :annotation,
:xlab => :xlabel,
:ylab => :ylabel,
:yrlab => :yrightlabel,
:ylabr => :yrightlabel,
:y2lab => :yrightlabel,
:ylab2 => :yrightlabel,
:ylabelright => :yrightlabel,
:ylabel2 => :yrightlabel,
:y2label => :yrightlabel,
:leg => :legend,
:key => :legend,
:cbar => :colorbar,
:cb => :colorbar,
:bg => :background_color,
:bgcolor => :background_color,
:bg_color => :background_color,
:background => :background_color,
:background_colour => :background_color,
:fg => :foreground_color,
:fgcolor => :foreground_color,
:fg_color => :foreground_color,
:foreground => :foreground_color,
:foreground_colour => :foreground_color,
:regression => :smooth,
:reg => :smooth,
:nlevels => :levels,
:nlev => :levels,
:levs => :levels,
:xlim => :xlims,
:xlimit => :xlims,
:xlimits => :xlims,
:ylim => :ylims,
:ylimit => :ylims,
:ylimits => :ylims,
:xtick => :xticks,
:ytick => :yticks,
:windowsize => :size,
:wsize => :size,
:wtitle => :windowtitle,
:gui => :show,
:display => :show,
:palette => :color_palette,
:xlink => :linkx,
:ylink => :linky,
:nrow => :nr,
:nrows => :nr,
:ncol => :nc,
:ncols => :nc,
:clf => :overwrite_figure,
:clearfig => :overwrite_figure,
:overwrite => :overwrite_figure,
:reuse => :overwrite_figure,
)
# add all pluralized forms to the _keyAliases dict
@@ -337,12 +365,6 @@ end
# -----------------------------------------------------------------------------
wraptuple(x::@compat(Tuple)) = x
wraptuple(x) = (x,)
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
trueOrAllTrue(f::Function, x) = f(x)
function handleColors!(d::Dict, arg, csym::Symbol)
try
if arg == :auto
@@ -394,23 +416,38 @@ end
function processLineArg(d::Dict, arg)
# linetype
if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
# if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
if allLineTypes(arg)
d[:linetype] = arg
# linestyle
elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
# elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
elseif allStyles(arg)
d[:linestyle] = arg
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[:linewidth] = arg.width)
arg.color == nothing || (d[:linecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:linealpha] = arg.alpha)
arg.style == nothing || (d[:linestyle] = arg.style)
elseif typeof(arg) <: Brush
arg.size == nothing || (d[:fillrange] = arg.size)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
# linealpha
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
elseif allAlphas(arg)
d[:linealpha] = arg
# linewidth
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
# elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
elseif allReals(arg)
d[:linewidth] = arg
# lineopacity
elseif trueOrAllTrue(a -> typeof(a) <: Real && a >= 0 && a <= 1, arg)
d[:lineopacity] = arg
# color
elseif !handleColors!(d, arg, :color)
elseif !handleColors!(d, arg, :linecolor)
warn("Skipped line arg $arg.")
end
@@ -420,37 +457,79 @@ end
function processMarkerArg(d::Dict, arg)
# markershape
if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
d[:markershape] = arg
elseif trueOrAllTrue(a -> isa(a, Shape), arg)
# if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
# d[:markershape] = arg
# elseif trueOrAllTrue(a -> isa(a, Shape), arg)
if allShapes(arg)
d[:markershape] = arg
# stroke style
# elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
elseif allStyles(arg)
d[:markerstrokestyle] = arg
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[:markerstrokewidth] = arg.width)
arg.color == nothing || (d[:markerstrokecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:markerstrokealpha] = arg.alpha)
arg.style == nothing || (d[:markerstrokestyle] = arg.style)
elseif typeof(arg) <: Brush
arg.size == nothing || (d[:markersize] = arg.size)
arg.color == nothing || (d[:markercolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:markeralpha] = arg.alpha)
# linealpha
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
elseif allAlphas(arg)
d[:markeralpha] = arg
# markersize
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
# elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
elseif allReals(arg)
d[:markersize] = arg
# lineopacity
elseif trueOrAllTrue(a -> typeof(a) <: Real && a >= 0 && a <= 1, arg)
d[:markeropacity] = arg
# markercolor
elseif !handleColors!(d, arg, :markercolor)
warn("Skipped marker arg $arg.")
end
end
function processFillArg(d::Dict, arg)
if !handleColors!(d, arg, :fillcolor)
if typeof(arg) <: Brush
arg.size == nothing || (d[:fillrange] = arg.size)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
# fillrange function
# elseif trueOrAllTrue(a -> isa(a, Function), arg)
elseif allFunctions(arg)
d[:fillrange] = arg
# fillalpha
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
elseif allAlphas(arg)
d[:fillalpha] = arg
elseif !handleColors!(d, arg, :fillcolor)
d[:fillrange] = arg
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
_replace_markershape(shape) = shape
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
function preprocessArgs!(d::Dict)
replaceAliases!(d, _keyAliases)
# handle axis args
for axisletter in ("x", "y")
asym = symbol(axisletter * "axis")
@@ -458,6 +537,12 @@ function preprocessArgs!(d::Dict)
processAxisArg(d, axisletter, arg)
end
delete!(d, asym)
# turn :labels into :ticks_and_labels
tsym = symbol(axisletter * "ticks")
if haskey(d, tsym) && ticksType(d[tsym]) == :labels
d[tsym] = (1:length(d[tsym]), d[tsym])
end
end
# handle line args
@@ -473,7 +558,12 @@ function preprocessArgs!(d::Dict)
anymarker = true
end
delete!(d, :marker)
if anymarker && !haskey(d, :markershape)
# if anymarker && !haskey(d, :markershape)
# d[:markershape] = :ellipse
# end
if haskey(d, :markershape)
d[:markershape] = _replace_markershape(d[:markershape])
elseif anymarker
d[:markershape] = :ellipse
end
@@ -483,6 +573,16 @@ function preprocessArgs!(d::Dict)
end
delete!(d, :fill)
# convert into strokes and brushes
# legends
if haskey(d, :legend)
d[:legend] = convertLegendValue(d[:legend])
end
if haskey(d, :colorbar)
d[:colorbar] = convertLegendValue(d[:colorbar])
end
# handle subplot links
if haskey(d, :link)
l = d[:link]
@@ -543,9 +643,12 @@ function warnOnUnsupportedArgs(pkg::PlottingPackage, d::Dict)
end
end
_markershape_supported(pkg::PlottingPackage, shape::Symbol) = shape in supportedMarkers(pkg)
_markershape_supported(pkg::PlottingPackage, shape::Shape) = Shape in supportedMarkers(pkg)
_markershape_supported(pkg::PlottingPackage, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
(d[:axis] in supportedAxes(pkg)
(d[:axis] in supportedAxes(pkg)
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
(d[:linetype] == :none
|| d[:linetype] in supportedTypes(pkg)
@@ -553,8 +656,9 @@ function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
(d[:linestyle] in supportedStyles(pkg)
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
(d[:markershape] == :none
|| d[:markershape] in supportedMarkers(pkg)
|| (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
|| _markershape_supported(pkg, d[:markershape])
# || d[:markershape] in supportedMarkers(pkg)
# || (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
end
@@ -590,6 +694,19 @@ function setDictValue(d_in::Dict, d_out::Dict, k::Symbol, idx::Int, defaults::Di
end
end
function convertLegendValue(val::Symbol)
if val in (:both, :all, :yes)
:best
elseif val in (:no, :none)
:none
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend)
val
else
error("Invalid symbol for legend: $val")
end
end
convertLegendValue(val::Bool) = val ? :best : :none
# -----------------------------------------------------------------------------
# build the argument dictionary for the plot
@@ -610,6 +727,13 @@ function getPlotArgs(pkg::PlottingPackage, kw, idx::Int; set_defaults = true)
end
end
# handle legend/colorbar
d[:legend] = convertLegendValue(d[:legend])
d[:colorbar] = convertLegendValue(d[:colorbar])
if d[:colorbar] == :legend
d[:colorbar] = d[:legend]
end
# convert color
handlePlotColors(pkg, d)
@@ -623,7 +747,7 @@ end
# build the argument dictionary for a series
function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in initargs, not plt
function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt
kwdict = Dict(kw)
d = Dict()
@@ -638,7 +762,7 @@ function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::I
d[k] = kwdict[k]
end
end
if haskey(_typeAliases, d[:linetype])
d[:linetype] = _typeAliases[d[:linetype]]
end
@@ -648,17 +772,22 @@ function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::I
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
# update color
d[:color] = getSeriesRGBColor(d[:color], initargs, plotIndex)
d[:linecolor] = getSeriesRGBColor(d[:linecolor], plotargs, plotIndex)
# update markercolor
mc = d[:markercolor]
mc = (mc == :match ? d[:color] : getSeriesRGBColor(mc, initargs, plotIndex))
d[:markercolor] = mc
c = d[:markercolor]
c = (c == :match ? d[:linecolor] : getSeriesRGBColor(c, plotargs, plotIndex))
d[:markercolor] = c
# update markerstrokecolor
c = d[:markerstrokecolor]
c = (c == :match ? plotargs[:foreground_color] : getSeriesRGBColor(c, plotargs, plotIndex))
d[:markerstrokecolor] = c
# update fillcolor
mc = d[:fillcolor]
mc = (mc == :match ? d[:color] : getSeriesRGBColor(mc, initargs, plotIndex))
d[:fillcolor] = mc
c = d[:fillcolor]
c = (c == :match ? d[:linecolor] : getSeriesRGBColor(c, plotargs, plotIndex))
d[:fillcolor] = c
# set label
label = d[:label]
+176
View File
@@ -0,0 +1,176 @@
# https://github.com/bokeh/Bokeh.jl
function _initialize_backend(::BokehPackage; kw...)
@eval begin
warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
end
# make255(x) = round(Int, 255 * x)
# function bokehcolor(c::Colorant)
# @sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
# end
# bokehcolor(cs::ColorScheme) = bokehcolor(getColor(cs))
const _glyphtypes = Dict(
:ellipse => :Circle,
:rect => :Square,
:diamond => :Diamond,
:utriangle => :Triangle,
:dtriangle => :InvertedTriangle,
# :pentagon =>
# :hexagon =>
# :heptagon =>
# :octagon =>
:cross => :Cross,
:xcross => :X,
:star5 => :Asterisk,
)
function bokeh_glyph_type(d::Dict)
lt = d[:linetype]
mt = d[:markershape]
if lt == :scatter && mt == :none
mt = :ellipse
end
# if we have a marker, use that
if lt == :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::BokehPackage; kw...)
d = Dict(kw)
# dumpdict(d, "plot", true)
# 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 = d[:title]
w, h = d[:size]
xaxis_type = d[:xscale] == :log10 ? :log : :auto
yaxis_type = d[:yscale] == :log10 ? :log : :auto
# legend = d[:legend] ? xxxx : nothing
legend = nothing
extra_args = Dict() # TODO: we'll put extra settings (xlim, etc) here
bplt = Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
Plot(bplt, pkg, 0, d, Dict[])
end
function _add_series(::BokehPackage, plt::Plot; kw...)
d = Dict(kw)
# dumpdict(d, "plot!", true)
bdata = Dict{Symbol, Vector}(:x => collect(d[:x]), :y => collect(d[:y]))
glyph = Bokeh.Bokehjs.Glyph(
glyphtype = bokeh_glyph_type(d),
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
linewidth = d[:linewidth], # shape's stroke width or line width
fillcolor = webcolor(d[:markercolor]),
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
dash = get_stroke_vector(d[:linestyle])
)
legend = nothing # TODO
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
push!(plt.seriesargs, d)
plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{BokehPackage}, d::Dict)
end
function _update_plot_pos_size(plt::PlottingObject{BokehPackage}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{BokehPackage}, i::Int)
series = plt.o.datacolumns[i].data
series[:x], series[:y]
end
function Base.setindex!(plt::Plot{BokehPackage}, xy::Tuple, i::Integer)
series = plt.o.datacolumns[i].data
series[:x], series[:y] = xy
plt
end
# ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{BokehPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
# TODO: add the annotation to the plot
end
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{BokehPackage}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end
function _expand_limits(lims, plt::Plot{BokehPackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{BokehPackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{BokehPackage})
# TODO: write a png to io
warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehPackage})
Bokeh.showplot(plt.o)
end
function Base.display(::PlotsDisplay, plt::Subplot{BokehPackage})
# TODO: display/show the subplot
end
+193 -91
View File
@@ -1,14 +1,27 @@
# https://github.com/dcjones/Gadfly.jl
function _initialize_backend(::GadflyPackage; kw...)
@eval begin
import Gadfly, Compose
export Gadfly, Compose
include(joinpath(Pkg.dir("Plots"), "src", "backends", "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(d::Dict)
gplt = Gadfly.Plot()
gplt.mapping = Dict()
gplt.data_source = DataFrames.DataFrame()
gplt.layers = gplt.layers[1:0]
gplt.data_source = Gadfly.DataFrames.DataFrame()
# gplt.layers = gplt.layers[1:0]
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]),
Gadfly.Guide.ylabel(d[:ylabel]),
Gadfly.Guide.title(d[:title])]
@@ -36,42 +49,61 @@ function getLineGeom(d::Dict)
elseif lt == :steppre
Gadfly.Geom.step(direction = :vh)
elseif lt == :hline
Gadfly.Geom.hline(color = getColor(d[:color]), size = d[:linewidth] * Gadfly.px)
Gadfly.Geom.hline
elseif lt == :vline
Gadfly.Geom.vline(color = getColor(d[:color]), size = d[:linewidth] * Gadfly.px)
Gadfly.Geom.vline
elseif lt == :contour
Gadfly.Geom.contour(levels = d[:nlevels])
Gadfly.Geom.contour(levels = d[:levels])
else
nothing
end
end
function get_extra_theme_args(d::Dict, k::Symbol)
# gracefully handles old Gadfly versions
extra_theme_args = Dict()
try
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[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(d::Dict)
lc = getColor(d[:color])
α = d[:lineopacity]
if α != nothing
lc = RGBA(lc, α)
end
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
# lc = getColor(d[:linecolor])
# α = d[:linealpha]
# if α != nothing
# lc = RGBA(lc, α)
# end
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
# fc = getColor(d[:fillcolor])
# α = d[:fillalpha]
# if α != nothing
# fc = RGBA(fc, α)
# end
fc = getColor(d[:fillcolor])
α = d[:fillopacity]
if α != nothing
fc = RGBA(fc, α)
end
Gadfly.Theme(;
default_color = lc,
line_width = (d[:linetype] == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
line_style = Gadfly.get_stroke_vector(d[:linestyle]),
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
lowlight_color = x->RGB(fc), # fill/ribbon
lowlight_opacity = alpha(fc), # fill/ribbon
bar_highlight = RGB(lc), # bars
get_extra_theme_args(d, :linestyle)...
)
end
# add a line as a new layer
function addGadflyLine!(plt::Plot, d::Dict, geoms...)
function addGadflyLine!(plt::Plot, numlayers::Int, d::Dict, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms...,
getGadflyLineTheme(d))
@@ -87,68 +119,118 @@ function addGadflyLine!(plt::Plot, d::Dict, geoms...)
push!(gfargs, Gadfly.Geom.ribbon)
end
# h/vlines
if lt == :hline
kwargs[:yintercept] = d[:y]
elseif lt == :vline
kwargs[:xintercept] = d[:y]
elseif lt == :sticks
w = 0.01 * mean(diff(d[:x]))
kwargs[:xmin] = d[:x] - w
kwargs[:xmax] = d[:x] + w
elseif lt == :contour
d[:y] = reverse(d[:y])
kwargs[:z] = d[:surface]
if lt in (:hline, :vline)
kwargs[lt == :hline ? :yintercept : :xintercept] = d[:y]
else
if lt == :sticks
w = 0.01 * mean(diff(d[:x]))
kwargs[:xmin] = d[:x] - w
kwargs[:xmax] = d[:x] + w
elseif lt == :contour
# d[:y] = reverse(d[:y])
kwargs[:z] = d[:z].surf
addGadflyContColorScale(plt, d[:linecolor])
end
kwargs[:x] = d[lt == :hist ? :y : :x]
kwargs[:y] = d[:y]
end
# # h/vlines
# if lt == :hline
# kwargs[:yintercept] = d[:y]
# elseif lt == :vline
# kwargs[:xintercept] = d[:y]
# elseif lt == :sticks
# w = 0.01 * mean(diff(d[:x]))
# kwargs[:xmin] = d[:x] - w
# kwargs[:xmax] = d[:x] + w
# elseif lt == :contour
# d[:y] = reverse(d[:y])
# kwargs[:z] = d[:surface]
# end
# if lt == :hist
# kwargs[:x] = kwargs[:y] = d[:y]
# elseif lt != :hline && lt != :vline
# kwargs[:x] = d[:x]
# kwargs[:y] = d[:y]
# end
# add the layer
x = d[d[:linetype] == :hist ? :y : :x]
Gadfly.layer(gfargs...; x = x, y = d[:y], kwargs...)
# # add the layer
# x = d[d[:linetype] == :hist ? :y : :x]
# Gadfly.layer(gfargs...; x = x, y = d[:y], order=numlayers, kwargs...)
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
# extract the underlying ShapeGeometry object(s)
getMarkerGeom(shape::Shape) = gadflyshape(shape)
getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
getMarkerGeom(shapes::AVec) = map(getMarkerGeom, shapes)
getMarkerGeom(d::Dict) = getMarkerGeom(d[:markershape])
function getMarkerGeom(d::Dict)
shape = d[:markershape]
gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
end
# function getMarkerGeom(d::Dict)
# shape = d[:markershape]
# gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
# end
function getGadflyMarkerTheme(d::Dict, initargs::Dict)
function getGadflyMarkerTheme(d::Dict, plotargs::Dict)
c = getColor(d[:markercolor])
α = d[:markeropacity]
α = d[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
fg = getColor(initargs[:foreground_color])
Gadfly.Theme(
ms = d[: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
# fg = getColor(plotargs[:foreground_color])
Gadfly.Theme(;
default_color = c,
default_point_size = d[:markersize] * Gadfly.px,
discrete_highlight_color = c -> RGB(fg),
highlight_width = d[:linewidth] * Gadfly.px,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
highlight_width = d[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(d, :markerstrokestyle)...
)
end
function addGadflyMarker!(plt::Plot, d::Dict, initargs::Dict, geoms...)
function addGadflyContColorScale(plt::Plot{GadflyPackage}, c)
plt.plotargs[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = colorscheme(:bluesreds)
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, d::Dict, plotargs::Dict, geoms...)
gfargs = vcat(geoms...,
getGadflyMarkerTheme(d, initargs),
getGadflyMarkerTheme(d, plotargs),
getMarkerGeom(d))
kwargs = Dict()
# handle continuous color scales for the markers
z = d[:z]
if z != nothing && typeof(z) <: AVec
kwargs[:color] = z
if !isa(d[:markercolor], ColorGradient)
d[:markercolor] = colorscheme(:bluesreds)
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:markercolor], p))))
zcolor = d[:zcolor]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, d[:markercolor])
# if !isa(d[:markercolor], ColorGradient)
# d[:markercolor] = colorscheme(:bluesreds)
# end
# push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:markercolor], p))))
end
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], kwargs...)
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
end
@@ -157,7 +239,7 @@ end
function addToGadflyLegend(plt::Plot, d::Dict)
# add the legend?
if plt.initargs[:legend]
if plt.plotargs[:legend] != :none && d[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
@@ -172,7 +254,7 @@ function addToGadflyLegend(plt::Plot, d::Dict)
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(d[d[:markershape] == :none ? :color : :markercolor])
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
foundit = false
# extend the label if we found this color
@@ -202,6 +284,7 @@ getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=
function addGadflySeries!(plt::Plot, d::Dict)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
@@ -210,7 +293,7 @@ function addGadflySeries!(plt::Plot, d::Dict)
# lines
geom = getLineGeom(d)
if geom != nothing
prepend!(layers, addGadflyLine!(plt, d, geom, smooth...))
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
# don't add a regression for markers too
smooth = Any[]
@@ -220,20 +303,22 @@ function addGadflySeries!(plt::Plot, d::Dict)
lt = d[:linetype]
if lt == :ohlc
error("Haven't re-implemented after refactoring")
elseif lt in (:heatmap, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:linecolor], p))))
elseif lt == :scatter && d[:markershape] == :none
d[:markershape] = :ellipse
end
# markers
if d[:markershape] != :none
prepend!(layers, addGadflyMarker!(plt, d, plt.initargs, smooth...))
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...))
end
lt in (:hist, :heatmap, :hexbin, :contour) || addToGadflyLegend(plt, d)
lt in (:heatmap, :hexbin, :contour) || addToGadflyLegend(plt, d)
# now save the layers that apply to this series
d[:gadflylayers] = layers
prepend!(getGadflyContext(plt).layers, layers)
prepend!(gplt.layers, layers)
end
@@ -245,7 +330,7 @@ end
# z = d[:z]
# # handle line segments of different colors
# cscheme = d[:color]
# cscheme = d[: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...))
@@ -257,7 +342,7 @@ end
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
# colorgroup = [(:color, cs), (:group, grp)]
# colorgroup = [(:linecolor, cs), (:group, grp)]
# ---------------------------------------------------------------------------
@@ -289,7 +374,7 @@ function addGadflyTicksGuide(gplt, ticks, isx::Bool)
gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
push!(gplt.scales, gfunc(levels = ticks[1], labels = labelfunc))
push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
@@ -305,7 +390,7 @@ function getGadflyScaleFunction(d::Dict, isx::Bool)
hasScaleKey = haskey(d, scalekey)
if hasScaleKey
scale = d[scalekey]
scale == :log && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey
@@ -323,14 +408,19 @@ function addGadflyLimitsScale(gplt, d::Dict, isx::Bool)
# do we want to add min/max limits for the axis?
limsym = isx ? :xlims : :ylims
limargs = Any[]
lims = get(d, limsym, :auto)
lims == :auto && return
if limsType(lims) == :limits
push!(limargs, (:minvalue, min(lims...)))
push!(limargs, (:maxvalue, max(lims...)))
# map :auto to nothing, otherwise add to limargs
lims = get(d, limsym, :auto)
# lims == :auto && return
if lims == :auto
lims = nothing
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
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
@@ -385,13 +475,13 @@ function updateGadflyGuides(plt::Plot, d::Dict)
ticks = get(d, :xticks, :auto)
if ticks == :none
handleLinkInner(plt, true)
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(d, :yticks, :auto)
if ticks == :none
handleLinkInner(plt, false)
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
@@ -403,13 +493,17 @@ end
function updateGadflyPlotTheme(plt::Plot, d::Dict)
kwargs = Dict()
# # get the full initargs, overriding any new settings
# # get the full plotargs, overriding any new settings
# # TODO: should this be part of the main `plot` command in plot.jl???
# d = merge!(plt.initargs, d)
# d = merge!(plt.plotargs, d)
# hide the legend?
if !get(d, :legend, true)
kwargs[:key_position] = :none
# # hide the legend?
# if !get(d, :legend, true)
# kwargs[:key_position] = :none
# end
leg = d[d[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(d, :grid, true)
@@ -463,7 +557,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
))
end
function addAnnotations{X,Y,V}(plt::Plot{GadflyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
function _add_annotations{X,Y,V}(plt::Plot{GadflyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
@@ -473,7 +567,7 @@ end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
function plot(pkg::GadflyPackage; kw...)
function _create_plot(pkg::GadflyPackage; kw...)
d = Dict(kw)
gplt = createGadflyPlotObject(d)
Plot(gplt, pkg, 0, d, Dict[])
@@ -481,7 +575,14 @@ end
# plot one data series
function plot!(::GadflyPackage, plt::Plot; kw...)
function _add_series(::GadflyPackage, plt::Plot; kw...)
# first clear out the temporary layer
gplt = getGadflyContext(plt)
if gplt.layers[1].geom.tag == :remove
gplt.layers = gplt.layers[2:end]
end
d = Dict(kw)
addGadflySeries!(plt, d)
push!(plt.seriesargs, d)
@@ -490,7 +591,7 @@ end
function updatePlotItems(plt::Plot{GadflyPackage}, d::Dict)
function _update_plot(plt::Plot{GadflyPackage}, d::Dict)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
@@ -522,22 +623,22 @@ end
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(subplt::Subplot{GadflyPackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{GadflyPackage}, isbefore::Bool)
isbefore && return false # wait until after plotting to create the subplots
subplt.o = nothing
true
end
function handleLinkInner(plt::Plot{GadflyPackage}, isx::Bool)
function _remove_axis(plt::Plot{GadflyPackage}, 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 expandLimits!(lims, plt::Plot{GadflyPackage}, isx::Bool)
function _expand_limits(lims, plt::Plot{GadflyPackage}, isx::Bool)
for l in getGadflyContext(plt).layers
expandLimits!(lims, l.mapping[isx ? :x : :y])
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
@@ -569,12 +670,12 @@ function buildGadflySubplotContext(subplt::Subplot)
end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.initargs[:size]...)
setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getinitargs(subplt, 1)[:size]...)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.plotargs[:size]...)
setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, 1)[:size]...)
# -------------------------------------------------------------------------
function dowritemime{P<:GadflyOrImmerse}(io::IO, func, plt::PlottingObject{P})
function dowritemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, func, plt::PlottingObject{P})
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
@@ -585,10 +686,11 @@ 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")
@eval function Base.writemime{P<:GadflyOrImmerse}(io::IO, ::$mime, plt::PlottingObject{P})
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.writemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, ::$mime, plt::PlottingObject{P})
func = getGadflyWriteFunc($mime())
dowritemime(io, func, plt)
end
@@ -597,14 +699,14 @@ end
function Base.display(::PlotsDisplay, plt::Plot{GadflyPackage})
setGadflyDisplaySize(plt.initargs[:size]...)
setGadflyDisplaySize(plt.plotargs[:size]...)
display(plt.o)
end
function Base.display(::PlotsDisplay, subplt::Subplot{GadflyPackage})
setGadflyDisplaySize(getinitargs(subplt,1)[:size]...)
setGadflyDisplaySize(getplotargs(subplt,1)[:size]...)
ctx = buildGadflySubplotContext(subplt)
+1 -1
View File
@@ -66,7 +66,7 @@ function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aes
end
function gadflyshape(sv::Shape)
ShapeGeometry([(x,-y) for (x,y) in sv.vertices])
ShapeGeometry(sv.vertices)
end
+112
View File
@@ -0,0 +1,112 @@
# [WEBSITE]
function _initialize_backend(::GLVisualizePackage; kw...)
@eval begin
import GLVisualize
export GLVisualize
end
end
# ---------------------------------------------------------------------------
immutable GLScreenWrapper
window
render
end
function _create_plot(pkg::GLVisualizePackage; kw...)
d = Dict(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
# TODO: this should be moved to the display method?
w,r=GLVisualize.glscreen()
@async r()
o = GLScreenWrapper(w,r)
Plot(o, pkg, 0, d, Dict[])
end
function _add_series(::GLVisualizePackage, plt::Plot; kw...)
d = Dict(kw)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
# TODO: this should be moved to the display method?
x, y, z = map(Float32, d[:x]), map(Float32, d[:y]), map(Float32, d[:z].surf)
viz = GLVisualize.visualize(x*ones(y)', ones(x)*y', z, :surface)
GLVisualize.view(viz)
plt
end
function _add_annotations{X,Y,V}(plt::Plot{GLVisualizePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
# TODO: add the annotation to the plot
end
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{GLVisualizePackage})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{GLVisualizePackage}, d::Dict)
end
function _update_plot_pos_size(plt::PlottingObject{GLVisualizePackage}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{GLVisualizePackage}, i::Int)
# TODO:
# series = plt.o.lines[i]
# series.x, series.y
nothing, nothing
end
function Base.setindex!(plt::Plot{GLVisualizePackage}, xy::Tuple, i::Integer)
# TODO:
# series = plt.o.lines[i]
# series.x, series.y = xy
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{GLVisualizePackage})
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end
function _expand_limits(lims, plt::Plot{GLVisualizePackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{GLVisualizePackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{GLVisualizePackage})
# TODO: write a png to io
end
function Base.display(::PlotsDisplay, plt::Plot{GLVisualizePackage})
# TODO: display/show the plot
# NOTE: I think maybe this should be empty? We can start with the assumption that creating
# and adding to a plot will automatically open a window and draw to it, then the display
# wouldn't actually need to do anything
end
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizePackage})
# TODO: display/show the subplot
end
+790
View File
@@ -0,0 +1,790 @@
# https://github.com/jheinen/GR.jl
function _initialize_backend(::GRPackage; kw...)
@eval begin
import GR
export GR
end
end
const gr_linetype = Dict(
:auto => 1, :solid => 1, :dash => 2, :dot => 3, :dashdot => 4,
:dashdotdot => -1 )
const gr_markertype = Dict(
:auto => 1, :none => -1, :ellipse => -1, :rect => -7, :diamond => -13,
:utriangle => -3, :dtriangle => -5, :pentagon => -21, :hexagon => -22,
:heptagon => -23, :octagon => -24, :cross => 2, :xcross => 5,
:star4 => -25, :star5 => -26, :star6 => -27, :star7 => -28, :star8 => -29,
:vline => -30, :hline => -31 )
const gr_halign = Dict(:left => 1, :hcenter => 2, :right => 3)
const gr_valign = Dict(:top => 1, :vcenter => 3, :bottom => 5)
const gr_font_family = Dict(
"times" => 1, "helvetica" => 5, "courier" => 9, "bookman" => 14,
"newcenturyschlbk" => 18, "avantgarde" => 22, "palatino" => 26)
function gr_getcolorind(v)
c = getColor(v)
return convert(Int, GR.inqcolorfromrgb(c.r, c.g, c.b))
end
function gr_getaxisind(p)
axis = get(p, :axis, :none)
if axis in [:none, :left]
return 1
else
return 2
end
end
function gr_setmarkershape(p)
if haskey(p, :markershape)
shape = p[:markershape]
if isa(shape, Shape)
p[:vertices] = shape.vertices
else
GR.setmarkertype(gr_markertype[shape])
p[:vertices] = :none
end
end
end
function gr_polymarker(p, x, y)
if p[:vertices] != :none
vertices= p[:vertices]
dx = Float64[el[1] for el in vertices] * 0.01
dy = Float64[el[2] for el in vertices] * 0.01
GR.selntran(0)
GR.setfillcolorind(gr_getcolorind(p[:markercolor]))
GR.setfillintstyle(GR.INTSTYLE_SOLID)
for i = 1:length(x)
xn, yn = GR.wctondc(x[i], y[i])
GR.fillarea(xn + dx, yn + dy)
end
GR.selntran(1)
else
GR.polymarker(x, y)
end
end
function gr_polyline(x, y)
if NaN in x || NaN in y
i = 1
j = 1
n = length(x)
while i < n
while j < n && x[j] != Nan && y[j] != NaN
j += 1
end
if i < j
GR.polyline(x[i:j], y[i:j])
end
i = j + 1
end
else
GR.polyline(x, y)
end
end
function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
subplot=[0, 1, 0, 1])
d = plt.plotargs
clear && GR.clearws()
mwidth, mheight, width, height = GR.inqdspsize()
w, h = d[:size]
viewport = zeros(4)
if w > h
ratio = float(h) / w
msize = mwidth * w / width
GR.setwsviewport(0, msize, 0, msize * ratio)
GR.setwswindow(0, 1, 0, ratio)
viewport[1] = subplot[1] + 0.125 * (subplot[2] - subplot[1])
viewport[2] = subplot[1] + 0.95 * (subplot[2] - subplot[1])
viewport[3] = ratio * (subplot[3] + 0.125 * (subplot[4] - subplot[3]))
viewport[4] = ratio * (subplot[3] + 0.95 * (subplot[4] - subplot[3]))
else
ratio = float(w) / h
msize = mheight * h / height
GR.setwsviewport(0, msize * ratio, 0, msize)
GR.setwswindow(0, ratio, 0, 1)
viewport[1] = ratio * (subplot[1] + 0.125 * (subplot[2] - subplot[1]))
viewport[2] = ratio * (subplot[1] + 0.95 * (subplot[2] - subplot[1]))
viewport[3] = subplot[3] + 0.125 * (subplot[4] - subplot[3])
viewport[4] = subplot[3] + 0.95 * (subplot[4] - subplot[3])
end
if haskey(d, :background_color)
GR.savestate()
GR.selntran(0)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
GR.setfillcolorind(gr_getcolorind(d[:background_color]))
if w > h
GR.fillrect(subplot[1], subplot[2], ratio*subplot[3], ratio*subplot[4])
else
GR.fillrect(ratio*subplot[1], ratio*subplot[2], subplot[3], subplot[4])
end
GR.selntran(1)
GR.restorestate()
c = getColor(d[:background_color])
if 0.21 * c.r + 0.72 * c.g + 0.07 * c.b < 0.9
fg = convert(Int, GR.inqcolorfromrgb(1-c.r, 1-c.g, 1-c.b))
else
fg = 1
end
else
fg = 1
end
extrema = zeros(2, 4)
num_axes = 1
cmap = false
axes_2d = true
grid_flag = get(d, :grid, true)
for axis = 1:2
xmin = ymin = typemax(Float64)
xmax = ymax = typemin(Float64)
for p in plt.seriesargs
if axis == gr_getaxisind(p)
if axis == 2
num_axes = 2
end
if p[:linetype] == :bar
x, y = 1:length(p[:y]), p[:y]
elseif p[:linetype] == :ohlc
x, y = 1:size(p[:y], 1), p[:y]
elseif p[:linetype] in [:hist, :density]
x, y = Base.hist(p[:y])
elseif p[:linetype] in [:heatmap, :hexbin]
E = zeros(length(p[:x]),2)
E[:,1] = p[:x]
E[:,2] = p[:y]
if isa(p[:nbins], Tuple)
xbins, ybins = p[:nbins]
else
xbins = ybins = p[:nbins]
end
cmap = true
x, y, H = Base.hist2d(E, xbins, ybins)
elseif p[:linetype] == :pie
axes_2d = false
xmin, xmax, ymin, ymax = 0, 1, 0, 1
x, y = p[:x], p[:y]
else
if p[:linetype] in [:contour, :surface]
cmap = true
end
if p[:linetype] in [:surface, :wireframe, :path3d, :scatter3d]
axes_2d = false
end
x, y = p[:x], p[:y]
end
if p[:linetype] != :pie
xmin = min(minimum(x), xmin)
xmax = max(maximum(x), xmax)
if p[:linetype] == :ohlc
for val in y
ymin = min(val.open, val.high, val.low, val.close, ymin)
ymax = max(val.open, val.high, val.low, val.close, ymax)
end
else
ymin = min(minimum(y), ymin)
ymax = max(maximum(y), ymax)
end
end
end
end
if d[:xlims] != :auto
xmin, xmax = d[:xlims]
end
if d[:ylims] != :auto
ymin, ymax = d[:ylims]
end
if xmax <= xmin
xmax = xmin + 1
end
if ymax <= ymin
ymax = ymin + 1
end
extrema[axis,:] = [xmin, xmax, ymin, ymax]
end
if num_axes == 2 || !axes_2d
viewport[2] -= 0.0525
end
if cmap
viewport[2] -= 0.1
end
GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
scale = 0
d[:xscale] == :log10 && (scale |= GR.OPTION_X_LOG)
d[:yscale] == :log10 && (scale |= GR.OPTION_Y_LOG)
get(d, :xflip, false) && (scale |= GR.OPTION_FLIP_X)
get(d, :yflip, false) && (scale |= GR.OPTION_FLIP_Y)
for axis = 1:num_axes
xmin, xmax, ymin, ymax = extrema[axis,:]
if scale & GR.OPTION_X_LOG == 0
xmin, xmax = GR.adjustlimits(xmin, xmax)
majorx = 5
xtick = GR.tick(xmin, xmax) / majorx
else
xtick = majorx = 1
end
if scale & GR.OPTION_Y_LOG == 0
ymin, ymax = GR.adjustlimits(ymin, ymax)
majory = 5
ytick = GR.tick(ymin, ymax) / majory
else
ytick = majory = 1
end
if scale & GR.OPTION_FLIP_X == 0
xorg = (xmin, xmax)
else
xorg = (xmax, xmin)
end
if scale & GR.OPTION_FLIP_Y == 0
yorg = (ymin, ymax)
else
yorg = (ymax, ymin)
end
GR.setwindow(xmin, xmax, ymin, ymax)
GR.setscale(scale)
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
charheight = max(0.018 * diag, 0.01)
GR.setcharheight(charheight)
GR.settextcolorind(fg)
if axes_2d
GR.setlinewidth(1)
GR.setlinecolorind(fg)
ticksize = 0.0075 * diag
if grid_flag && fg == 1
GR.grid(xtick, ytick, 0, 0, majorx, majory)
end
if num_axes == 1
GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, -majory, -ticksize)
elseif axis == 1
GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
else
GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, majory, -ticksize)
end
end
end
if get(d, :title, "") != ""
GR.savestate()
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.settextcolorind(fg)
GR.text(0.5 * (viewport[1] + viewport[2]), min(ratio, 1), d[:title])
GR.restorestate()
end
if get(d, :xlabel, "") != ""
GR.savestate()
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
GR.settextcolorind(fg)
GR.text(0.5 * (viewport[1] + viewport[2]), 0, d[:xlabel])
GR.restorestate()
end
if get(d, :ylabel, "") != ""
GR.savestate()
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(-1, 0)
GR.settextcolorind(fg)
GR.text(0, 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
GR.restorestate()
end
if get(d, :yrightlabel, "") != ""
GR.savestate()
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(1, 0)
GR.settextcolorind(fg)
GR.text(1, 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
GR.restorestate()
end
legend = false
for p in plt.seriesargs
GR.savestate()
xmin, xmax, ymin, ymax = extrema[gr_getaxisind(p),:]
GR.setwindow(xmin, xmax, ymin, ymax)
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks, :hline, :vline, :ohlc]
haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
end
if p[:linetype] == :path
if haskey(p, :fillcolor)
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
GR.setfillintstyle(GR.INTSTYLE_SOLID)
end
if length(p[:x]) > 1
if p[:fillrange] != nothing
GR.fillarea([p[:x][1]; p[:x]; p[:x][length(p[:x])]], [p[:fillrange]; p[:y]; p[:fillrange]])
end
GR.polyline(p[:x], p[:y])
end
legend = true
end
if p[:linetype] == :line
if length(p[:x]) > 1
gr_polyline(p[:x], p[:y])
end
legend = true
elseif p[:linetype] in [:steppre, :steppost]
n = length(p[:x])
x = zeros(2*n + 1)
y = zeros(2*n + 1)
x[1], y[1] = p[:x][1], p[:y][1]
j = 2
for i = 2:n
if p[:linetype] == :steppre
x[j], x[j+1] = p[:x][i-1], p[:x][i]
y[j], y[j+1] = p[:y][i], p[:y][i]
else
x[j], x[j+1] = p[:x][i], p[:x][i]
y[j], y[j+1] = p[:y][i-1], p[:y][i]
end
j += 2
end
if n > 1
GR.polyline(x, y)
end
legend = true
elseif p[:linetype] == :sticks
x, y = p[:x], p[:y]
for i = 1:length(y)
GR.polyline([x[i], x[i]], [ymin, y[i]])
end
legend = true
elseif p[:linetype] == :scatter || (p[:markershape] != :none && axes_2d)
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
gr_setmarkershape(p)
if haskey(d, :markersize)
if typeof(d[:markersize]) <: Number
GR.setmarkersize(d[:markersize] / 4.0)
if length(p[:x]) > 0
gr_polymarker(p, p[:x], p[:y])
end
else
c = p[:markercolor]
GR.setcolormap(-GR.COLORMAP_GLOWING)
for i = 1:length(p[:x])
if isa(c, ColorGradient) && p[:zcolor] != nothing
ci = round(Int, 1000 + p[:zcolor][i] * 255)
GR.setmarkercolorind(ci)
end
GR.setmarkersize(d[:markersize][i] / 4.0)
gr_polymarker(p, [p[:x][i]], [p[:y][i]])
end
end
else
if length(p[:x]) > 0
gr_polymarker(p, p[:x], p[:y])
end
end
legend = true
elseif p[:linetype] == :bar
y = p[:y]
for i = 1:length(y)
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
GR.setfillintstyle(GR.INTSTYLE_SOLID)
GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
GR.setfillcolorind(1)
GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
end
elseif p[:linetype] in [:hist, :density]
h = Base.hist(p[:y])
x, y = float(collect(h[1])), float(h[2])
for i = 2:length(y)
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
GR.setfillintstyle(GR.INTSTYLE_SOLID)
GR.fillrect(x[i-1], x[i], ymin, y[i])
GR.setfillcolorind(1)
GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
GR.fillrect(x[i-1], x[i], ymin, y[i])
end
elseif p[:linetype] in [:hline, :vline]
for xy in p[:y]
if p[:linetype] == :hline
GR.polyline([xmin, xmax], [xy, xy])
else
GR.polyline([xy, xy], [ymin, ymax])
end
end
elseif p[:linetype] in [:heatmap, :hexbin]
E = zeros(length(p[:x]),2)
E[:,1] = p[:x]
E[:,2] = p[:y]
if isa(p[:nbins], Tuple)
xbins, ybins = p[:nbins]
else
xbins = ybins = p[:nbins]
end
x, y, H = Base.hist2d(E, xbins, ybins)
counts = round(Int32, 1000 + 255 * H / maximum(H))
n, m = size(counts)
GR.setcolormap(GR.COLORMAP_COOLWARM)
GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts)
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
viewport[3], viewport[4])
GR.setspace(0, maximum(counts), 0, 90)
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
charheight = max(0.016 * diag, 0.01)
GR.setcharheight(charheight)
GR.colormap()
elseif p[:linetype] == :contour
x, y, z = p[:x], p[:y], p[:z].surf
zmin, zmax = minimum(z), maximum(z)
if typeof(p[:levels]) <: Array
h = p[:levels]
else
h = linspace(zmin, zmax, p[:levels])
end
GR.setspace(zmin, zmax, 0, 90)
GR.setcolormap(GR.COLORMAP_COOLWARM)
GR.contour(x, y, h, reshape(z, length(x) * length(y)), 1000)
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
viewport[3], viewport[4])
l = round(Int32, 1000 + (h - minimum(h)) / (maximum(h) - minimum(h)) * 255)
GR.setwindow(xmin, xmax, zmin, zmax)
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
ztick = 0.5 * GR.tick(zmin, zmax)
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
charheight = max(0.016 * diag, 0.01)
GR.setcharheight(charheight)
GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005)
elseif p[:linetype] in [:surface, :wireframe]
x, y, z = p[:x], p[:y], p[:z].surf
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
GR.setspace(zmin, zmax, 40, 70)
xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
charheight = max(0.018 * diag, 0.01)
ticksize = 0.01 * (viewport[2] - viewport[1])
GR.setlinewidth(1)
if grid_flag
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
end
z = reshape(z, length(x) * length(y))
if p[:linetype] == :surface
GR.setcolormap(GR.COLORMAP_COOLWARM)
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
else
GR.setfillcolorind(0)
GR.surface(x, y, z, GR.OPTION_FILLED_MESH)
end
GR.setlinewidth(1)
GR.setcharheight(charheight)
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
if cmap
GR.setviewport(viewport[2] + 0.07, viewport[2] + 0.1,
viewport[3], viewport[4])
GR.colormap()
end
elseif p[:linetype] in [:path3d, :scatter3d]
x, y, z = p[:x], p[:y], p[:z]
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
GR.setspace(zmin, zmax, 40, 70)
xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
charheight = max(0.018 * diag, 0.01)
ticksize = 0.01 * (viewport[2] - viewport[1])
GR.setlinewidth(1)
if grid_flag && p[:linetype] == :path3d
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
end
if p[:linetype] == :scatter3d
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
gr_setmarkershape(p)
for i = 1:length(z)
px, py = GR.wc3towc(x[i], y[i], z[i])
gr_polymarker(p, [px], [py])
end
else
haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
if length(x) > 0
GR.polyline3d(x, y, z)
end
end
GR.setlinewidth(1)
GR.setcharheight(charheight)
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
elseif p[:linetype] == :ohlc
y = p[:y]
n = size(y, 1)
ticksize = 0.5 * (xmax - xmin) / n
for i in 1:n
GR.polyline([i-ticksize, i], [y[i].open, y[i].open])
GR.polyline([i, i], [y[i].low, y[i].high])
GR.polyline([i, i+ticksize], [y[i].close, y[i].close])
end
elseif p[:linetype] == :pie
GR.selntran(0)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
xmin, xmax, ymin, ymax = viewport
ymax -= 0.05 * (xmax - xmin)
xcenter = 0.5 * (xmin + xmax)
ycenter = 0.5 * (ymin + ymax)
if xmax - xmin > ymax - ymin
r = 0.5 * (ymax - ymin)
xmin, xmax = xcenter - r, xcenter + r
else
r = 0.5 * (xmax - xmin)
ymin, ymax = ycenter - r, ycenter + r
end
labels, slices = p[:x], p[:y]
numslices = length(slices)
total = sum(slices)
a1 = 0
x = zeros(3)
y = zeros(3)
for i in 1:numslices
a2 = round(Int, a1 + (slices[i] / total) * 360.0)
GR.setfillcolorind(980 + (i-1) % 20)
GR.fillarc(xmin, xmax, ymin, ymax, a1, a2)
alpha = 0.5 * (a1 + a2)
cosf = r * cos(alpha * pi / 180)
sinf = r * sin(alpha * pi / 180)
x[1] = xcenter + cosf
y[1] = ycenter + sinf
x[2] = x[1] + 0.1 * cosf
y[2] = y[1] + 0.1 * sinf
y[3] = y[2]
if 90 <= alpha < 270
x[3] = x[2] - 0.05
GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF)
GR.text(x[3] - 0.01, y[3], string(labels[i]))
else
x[3] = x[2] + 0.05
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
GR.text(x[3] + 0.01, y[3], string(labels[i]))
end
GR.polyline(x, y)
a1 = a2
end
GR.selntran(1)
end
GR.restorestate()
end
if d[:legend] != :none && legend
GR.savestate()
GR.selntran(0)
GR.setscale(0)
w = 0
i = 0
for p in plt.seriesargs
if typeof(p[:label]) <: Array
i += 1
lab = p[:label][i]
else
lab = p[:label]
end
tbx, tby = GR.inqtext(0, 0, lab)
w = max(w, tbx[3])
end
px = viewport[2] - 0.05 - w
py = viewport[4] - 0.06
dy = 0.03 * sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
GR.setfillcolorind(0)
GR.fillrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
GR.setlinetype(1)
GR.setlinewidth(1)
GR.drawrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
haskey(d, :linewidth) && GR.setlinewidth(d[:linewidth])
i = 0
for p in plt.seriesargs
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
GR.polyline([px - 0.07, px - 0.01], [py, py])
end
if p[:linetype] == :scatter || p[:markershape] != :none
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
gr_setmarkershape(p)
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
gr_polymarker(p, [px - 0.06, px - 0.02], [py, py])
else
gr_polymarker(p, [px - 0.06, px - 0.04, px - 0.02], [py, py, py])
end
end
if typeof(p[:label]) <: Array
i += 1
lab = p[:label][i]
else
lab = p[:label]
end
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
GR.settextcolorind(1)
GR.text(px, py, lab)
py -= dy
end
GR.selntran(1)
GR.restorestate()
end
if haskey(d, :anns)
GR.savestate()
for ann in d[:anns]
x, y, val = ann
x, y = GR.wctondc(x, y)
alpha = val.font.rotation
family = lowercase(val.font.family)
GR.setcharheight(0.7 * val.font.pointsize / d[:size][2])
GR.setcharup(sin(val.font.rotation), cos(val.font.rotation))
if haskey(gr_font_family, family)
GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
end
GR.settextcolorind(gr_getcolorind(val.font.color))
GR.settextalign(gr_halign[val.font.halign], gr_valign[val.font.valign])
GR.text(x, y, val.str)
end
GR.restorestate()
end
update && GR.updatews()
end
function gr_display(subplt::Subplot{GRPackage})
clear = true
update = false
l = enumerate(subplt.layout)
nr = nrows(subplt.layout)
for (i, (r, c)) in l
nc = ncols(subplt.layout, r)
if i == length(l)
update = true
end
subplot = [(c-1)/nc, c/nc, 1-r/nr, 1-(r-1)/nr]
gr_display(subplt.plts[i], clear, update, subplot)
clear = false
end
end
function _create_plot(pkg::GRPackage; kw...)
d = Dict(kw)
Plot(nothing, pkg, 0, d, Dict[])
end
function _add_series(::GRPackage, plt::Plot; kw...)
d = Dict(kw)
push!(plt.seriesargs, d)
plt
end
function _add_annotations{X,Y,V}(plt::Plot{GRPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
if haskey(plt.plotargs, :anns)
append!(plt.plotargs[:anns], anns)
else
plt.plotargs[:anns] = anns
end
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{GRPackage})
end
function _update_plot(plt::Plot{GRPackage}, d::Dict)
for k in (:title, :xlabel, :ylabel)
haskey(d, k) && (plt.plotargs[k] = d[k])
end
end
function _update_plot_pos_size(plt::PlottingObject{GRPackage}, d::Dict)
end
# ----------------------------------------------------------------
function Base.getindex(plt::Plot{GRPackage}, i::Int)
d = plt.seriesargs[i]
d[:x], d[:y]
end
function Base.setindex!(plt::Plot{GRPackage}, xy::Tuple, i::Integer)
d = plt.seriesargs[i]
d[:x], d[:y] = xy
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{GRPackage}, isbefore::Bool)
true
end
function _expand_limits(lims, plt::Plot{GRPackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{GRPackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{GRPackage})
GR.emergencyclosegks()
ENV["GKS_WSTYPE"] = "png"
gr_display(plt)
GR.emergencyclosegks()
write(io, readall("gks.png"))
end
function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::PlottingObject{GRPackage})
GR.emergencyclosegks()
ENV["GKS_WSTYPE"] = "svg"
gr_display(plt)
GR.emergencyclosegks()
write(io, readall("gks.svg"))
end
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{GRPackage})
writemime(io, MIME("image/svg+xml"), plt)
end
function Base.writemime(io::IO, m::MIME"application/pdf", plt::PlottingObject{GRPackage})
GR.emergencyclosegks()
ENV["GKS_WSTYPE"] = "pdf"
gr_display(plt)
GR.emergencyclosegks()
write(io, readall("gks.pdf"))
end
function Base.writemime(io::IO, m::MIME"application/postscript", plt::PlottingObject{GRPackage})
GR.emergencyclosegks()
ENV["GKS_WSTYPE"] = "ps"
gr_display(plt)
GR.emergencyclosegks()
write(io, readall("gks.ps"))
end
function Base.display(::PlotsDisplay, plt::Plot{GRPackage})
gr_display(plt)
end
function Base.display(::PlotsDisplay, plt::Subplot{GRPackage})
gr_display(plt)
true
end
+19 -23
View File
@@ -1,19 +1,13 @@
# https://github.com/JuliaGraphics/Immerse.jl
# immutable ImmersePackage <: PlottingPackage end
# export immerse
# immerse() = backend(:immerse)
# supportedArgs(::ImmersePackage) = supportedArgs(GadflyPackage())
# supportedAxes(::ImmersePackage) = supportedAxes(GadflyPackage())
# supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
# supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
# supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
# supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
function _initialize_backend(::ImmersePackage; kw...)
@eval begin
import Immerse, Gadfly, Compose, Gtk
export Immerse, Gadfly, Compose, Gtk
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
end
end
function createImmerseFigure(d::Dict)
w,h = d[:size]
@@ -21,9 +15,11 @@ function createImmerseFigure(d::Dict)
Immerse.Figure(figidx)
end
# ----------------------------------------------------------------
# create a blank Gadfly.Plot object
function plot(pkg::ImmersePackage; kw...)
function _create_plot(pkg::ImmersePackage; kw...)
d = Dict(kw)
# create the underlying Gadfly.Plot object
@@ -35,7 +31,7 @@ end
# plot one data series
function plot!(::ImmersePackage, plt::Plot; kw...)
function _add_series(::ImmersePackage, plt::Plot; kw...)
d = Dict(kw)
addGadflySeries!(plt, d)
push!(plt.seriesargs, d)
@@ -43,7 +39,7 @@ function plot!(::ImmersePackage, plt::Plot; kw...)
end
function updatePlotItems(plt::Plot{ImmersePackage}, d::Dict)
function _update_plot(plt::Plot{ImmersePackage}, d::Dict)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
@@ -52,7 +48,7 @@ end
# ----------------------------------------------------------------
function addAnnotations{X,Y,V}(plt::Plot{ImmersePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
function _add_annotations{X,Y,V}(plt::Plot{ImmersePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
@@ -78,14 +74,14 @@ end
# ----------------------------------------------------------------
function buildSubplotObject!(subplt::Subplot{ImmersePackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{ImmersePackage}, isbefore::Bool)
return false
# isbefore && return false
end
function showSubplotObject(subplt::Subplot{ImmersePackage})
# create the Gtk window with vertical box vsep
d = getinitargs(subplt,1)
d = getplotargs(subplt,1)
w,h = d[:size]
vsep = Gtk.GtkBoxLeaf(:v)
win = Gtk.GtkWindowLeaf(vsep, d[:windowtitle], w, h)
@@ -125,15 +121,15 @@ function showSubplotObject(subplt::Subplot{ImmersePackage})
end
function handleLinkInner(plt::Plot{ImmersePackage}, isx::Bool)
function _remove_axis(plt::Plot{ImmersePackage}, 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 expandLimits!(lims, plt::Plot{ImmersePackage}, isx::Bool)
function _expand_limits(lims, plt::Plot{ImmersePackage}, isx::Bool)
for l in getGadflyContext(plt).layers
expandLimits!(lims, l.mapping[isx ? :x : :y])
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
@@ -148,7 +144,7 @@ function Base.display(::PlotsDisplay, plt::Plot{ImmersePackage})
fig, gplt = plt.o
if fig == nothing
fig = createImmerseFigure(plt.initargs)
fig = createImmerseFigure(plt.plotargs)
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
plt.o = (fig, gplt)
end
+107
View File
@@ -0,0 +1,107 @@
# https://github.com/sisl/PGFPlots.jl
function _initialize_backend(::PGFPlotsPackage; kw...)
@eval begin
import PGFPlots
export PGFPlots
# TODO: other initialization that needs to be eval-ed
end
# TODO: other initialization
end
# ---------------------------------------------------------------------------
function _create_plot(pkg::PGFPlotsPackage; kw...)
d = Dict{Symbol,Any}(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
Plot(nothing, pkg, 0, d, Dict[])
end
function _add_series(::PGFPlotsPackage, plt::Plot; kw...)
d = Dict{Symbol,Any}(kw)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
plt
end
function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
# set or add to the annotation_list
if haskey(plt.plotargs, :annotation_list)
append!(plt.plotargs[:annotation_list], anns)
else
plt.plotargs[:annotation_list] = anns
end
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{PGFPlotsPackage})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PGFPlotsPackage}, d::Dict)
end
function _update_plot_pos_size(plt::PlottingObject{PGFPlotsPackage}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{PGFPlotsPackage}, i::Int)
d = plt.seriesargs[i]
d[:x], d[:y]
end
function Base.setindex!(plt::Plot{PGFPlotsPackage}, xy::Tuple, i::Integer)
d = plt.seriesargs[i]
d[:x], d[:y] = xy
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PGFPlotsPackage}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true
end
function _expand_limits(lims, plt::Plot{PGFPlotsPackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{PGFPlotsPackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
# ----------------------------------------------------------------
################# This is the important method to implement!!! #################
function _make_pgf_plot(plt::Plot{PGFPlotsPackage})
# TODO: convert plt.plotargs and plt.seriesargs into PGFPlots calls
# TODO: return the PGFPlots object
end
function Base.writemime(io::IO, mime::MIME"image/png", plt::PlottingObject{PGFPlotsPackage})
plt.o = _make_pgf_plot(plt)
writemime(io, mime, plt.o)
end
# function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PGFPlotsPackage})
# end
function Base.display(::PlotsDisplay, plt::PlottingObject{PGFPlotsPackage})
plt.o = _make_pgf_plot(plt)
display(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsPackage})
# # TODO: display/show the subplot
# end
+474
View File
@@ -0,0 +1,474 @@
# https://plot.ly/javascript/getting-started
function _initialize_backend(::PlotlyPackage; kw...)
@eval begin
import JSON
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
############################
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
# the first script is some hack I needed to do in order for the notebook
# to not complain about Plotly being undefined
display("text/html", """
<script type="text/javascript">
require=requirejs=define=undefined;
</script>
<script type="text/javascript">
$(open(readall, _js_path, "r"))
</script>
""")
# display("text/html", "<p>Plotly javascript loaded.</p>")
end
# end borrowing (thanks :)
###########################
end
# TODO: other initialization
end
# ---------------------------------------------------------------------------
function _create_plot(pkg::PlotlyPackage; kw...)
d = Dict{Symbol,Any}(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
Plot(nothing, pkg, 0, d, Dict[])
end
function _add_series(::PlotlyPackage, plt::Plot; kw...)
d = Dict{Symbol,Any}(kw)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
plt
end
function _add_annotations{X,Y,V}(plt::Plot{PlotlyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
# set or add to the annotation_list
if haskey(plt.plotargs, :annotation_list)
append!(plt.plotargs[:annotation_list], anns)
else
plt.plotargs[:annotation_list] = anns
end
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{PlotlyPackage})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PlotlyPackage}, d::Dict)
end
function _update_plot_pos_size(plt::PlottingObject{PlotlyPackage}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{PlotlyPackage}, i::Int)
d = plt.seriesargs[i]
d[:x], d[:y]
end
function Base.setindex!(plt::Plot{PlotlyPackage}, xy::Tuple, i::Integer)
d = plt.seriesargs[i]
d[:x], d[:y] = xy
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PlotlyPackage}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true
end
function _expand_limits(lims, plt::Plot{PlotlyPackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{PlotlyPackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
# TODO:
# _plotDefaults[:yrightlabel] = ""
# _plotDefaults[:xlims] = :auto
# _plotDefaults[:ylims] = :auto
# _plotDefaults[:xticks] = :auto
# _plotDefaults[:yticks] = :auto
# _plotDefaults[:xscale] = :identity
# _plotDefaults[:yscale] = :identity
# _plotDefaults[:xflip] = false
# _plotDefaults[:yflip] = false
function plotlyfont(font::Font, color = font.color)
Dict{Symbol,Any}(
:family => font.family,
:size => round(Int, font.pointsize*1.4),
:color => webcolor(color),
)
end
function get_annotation_dict(x, y, val::Union{AbstractString,Symbol})
Dict{Symbol,Any}(
:text => val,
:xref => "x",
:x => x,
:yref => "y",
:y => y,
:showarrow => false,
)
end
function get_annotation_dict(x, y, ptxt::PlotText)
merge(get_annotation_dict(x, y, ptxt.str), Dict{Symbol,Any}(
:font => plotlyfont(ptxt.font),
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
:rotation => ptxt.font.rotation,
))
end
function plotlyscale(scale::Symbol)
if scale == :log10
"log"
else
"-"
end
end
use_axis_field(ticks) = !(ticks in (nothing, :none))
tickssym(isx::Bool) = symbol((isx ? "x" : "y") * "ticks")
limssym(isx::Bool) = symbol((isx ? "x" : "y") * "lims")
flipsym(isx::Bool) = symbol((isx ? "x" : "y") * "flip")
scalesym(isx::Bool) = symbol((isx ? "x" : "y") * "scale")
labelsym(isx::Bool) = symbol((isx ? "x" : "y") * "label")
function plotlyaxis(d::Dict, isx::Bool)
ax = Dict{Symbol,Any}(
:title => d[labelsym(isx)],
:showgrid => d[:grid],
:zeroline => false,
)
fgcolor = webcolor(d[:foreground_color])
tsym = tickssym(isx)
if use_axis_field(d[tsym])
ax[:titlefont] = plotlyfont(d[:guidefont], fgcolor)
ax[:type] = plotlyscale(d[scalesym(isx)])
ax[:tickfont] = plotlyfont(d[:tickfont], fgcolor)
ax[:tickcolor] = fgcolor
ax[:linecolor] = fgcolor
# xlims
lims = d[limssym(isx)]
if lims != :auto && limsType(lims) == :limits
ax[:range] = lims
end
# xflip
if d[flipsym(isx)]
ax[:autorange] = "reversed"
end
# xticks
ticks = d[tsym]
if ticks != :auto
ttype = ticksType(ticks)
if ttype == :ticks
ax[:tickmode] = "array"
ax[:tickvals] = ticks
elseif ttype == :ticks_and_labels
ax[:tickmode] = "array"
ax[:tickvals], ax[:ticktext] = ticks
end
end
ax
else
ax[:showticklabels] = false
ax[:showgrid] = false
end
ax
end
# function get_plot_json(plt::Plot{PlotlyPackage})
# d = plt.plotargs
function plotly_layout(d::Dict)
d_out = Dict{Symbol,Any}()
bgcolor = webcolor(d[:background_color])
fgcolor = webcolor(d[:foreground_color])
# set the fields for the plot
d_out[:title] = d[:title]
d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor)
d_out[:margin] = Dict{Symbol,Any}(:l=>35, :b=>30, :r=>8, :t=>20)
d_out[:plot_bgcolor] = bgcolor
d_out[:paper_bgcolor] = bgcolor
# TODO: x/y axis tick values/labels
d_out[:xaxis] = plotlyaxis(d, true)
d_out[:yaxis] = plotlyaxis(d, false)
# legend
d_out[:showlegend] = d[:legend] != :none
if d[:legend] != :none
d_out[:legend] = Dict{Symbol,Any}(
:bgcolor => bgcolor,
:bordercolor => fgcolor,
:font => plotlyfont(d[:legendfont]),
)
end
# annotations
anns = get(d, :annotation_list, [])
if !isempty(anns)
d_out[:annotations] = [get_annotation_dict(ann...) for ann in anns]
end
d_out
end
function get_plot_json(plt::Plot{PlotlyPackage})
JSON.json(plotly_layout(plt.plotargs))
end
function plotly_colorscale(grad::ColorGradient)
[[grad.values[i], webcolor(grad.colors[i])] for i in 1:length(grad.colors)]
end
plotly_colorscale(c) = plotly_colorscale(ColorGradient(:bluesreds))
const _plotly_markers = Dict{Symbol,Any}(
:rect => "square",
:xcross => "x",
:utriangle => "triangle-up",
:dtriangle => "triangle-down",
:star5 => "star-triangle-up",
:vline => "line-ns",
:hline => "line-ew",
)
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
function plotly_series(d::Dict; plot_index = nothing)
d_out = Dict{Symbol,Any}()
x, y = collect(d[:x]), collect(d[:y])
d_out[:name] = d[:label]
lt = d[:linetype]
isscatter = lt in (:scatter, :scatter3d)
hasmarker = isscatter || d[:markershape] != :none
hasline = !isscatter
# set the "type"
if lt in (:line, :path, :scatter, :steppre, :steppost)
d_out[:type] = "scatter"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if d[:fillrange] == true || d[:fillrange] == 0
d_out[:fill] = "tozeroy"
d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha])
elseif !(d[:fillrange] in (false, nothing))
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(d[:fillrange])")
end
d_out[:x], d_out[:y] = x, y
elseif lt == :bar
d_out[:type] = "bar"
d_out[:x], d_out[:y] = x, y
elseif lt == :heatmap
d_out[:type] = "histogram2d"
d_out[:x], d_out[:y] = x, y
if isa(d[:nbins], Tuple)
xbins, ybins = d[:nbins]
else
xbins = ybins = d[:nbins]
end
d_out[:nbinsx] = xbins
d_out[:nbinsy] = ybins
elseif lt in (:hist, :density)
d_out[:type] = "histogram"
isvert = d[:orientation] in (:vertical, :v, :vert)
d_out[isvert ? :x : :y] = y
d_out[isvert ? :nbinsx : :nbinsy] = d[:nbins]
if lt == :density
d_out[:histnorm] = "probability density"
end
elseif lt in (:contour, :surface, :wireframe)
d_out[:type] = lt == :wireframe ? :surface : string(lt)
d_out[:x], d_out[:y] = x, y
d_out[:z] = d[:z].surf
# d_out[:showscale] = d[:legend]
if lt == :contour
d_out[:ncontours] = d[:levels]
d_out[:contours] = Dict{Symbol,Any}(:coloring => d[:fillrange] != nothing ? "fill" : "lines")
end
d_out[:colorscale] = plotly_colorscale(d[lt == :contour ? :linecolor : :fillcolor])
elseif lt == :pie
d_out[:type] = "pie"
d_out[:labels] = x
d_out[:values] = y
d_out[:hoverinfo] = "label+percent+name"
elseif lt in (:path3d, :scatter3d)
d_out[:type] = "scatter3d"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y] = x, y
d_out[:z] = collect(d[:z])
else
warn("Plotly: linetype $lt isn't supported.")
return Dict{Symbol,Any}()
end
# add "marker"
if hasmarker
d_out[:marker] = Dict{Symbol,Any}(
:symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])),
:opacity => d[:markeralpha],
:size => 2 * d[:markersize],
:color => webcolor(d[:markercolor], d[:markeralpha]),
:line => Dict{Symbol,Any}(
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
:width => d[:markerstrokewidth],
),
)
if d[:zcolor] != nothing
d_out[:marker][:color] = d[:zcolor]
d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor])
end
end
# add "line"
if hasline
d_out[:line] = Dict{Symbol,Any}(
:color => webcolor(d[:linecolor], d[:linealpha]),
:width => d[:linewidth],
:shape => if lt == :steppre
"vh"
elseif lt == :steppost
"hv"
else
"linear"
end,
:dash => string(d[:linestyle]),
# :dash => "solid",
)
end
# # for subplots, we need to add the xaxis/yaxis fields
# if plot_index != nothing
# d_out[:xaxis] = "x$(plot_index)"
# d_out[:yaxis] = "y$(plot_index)"
# end
d_out
end
# get a list of dictionaries, each representing the series params
function get_series_json(plt::Plot{PlotlyPackage})
JSON.json(map(plotly_series, plt.seriesargs))
end
function get_series_json(subplt::Subplot{PlotlyPackage})
ds = Dict[]
for (i,plt) in enumerate(subplt.plts)
for d in plt.seriesargs
push!(ds, plotly_series(d, plot_index = i))
end
end
JSON.json(ds)
end
# ----------------------------------------------------------------
function html_head(plt::PlottingObject{PlotlyPackage})
"<script src=\"$(Pkg.dir("Plots","deps","plotly-latest.min.js"))\"></script>"
end
function html_body(plt::Plot{PlotlyPackage}, style = nothing)
if style == nothing
w, h = plt.plotargs[:size]
style = "width:$(w)px;height:$(h)px;"
end
uuid = Base.Random.uuid4()
"""
<div id=\"$(uuid)\" style=\"$(style)\"></div>
<script>
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(get_series_json(plt)), $(get_plot_json(plt)));
</script>
"""
end
function html_body(subplt::Subplot{PlotlyPackage})
w, h = subplt.plts[1].plotargs[:size]
html = ["<div style=\"width:$(w)px;height:$(h)px;\">"]
nr = nrows(subplt.layout)
ph = h / nr
for r in 1:nr
push!(html, "<div style=\"clear:both;\">")
nc = ncols(subplt.layout, r)
pw = w / nc
for c in 1:nc
plt = subplt[r,c]
push!(html, html_body(plt, "float:left; width:$(pw)px; height:$(ph)px;"))
end
push!(html, "</div>")
end
push!(html, "</div>")
join(html)
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{PlotlyPackage})
warn("todo: png")
end
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PlotlyPackage})
write(io, html_head(plt) * html_body(plt))
end
function Base.display(::PlotsDisplay, plt::PlottingObject{PlotlyPackage})
standalone_html_window(plt)
end
# function Base.display(::PlotsDisplay, plt::Subplot{PlotlyPackage})
# # TODO: display/show the subplot
# end
+128
View File
@@ -0,0 +1,128 @@
# https://github.com/spencerlyon2/PlotlyJS.jl
function _initialize_backend(::PlotlyJSPackage; kw...)
@eval begin
import PlotlyJS
export PlotlyJS
end
for (mime, fmt) in PlotlyJS._mimeformats
@eval Base.writemime(io::IO, m::MIME{symbol($mime)}, p::Plot{PlotlyJSPackage}) = writemime(io, m, p.o)
end
# override IJulia inline display
if isijulia()
IJulia.display_dict(plt::PlottingObject{PlotlyJSPackage}) = IJulia.display_dict(plt.o)
end
end
# ---------------------------------------------------------------------------
function _create_plot(pkg::PlotlyJSPackage; kw...)
d = Dict(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
# o = PlotlyJS.Plot(PlotlyJS.GenericTrace[], PlotlyJS.Layout(),
# Base.Random.uuid4(), PlotlyJS.ElectronDisplay())
# T = isijulia() ? PlotlyJS.JupyterPlot : PlotlyJS.ElectronPlot
# o = T(PlotlyJS.Plot())
o = PlotlyJS.plot()
Plot(o, pkg, 0, d, Dict[])
end
function _add_series(::PlotlyJSPackage, plt::Plot; kw...)
d = Dict(kw)
syncplot = plt.o
# dumpdict(d, "addseries", true)
# add to the data array
pdict = plotly_series(d)
typ = pop!(pdict, :type)
gt = PlotlyJS.GenericTrace(typ; pdict...)
PlotlyJS.addtraces!(syncplot, gt)
push!(plt.seriesargs, d)
plt
end
# ---------------------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{PlotlyJSPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
# set or add to the annotation_list
if !haskey(plt.plotargs, :annotation_list)
plt.plotargs[:annotation_list] = Any[]
end
append!(plt.plotargs[:annotation_list], anns)
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{PlotlyJSPackage})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PlotlyJSPackage}, d::Dict)
pdict = plotly_layout(d)
# dumpdict(pdict, "pdict updateplot", true)
syncplot = plt.o
w,h = d[:size]
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
end
function _update_plot_pos_size(plt::PlottingObject{PlotlyJSPackage}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{PlotlyJSPackage}, i::Int)
d = plt.seriesargs[i]
d[:x], d[:y]
end
function Base.setindex!(plt::Plot{PlotlyJSPackage}, xy::Tuple, i::Integer)
d = plt.seriesargs[i]
d[:x], d[:y] = xy
# TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
# PlotlyJS.restyle!(plt.o, i, plotly_series(d))
PlotlyJS.restyle!(plt.o, i, Dict(:x=>(d[:x],), :y=>(d[:y],)))
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PlotlyJSPackage}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true
end
function _expand_limits(lims, plt::Plot{PlotlyJSPackage}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{PlotlyJSPackage}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{PlotlyJSPackage})
Base.writemime(io, m, plt.o)
end
function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSPackage})
display(plt.o)
end
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSPackage})
error()
end
+349 -126
View File
@@ -1,10 +1,37 @@
# https://github.com/stevengj/PyPlot.jl
function _initialize_backend(::PyPlotPackage)
@eval begin
import PyPlot
export PyPlot
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
# const pycolorbar = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colorbar"))
end
if !isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
PyPlot.ioff() # stops wierd behavior of displaying incomplete graphs in IJulia
# # TODO: how the hell can I use PyQt4??
# "pyqt4"=>:qt_pyqt4
# PyPlot.backend[1] = "pyqt4"
# PyPlot.gui[1] = :qt_pyqt4
# PyPlot.switch_backend("Qt4Agg")
# only turn on the gui if we want it
if PyPlot.gui != :none
PyPlot.pygui(true)
end
end
end
# -------------------------------
# convert colorant to 4-tuple RGBA
getPyPlotColor(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
getPyPlotColor(cvec::ColorVector, α=nothing) = map(getPyPlotColor, convertColor(cvec, α).v)
getPyPlotColor(scheme::ColorScheme, α=nothing) = getPyPlotColor(convertColor(getColor(scheme), α))
getPyPlotColor(c, α=nothing) = getPyPlotColor(convertColor(c, α))
# getPyPlotColor(c, alpha) = getPyPlotColor(colorscheme(c, alpha))
@@ -12,12 +39,14 @@ getPyPlotColor(c, α=nothing) = getPyPlotColor(convertColor(c, α))
function getPyPlotColorMap(c::ColorGradient, α=nothing)
# c = ColorGradient(c.colors, c.values, alpha=α)
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", map(getPyPlotColor, getColorVector(c)))
pyvals = [(c.values[i], getPyPlotColor(c.colors[i], α)) for i in 1:length(c.colors)]
# pyvals = [(c.values[i], getPyPlotColor(c.colors[i], α)) for i in 1:length(c.colors)]
pyvals = [(v, getPyPlotColor(getColorZ(c, v), α)) for v in c.values]
# @show c α pyvals
pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
end
# anything else just gets a redsblue gradient
getPyPlotColorMap(c, α=nothing) = getPyPlotColorMap(ColorGradient(:redsblues), α)
# anything else just gets a bluesred gradient
getPyPlotColorMap(c, α=nothing) = getPyPlotColorMap(ColorGradient(:bluesreds), α)
# get the style (solid, dashed, etc)
function getPyPlotLineStyle(linetype::Symbol, linestyle::Symbol)
@@ -62,8 +91,14 @@ function getPyPlotMarker(marker::Symbol)
return "o"
end
# getPyPlotMarker(markers::AVec) = map(getPyPlotMarker, markers)
function getPyPlotMarker(markers::AVec)
warn("Vectors of markers are currently unsupported in PyPlot: $markers")
getPyPlotMarker(markers[1])
end
# pass through
function getPyPlotMarker(marker::@compat(AbstractString))
function getPyPlotMarker(marker::AbstractString)
@assert length(marker) == 1
marker
end
@@ -75,46 +110,73 @@ function getPyPlotStepStyle(linetype::Symbol)
end
immutable PyPlotFigWrapper
fig
end
# immutable PyPlotFigWrapper
# fig
# kwargs # for add_subplot
# end
immutable PyPlotAxisWrapper
type PyPlotAxisWrapper
ax
rightax
fig
kwargs # for add_subplot
end
getfig(wrap::@compat(Union{PyPlotAxisWrapper,PyPlotFigWrapper})) = wrap.fig
# getfig(wrap::@compat(Union{PyPlotAxisWrapper,PyPlotFigWrapper})) = wrap.fig
getfig(wrap::PyPlotAxisWrapper) = wrap.fig
# get a reference to the correct axis
function getLeftAxis(wrap::PyPlotFigWrapper)
axes = wrap.fig.o[:axes]
if isempty(axes)
return wrap.fig.o[:add_subplot](111)
function getLeftAxis(wrap::PyPlotAxisWrapper)
if wrap.ax == nothing
axes = wrap.fig.o[:axes]
if isempty(axes)
return wrap.fig.o[:add_subplot](111; wrap.kwargs...)
end
axes[1]
else
wrap.ax
end
axes[1]
end
getLeftAxis(wrap::PyPlotAxisWrapper) = wrap.ax
# getLeftAxis(wrap::PyPlotAxisWrapper) = wrap.ax
# getRightAxis(x) = getLeftAxis(x)[:twinx]()
function getRightAxis(wrap::PyPlotAxisWrapper)
if wrap.rightax == nothing
wrap.rightax = getLeftAxis(wrap)[:twinx]()
end
wrap.rightax
end
getLeftAxis(plt::Plot{PyPlotPackage}) = getLeftAxis(plt.o)
getRightAxis(x) = getLeftAxis(x)[:twinx]()
getRightAxis(plt::Plot{PyPlotPackage}) = getRightAxis(plt.o)
getAxis(plt::Plot{PyPlotPackage}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt)
# left axis is PyPlot.<func>, right axis is "f.axes[0].twinx().<func>"
function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol)
# # need to access mplot3d functions differently
# if linetype == :surface
# return mplot3d.pymember("Axes3D")[:plot_surface]
# end
# in the 2-axis case we need to get: <rightaxis>[:<func>]
ax = getAxis(plt, axis)
ax[:set_ylabel](plt.initargs[:yrightlabel])
# ax[:set_ylabel](plt.plotargs[:yrightlabel])
fmap = @compat Dict(
:hist => :hist,
:sticks => :bar,
:bar => :bar,
:heatmap => :hexbin,
:hexbin => :hexbin,
:scatter => :scatter,
:contour => :contour,
:hist => :hist,
:density => :hist,
:sticks => :bar,
:bar => :bar,
:heatmap => :hexbin,
:hexbin => :hexbin,
:scatter => :scatter,
:contour => :contour,
:scatter3d => :scatter,
:surface => :plot_surface,
:wireframe => :plot_wireframe,
# :surface => pycolors.pymember("LinearSegmentedColormap")[:from_list]
)
return ax[get(fmap, linetype, :plot)]
end
@@ -138,7 +200,7 @@ function handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Bool)
xs, ys = regressionXY(d[:x], d[:y])
ax[:plot](xs, ys,
# linestyle = getPyPlotLineStyle(:path, :dashdot),
color = getPyPlotColor(d[:color]),
color = getPyPlotColor(d[:linecolor]),
linewidth = 2
)
end
@@ -146,21 +208,56 @@ end
handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Real) = handleSmooth(plt, ax, d, true)
nop() = nothing
makePyPlotCurrent(wrap::PyPlotFigWrapper) = PyPlot.figure(wrap.fig.o[:number])
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = nothing #PyPlot.sca(wrap.ax.o)
makePyPlotCurrent(plt::Plot{PyPlotPackage}) = makePyPlotCurrent(plt.o)
# makePyPlotCurrent(wrap::PyPlotFigWrapper) = PyPlot.figure(wrap.fig.o[:number])
# makePyPlotCurrent(wrap::PyPlotAxisWrapper) = nothing #PyPlot.sca(wrap.ax.o)
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = wrap.ax == nothing ? PyPlot.figure(wrap.fig.o[:number]) : nothing
makePyPlotCurrent(plt::Plot{PyPlotPackage}) = plt.o == nothing ? nothing : makePyPlotCurrent(plt.o)
function preparePlotUpdate(plt::Plot{PyPlotPackage})
function _before_add_series(plt::Plot{PyPlotPackage})
makePyPlotCurrent(plt)
end
# ------------------------------------------------------------------
function pyplot_figure(plotargs::Dict)
w,h = map(px2inch, plotargs[:size])
bgcolor = getPyPlotColor(plotargs[:background_color])
# reuse the current figure?
fig = if plotargs[:overwrite_figure]
PyPlot.gcf()
else
PyPlot.figure()
end
# update the specs
# fig[:set_size_inches](w,h, (isijulia() ? [] : [true])...)
fig[:set_size_inches](w, h, forward = true)
fig[:set_facecolor](bgcolor)
fig[:set_dpi](DPI)
fig[:set_tight_layout](true)
# clear the figure
PyPlot.clf()
# resize the window
PyPlot.plt[:get_current_fig_manager]()[:resize](plotargs[:size]...)
fig
end
function pyplot_3d_setup!(wrap, d)
# 3D?
# if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper)
if trueOrAllTrue(lt -> lt in _3dTypes, get(d, :linetype, :none))
push!(wrap.kwargs, (:projection, "3d"))
end
end
# TODO:
# fillto # might have to use barHack/histogramHack??
# reg # true or false, add a regression line for each line
@@ -169,7 +266,7 @@ end
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
# show # true or false, show the plot (in case you don't want the window to pop up right away)
function plot(pkg::PyPlotPackage; kw...)
function _create_plot(pkg::PyPlotPackage; kw...)
# create the figure
d = Dict(kw)
@@ -177,9 +274,13 @@ function plot(pkg::PyPlotPackage; kw...)
if haskey(d, :subplot)
wrap = nothing
else
w,h = map(px2inch, d[:size])
bgcolor = getPyPlotColor(d[:background_color])
wrap = PyPlotFigWrapper(PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96))
wrap = PyPlotAxisWrapper(nothing, nothing, pyplot_figure(d), [])
# wrap = PyPlotAxisWrapper(nothing, nothing, PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true), [])
# if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper)
# push!(wrap.kwargs, (:projection, "3d"))
# end
pyplot_3d_setup!(wrap, d)
end
plt = Plot(wrap, pkg, 0, d, Dict[])
@@ -187,22 +288,36 @@ function plot(pkg::PyPlotPackage; kw...)
end
function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
d = Dict(kw)
ax = getAxis(plt, d[:axis])
# 3D plots have a different underlying Axes object in PyPlot
lt = d[:linetype]
if lt in _3dTypes && isempty(plt.o.kwargs)
push!(plt.o.kwargs, (:projection, "3d"))
end
# handle mismatched x/y sizes, as PyPlot doesn't like that
x, y = d[:x], d[:y]
nx, ny = map(length, (x,y))
if nx < ny
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
else
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
end
ax = getAxis(plt, d[:axis])
if !(lt in supportedTypes(pkg))
error("linetype $(lt) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))")
end
color = getPyPlotColor(d[:color], d[:lineopacity])
color = getPyPlotColor(d[:linecolor], d[:linealpha])
if lt == :sticks
d,_ = sticksHack(;d...)
elseif lt == :scatter
elseif lt in (:scatter, :scatter3d)
if d[:markershape] == :none
d[:markershape] = :ellipse
end
@@ -212,82 +327,140 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
linecolor = color
linestyle = getPyPlotLineStyle(lt, d[:linestyle])
for yi in d[:y]
func = ax[lt == :hline ? :axhline : axvline]
func = ax[lt == :hline ? :axhline : :axvline]
func(yi, linewidth=d[:linewidth], color=linecolor, linestyle=linestyle)
end
end
lt = d[:linetype]
# lt = d[:linetype]
extra_kwargs = Dict()
plotfunc = getPyPlotFunction(plt, d[:axis], lt)
# we have different args depending on plot type
if lt in (:hist, :sticks, :bar)
if lt in (:hist, :density, :sticks, :bar)
# NOTE: this is unsupported because it does the wrong thing... it shifts the whole axis
# extra_kwargs[:bottom] = d[:fill]
if lt == :hist
if ishistlike(lt)
extra_kwargs[:bins] = d[:nbins]
extra_kwargs[:normed] = lt == :density
else
extra_kwargs[:linewidth] = (lt == :sticks ? 0.1 : 0.9)
end
elseif lt in (:heatmap, :hexbin)
extra_kwargs[:gridsize] = d[:nbins]
extra_kwargs[:cmap] = getPyPlotColorMap(d[:color])
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor])
elseif lt == :contour
extra_kwargs[:cmap] = getPyPlotColorMap(d[:color])
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor])
extra_kwargs[:linewidths] = d[:linewidth]
extra_kwargs[:linestyles] = getPyPlotLineStyle(lt, d[:linestyle])
# TODO: will need to call contourf to fill in the contours
elseif lt in (:surface, :wireframe)
if lt == :surface
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
end
extra_kwargs[:rstride] = 1
extra_kwargs[:cstride] = 1
extra_kwargs[:linewidth] = d[:linewidth]
extra_kwargs[:edgecolor] = getPyPlotColor(d[:linecolor], d[:linealpha])
else
extra_kwargs[:linestyle] = getPyPlotLineStyle(lt, d[:linestyle])
extra_kwargs[:marker] = getPyPlotMarker(d[:markershape])
if lt == :scatter
extra_kwargs[:s] = d[:markersize]^2
if lt in (:scatter, :scatter3d)
extra_kwargs[:s] = d[:markersize].^2
c = d[:markercolor]
if isa(c, ColorGradient) && d[:z] != nothing
extra_kwargs[:c] = convert(Vector{Float64}, d[:z])
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeropacity])
if d[:zcolor] != nothing
if !isa(c, ColorGradient)
c = colorscheme(:bluesreds)
end
extra_kwargs[:c] = convert(Vector{Float64}, d[:zcolor])
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeralpha])
else
extra_kwargs[:c] = getPyPlotColor(c, d[:markeropacity])
# extra_kwargs[:c] = getPyPlotColor(c, d[:markeralpha])
ppc = getPyPlotColor(c, d[:markeralpha])
# 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
if (typeof(ppc) <: AbstractArray && length(ppc)*4 == length(x)) ||
(typeof(ppc) <: Tuple && length(x) == 4)
ppc = vcat(ppc, ppc)
end
extra_kwargs[:c] = ppc
end
# if d[:markeralpha] != nothing
# extra_kwargs[:alpha] = d[:markeralpha]
# end
extra_kwargs[:edgecolors] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
extra_kwargs[:linewidths] = d[:markerstrokewidth]
else
extra_kwargs[:markersize] = d[:markersize]
extra_kwargs[:markerfacecolor] = getPyPlotColor(d[:markercolor], d[:markeropacity])
extra_kwargs[:markeredgecolor] = getPyPlotColor(plt.initargs[:foreground_color])
extra_kwargs[:markeredgewidth] = d[:linewidth]
extra_kwargs[:markerfacecolor] = getPyPlotColor(d[:markercolor], d[:markeralpha])
extra_kwargs[:markeredgecolor] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
extra_kwargs[:markeredgewidth] = d[:markerstrokewidth]
extra_kwargs[:drawstyle] = getPyPlotStepStyle(lt)
end
end
# if d[:markeralpha] != nothing
# extra_kwargs[:alpha] = d[:markeralpha]
# elseif d[:linealpha] != nothing
# extra_kwargs[:alpha] = d[:linealpha]
# end
# set these for all types
if lt != :contour
extra_kwargs[:color] = color
extra_kwargs[:linewidth] = d[:linewidth]
if !(lt in (:contour,:surface,:wireframe))
if !(lt in (:scatter, :scatter3d))
extra_kwargs[:color] = color
extra_kwargs[:linewidth] = d[:linewidth]
end
extra_kwargs[:label] = d[:label]
extra_kwargs[:zorder] = plt.n
end
# do the plot
d[:serieshandle] = if lt == :hist
d[:serieshandle] = if ishistlike(lt)
plotfunc(d[:y]; extra_kwargs...)[1]
elseif lt == :contour
# NOTE: x/y are backwards in pyplot, so we switch the x and y args (also y is reversed),
# and take the transpose of the surface matrix
x, y = d[:y], d[:x]
surf = d[:surface]'
handle = plotfunc(x, y, surf, d[:nlevels]; extra_kwargs...)
x, y = d[:x], d[:y]
surf = d[:z].surf'
levels = d[:levels]
if isscalar(levels)
extra_args = (levels)
elseif isvector(levels)
extra_args = ()
extra_kwargs[:levels] = levels
else
error("Only numbers and vectors are supported with levels keyword")
end
handle = plotfunc(x, y, surf, extra_args...; extra_kwargs...)
if d[:fillrange] != nothing
handle = ax[:contourf](x, y, surf, d[:nlevels]; cmap = getPyPlotColorMap(d[:fillcolor], d[:fillopacity]))
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
delete!(extra_kwargs, :linewidths)
handle = ax[:contourf](x, y, surf, extra_args...; extra_kwargs...)
end
handle
elseif lt in (:surface,:wireframe)
x, y, z = d[:x], d[:y], Array(d[:z])
if !ismatrix(x) || !ismatrix(y)
x = repmat(x', length(y), 1)
y = repmat(y, 1, length(d[:x]))
z = z'
end
plotfunc(x, y, z; extra_kwargs...)
elseif lt in _3dTypes
plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...)
elseif lt in (:scatter, :heatmap, :hexbin)
plotfunc(d[:x], d[:y]; extra_kwargs...)
else
@@ -297,20 +470,22 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
handleSmooth(plt, ax, d, d[:smooth])
# add the colorbar legend
if plt.initargs[:legend] && haskey(extra_kwargs, :cmap)
PyPlot.colorbar(d[:serieshandle])
if plt.plotargs[:colorbar] != :none && haskey(extra_kwargs, :cmap)
PyPlot.colorbar(d[:serieshandle], ax=ax)
end
# @show extra_kwargs
# this sets the bg color inside the grid
ax[:set_axis_bgcolor](getPyPlotColor(plt.initargs[:background_color]))
ax[:set_axis_bgcolor](getPyPlotColor(plt.plotargs[:background_color]))
fillrange = d[:fillrange]
if fillrange != nothing && lt != :contour
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillopacity])
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillalpha])
if typeof(fillrange) <: @compat(Union{Real, AVec})
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor)
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor, zorder = plt.n)
else
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor)
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor, zorder = plt.n)
end
end
@@ -329,34 +504,57 @@ function Base.getindex(plt::Plot{PyPlotPackage}, i::Integer)
xy = series[:get_offsets]()
return vec(xy[:,1]), vec(xy[:,2])
end
# series[:relim]()
# mapping = getGadflyMappings(plt, i)[1]
# mapping[:x], mapping[:y]
end
function Base.setindex!(plt::Plot{PyPlotPackage}, xy::Tuple, i::Integer)
series = plt.seriesargs[i][:serieshandle]
function minmaxseries(ds, vec, axis)
lo, hi = Inf, -Inf
for d in ds
d[:axis] == axis || continue
v = d[vec]
if length(v) > 0
vlo, vhi = extrema(v)
lo = min(lo, vlo)
hi = max(hi, vhi)
end
end
if lo == hi
hi = if lo == 0
1e-6
else
hi + min(abs(1e-2hi), 1e-6)
end
end
lo, hi
end
# TODO: this needs to handle one-sided fixed limits
function set_lims!(plt::Plot{PyPlotPackage}, axis::Symbol)
ax = getAxis(plt, axis)
if plt.plotargs[:xlims] == :auto
ax[:set_xlim](minmaxseries(plt.seriesargs, :x, axis)...)
end
if plt.plotargs[:ylims] == :auto
ax[:set_ylim](minmaxseries(plt.seriesargs, :y, axis)...)
end
end
function Base.setindex!{X,Y}(plt::Plot{PyPlotPackage}, xy::Tuple{X,Y}, i::Integer)
d = plt.seriesargs[i]
series = d[:serieshandle]
x, y = xy
d[:x], d[:y] = x, y
try
series[:set_data](xy...)
series[:set_data](x, y)
catch
series[:set_offsets](hcat(xy...))
series[:set_offsets](hcat(x, y))
end
ax = series[:axes]
if plt.initargs[:xlims] == :auto
xmin, xmax = ax[:get_xlim]()
ax[:set_xlim](min(xmin, minimum(xy[1])), max(xmax, maximum(xy[1])))
end
if plt.initargs[:ylims] == :auto
ymin, ymax = ax[:get_ylim]()
ax[:set_ylim](min(ymin, minimum(xy[2])), max(ymax, maximum(xy[2])))
end
set_lims!(plt, d[:axis])
plt
end
# getLeftAxis(plt)[:relim]()
# getRightAxis(plt)[:relim]()
# for mapping in getGadflyMappings(plt, i)
# mapping[:x], mapping[:y] = xy
# end
function Base.setindex!{X,Y,Z}(plt::Plot{PyPlotPackage}, xyz::Tuple{X,Y,Z}, i::Integer)
warn("setindex not implemented for xyz")
plt
end
@@ -366,7 +564,13 @@ function addPyPlotLims(ax, lims, isx::Bool)
lims == :auto && return
ltype = limsType(lims)
if ltype == :limits
ax[isx ? :set_xlim : :set_ylim](lims...)
if isx
isfinite(lims[1]) && ax[:set_xlim](left = lims[1])
isfinite(lims[2]) && ax[:set_xlim](right = lims[2])
else
isfinite(lims[1]) && ax[:set_ylim](bottom = lims[1])
isfinite(lims[2]) && ax[:set_ylim](top = lims[2])
end
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
@@ -382,7 +586,8 @@ function addPyPlotTicks(ax, ticks, isx::Bool)
if ttype == :ticks
ax[isx ? :set_xticks : :set_yticks](ticks)
elseif ttype == :ticks_and_labels
ax[isx ? :set_xticks : :set_yticks](ticks...)
ax[isx ? :set_xticks : :set_yticks](ticks[1])
ax[isx ? :set_xticklabels : :set_yticklabels](ticks[2])
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
@@ -390,7 +595,7 @@ end
usingRightAxis(plt::Plot{PyPlotPackage}) = any(args -> args[:axis] in (:right,:auto), plt.seriesargs)
function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
function _update_plot(plt::Plot{PyPlotPackage}, d::Dict)
figorax = plt.o
ax = getLeftAxis(figorax)
# PyPlot.sca(ax)
@@ -403,7 +608,7 @@ function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
ax[:set_ylabel](d[:ylabel])
end
if usingRightAxis(plt) && get(d, :yrightlabel, "") != ""
rightax = getRightAxis(figorax)
rightax = getRightAxis(figorax)
rightax[:set_ylabel](d[:yrightlabel])
end
@@ -432,22 +637,22 @@ function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
# font sizes
for ax in axes
# haskey(d, :yrightlabel) || continue
# guides
sz = get(d, :guidefont, plt.initargs[:guidefont]).pointsize
sz = get(d, :guidefont, plt.plotargs[:guidefont]).pointsize
ax[:title][:set_fontsize](sz)
ax[:xaxis][:label][:set_fontsize](sz)
ax[:yaxis][:label][:set_fontsize](sz)
# ticks
sz = get(d, :tickfont, plt.initargs[:tickfont]).pointsize
sz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize
for sym in (:get_xticklabels, :get_yticklabels)
for lab in ax[sym]()
lab[:set_fontsize](sz)
end
end
# grid
if get(d, :grid, false)
ax[:xaxis][:grid](true)
@@ -461,7 +666,7 @@ end
function applyPyPlotScale(ax, scaleType::Symbol, isx::Bool)
func = ax[isx ? :set_xscale : :set_yscale]
scaleType == :identity && return func("linear")
scaleType == :log && return func("log", basex = e, basey = e)
scaleType == :ln && return func("log", basex = e, basey = e)
scaleType == :log2 && return func("log", basex = 2, basey = 2)
scaleType == :log10 && return func("log", basex = 10, basey = 10)
warn("Unhandled scaleType: ", scaleType)
@@ -488,7 +693,7 @@ function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::PlotT
)
end
function addAnnotations{X,Y,V}(plt::Plot{PyPlotPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
function _add_annotations{X,Y,V}(plt::Plot{PyPlotPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createPyPlotAnnotationObject(plt, ann...)
end
@@ -497,12 +702,14 @@ end
# -----------------------------------------------------------------
# NOTE: pyplot needs to build before
function buildSubplotObject!(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
l = subplt.layout
w,h = map(px2inch, getinitargs(subplt,1)[:size])
bgcolor = getPyPlotColor(getinitargs(subplt,1)[:background_color])
fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96)
# w,h = map(px2inch, getplotargs(subplt,1)[:size])
# bgcolor = getPyPlotColor(getplotargs(subplt,1)[:background_color])
# fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true)
plotargs = getplotargs(subplt, 1)
fig = pyplot_figure(plotargs)
nr = nrows(l)
for (i,(r,c)) in enumerate(l)
@@ -512,10 +719,13 @@ function buildSubplotObject!(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
fakeidx = (r-1) * nc + c
ax = fig[:add_subplot](nr, nc, fakeidx)
subplt.plts[i].o = PyPlotAxisWrapper(ax, fig)
subplt.plts[i].o = PyPlotAxisWrapper(ax, nothing, fig, [])
pyplot_3d_setup!(subplt.plts[i].o, plotargs)
end
subplt.o = PyPlotFigWrapper(fig)
# subplt.o = PyPlotFigWrapper(fig, [])
subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, [])
pyplot_3d_setup!(subplt.o, plotargs)
true
end
@@ -528,26 +738,26 @@ function subplot(plts::AVec{Plot{PyPlotPackage}}, layout::SubplotLayout, d::Dict
n = sum([plt.n for plt in plts])
pkg = PyPlotPackage()
newplts = Plot{PyPlotPackage}[plot(pkg; subplot=true, plt.initargs...) for plt in plts]
newplts = Plot{PyPlotPackage}[_create_plot(pkg; subplot=true, plt.plotargs...) for plt in plts]
subplt = Subplot(nothing, newplts, PyPlotPackage(), p, n, layout, d, true, false, false, (r,c) -> (nothing,nothing))
preprocessSubplot(subplt, d)
buildSubplotObject!(subplt, true)
_preprocess_subplot(subplt, d)
_create_subplot(subplt, true)
for (i,plt) in enumerate(plts)
for seriesargs in plt.seriesargs
_plot_from_subplot!(newplts[i]; seriesargs...)
_add_series_subplot(newplts[i]; seriesargs...)
end
end
postprocessSubplot(subplt, d)
_postprocess_subplot(subplt, d)
subplt
end
function handleLinkInner(plt::Plot{PyPlotPackage}, isx::Bool)
function _remove_axis(plt::Plot{PyPlotPackage}, isx::Bool)
if isx
plot!(plt, xticks=zeros(0), xlabel="")
else
@@ -555,25 +765,35 @@ function handleLinkInner(plt::Plot{PyPlotPackage}, isx::Bool)
end
end
function expandLimits!(lims, plt::Plot{PyPlotPackage}, isx::Bool)
function _expand_limits(lims, plt::Plot{PyPlotPackage}, isx::Bool)
pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]()
expandLimits!(lims, pltlims)
_expand_limits(lims, pltlims)
end
# -----------------------------------------------------------------
const _pyplot_legend_pos = Dict(
:right => "right",
:left => "center left",
:top => "upper center",
:bottom => "lower center"
)
# function addPyPlotLegend(plt::Plot)
function addPyPlotLegend(plt::Plot, ax)
if plt.initargs[:legend]
leg = plt.plotargs[:legend]
if leg != :none
# gotta do this to ensure both axes are included
args = filter(x -> !(x[:linetype] in (:hist,:hexbin,:heatmap,:hline,:vline,:contour)), plt.seriesargs)
args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:heatmap,:hline,:vline,:contour, :surface, :wireframe, :path3d, :scatter3d)), plt.seriesargs)
args = filter(x -> x[:label] != "", args)
if length(args) > 0
ax[:legend]([d[:serieshandle] for d in args],
leg = ax[:legend]([d[:serieshandle] for d in args],
[d[:label] for d in args],
loc="best",
fontsize = plt.initargs[:legendfont].pointsize
loc = get(_pyplot_legend_pos, leg, "best"),
fontsize = plt.plotargs[:legendfont].pointsize
# framealpha = 0.6
)
leg[:set_zorder](1000)
end
end
end
@@ -581,7 +801,7 @@ end
function finalizePlot(plt::Plot{PyPlotPackage})
ax = getLeftAxis(plt)
addPyPlotLegend(plt, ax)
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
PyPlot.draw()
end
@@ -590,8 +810,9 @@ function finalizePlot(subplt::Subplot{PyPlotPackage})
for (i,plt) in enumerate(subplt.plts)
ax = getLeftAxis(plt)
addPyPlotLegend(plt, ax)
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
end
# fig[:tight_layout]()
PyPlot.draw()
end
@@ -648,7 +869,7 @@ const _pyplot_mimeformats = @compat Dict(
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
# "image/svg+xml" => "svg"
"image/svg+xml" => "svg"
)
@@ -658,14 +879,16 @@ for (mime, fmt) in _pyplot_mimeformats
fig = getfig(plt.o)
fig.o["canvas"][:print_figure](io,
format=$fmt,
bbox_inches="tight",
# bbox_inches = "tight",
# figsize = map(px2inch, plt.plotargs[:size]),
facecolor = fig.o["get_facecolor"](),
edgecolor = "none"
# edgecolor = fig.o["get_edgecolor"]()
edgecolor = "none",
dpi = DPI
)
end
end
# function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotPackage})
# finalizePlot(subplt)
# writemime(io, m, getfig(subplt.o))
+18 -19
View File
@@ -1,6 +1,13 @@
# https://github.com/tbreloff/Qwt.jl
function _initialize_backend(::QwtPackage; kw...)
@eval begin
warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
end
# -------------------------------
@@ -70,7 +77,7 @@ function adjustQwtKeywords(plt::Plot{QwtPackage}, iscreating::Bool; kw...)
d
end
function plot(pkg::QwtPackage; kw...)
function _create_plot(pkg::QwtPackage; kw...)
d = Dict(kw)
fixcolors(d)
dumpdict(d,"\n\n!!! plot")
@@ -79,7 +86,7 @@ function plot(pkg::QwtPackage; kw...)
plt
end
function plot!(::QwtPackage, plt::Plot; kw...)
function _add_series(::QwtPackage, plt::Plot; kw...)
d = adjustQwtKeywords(plt, false; kw...)
fixcolors(d)
dumpdict(d,"\n\n!!! plot!")
@@ -131,7 +138,7 @@ function updateLimsAndTicks(plt::Plot{QwtPackage}, d::Dict, isx::Bool)
end
function updatePlotItems(plt::Plot{QwtPackage}, d::Dict)
function _update_plot(plt::Plot{QwtPackage}, d::Dict)
haskey(d, :title) && Qwt.title(plt.o, d[:title])
haskey(d, :xlabel) && Qwt.xlabel(plt.o, d[:xlabel])
haskey(d, :ylabel) && Qwt.ylabel(plt.o, d[:ylabel])
@@ -139,7 +146,7 @@ function updatePlotItems(plt::Plot{QwtPackage}, d::Dict)
updateLimsAndTicks(plt, d, false)
end
function updatePositionAndSize(plt::PlottingObject{QwtPackage}, d::Dict)
function _update_plot_pos_size(plt::PlottingObject{QwtPackage}, d::Dict)
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
end
@@ -154,7 +161,7 @@ function addLineMarker(plt::Plot{QwtPackage}, d::Dict)
ishorizontal = (d[:linetype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
qcolor = Qwt.convertRGBToQColor(getColor(d[:color]))
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
marker[:attach](plt.o.widget)
@@ -182,7 +189,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
marker[:attach](plt.o.widget)
end
function addAnnotations{X,Y,V}(plt::Plot{QwtPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
function _add_annotations{X,Y,V}(plt::Plot{QwtPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createQwtAnnotation(plt, ann...)
end
@@ -211,7 +218,7 @@ end
# -------------------------------
# create the underlying object (each backend will do this differently)
function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{QwtPackage}, isbefore::Bool)
isbefore && return false
i = 0
rows = Any[]
@@ -228,23 +235,19 @@ function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool)
# i += rowcnt
# end
subplt.o = Qwt.vsplitter(rows...)
# Qwt.resizewidget(subplt.o, getinitargs(subplt,1)[:size]...)
# Qwt.resizewidget(subplt.o, getplotargs(subplt,1)[:size]...)
# Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
true
end
function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool)
warn("handleLinkInner isn't implemented for qwt")
end
function expandLimits!(lims, plt::Plot{QwtPackage}, isx::Bool)
function _expand_limits(lims, plt::Plot{QwtPackage}, isx::Bool)
for series in plt.o.lines
expandLimits!(lims, isx ? series.x : series.y)
_expand_limits(lims, isx ? series.x : series.y)
end
end
function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool)
function _remove_axis(plt::Plot{QwtPackage}, isx::Bool)
end
@@ -274,10 +277,6 @@ function Base.display(::PlotsDisplay, subplt::Subplot{QwtPackage})
for plt in subplt.plts
Qwt.refresh(plt.o)
end
# iargs = getinitargs(subplt,1)
# # iargs = subplt.initargs
# Qwt.resizewidget(subplt.o, iargs[:size]...)
# Qwt.movewidget(subplt.o, iargs[:pos]...)
Qwt.showwidget(subplt.o)
end
+481 -21
View File
@@ -1,26 +1,51 @@
supportedAxes(::PlottingPackage) = [:left]
supportedTypes(::PlottingPackage) = []
supportedStyles(::PlottingPackage) = [:solid]
supportedMarkers(::PlottingPackage) = [:none]
supportedScales(::PlottingPackage) = [:identity]
subplotSupported(::PlottingPackage) = false
stringsSupported(::PlottingPackage) = false
supportedAxes() = supportedAxes(backend())
supportedTypes() = supportedTypes(backend())
supportedStyles() = supportedStyles(backend())
supportedMarkers() = supportedMarkers(backend())
supportedScales() = supportedScales(backend())
subplotSupported() = subplotSupported(backend())
stringsSupported() = stringsSupported(backend())
# --------------------------------------------------------------------------------------
supportedArgs(::GadflyPackage) = [
:annotation,
# :axis,
:background_color,
:color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
:fillopacity,
:fillalpha,
:foreground_color,
:group,
:label,
:layout,
:legend,
:colorbar,
:linestyle,
:linetype,
:linewidth,
:lineopacity,
:linealpha,
:markershape,
:markercolor,
:markersize,
:markeropacity,
:markeralpha,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokealpha,
# :markerstrokestyle,
:n,
:nbins,
:nc,
@@ -45,18 +70,22 @@ supportedArgs(::GadflyPackage) = [
:xflip,
:yflip,
:z,
:zcolor,
:tickfont,
:guidefont,
:legendfont,
:grid,
:surface,
:nlevels,
# :surface,
:levels,
]
supportedAxes(::GadflyPackage) = [:auto, :left]
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppre, :steppost, :sticks,
:scatter, :heatmap, :hexbin, :hist, :bar,
:hline, :vline, :contour]
supportedStyles(::GadflyPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GadflyPackage) = vcat(_allMarkers, Shape)
supportedScales(::GadflyPackage) = [:identity, :log, :log2, :log10, :asinh, :sqrt]
supportedScales(::GadflyPackage) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::GadflyPackage) = true
# --------------------------------------------------------------------------------------
@@ -68,6 +97,7 @@ supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
subplotSupported(::ImmersePackage) = true
# --------------------------------------------------------------------------------------
@@ -77,7 +107,7 @@ supportedArgs(::PyPlotPackage) = [
:annotation,
:axis,
:background_color,
:color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
@@ -86,12 +116,17 @@ supportedArgs(::PyPlotPackage) = [
:label,
:layout,
:legend,
:colorbar,
:linestyle,
:linetype,
:linewidth,
:markershape,
:markercolor,
:markersize,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokealpha,
# :markerstrokestyle,
:n,
:nbins,
:nc,
@@ -117,22 +152,26 @@ supportedArgs(::PyPlotPackage) = [
:xflip,
:yflip,
:z,
:zcolor, # only supported for scatter/scatter3d
:tickfont,
:guidefont,
:legendfont,
:grid,
:surface,
:nlevels,
:fillopacity,
:lineopacity,
:markeropacity,
# :surface,
:levels,
:fillalpha,
:linealpha,
:markeralpha,
:overwrite_figure,
]
supportedAxes(::PyPlotPackage) = _allAxes
supportedTypes(::PyPlotPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedTypes(::PyPlotPackage) = [:none, :line, :path, :steppre, :steppost, #:sticks,
:scatter, :heatmap, :hexbin, :hist, :density, :bar,
:hline, :vline, :contour, :path3d, :scatter3d, :surface, :wireframe]
supportedStyles(::PyPlotPackage) = [:auto, :solid, :dash, :dot, :dashdot]
# supportedMarkers(::PyPlotPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :hexagon]
supportedMarkers(::PyPlotPackage) = vcat(_allMarkers, Shape)
supportedScales(::PyPlotPackage) = [:identity, :log, :log2, :log10]
supportedScales(::PyPlotPackage) = [:identity, :ln, :log2, :log10]
subplotSupported(::PyPlotPackage) = true
@@ -140,12 +179,86 @@ subplotSupported(::PyPlotPackage) = true
supportedArgs(::GRPackage) = [
:annotation,
:axis,
:background_color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
:foreground_color,
:group,
:label,
:layout,
:legend,
:colorbar,
:linestyle,
:linetype,
:linewidth,
:markershape,
:markercolor,
:markersize,
:markerstrokewidth,
:markerstrokecolor,
# :markerstrokestyle,
:n,
:nbins,
:nc,
:nr,
# :pos,
:smooth,
# :ribbon,
:show,
:size,
:title,
:windowtitle,
:x,
:xlabel,
:xlims,
:xticks,
:y,
:ylabel,
:ylims,
:yrightlabel,
:yticks,
:xscale,
:yscale,
:xflip,
:yflip,
:z,
:zcolor, # only supported for scatter/scatter3d
:tickfont,
:guidefont,
:legendfont,
:grid,
# :surface,
:nlevels,
:fillalpha,
:linealpha,
:markeralpha,
]
supportedAxes(::GRPackage) = _allAxes
supportedTypes(::GRPackage) = [:none, :line, :path, :steppre, :steppost, :sticks,
:scatter, :heatmap, :hexbin, :hist, :density, :bar,
:hline, :vline, :contour, :path3d, :scatter3d, :surface,
:wireframe, :ohlc, :pie]
supportedStyles(::GRPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GRPackage) = vcat(_allMarkers, Shape)
supportedScales(::GRPackage) = [:identity, :log10]
subplotSupported(::GRPackage) = true
# --------------------------------------------------------------------------------------
supportedArgs(::QwtPackage) = [
:annotation,
# :args,
:axis,
:background_color,
:color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
@@ -162,6 +275,9 @@ supportedArgs(::QwtPackage) = [
:markershape,
:markercolor,
:markersize,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
:n,
:nbins,
:nc,
@@ -191,6 +307,7 @@ supportedArgs(::QwtPackage) = [
supportedTypes(::QwtPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
supportedMarkers(::QwtPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supportedScales(::QwtPackage) = [:identity, :log10]
subplotSupported(::QwtPackage) = true
# --------------------------------------------------------------------------------------
@@ -201,7 +318,7 @@ supportedArgs(::UnicodePlotsPackage) = [
# :args,
# :axis,
# :background_color,
# :color,
# :linecolor,
# :fill,
# :foreground_color,
:group,
@@ -216,6 +333,9 @@ supportedArgs(::UnicodePlotsPackage) = [
:markershape,
# :markercolor,
# :markersize,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
:nbins,
# :nc,
@@ -243,10 +363,11 @@ supportedArgs(::UnicodePlotsPackage) = [
# :z,
]
supportedAxes(::UnicodePlotsPackage) = [:auto, :left]
supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
supportedStyles(::UnicodePlotsPackage) = [:auto, :solid]
supportedMarkers(::UnicodePlotsPackage) = [:none, :auto, :ellipse]
supportedScales(::UnicodePlotsPackage) = [:identity]
subplotSupported(::UnicodePlotsPackage) = true
@@ -259,7 +380,7 @@ supportedArgs(::WinstonPackage) = [
# :args,
# :axis,
# :background_color,
:color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
@@ -276,6 +397,9 @@ supportedArgs(::WinstonPackage) = [
:markershape,
:markercolor,
:markersize,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
:nbins,
# :nc,
@@ -310,4 +434,340 @@ supportedScales(::WinstonPackage) = [:identity, :log10]
subplotSupported(::WinstonPackage) = false
# --------------------------------------------------------------------------------------
# --------------------------------------------------------------------------------------
supportedArgs(::BokehPackage) = [
# :annotation,
# :axis,
# :background_color,
:linecolor,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
:group,
# :label,
# :layout,
# :legend,
:linestyle,
:linetype,
:linewidth,
# :linealpha,
:markershape,
:markercolor,
:markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :nbins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
:size,
:title,
# :windowtitle,
:x,
# :xlabel,
# :xlims,
# :xticks,
:y,
# :ylabel,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface,
# :levels,
]
supportedAxes(::BokehPackage) = [:auto, :left]
supportedTypes(::BokehPackage) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedStyles(::BokehPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::BokehPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::BokehPackage) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::BokehPackage) = false
# --------------------------------------------------------------------------------------
supportedArgs(::PlotlyPackage) = [
:annotation,
# :axis,
:background_color,
:color_palette,
:fillrange,
:fillcolor,
:fillalpha,
:foreground_color,
:group,
:label,
:layout,
:legend,
:linecolor,
:linestyle,
:linetype,
:linewidth,
:linealpha,
:markershape,
:markercolor,
:markersize,
:markeralpha,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokestyle,
:n,
:nbins,
:nc,
:nr,
# :pos,
# :smooth,
:show,
:size,
:title,
:windowtitle,
:x,
:xlabel,
:xlims,
:xticks,
:y,
:ylabel,
:ylims,
# :yrightlabel,
:yticks,
:xscale,
:yscale,
:xflip,
:yflip,
:z,
:zcolor,
:tickfont,
:guidefont,
:legendfont,
:grid,
:levels,
]
supportedAxes(::PlotlyPackage) = [:auto, :left]
supportedTypes(::PlotlyPackage) = [:none, :line, :path, :scatter, :steppre, :steppost,
:heatmap, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
:pie] #,, :sticks, :hexbin, :hline, :vline]
supportedStyles(::PlotlyPackage) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::PlotlyPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
supportedScales(::PlotlyPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PlotlyPackage) = true
stringsSupported(::PlotlyPackage) = true
# --------------------------------------------------------------------------------------
supportedArgs(::PlotlyJSPackage) = [
:annotation,
# :axis,
:background_color,
:color_palette,
:fillrange,
:fillcolor,
:fillalpha,
:foreground_color,
:group,
:label,
:layout,
:legend,
:linecolor,
:linestyle,
:linetype,
:linewidth,
:linealpha,
:markershape,
:markercolor,
:markersize,
:markeralpha,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokestyle,
:n,
:nbins,
:nc,
:nr,
# :pos,
# :smooth,
:show,
:size,
:title,
:windowtitle,
:x,
:xlabel,
:xlims,
:xticks,
:y,
:ylabel,
:ylims,
# :yrightlabel,
:yticks,
:xscale,
:yscale,
:xflip,
:yflip,
:z,
:zcolor,
:tickfont,
:guidefont,
:legendfont,
:grid,
:levels,
]
supportedAxes(::PlotlyJSPackage) = [:auto, :left]
supportedTypes(::PlotlyJSPackage) = [:none, :line, :path, :scatter, :steppre, :steppost,
:heatmap, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
:pie] #,, :sticks, :hexbin, :hline, :vline]
supportedStyles(::PlotlyJSPackage) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::PlotlyJSPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
supportedScales(::PlotlyJSPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PlotlyJSPackage) = true
stringsSupported(::PlotlyJSPackage) = true
# --------------------------------------------------------------------------------------
supportedArgs(::GLVisualizePackage) = [
# :annotation,
# :axis,
# :background_color,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
# :group,
# :label,
# :layout,
# :legend,
# :linecolor,
# :linestyle,
# :linetype,
# :linewidth,
# :linealpha,
# :markershape,
# :markercolor,
# :markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :nbins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
# :size,
# :title,
# :windowtitle,
# :x,
# :xlabel,
# :xlims,
# :xticks,
# :y,
# :ylabel,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface
# :levels,
]
supportedAxes(::GLVisualizePackage) = [:auto, :left]
supportedTypes(::GLVisualizePackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedStyles(::GLVisualizePackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GLVisualizePackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::GLVisualizePackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
subplotSupported(::GLVisualizePackage) = false
# --------------------------------------------------------------------------------------
supportedArgs(::PGFPlotsPackage) = [
# :annotation,
# :axis,
# :background_color,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
# :group,
# :label,
# :layout,
# :legend,
# :linecolor,
# :linestyle,
# :linetype,
# :linewidth,
# :linealpha,
# :markershape,
# :markercolor,
# :markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :nbins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
# :size,
# :title,
# :windowtitle,
# :x,
# :xlabel,
# :xlims,
# :xticks,
# :y,
# :ylabel,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface
# :levels,
]
supportedAxes(::PGFPlotsPackage) = [:auto, :left]
supportedTypes(::PGFPlotsPackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedStyles(::PGFPlotsPackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::PGFPlotsPackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::PGFPlotsPackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PGFPlotsPackage) = false
+49 -64
View File
@@ -3,92 +3,77 @@
# [WEBSITE]
# ---------------------------------------------------------------------------
# supportedArgs(::[PkgName]Package) = _allArgs
supportedArgs(::[PkgName]Package) = [
:annotation,
# :args,
:axis,
:background_color,
:color,
:fillrange,
:fillcolor,
:foreground_color,
:group,
# :heatmap_c,
# :kwargs,
:label,
:layout,
:legend,
:linestyle,
:linetype,
:linewidth,
:markershape,
:markercolor,
:markersize,
:n,
:nbins,
:nc,
:nr,
# :pos,
:smooth,
# :ribbon,
:show,
:size,
:title,
:windowtitle,
:x,
:xlabel,
:xlims,
:xticks,
:y,
:ylabel,
:ylims,
# :yrightlabel,
:yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
]
supportedAxes(::[PkgName]Package) = _allAxes
supportedTypes(::[PkgName]Package) = _allTypes
supportedStyles(::[PkgName]Package) = _allStyles
supportedMarkers(::[PkgName]Package) = _allMarkers
supportedScales(::[PkgName]Package) = _allScales
subplotSupported(::[PkgName]Package) = false
function _initialize_backend(::[PkgName]Package; kw...)
@eval begin
import [PkgName]
export [PkgName]
# TODO: other initialization that needs to be eval-ed
end
# TODO: other initialization
end
# ---------------------------------------------------------------------------
function plot(pkg::[PkgName]Package; kw...)
function _create_plot(pkg::[PkgName]Package; kw...)
d = Dict(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
Plot(o, pkg, 0, d, Dict[])
Plot(nothing, pkg, 0, d, Dict[])
end
function plot!(::[PkgName]Package, plt::Plot; kw...)
function _add_series(::[PkgName]Package, plt::Plot; kw...)
d = Dict(kw)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
plt
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function updatePlotItems(plt::Plot{[PkgName]Package}, d::Dict)
function _add_annotations{X,Y,V}(plt::Plot{[PkgName]Package}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
# TODO: add the annotation to the plot
end
end
# ----------------------------------------------------------------
function buildSubplotObject!(subplt::Subplot{[PkgName]Package})
function _before_update_plot(plt::Plot{[PkgName]Package})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{[PkgName]Package}, d::Dict)
end
function _update_plot_pos_size(plt::PlottingObject{[PkgName]Package}, d::Dict)
end
# ----------------------------------------------------------------
# accessors for x/y data
function Base.getindex(plt::Plot{[PkgName]Package}, i::Int)
# TODO: return a tuple of (x, y) vectors
end
function Base.setindex!(plt::Plot{[PkgName]Package}, xy::Tuple, i::Integer)
# TODO: set the plot data from the (x,y) tuple
plt
end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{[PkgName]Package}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
end
function _expand_limits(lims, plt::Plot{[PkgName]Package}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{[PkgName]Package}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{[PkgName]Package})
+21 -14
View File
@@ -1,6 +1,13 @@
# https://github.com/Evizero/UnicodePlots.jl
function _initialize_backend(::UnicodePlotsPackage; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
@@ -9,13 +16,13 @@ function rebuildUnicodePlot!(plt::Plot)
# figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
sargs = plt.seriesargs
iargs = plt.initargs
iargs = plt.plotargs
# get the x/y limits
if get(iargs, :xlims, :auto) == :auto
xlim = [Inf, -Inf]
for d in sargs
expandLimits!(xlim, d[:x])
_expand_limits(xlim, d[:x])
end
else
xmin, xmax = iargs[:xlims]
@@ -25,7 +32,7 @@ function rebuildUnicodePlot!(plt::Plot)
if get(iargs, :ylims, :auto) == :auto
ylim = [Inf, -Inf]
for d in sargs
expandLimits!(ylim, d[:y])
_expand_limits(ylim, d[:y])
end
else
ymin, ymax = iargs[:ylims]
@@ -39,7 +46,7 @@ function rebuildUnicodePlot!(plt::Plot)
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
width, height = iargs[:size]
o = UnicodePlots.createPlotWindow(x, y; width = width,
o = UnicodePlots.Plot(x, y; width = width,
height = height,
title = iargs[:title],
# labels = iargs[:legend],
@@ -52,7 +59,7 @@ function rebuildUnicodePlot!(plt::Plot)
# now use the ! functions to add to the plot
for d in sargs
addUnicodeSeries!(o, d, iargs[:legend], xlim, ylim)
addUnicodeSeries!(o, d, iargs[:legend] != :none, xlim, ylim)
end
# save the object
@@ -91,13 +98,13 @@ function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
else
error("Linestyle $lt not supported by UnicodePlots")
end
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
label = addlegend ? d[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:color] in UnicodePlots.autoColors ? d[:color] : :auto
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# add the series
func(o, x, y; color = color, name = label, style = stepstyle)
@@ -112,18 +119,18 @@ end
# -------------------------------
function plot(pkg::UnicodePlotsPackage; kw...)
function _create_plot(pkg::UnicodePlotsPackage; kw...)
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
# do we want to give a new default size?
if !haskey(plt.initargs, :size) || plt.initargs[:size] == _plotDefaults[:size]
plt.initargs[:size] = (60,20)
if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == _plotDefaults[:size]
plt.plotargs[:size] = (60,20)
end
plt
end
function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
function _add_series(::UnicodePlotsPackage, plt::Plot; kw...)
d = Dict(kw)
if d[:linetype] in (:sticks, :bar)
d = barHack(; d...)
@@ -135,10 +142,10 @@ function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
end
function updatePlotItems(plt::Plot{UnicodePlotsPackage}, d::Dict)
function _update_plot(plt::Plot{UnicodePlotsPackage}, d::Dict)
for k in (:title, :xlabel, :ylabel, :xlims, :ylims)
if haskey(d, k)
plt.initargs[k] = d[k]
plt.plotargs[k] = d[k]
end
end
end
@@ -175,7 +182,7 @@ end
# we don't do very much for subplots... just stack them vertically
function buildSubplotObject!(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
isbefore && return false
true
end
+38
View File
@@ -0,0 +1,38 @@
# NOTE: backend should implement `html_body` and `html_head`
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
function standalone_html(plt::PlottingObject; title::AbstractString = get(plt.plotargs, :window_title, "Plots.jl"))
"""
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
$(html_head(plt))
</head>
<body>
$(html_body(plt))
</body>
</html>
"""
end
function open_browser_window(filename::AbstractString)
@osx_only return run(`open $(filename)`)
@linux_only return run(`xdg-open $(filename)`)
@windows_only return run(`$(ENV["COMSPEC"]) /c start $(filename)`)
warn("Unknown OS... cannot open browser window.")
end
function standalone_html_window(plt::PlottingObject; kw...)
html = standalone_html(plt; kw...)
# println(html)
filename = string(tempname(), ".html")
output = open(filename, "w")
write(output, html)
close(output)
open_browser_window(filename)
end
+18 -10
View File
@@ -3,6 +3,14 @@
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
function _initialize_backend(::WinstonPackage; 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
# ---------------------------------------------------------------------------
@@ -25,14 +33,14 @@
:star5 => "asterisk"
)
function preparePlotUpdate(plt::Plot{WinstonPackage})
function _before_add_series(plt::Plot{WinstonPackage})
Winston.ghf(plt.o)
end
# ---------------------------------------------------------------------------
function plot(pkg::WinstonPackage; kw...)
function _create_plot(pkg::WinstonPackage; kw...)
d = Dict(kw)
wplt = Winston.FramedPlot(title = d[:title], xlabel = d[:xlabel], ylabel = d[:ylabel])
@@ -56,7 +64,7 @@ function getWinstonItems(plt::Plot)
window, canvas, wplt
end
function plot!(::WinstonPackage, plt::Plot; kw...)
function _add_series(::WinstonPackage, plt::Plot; kw...)
d = Dict(kw)
window, canvas, wplt = getWinstonItems(plt)
@@ -68,7 +76,7 @@ function plot!(::WinstonPackage, plt::Plot; kw...)
e = Dict()
e[:color] = getColor(d[:color])
e[:color] = getColor(d[:linecolor])
e[:linewidth] = d[:linewidth]
e[:kind] = winston_linestyle[d[:linestyle]]
e[:symbolkind] = winston_marker[d[:markershape]]
@@ -157,7 +165,7 @@ end
:yscale => :ylog,
)
function updatePlotItems(plt::Plot{WinstonPackage}, d::Dict)
function _update_plot(plt::Plot{WinstonPackage}, d::Dict)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xlabel, :ylabel, :title, :xlims, :ylims)
if haskey(d, k)
@@ -182,7 +190,7 @@ function createWinstonAnnotationObject(plt::Plot{WinstonPackage}, x, y, val::@co
Winston.text(x, y, val)
end
function addAnnotations{X,Y,V}(plt::Plot{WinstonPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
function _add_annotations{X,Y,V}(plt::Plot{WinstonPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
@@ -191,14 +199,14 @@ end
# ----------------------------------------------------------------
function buildSubplotObject!(subplt::Subplot{WinstonPackage}, isbefore::Bool)
function _create_subplot(subplt::Subplot{WinstonPackage}, 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.initargs[:legend]
if plt.plotargs[:legend] != :none
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
end
end
@@ -219,9 +227,9 @@ function Base.display(::PlotsDisplay, plt::Plot{WinstonPackage})
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.initargs[:size]
w,h = plt.plotargs[:size]
canvas = Gtk.GtkCanvasLeaf()
window = Gtk.GtkWindowLeaf(canvas, plt.initargs[:windowtitle], w, h)
window = Gtk.GtkWindowLeaf(canvas, plt.plotargs[:windowtitle], w, h)
plt.o = (window, canvas, wplt)
end
+60 -96
View File
@@ -1,88 +1,4 @@
# 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,
]
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
# --------------------------------------------------------------
abstract ColorScheme
getColor(scheme::ColorScheme) = getColor(scheme, 1)
@@ -119,6 +35,19 @@ 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"blue", colorant"purple", 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)]
@@ -146,28 +75,35 @@ immutable ColorGradient <: ColorScheme
colors::Vector{Colorant}
values::Vector{Float64}
function ColorGradient{T<:Colorant,S<:Real}(cs::AVec{T}, vals::AVec{S} = 0:1; alpha = nothing)
function ColorGradient{T<:Colorant,S<:Real}(cs::AVec{T}, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals))
end
# otherwise interpolate evenly between the minval and maxval
minval, maxval = minimum(vals), maximum(vals)
vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
new(convertColor(cs,alpha), vs)
# # otherwise interpolate evenly between the minval and maxval
# minval, maxval = minimum(vals), maximum(vals)
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
# new(convertColor(cs,alpha), vs)
# interpolate the colors for each value
vals = merge(linspace(0, 1, length(cs)), vals)
grad = ColorGradient(cs)
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
new(convertColor(cs, alpha), vals)
end
end
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:1; kw...)
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
# if we passed in the right number of values, create the gradient directly
cs = _gradients[s]
if vals == 0:0
vals = linspace(0, 1, length(cs))
end
ColorGradient(cs, vals; kw...)
end
function ColorGradient{T<:Real}(cs::AVec{Symbol}, vals::AVec{T} = 0:1; kw...)
function ColorGradient{T<:Real}(cs::AVec{Symbol}, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
ColorGradient(map(convertColor, cs), vals; kw...)
end
@@ -286,6 +222,16 @@ function convertHexToRGB(h::Unsigned)
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)
@@ -347,6 +293,10 @@ function get_color_palette(palette, bgcolor::@compat(Union{Colorant,ColorWrapper
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette(palette::Vector{RGBA}, bgcolor::@compat(Union{Colorant,ColorWrapper}), numcolors::Integer)
palette
end
# ----------------------------------------------------------------------------------
@@ -382,7 +332,21 @@ end
# ----------------------------------------------------------------------------------
# TODO: try to use the algorithms from https://github.com/timothyrenner/ColorBrewer.jl
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), α))
# ----------------------------------------------------------------------------------
# TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function?
# function getBackgroundRGBColor(c, d::Dict)
@@ -415,10 +379,10 @@ function handlePlotColors(::PlottingPackage, d::Dict)
end
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, initargs::Dict, n::Int)
function getSeriesRGBColor(c, plotargs::Dict, n::Int)
if c == :auto
c = autopick(initargs[:color_palette], n)
c = autopick(plotargs[:color_palette], n)
end
# c should now be a subtype of ColorScheme
+326
View File
@@ -0,0 +1,326 @@
immutable Shape
vertices::AVec
end
"get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1)
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
function weave(x,y; ordering = Vector[x,y])
ret = eltype(x)[]
done = false
while !done
for o in ordering
try
push!(ret, shift!(o))
end
# try
# push!(ret, shift!(y))
# end
end
done = isempty(x) && isempty(y)
end
ret
end
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
function makestar(n; offset = -0.5, radius = 1.0)
z1 = offset * π
z2 = z1 + π / (n)
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
Shape(weave(outercircle, innercircle)[1:end-2])
end
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
function makeshape(n; offset = -0.5, radius = 1.0)
z = offset * π
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
end
function makecross(; offset = -0.5, radius = 1.0)
z2 = offset * π
z1 = z2 - π/8
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
Shape(weave(outercircle, innercircle,
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
end
const _shapes = @compat Dict(
:ellipse => makeshape(20),
:rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3),
:dtriangle => makeshape(3, offset=0.5),
:pentagon => makeshape(5),
:hexagon => makeshape(6),
:heptagon => makeshape(7),
:octagon => makeshape(8),
:cross => makecross(offset=-0.25),
:xcross => makecross(),
:vline => Shape([(0,1),(0,-1)]),
:hline => Shape([(1,0),(-1,0)]),
)
for n in [4,5,6,7,8]
_shapes[symbol("star$n")] = makestar(n)
end
# -----------------------------------------------------------------------
immutable Font
family::AbstractString
pointsize::Int
halign::Symbol
valign::Symbol
rotation::Float64
color::Colorant
end
"Create a Font from a list of unordered features"
function font(args...)
# defaults
family = "Helvetica"
pointsize = 14
halign = :hcenter
valign = :vcenter
rotation = 0.0
color = colorant"black"
for arg in args
T = typeof(arg)
if arg == :center
halign = :hcenter
valign = :vcenter
elseif arg in (:hcenter, :left, :right)
halign = arg
elseif arg in (:vcenter, :top, :bottom)
valign = arg
elseif T <: Colorant
color = arg
elseif T <: @compat Union{Symbol,AbstractString}
try
color = parse(Colorant, string(arg))
catch
family = string(arg)
end
elseif typeof(arg) <: Integer
pointsize = arg
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
Font(family, pointsize, halign, valign, rotation, color)
end
"Wrap a string with font info"
immutable PlotText
str::@compat(AbstractString)
font::Font
end
PlotText(str) = PlotText(string(str), font())
function text(str, args...)
PlotText(string(str), font(args...))
end
# -----------------------------------------------------------------------
immutable Stroke
width
color
alpha
style
end
function stroke(args...; alpha = nothing)
# defaults
# width = 1
# color = colorant"black"
# style = :solid
width = nothing
color = nothing
style = nothing
for arg in args
T = typeof(arg)
# if arg in _allStyles
if allStyles(arg)
style = arg
elseif T <: Colorant
color = arg
elseif T <: @compat Union{Symbol,AbstractString}
try
color = parse(Colorant, string(arg))
end
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
elseif allAlphas(arg)
alpha = arg
# elseif typeof(arg) <: Real
elseif allReals(arg)
width = arg
else
warn("Unused stroke arg: $arg ($(typeof(arg)))")
end
end
Stroke(width, color, alpha, style)
end
immutable Brush
size # fillrange, markersize, or any other sizey attribute
color
alpha
end
function brush(args...; alpha = nothing)
# defaults
# sz = 1
# color = colorant"black"
size = nothing
color = nothing
for arg in args
T = typeof(arg)
if T <: Colorant
color = arg
elseif T <: @compat Union{Symbol,AbstractString}
try
color = parse(Colorant, string(arg))
end
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
elseif allAlphas(arg)
alpha = arg
# elseif typeof(arg) <: Real
elseif allReals(arg)
size = arg
else
warn("Unused brush arg: $arg ($(typeof(arg)))")
end
end
Brush(size, color, alpha)
end
# -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)"
immutable ZValues
values::Vector{Float64}
zrange::Tuple{Float64,Float64}
end
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (minimum(values), maximum(values)))
ZValues(collect(float(values)), map(Float64, zrange))
end
# -----------------------------------------------------------------------
"represents a contour or surface mesh"
immutable Surface{M<:AMat}
# x::AVec
# y::AVec
surf::M
end
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for xi in x, yi in y])
Base.Array(surf::Surface) = surf.surf
for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end
Base.copy(surf::Surface) = Surface(copy(surf.surf))
# -----------------------------------------------------------------------
type OHLC{T<:Real}
open::T
high::T
low::T
close::T
end
# @require FixedSizeArrays begin
export
P2,
P3,
BezierCurve,
curve_points,
directed_curve
typealias P2 FixedSizeArrays.Vec{2,Float64}
typealias P3 FixedSizeArrays.Vec{3,Float64}
type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end
function Base.call(bc::BezierCurve, t::Real)
p = zero(P2)
n = length(bc.control_points)-1
for i in 0:n
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
end
p
end
Base.mean(x::Real, y::Real) = 0.5*(x+y)
Base.mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps)
curve_points(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
# may create a loop if necessary. Assumes the view is [0,1]
function directed_curve(p::P2, q::P2; xview = 0:1, yview = 0:1)
mn = mean(p, q)
diff = q - p
minx, maxx = minimum(xview), maximum(xview)
miny, maxy = minimum(yview), maximum(yview)
diffpct = P2(diff[1] / (maxx - minx),
diff[2] / (maxy - miny))
# these points give the initial/final "rise"
# vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0)))
vertical_offset = P2(0, max(0.15, 0.5norm(diff)))
upper_control = p + vertical_offset
lower_control = q - vertical_offset
# try to figure out when to loop around vs just connecting straight
# TODO: choose loop direction based on sign of p[1]??
# x_close_together = abs(diffpct[1]) <= 0.05
p_is_higher = diff[2] <= 0
inside_control_points = if p_is_higher
# add curve points which will create a loop
sgn = mn[1] < 0.5 * (maxx + minx) ? -1 : 1
inside_offset = P2(0.3 * (maxx - minx), 0)
additional_offset = P2(sgn * diff[1], 0) # make it even loopier
[upper_control + sgn * (inside_offset + max(0, additional_offset)),
lower_control + sgn * (inside_offset + max(0, -additional_offset))]
else
[]
end
BezierCurve([p, upper_control, inside_control_points..., lower_control, q])
end
# end
+15
View File
@@ -37,6 +37,15 @@ end
ps(fn::@compat(AbstractString)) = ps(current(), fn)
function tex(plt::PlottingObject, fn::@compat(AbstractString))
fn = addExtension(fn, "tex")
io = open(fn, "w")
writemime(io, MIME("application/x-tex"), plt)
close(io)
end
tex(fn::@compat(AbstractString)) = tex(current(), fn)
# ----------------------------------------------------------------
@@ -45,6 +54,7 @@ ps(fn::@compat(AbstractString)) = ps(current(), fn)
"svg" => svg,
"pdf" => pdf,
"ps" => ps,
"tex" => tex,
)
function getExtension(fn::@compat(AbstractString))
@@ -102,3 +112,8 @@ gui(plt::PlottingObject = current()) = display(PlotsDisplay(), plt)
# override the REPL display to open a gui window
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::PlottingObject) = gui(plt)
# a backup for html... passes to svg
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject)
writemime(io, MIME("image/svg+xml"), plt)
end
+204 -62
View File
@@ -22,7 +22,7 @@ Base.print(io::IO, plt::Plot) = print(io, string(plt))
Base.show(io::IO, plt::Plot) = print(io, string(plt))
getplot(plt::Plot) = plt
getinitargs(plt::Plot, idx::Int = 1) = plt.initargs
getplotargs(plt::Plot, idx::Int = 1) = plt.plotargs
convertSeriesIndex(plt::Plot, n::Int) = n
# ---------------------------------------------------------
@@ -48,9 +48,9 @@ function plot(args...; kw...)
preprocessArgs!(d)
dumpdict(d, "After plot preprocessing")
plotargs = getPlotArgs(pkg, d, 1)
plotargs = merge(d, getPlotArgs(pkg, d, 1))
dumpdict(plotargs, "Plot args")
plt = plot(pkg; plotargs...) # create a new, blank plot
plt = _create_plot(pkg; plotargs...) # create a new, blank plot
delete!(d, :background_color)
plot!(plt, args...; d...) # add to it
@@ -79,6 +79,9 @@ function plot!(plt::Plot, args...; kw...)
d = Dict(kw)
preprocessArgs!(d)
# for plotting recipes, swap out the args and update the parameter dictionary
args = _apply_recipe(d, args...; kw...)
dumpdict(d, "After plot! preprocessing")
warnOnUnsupportedArgs(plt.backend, d)
@@ -87,22 +90,24 @@ function plot!(plt::Plot, args...; kw...)
groupargs = get(d, :group, nothing) == nothing ? [] : [extractGroupArgs(d[:group], args...)]
# just in case the backend needs to set up the plot (make it current or something)
preparePlotUpdate(plt)
_before_add_series(plt)
# get the list of dictionaries, one per series
kwList, xmeta, ymeta = createKWargsList(plt, groupargs..., args...; d...)
seriesArgList, xmeta, ymeta = createKWargsList(plt, groupargs..., args...; d...)
# if we were able to extract guide information from the series inputs, then update the plot
# @show xmeta, ymeta
updateDictWithMeta(d, plt.initargs, xmeta, true)
updateDictWithMeta(d, plt.initargs, ymeta, false)
updateDictWithMeta(d, plt.plotargs, xmeta, true)
updateDictWithMeta(d, plt.plotargs, ymeta, false)
# now we can plot the series
for (i,di) in enumerate(kwList)
for (i,di) in enumerate(seriesArgList)
plt.n += 1
setTicksFromStringVector(d, di, :x, :xticks)
setTicksFromStringVector(d, di, :y, :yticks)
if !stringsSupported()
setTicksFromStringVector(d, di, :x, :xticks)
setTicksFromStringVector(d, di, :y, :yticks)
end
# remove plot args
for k in keys(_plotDefaults)
@@ -111,22 +116,22 @@ function plot!(plt::Plot, args...; kw...)
dumpdict(di, "Series $i")
plot!(plt.backend, plt; di...)
_add_series(plt.backend, plt; di...)
end
addAnnotations(plt, d)
_add_annotations(plt, d)
warnOnUnsupportedScales(plt.backend, d)
# add title, axis labels, ticks, etc
if !haskey(d, :subplot)
merge!(plt.initargs, d)
dumpdict(plt.initargs, "Updating plot items")
updatePlotItems(plt, plt.initargs)
merge!(plt.plotargs, d)
dumpdict(plt.plotargs, "Updating plot items")
_update_plot(plt, plt.plotargs)
end
updatePositionAndSize(plt, d)
_update_plot_pos_size(plt, d)
current(plt)
@@ -163,37 +168,57 @@ end
# --------------------------------------------------------------------
preparePlotUpdate(plt::Plot) = nothing
_before_add_series(plt::Plot) = nothing
# --------------------------------------------------------------------
# should we update the x/y label given the meta info during input slicing?
function updateDictWithMeta(d::Dict, initargs::Dict, meta::Symbol, isx::Bool)
function updateDictWithMeta(d::Dict, plotargs::Dict, meta::Symbol, isx::Bool)
lsym = isx ? :xlabel : :ylabel
if initargs[lsym] == default(lsym)
if plotargs[lsym] == default(lsym)
d[lsym] = string(meta)
end
end
updateDictWithMeta(d::Dict, initargs::Dict, meta, isx::Bool) = nothing
updateDictWithMeta(d::Dict, plotargs::Dict, meta, isx::Bool) = nothing
# --------------------------------------------------------------------
annotations(::@compat(Void)) = []
annotations{X,Y,V}(v::AVec{@compat(Tuple{X,Y,V})}) = v
annotations{X,Y,V}(t::@compat(Tuple{X,Y,V})) = [t]
annotations(v::AVec{PlotText}) = v
annotations(v::AVec) = map(PlotText, v)
annotations(anns) = error("Expecting a tuple (or vector of tuples) for annotations: ",
"(x, y, annotation)\n got: $(typeof(anns))")
function addAnnotations(plt::Plot, d::Dict)
function _add_annotations(plt::Plot, d::Dict)
anns = annotations(get(d, :annotation, nothing))
if !isempty(anns)
addAnnotations(plt, anns)
# if we just have a list of PlotText objects, then create (x,y,text) tuples
if typeof(anns) <: AVec{PlotText}
x, y = plt[plt.n]
anns = Tuple{Float64,Float64,PlotText}[(x[i], y[i], t) for (i,t) in enumerate(anns)]
end
_add_annotations(plt, anns)
end
end
# --------------------------------------------------------------------
function Base.copy(plt::Plot)
backend(plt.backend)
plt2 = plot(; plt.plotargs...)
for sargs in plt.seriesargs
sargs = filter((k,v) -> haskey(_seriesDefaults,k), sargs)
plot!(plt2; sargs...)
end
plt2
end
# --------------------------------------------------------------------
# create a new "createKWargsList" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
@@ -203,36 +228,59 @@ end
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
all3D(d::Dict) = trueOrAllTrue(lt -> lt in (:contour, :surface, :wireframe, :image), get(d, :linetype, :none))
# missing
convertToAnyVector(v::@compat(Void); kw...) = Any[nothing], nothing
convertToAnyVector(v::@compat(Void), d::Dict) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer; kw...) = Any[zeros(0) for i in 1:n], nothing
convertToAnyVector(n::Integer, d::Dict) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Real}(v::AVec{T}; kw...) = Any[v], nothing
convertToAnyVector{T<:Real}(v::AVec{T}, d::Dict) = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}; kw...) = Any[v], nothing
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::Dict) = Any[v], nothing
# numeric matrix
convertToAnyVector{T<:Real}(v::AMat{T}; kw...) = Any[v[:,i] for i in 1:size(v,2)], nothing
function convertToAnyVector{T<:Real}(v::AMat{T}, d::Dict)
if all3D(d)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# function
convertToAnyVector(f::Function; kw...) = Any[f], nothing
convertToAnyVector(f::Function, d::Dict) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::Dict) = Any[s], nothing
# vector of OHLC
convertToAnyVector(v::AVec{OHLC}; kw...) = Any[v], nothing
convertToAnyVector(v::AVec{OHLC}, d::Dict) = Any[v], nothing
# dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::Dict) = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
convertToAnyVector(v::AVec; kw...) = Any[vi for vi in v], nothing
function convertToAnyVector(v::AVec, d::Dict)
if all(x -> typeof(x) <: Real, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
# --------------------------------------------------------------------
# in computeXandY, we take in any of the possible items, convert into proper x/y vectors, then return.
# this is also where all the "set x to 1:length(y)" happens, and also where we assert on lengths.
computeX(x::@compat(Void), y) = 1:length(y)
computeX(x::@compat(Void), y) = 1:size(y,1)
computeX(x, y) = copy(x)
computeY(x, y::Function) = map(y, x)
computeY(x, y) = copy(y)
@@ -241,7 +289,7 @@ function computeXandY(x, y)
error("If you want to plot the function `$y`, you need to define the x values somehow!")
end
x, y = computeX(x,y), computeY(x,y)
@assert length(x) == length(y)
# @assert length(x) == length(y)
x, y
end
@@ -251,10 +299,9 @@ end
# create n=max(mx,my) series arguments. the shorter list is cycled through
# note: everything should flow through this
function createKWargsList(plt::PlottingObject, x, y; kw...)
xs, xmeta = convertToAnyVector(x; kw...)
ys, ymeta = convertToAnyVector(y; kw...)
# _debugMode.on && dumpcallstack()
kwdict = Dict(kw)
xs, xmeta = convertToAnyVector(x, kwdict)
ys, ymeta = convertToAnyVector(y, kwdict)
mx = length(xs)
my = length(ys)
@@ -262,7 +309,7 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
for i in 1:max(mx, my)
# try to set labels using ymeta
d = Dict(kw)
d = copy(kwdict)
if !haskey(d, :label) && ymeta != nothing
if isa(ymeta, Symbol)
d[:label] = string(ymeta)
@@ -275,17 +322,26 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
numUncounted = get(d, :numUncounted, 0)
n = plt.n + i + numUncounted
dumpdict(d, "before getSeriesArgs")
d = getSeriesArgs(plt.backend, getinitargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
dumpdict(d, "after getSeriesArgs")
d[:x], d[:y] = computeXandY(xs[mod1(i,mx)], ys[mod1(i,my)])
lt = d[:linetype]
if isa(d[:y], Surface)
if lt in (:contour, :surface, :wireframe, :image)
z = d[:y]
d[:y] = 1:size(z,2)
d[lt == :image ? :zcolor : :z] = z
end
end
if haskey(d, :idxfilter)
d[:x] = d[:x][d[:idxfilter]]
d[:y] = d[:y][d[:idxfilter]]
end
# for linetype `line`, need to sort by x values
if d[:linetype] == :line
if lt == :line
# order by x
indices = sortperm(d[:x])
d[:x] = d[:x][indices]
@@ -293,6 +349,14 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
d[:linetype] = :path
end
# map functions to vectors
if isa(d[:zcolor], Function)
d[:zcolor] = map(d[:zcolor], d[:x])
end
if isa(d[:fillrange], Function)
d[:fillrange] = map(d[:fillrange], d[:x])
end
# cleanup those fields that were used only for generating kw args
for k in (:idxfilter, :numUncounted, :dataframe)
delete!(d, k)
@@ -324,9 +388,23 @@ function createKWargsList(plt::PlottingObject, y; kw...)
createKWargsList(plt, nothing, y; kw...)
end
# contours or surfaces... irregular data
# 3d line or scatter
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, zvec::AVec; kw...)
error("TODO: contours or surfaces... irregular data")
d = Dict(kw)
if !(get(d, :linetype, :none) in _3dTypes)
d[:linetype] = :path3d
end
createKWargsList(plt, x, y; z=zvec, d...)
end
function createKWargsList{T<:Real}(plt::PlottingObject, z::AMat{T}; kw...)
d = Dict(kw)
if all3D(d)
n,m = size(z)
createKWargsList(plt, 1:n, 1:m, z; kw...)
else
createKWargsList(plt, nothing, z; kw...)
end
end
# contours or surfaces... function grid
@@ -346,13 +424,42 @@ function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec, y::AVec, zmat::
@assert x == sort(x)
@assert y == sort(y)
@assert size(zmat) == (length(x), length(y))
surf = Array(Any,1,1)
surf[1,1] = convert(Matrix{Float64}, zmat)
createKWargsList(plt, x, y; kw..., surface = surf, linetype = :contour)
# surf = Surface(convert(Matrix{Float64}, zmat))
# surf = Array(Any,1,1)
# surf[1,1] = convert(Matrix{Float64}, zmat)
d = Dict(kw)
d[:z] = Surface(convert(Matrix{Float64}, zmat))
if !(get(d, :linetype, :none) in (:contour, :surface, :wireframe))
d[:linetype] = :contour
end
createKWargsList(plt, x, y; d...) #, z = surf)
end
# contours or surfaces... general x, y grid
function createKWargsList{T<:Real}(plt::PlottingObject, x::AMat{T}, y::AMat{T}, zmat::AMat{T}; kw...)
@assert size(zmat) == size(x) == size(y)
surf = Surface(convert(Matrix{Float64}, zmat))
# surf = Array(Any,1,1)
# surf[1,1] = convert(Matrix{Float64}, zmat)
d = Dict(kw)
d[:z] = Surface(convert(Matrix{Float64}, zmat))
if !(get(d, :linetype, :none) in (:contour, :surface, :wireframe))
d[:linetype] = :contour
end
createKWargsList(plt, Any[x], Any[y]; d...) #kw..., z = surf, linetype = :contour)
end
function createKWargsList(plt::PlottingObject, surf::Surface; kw...)
createKWargsList(plt, 1:size(surf.surf,1), 1:size(surf.surf,2), convert(Matrix{Float64}, surf.surf); kw...)
end
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, surf::Surface; kw...)
createKWargsList(plt, x, y, convert(Matrix{Float64}, surf.surf); kw...)
end
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs; kw...)
error("Can't pass a Function or Vector{Function} for y without also passing x")
createKWargsList(plt, f, xmin(plt), xmax(plt); kw...)
end
# list of functions
@@ -363,7 +470,7 @@ end
# special handling... xmin/xmax with function(s)
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs, xmin::Real, xmax::Real; kw...)
width = plt.initargs[:size][1]
width = get(plt.plotargs, :size, (100,))[1]
x = collect(linspace(xmin, xmax, width)) # we don't need more than the width
createKWargsList(plt, x, f; kw...)
end
@@ -376,6 +483,19 @@ createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs,
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, linspace(umin, umax, numPoints); kw...)
# special handling... 3D parametric function(s)
createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, fz, linspace(umin, umax, numPoints); kw...)
# (x,y) tuples
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::AVec{Tuple{R1,R2}}; kw...)
createKWargsList(plt, unzip(xy)...; kw...)
end
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::Tuple{R1,R2}; kw...)
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
end
# special handling... no args... 1 series
@@ -386,7 +506,7 @@ function createKWargsList(plt::PlottingObject; kw...)
return [], nothing, nothing
# error("Called plot/subplot without args... must set y in the keyword args. Example: plot(; y=rand(10))")
end
if haskey(d, :x)
return createKWargsList(plt, d[:x], d[:y]; kw...)
else
@@ -396,16 +516,34 @@ end
# --------------------------------------------------------------------
"For DataFrame support. Imports DataFrames and defines the necessary methods which support them."
function dataframes()
@eval import DataFrames
@eval function createKWargsList(plt::PlottingObject, df::DataFrames.DataFrame, args...; kw...)
# @require FixedSizeArrays begin
unzip{T}(x::AVec{FixedSizeArrays.Vec{2,T}}) = T[xi[1] for xi in x], T[xi[2] for xi in x]
unzip{T}(x::FixedSizeArrays.Vec{2,T}) = T[x[1]], T[x[2]]
function createKWargsList{T<:Real}(plt::PlottingObject, xy::AVec{FixedSizeArrays.Vec{2,T}}; kw...)
createKWargsList(plt, unzip(xy)...; kw...)
end
function createKWargsList{T<:Real}(plt::PlottingObject, xy::FixedSizeArrays.Vec{2,T}; kw...)
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
end
# end
# --------------------------------------------------------------------
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
@require DataFrames begin
function createKWargsList(plt::PlottingObject, df::DataFrames.AbstractDataFrame, args...; kw...)
createKWargsList(plt, args...; kw..., dataframe = df)
end
# expecting the column name of a dataframe that was passed in... anything else should error
@eval function extractGroupArgs(s::Symbol, df::DataFrames.DataFrame, args...)
function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
if haskey(df, s)
return extractGroupArgs(df[s])
else
@@ -413,20 +551,24 @@ function dataframes()
end
end
@eval function getDataFrameFromKW(; kw...)
for (k,v) in kw
if k == :dataframe
return v
end
function getDataFrameFromKW(d::Dict)
# for (k,v) in kw
# if k == :dataframe
# return v
# end
# end
get(d, :dataframe) do
error("Missing dataframe argument!")
end
error("Missing dataframe argument in arguments!")
end
# the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
@eval convertToAnyVector(s::Symbol; kw...) = Any[getDataFrameFromKW(;kw...)[s]], s
@eval convertToAnyVector(v::AVec{Symbol}; kw...) = (df = getDataFrameFromKW(;kw...); Any[df[s] for s in v]), v
# convertToAnyVector(s::Symbol; kw...) = Any[getDataFrameFromKW(;kw...)[s]], s
# convertToAnyVector(v::AVec{Symbol}; kw...) = (df = getDataFrameFromKW(;kw...); Any[df[s] for s in v]), v
convertToAnyVector(s::Symbol, d::Dict) = Any[getDataFrameFromKW(d)[s]], s
convertToAnyVector(v::AVec{Symbol}, d::Dict) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
end
# --------------------------------------------------------------------
+121
View File
@@ -0,0 +1,121 @@
immutable NoPackage <: PlottingPackage end
const _backendType = Dict{Symbol, DataType}(:none => NoPackage)
const _backendSymbol = Dict{DataType, Symbol}(NoPackage => :none)
const _backends = Symbol[]
const _initialized_backends = Set{Symbol}()
backends() = _backends
backend_name() = CURRENT_BACKEND.sym
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
macro init_plotting_pkg(s)
str = lowercase(string(s))
sym = symbol(str)
T = symbol(string(s) * "Package")
esc(quote
immutable $T <: PlottingPackage end
export $sym
$sym(; kw...) = (default(; kw...); backend(symbol($str)))
backend_name(::$T) = symbol($str)
push!(_backends, symbol($str))
_backendType[symbol($str)] = $T
_backendSymbol[$T] = symbol($str)
include("backends/" * $str * ".jl")
end)
end
@init_plotting_pkg Immerse
@init_plotting_pkg Gadfly
@init_plotting_pkg PyPlot
@init_plotting_pkg Qwt
@init_plotting_pkg UnicodePlots
@init_plotting_pkg Winston
@init_plotting_pkg Bokeh
@init_plotting_pkg Plotly
@init_plotting_pkg PlotlyJS
@init_plotting_pkg GR
@init_plotting_pkg GLVisualize
@init_plotting_pkg PGFPlots
include("backends/web.jl")
include("backends/supported.jl")
# ---------------------------------------------------------
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
_update_plot(pkg::PlottingPackage, plt::Plot, d::Dict) = error("_update_plot($pkg, plt, d) is not implemented")
_update_plot_pos_size{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing
subplot(pkg::PlottingPackage; kw...) = error("subplot($pkg; kw...) is not implemented")
subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
# ---------------------------------------------------------
type CurrentBackend
sym::Symbol
pkg::PlottingPackage
end
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
return backend(symbol(lowercase(pkgstr)))
end
end
# the default if nothing else is installed
backend(:plotly)
end
# ---------------------------------------------------------
"""
Returns the current plotting package name. Initializes package on first call.
"""
function backend()
global CURRENT_BACKEND
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
end
sym = CURRENT_BACKEND.sym
if !(sym in _initialized_backends)
# initialize
println("[Plots.jl] Initializing backend: ", sym)
inst = _backend_instance(sym)
try
_initialize_backend(inst)
catch err
warn("Couldn't initialize $sym. (might need to install it?)")
rethrow(err)
end
push!(_initialized_backends, sym)
end
CURRENT_BACKEND.pkg
end
"""
Set the plot backend.
"""
function backend(pkg::PlottingPackage)
CURRENT_BACKEND.sym = backend_name(pkg)
CURRENT_BACKEND.pkg = pkg
end
function backend(modname::Symbol)
CURRENT_BACKEND.sym = modname
CURRENT_BACKEND.pkg = _backend_instance(modname)
end
+110 -91
View File
@@ -14,102 +14,115 @@ plot(recipe::PlotRecipe, args...; kw...) = plot(getRecipeXY(recipe)..., args...;
plot!(recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
plot!(plt::Plot, recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
num_series(x::AMat) = size(x,2)
num_series(x) = 1
# -------------------------------------------------
_apply_recipe(d::Dict; kw...) = ()
function rotate(x::Real, y::Real, θ::Real; center = (0,0))
cx = x - center[1]
cy = y - center[2]
xrot = cx * cos(θ) - cy * sin(θ)
yrot = cy * cos(θ) + cx * sin(θ)
xrot + center[1], yrot + center[2]
end
# -------------------------------------------------
type EllipseRecipe <: PlotRecipe
w::Float64
h::Float64
x::Float64
y::Float64
θ::Float64
end
EllipseRecipe(w,h,x,y) = EllipseRecipe(w,h,x,y,0)
# return x,y coords of a rotated ellipse, centered at the origin
function rotatedEllipse(w, h, x, y, θ, rotθ)
# # coord before rotation
xpre = w * cos(θ)
ypre = h * sin(θ)
# rotate and translate
r = rotate(xpre, ypre, rotθ)
x + r[1], y + r[2]
end
function getRecipeXY(ep::EllipseRecipe)
x, y = unzip([rotatedEllipse(ep.w, ep.h, ep.x, ep.y, u, ep.θ) for u in linspace(0,2π,100)])
top = rotate(0, ep.h, ep.θ)
right = rotate(ep.w, 0, ep.θ)
linex = Float64[top[1], 0, right[1]] + ep.x
liney = Float64[top[2], 0, right[2]] + ep.y
Any[x, linex], Any[y, liney]
end
function getRecipeArgs(ep::EllipseRecipe)
[(:line, (3, [:dot :solid], [:red :blue], :path))]
end
# -------------------------------------------------
"Correlation scatter matrix"
function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
colors = :redsblues,
labels = nothing, kw...)
m = size(mat,2)
centers = Float64[mean(extrema(mat[:,i])) for i in 1:m]
# might be a mistake?
@assert m <= 20
@assert size(corrmat) == (m,m)
# create a subplot grid, and a gradient from -1 to 1
p = subplot(rand(0,m^2); n=m^2, leg=false, grid=false, kw...)
cgrad = ColorGradient(colors, [-1,1])
# make all the plots
for i in 1:m
for j in 1:m
idx = p.layout[i,j]
plt = p.plts[idx]
if i==j
# histogram on diagonal
histogram!(plt, mat[:,i], c=:black)
i > 1 && plot!(plt, yticks = :none)
elseif i < j
# annotate correlation value in upper triangle
mi, mj = centers[i], centers[j]
plot!(plt, [mj], [mi],
ann = (mj, mi, text(@sprintf("Corr:\n%0.3f", corrmat[i,j]), 15)),
yticks=:none)
else
# scatter plots in lower triangle; color determined by correlation
c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3)
scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, smooth=true)
end
if labels != nothing && length(labels) >= m
i == m && xlabel!(plt, string(labels[j]))
j == 1 && ylabel!(plt, string(labels[i]))
end
# if it's not a recipe, just do nothing and return the args
function _apply_recipe(d::Dict, args...; issubplot=false, kw...)
if issubplot && !haskey(d, :n) && !haskey(d, :layout)
# put in a sensible default
d[:n] = maximum(map(num_series, args))
end
end
# link the axes
subplot!(p, link = (r,c) -> (true, r!=c))
args
end
# # -------------------------------------------------
# function rotate(x::Real, y::Real, θ::Real; center = (0,0))
# cx = x - center[1]
# cy = y - center[2]
# xrot = cx * cos(θ) - cy * sin(θ)
# yrot = cy * cos(θ) + cx * sin(θ)
# xrot + center[1], yrot + center[2]
# end
# # -------------------------------------------------
# type EllipseRecipe <: PlotRecipe
# w::Float64
# h::Float64
# x::Float64
# y::Float64
# θ::Float64
# end
# EllipseRecipe(w,h,x,y) = EllipseRecipe(w,h,x,y,0)
# # return x,y coords of a rotated ellipse, centered at the origin
# function rotatedEllipse(w, h, x, y, θ, rotθ)
# # # coord before rotation
# xpre = w * cos(θ)
# ypre = h * sin(θ)
# # rotate and translate
# r = rotate(xpre, ypre, rotθ)
# x + r[1], y + r[2]
# end
# function getRecipeXY(ep::EllipseRecipe)
# x, y = unzip([rotatedEllipse(ep.w, ep.h, ep.x, ep.y, u, ep.θ) for u in linspace(0,2π,100)])
# top = rotate(0, ep.h, ep.θ)
# right = rotate(ep.w, 0, ep.θ)
# linex = Float64[top[1], 0, right[1]] + ep.x
# liney = Float64[top[2], 0, right[2]] + ep.y
# Any[x, linex], Any[y, liney]
# end
# function getRecipeArgs(ep::EllipseRecipe)
# [(:line, (3, [:dot :solid], [:red :blue], :path))]
# end
# # -------------------------------------------------
# "Correlation scatter matrix"
# function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
# colors = :redsblues,
# labels = nothing, kw...)
# m = size(mat,2)
# centers = Float64[mean(extrema(mat[:,i])) for i in 1:m]
# # might be a mistake?
# @assert m <= 20
# @assert size(corrmat) == (m,m)
# # create a subplot grid, and a gradient from -1 to 1
# p = subplot(rand(0,m^2); n=m^2, leg=false, grid=false, kw...)
# cgrad = ColorGradient(colors, [-1,1])
# # make all the plots
# for i in 1:m
# for j in 1:m
# idx = p.layout[i,j]
# plt = p.plts[idx]
# if i==j
# # histogram on diagonal
# histogram!(plt, mat[:,i], c=:black)
# i > 1 && plot!(plt, yticks = :none)
# elseif i < j
# # annotate correlation value in upper triangle
# mi, mj = centers[i], centers[j]
# plot!(plt, [mj], [mi],
# ann = (mj, mi, text(@sprintf("Corr:\n%0.3f", corrmat[i,j]), 15)),
# yticks=:none)
# else
# # scatter plots in lower triangle; color determined by correlation
# c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3)
# scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, smooth=true)
# end
# if labels != nothing && length(labels) >= m
# i == m && xlabel!(plt, string(labels[j]))
# j == 1 && ylabel!(plt, string(labels[i]))
# end
# end
# end
# # link the axes
# subplot!(p, link = (r,c) -> (true, r!=c))
# end
"Sparsity plot... heatmap of non-zero values of a matrix"
function spy{T<:Real}(y::AMat{T}; kw...)
@@ -117,3 +130,9 @@ function spy{T<:Real}(y::AMat{T}; kw...)
heatmap(J, I; leg=false, yflip=true, nbins=size(y), kw...)
end
"Adds a+bx... straight line over the current plot"
function abline!(plt::Plot, a, b; kw...)
plot!(plt, [extrema(plt)...], x -> b + a*x; kw...)
end
abline!(args...; kw...) = abline!(current(), args...; kw...)
+48 -86
View File
@@ -81,8 +81,8 @@ Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c
Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]]
# handle "linking" the subplot axes together
# each backend should implement the handleLinkInner and expandLimits! methods
function linkAxis(subplt::Subplot, isx::Bool)
# each backend should implement the _remove_axis and _expand_limits methods
function link_axis(subplt::Subplot, isx::Bool)
# collect the list of plots and the expanded limits for those plots that should be linked on this axis
includedPlots = Any[]
@@ -104,7 +104,7 @@ function linkAxis(subplt::Subplot, isx::Bool)
isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone)
push!(includedPlots, (plt, isinner, k))
expandLimits!(lims[k], plt, isx)
_expand_limits(lims[k], plt, isx)
end
end
@@ -112,7 +112,7 @@ function linkAxis(subplt::Subplot, isx::Bool)
# do the axis adjustments
for (plt, isinner, k) in includedPlots
if isinner
handleLinkInner(plt, isx)
_remove_axis(plt, isx)
end
(isx ? xlims! : ylims!)(plt, lims[k]...)
end
@@ -128,14 +128,14 @@ Base.print(io::IO, subplt::Subplot) = print(io, string(subplt))
Base.show(io::IO, subplt::Subplot) = print(io, string(subplt))
getplot(subplt::Subplot, idx::Int = subplt.n) = subplt.plts[mod1(idx, subplt.p)]
getinitargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).initargs
getplotargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).plotargs
convertSeriesIndex(subplt::Subplot, n::Int) = ceil(Int, n / subplt.p)
# ------------------------------------------------------------
function validateSubplotSupported()
if !subplotSupported()
error(CURRENT_BACKEND.sym, " does not support the subplot/subplot! commands at this time. Try one of: ", join(filter(pkg->subplotSupported(backendInstance(pkg)), backends()),", "))
error(CURRENT_BACKEND.sym, " does not support the subplot/subplot! commands at this time. Try one of: ", join(filter(pkg->subplotSupported(_backend_instance(pkg)), backends()),", "))
end
end
@@ -156,6 +156,9 @@ function subplot(args...; kw...)
d = Dict(kw)
preprocessArgs!(d)
# for plotting recipes, swap out the args and update the parameter dictionary
args = _apply_recipe(d, args...; kw..., issubplot=true)
# figure out the layout
layoutarg = get(d, :layout, nothing)
if layoutarg != nothing
@@ -175,12 +178,12 @@ function subplot(args...; kw...)
di = getPlotArgs(pkg, d, i)
di[:subplot] = true
dumpdict(di, "Plot args (subplot $i)")
push!(plts, plot(pkg; di...))
push!(plts, _create_plot(pkg; di...))
end
# create the object and do the plotting
subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout, d, false, false, false, (r,c) -> (nothing,nothing))
subplot!(subplt, args...; kw...)
subplot!(subplt, args...; d...)
subplt
end
@@ -209,29 +212,8 @@ function subplot{P<:PlottingPackage}(plts::AVec{Plot{P}}, layout::SubplotLayout,
n = sum([plt.n for plt in plts])
subplt = Subplot(nothing, collect(plts), P(), p, n, layout, Dict(), false, false, false, (r,c) -> (nothing,nothing))
# preprocessArgs!(d)
# #
# for (i,plt) in enumerate(plts)
# di = copy(plt.initargs)
# for ck in (:background_color, :foreground_color, :color_palette)
# # if we have a value to override, do it
# if haskey(d, ck)
# di[ck] = get_mod(d[ck], i)
# end
# # build a new dict from the initargs of the plots
# iargs = Dict()
# for k in keys(_plotDefaults)
# iargs[k] = Any[plt.initargs[k] for plt in plts]'
# end
# merge!(iargs, d)
preprocessSubplot(subplt, d)
postprocessSubplot(subplt, d)
_preprocess_subplot(subplt, d)
_postprocess_subplot(subplt, d)
subplt
end
@@ -241,26 +223,28 @@ end
# ------------------------------------------------------------------------------------------------
function preprocessSubplot(subplt::Subplot, d::Dict)
function _preprocess_subplot(subplt::Subplot, d::Dict, args = ())
validateSubplotSupported()
preprocessArgs!(d)
# for plotting recipes, swap out the args and update the parameter dictionary
args = _apply_recipe(d, args...; d..., issubplot=true)
dumpdict(d, "After subplot! preprocessing")
# get the full initargs, overriding any new settings
# TODO: subplt.initargs should probably be merged sooner and actually used
# get the full plotargs, overriding any new settings
# TODO: subplt.plotargs should probably be merged sooner and actually used
# for color selection, etc. (i.e. if we overwrite the subplot palettes to [:heat :rainbow])
# then we need to overwrite plt[1].initargs[:color_palette] to :heat before it's actually used
# then we need to overwrite plt[1].plotargs[:color_palette] to :heat before it's actually used
# for color selection!
# first merge the new args into the subplot's initargs. then process the plot args and merge
# those into the plot's initargs. (example... `palette = [:blues :reds]` goes into subplt.initargs,
# then the ColorGradient for :blues/:reds is merged into plot 1/2 initargs, which is then used for color selection)
# first merge the new args into the subplot's plotargs. then process the plot args and merge
# those into the plot's plotargs. (example... `palette = [:blues :reds]` goes into subplt.plotargs,
# then the ColorGradient for :blues/:reds is merged into plot 1/2 plotargs, which is then used for color selection)
for i in 1:length(subplt.layout)
# di = getPlotArgs(backend(), subplt.initargs, i)
# merge!(subplt.plts[i].initargs, di)
subplt.plts[i].initargs = getPlotArgs(backend(), merge(subplt.plts[i].initargs, d), i)
subplt.plts[i].plotargs = getPlotArgs(backend(), merge(subplt.plts[i].plotargs, d), i)
end
merge!(subplt.initargs, d)
merge!(subplt.plotargs, d)
# process links. TODO: extract to separate function
for s in (:linkx, :linky, :linkfunc)
@@ -269,43 +253,28 @@ function preprocessSubplot(subplt::Subplot, d::Dict)
delete!(d, s)
end
end
args
end
function postprocessSubplot(subplt::Subplot, d::Dict)
function _postprocess_subplot(subplt::Subplot, d::Dict)
# init (after plot creation)
if !subplt.initialized
subplt.initialized = buildSubplotObject!(subplt, false)
subplt.initialized = _create_subplot(subplt, false)
end
# add title, axis labels, ticks, etc
for (i,plt) in enumerate(subplt.plts)
# # # get the full initargs, overriding any new settings
# # di = copy(merge(plt.initargs, d))
# di = copy(d)
# for (k,v) in di
# if typeof(v) <: AVec
# di[k] = v[mod1(i, length(v))]
# elseif typeof(v) <: AMat
# m = size(v,2)
# di[k] = (size(v,1) == 1 ? v[1, mod1(i, m)] : v[:, mod1(i, m)])
# end
# end
# di = merge!(plt.initargs, di)
di = plt.initargs
di = plt.plotargs
dumpdict(di, "Updating sp $i")
updatePlotItems(plt, di)
_update_plot(plt, di)
end
updatePositionAndSize(subplt, d)
_update_plot_pos_size(subplt, d)
# handle links
subplt.linkx && linkAxis(subplt, true)
subplt.linky && linkAxis(subplt, false)
subplt.linkx && link_axis(subplt, true)
subplt.linky && link_axis(subplt, false)
# set this to be current
current(subplt)
@@ -335,14 +304,14 @@ function subplot!(subplt::Subplot, args...; kw...)
# validateSubplotSupported()
d = Dict(kw)
preprocessSubplot(subplt, d)
args = _preprocess_subplot(subplt, d, args)
# create the underlying object (each backend will do this differently)
# note: we call it once before doing the individual plots, and once after
# this is because some backends need to set up the subplots and then plot,
# and others need to do it the other way around
if !subplt.initialized
subplt.initialized = buildSubplotObject!(subplt, true)
subplt.initialized = _create_subplot(subplt, true)
end
# handle grouping
@@ -365,17 +334,6 @@ function subplot!(subplt::Subplot, args...; kw...)
plt = getplot(subplt)
plt.n += 1
# # update the plot's initargs for things such as palettes, etc
# for (k,v) in subplt.initargs
# haskey(_plotDefaults, k) || continue
# if typeof(v) <: AVec
# plt.initargs[k] = v[mod1(i, length(v))]
# elseif typeof(v) <: AMat
# m = size(v,2)
# plt.initargs[k] = (size(v,1) == 1 ? v[1, mod1(i, m)] : v[:, mod1(i, m)])
# end
# end
# cleanup the dictionary that we pass into the plot! command
di[:show] = false
di[:subplot] = true
@@ -384,12 +342,12 @@ function subplot!(subplt::Subplot, args...; kw...)
delete!(di, k)
end
dumpdict(di, "subplot! kwList $i")
dumpdict(plt.initargs, "plt.initargs before plotting")
dumpdict(plt.plotargs, "plt.plotargs before plotting")
_plot_from_subplot!(plt; di...)
_add_series_subplot(plt; di...)
end
postprocessSubplot(subplt, d)
_postprocess_subplot(subplt, d)
# show it automatically?
if haskey(d, :show) && d[:show]
@@ -401,18 +359,22 @@ end
function _plot_from_subplot!(plt::Plot, args...; kw...)
function _add_series_subplot(plt::Plot, args...; kw...)
d = Dict(kw)
setTicksFromStringVector(d, d, :x, :xticks)
setTicksFromStringVector(d, d, :y, :yticks)
# dumpdict(d, "Plot from subplot")
plot!(plt.backend, plt; d...)
_add_series(plt.backend, plt; d...)
addAnnotations(plt, d)
_add_annotations(plt, d)
warnOnUnsupportedScales(plt.backend, d)
end
# --------------------------------------------------------------------
function Base.copy(subplt::Subplot)
subplot(subplt.plts, subplt.layout, subplt.plotargs)
end
+3 -148
View File
@@ -13,7 +13,7 @@ type Plot{T<:PlottingPackage} <: PlottingObject{T}
n::Int # number of series
# store these just in case
initargs::Dict
plotargs::Dict
seriesargs::Vector{Dict} # args for each series
end
@@ -38,8 +38,8 @@ type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
p::Int # number of plots
n::Int # number of series
layout::L
# initargs::Vector{Dict}
initargs::Dict
# plotargs::Vector{Dict}
plotargs::Dict
initialized::Bool
linkx::Bool
linky::Bool
@@ -47,148 +47,3 @@ type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
end
# -----------------------------------------------------------------------
immutable Shape
vertices::AVec
end
"get an array of tuples of points on a circle with radius `r`"
function partialcircle(start_θ, end_θ, n = 20, r=1)
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
end
"interleave 2 vectors into each other (like a zipper's teeth)"
function weave(x,y; ordering = Vector[x,y])
ret = eltype(x)[]
done = false
while !done
for o in ordering
try
push!(ret, shift!(o))
end
# try
# push!(ret, shift!(y))
# end
end
done = isempty(x) && isempty(y)
end
ret
end
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
function makestar(n; offset = -0.5, radius = 1.0)
z1 = offset * π
z2 = z1 + π / (n)
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
Shape(weave(outercircle, innercircle)[1:end-2])
end
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
function makeshape(n; offset = -0.5, radius = 1.0)
z = offset * π
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
end
function makecross(; offset = -0.5, radius = 1.0)
z2 = offset * π
z1 = z2 - π/8
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
Shape(weave(outercircle, innercircle,
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
end
const _shapes = @compat Dict(
:ellipse => makeshape(20),
:rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3),
:dtriangle => makeshape(3, offset=0.5),
:pentagon => makeshape(5),
:hexagon => makeshape(6),
:heptagon => makeshape(7),
:octagon => makeshape(8),
:cross => makecross(offset=-0.25),
:xcross => makecross(),
)
for n in [4,5,6,7,8]
_shapes[symbol("star$n")] = makestar(n)
end
# -----------------------------------------------------------------------
immutable Font
family::AbstractString
pointsize::Int
halign::Symbol
valign::Symbol
rotation::Float64
color::Colorant
end
"Create a Font from a list of unordered features"
function font(args...)
# defaults
family = "Helvetica"
pointsize = 14
halign = :hcenter
valign = :vcenter
rotation = 0.0
color = colorant"black"
for arg in args
T = typeof(arg)
if arg == :center
halign = :hcenter
valign = :vcenter
elseif arg in (:hcenter, :left, :right)
halign = arg
elseif arg in (:vcenter, :top, :bottom)
valign = arg
elseif T <: Colorant
color = arg
elseif T <: @compat Union{Symbol,AbstractString}
try
color = parse(Colorant, string(arg))
catch
family = string(arg)
end
elseif typeof(arg) <: Integer
pointsize = arg
elseif typeof(arg) <: Real
rotation = convert(Float64, arg)
else
warn("Unused font arg: $arg ($(typeof(arg)))")
end
end
Font(family, pointsize, halign, valign, rotation, color)
end
"Wrap a string with font info"
immutable PlotText
str::@compat(AbstractString)
font::Font
end
function text(str, args...)
PlotText(string(str), font(args...))
end
# -----------------------------------------------------------------------
type OHLC{T<:Real}
open::T
high::T
low::T
close::T
end
+145 -16
View File
@@ -116,6 +116,9 @@ end
# ------------------------------------------------------------------------------------
nop() = nothing
get_mod(v::AVec, idx::Int) = v[mod1(idx, length(v))]
get_mod(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
get_mod(v, idx::Int) = v
@@ -131,7 +134,7 @@ maketuple{T,S}(x::@compat(Tuple{T,S})) = x
unzip{T,S}(v::AVec{@compat(Tuple{T,S})}) = [vi[1] for vi in v], [vi[2] for vi in v]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function expandLimits!(lims, x)
function _expand_limits(lims, x)
try
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
@@ -162,7 +165,6 @@ end
function replaceAliases!(d::Dict, aliases::Dict)
ks = collect(keys(d))
# for (k,v) in d
for k in ks
if haskey(aliases, k)
d[aliases[k]] = d[k]
@@ -172,7 +174,9 @@ function replaceAliases!(d::Dict, aliases::Dict)
end
createSegments(z) = collect(repmat(z',2,1))[2:end]
Base.first(c::Colorant) = c
Base.first(x::Symbol) = x
sortedkeys(d::Dict) = sort(collect(keys(d)))
@@ -186,10 +190,23 @@ function fakedata(sz...)
y
end
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
istuple(::Tuple) = true
istuple(::Any) = false
isvector(::AVec) = true
isvector(::Any) = false
ismatrix(::AMat) = true
ismatrix(::Any) = false
isscalar(::Real) = true
isscalar(::Any) = false
# ticksType{T<:Real,S<:Real}(ticks::@compat(Tuple{T,S})) = :limits
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
ticksType{T<:AVec,S<:AVec}(ticks::@compat(Tuple{T,S})) = :ticks_and_labels
ticksType(ticks) = :invalid
@@ -198,6 +215,108 @@ limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
# ---------------------------------------------------------------
wraptuple(x::@compat(Tuple)) = x
wraptuple(x) = (x,)
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
trueOrAllTrue(f::Function, x) = f(x)
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
allShapes(arg) = trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg) ||
trueOrAllTrue(a -> isa(a, Shape), arg)
allAlphas(arg) = trueOrAllTrue(a -> (typeof(a) <: Real && a > 0 && a < 1) ||
(typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg)
allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg)
allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
# ---------------------------------------------------------------
"""
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
```
with(:gadfly, size=(400,400), type=:hist) do
plot(rand(10))
plot(rand(10))
end
```
"""
function with(f::Function, args...; kw...)
# dict to store old and new keyword args for anything that changes
newdefs = Dict(kw)
olddefs = Dict()
for k in keys(newdefs)
olddefs[k] = default(k)
end
# save the backend
if CURRENT_BACKEND.sym == :none
pickDefaultBackend()
end
oldbackend = CURRENT_BACKEND.sym
for arg in args
# change backend?
if arg in backends()
backend(arg)
end
# # TODO: generalize this strategy to allow args as much as possible
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
# # TODO: can we generalize this enough to also do something similar in the plot commands??
# k = :linetype
# if arg in _allTypes
# olddefs[k] = default(k)
# newdefs[k] = arg
# elseif haskey(_typeAliases, arg)
# olddefs[k] = default(k)
# newdefs[k] = _typeAliases[arg]
# end
k = :legend
if arg in (k, :leg)
olddefs[k] = default(k)
newdefs[k] = true
end
k = :grid
if arg == k
olddefs[k] = default(k)
newdefs[k] = true
end
end
# display(olddefs)
# display(newdefs)
# now set all those defaults
default(; newdefs...)
# call the function
ret = f()
# put the defaults back
default(; olddefs...)
# revert the backend
if CURRENT_BACKEND.sym != oldbackend
backend(oldbackend)
end
# return the result of the function
ret
end
# ---------------------------------------------------------------
@@ -213,8 +332,8 @@ end
debugshow(x) = show(x)
debugshow(x::AbstractArray) = print(summary(x))
function dumpdict(d::Dict, prefix = "")
_debugMode.on || return
function dumpdict(d::Dict, prefix = "", alwaysshow = false)
_debugMode.on || alwaysshow || return
println()
if prefix != ""
println(prefix, ":")
@@ -316,15 +435,15 @@ function supportGraph(allvals, func)
y = ASCIIString[]
for val in vals
for b in bs
supported = func(Plots.backendInstance(b))
supported = func(Plots._backend_instance(b))
if val in supported
push!(x, string(b))
push!(y, string(val))
end
end
end
end
n = length(vals)
scatter(x,y,
m=:rect,
ms=10,
@@ -345,7 +464,7 @@ function dumpSupportGraphs()
for func in (supportGraphArgs, supportGraphTypes, supportGraphStyles,
supportGraphMarkers, supportGraphScales, supportGraphAxes)
plt = func()
png(IMG_DIR * "/supported/$(string(func))")
png(joinpath(Pkg.dir("ExamplePlots"), "docs", "examples", "img", "supported", "$(string(func))"))
end
end
@@ -354,12 +473,22 @@ end
# Some conversion functions
# note: I borrowed these conversion constants from Compose.jl's Measure
const INCH_SCALAR = 25.4
const PX_SCALAR = 1 / 3.78
inch2px(inches::Real) = float(inches * INCH_SCALAR / PX_SCALAR)
px2inch(px::Real) = float(px * PX_SCALAR / INCH_SCALAR)
inch2mm(inches::Real) = float(inches * INCH_SCALAR)
mm2inch(mm::Real) = float(mm / INCH_SCALAR)
px2mm(px::Real) = float(px * PX_SCALAR)
mm2px(mm::Real) = float(px / PX_SCALAR)
const PX_PER_INCH = 100
const DPI = PX_PER_INCH
const MM_PER_INCH = 25.4
const MM_PER_PX = MM_PER_INCH / PX_PER_INCH
inch2px(inches::Real) = float(inches * PX_PER_INCH)
px2inch(px::Real) = float(px / PX_PER_INCH)
inch2mm(inches::Real) = float(inches * MM_PER_INCH)
mm2inch(mm::Real) = float(mm / MM_PER_INCH)
px2mm(px::Real) = float(px * MM_PER_PX)
mm2px(mm::Real) = float(px / MM_PER_PX)
"Smallest x in plot"
xmin(plt::Plot) = minimum([minimum(d[:x]) for d in plt.seriesargs])
"Largest x in plot"
xmax(plt::Plot) = maximum([maximum(d[:x]) for d in plt.seriesargs])
"Extrema of x-values in plot"
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
+4 -1
View File
@@ -1,9 +1,12 @@
julia 0.3
julia 0.4
Colors
Reexport
Requires
FactCheck
Gadfly
Images
ImageMagick
PyPlot
@osx QuartzImageIO
GR
+27 -142
View File
@@ -1,136 +1,45 @@
# include this first to help with crashing??
try
@eval using Gtk
end
using VisualRegressionTests
using ExamplePlots
# don't let pyplot use a gui... it'll crash
# note: Agg will set gui -> :none in PyPlot
ENV["MPLBACKEND"] = "Agg"
try
@eval import PyPlot
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
end
# macro test_approx_eq_sigma_eps(A, B, sigma, eps)
include("../docs/example_generation.jl")
# # make and display one plot
# function test_examples(pkg::Symbol, idx::Int; debug = true)
# Plots._debugMode.on = debug
# println("Testing plot: $pkg:$idx:$(examples[idx].header)")
# backend(pkg)
# backend()
# map(eval, examples[idx].exprs)
# plt = current()
# gui(plt)
# plt
# end
using Plots, FactCheck
import Images, ImageMagick
# if !isdefined(ImageMagick, :init_deps)
# function ImageMagick.init_deps()
# ccall((:MagickWandGenesis,libwand), Void, ())
# end
# end
function makeImageWidget(fn)
img = Gtk.GtkImageLeaf(fn)
vbox = Gtk.GtkBoxLeaf(:v)
push!(vbox, Gtk.GtkLabelLeaf(fn))
push!(vbox, img)
show(img)
vbox
end
function replaceReferenceImage(tmpfn, reffn)
cmd = `cp $tmpfn $reffn`
run(cmd)
info("Replaced reference image with: $cmd")
end
"Show a Gtk popup with both images and a confirmation whether we should replace the new image with the old one"
function compareToReferenceImage(tmpfn, reffn)
@eval import Gtk
# add the images
imgbox = Gtk.GtkBoxLeaf(:h)
push!(imgbox, makeImageWidget(tmpfn))
push!(imgbox, makeImageWidget(reffn))
# add the buttons
# doNothingButton = Gtk.GtkButtonLeaf("Skip")
# replaceReferenceButton = Gtk.GtkButtonLeaf("Replace reference image")
# btnbox = Gtk.GtkButtonBoxLeaf(:h)
# push!(btnbox, doNothingButton)
# push!(btnbox, replaceReferenceButton)
# # create the window
# box = Gtk.GtkBoxLeaf(:v)
# push!(box, imgbox)
# push!(box, btnbox)
win = Gtk.GtkWindowLeaf("Should we make this the new reference image?")
push!(win, Gtk.GtkFrameLeaf(imgbox))
showall(win)
# now ask the question
if Gtk.ask_dialog("Should we make this the new reference image?", "No", "Yes")
replaceReferenceImage(tmpfn, reffn)
end
destroy(win)
# # we'll wait on this condition
# c = Condition()
# Gtk.on_signal_destroy((x...) -> notify(c), win)
# Gtk.signal_connect(replaceReferenceButton, "clicked") do widget
# replaceReferenceImage(tmpfn, reffn)
# notify(c)
# end
# Gtk.signal_connect(doNothingButton, "clicked") do widget
# notify(c)
# end
# # wait until a button is clicked, then close the window
# Gtk.showall(win)
# wait(c)
# Gtk.destroy(win)
end
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)
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, sigma = [1,1], eps = 1e-2)
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
# first
Plots._debugMode.on = debug
info("Testing plot: $pkg:$idx:$(PlotExamples.examples[idx].header)")
example = ExamplePlots._examples[idx]
info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg)
backend()
# ensure consistent results
srand(1234)
# run the example
map(eval, PlotExamples.examples[idx].exprs)
# reference image directory setup
refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
# save the png
tmpfn = tempname() * ".png"
png(tmpfn)
# test function
func = (fn, idx) -> begin
map(eval, example.exprs)
png(fn)
end
# load the saved png
tmpimg = Images.load(tmpfn)
# reference image location
# refdir = joinpath(Pkg.dir("Plots"), "test", "refimg", "v$(VERSION.major).$(VERSION.minor)", string(pkg))
refdir = joinpath(Pkg.dir("Plots"), "test", "refimg", string(pkg))
try
run(`mkdir -p $refdir`)
catch err
@@ -138,45 +47,21 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, sigma = [1
end
reffn = joinpath(refdir, "ref$idx.png")
try
# info("Comparing $tmpfn to reference $reffn")
# load the reference image
refimg = Images.load(reffn)
# run the comparison test... a difference will throw an error
# NOTE: sigma is a 2-length vector with x/y values for the number of pixels
# to blur together when comparing images
diffpct = Images.test_approx_eq_sigma_eps(tmpimg, refimg, sigma, eps)
# we passed!
info("Reference image $reffn matches. Difference: $diffpct")
return true
catch err
warn("Image did not match reference image $reffn. err: $err")
showerror(Base.STDERR, err)
if isinteractive()
# if we're in interactive mode, open a popup and give us a chance to examine the images
warn("Should we make this the new reference image?")
compareToReferenceImage(tmpfn, reffn)
return
else
# if we rejected the image, or if we're in automated tests, throw the error
rethrow(err)
end
end
# the test
vtest = VisualTest(func, reffn, idx)
test_images(vtest, popup=popup, sigma=sigma, eps=eps)
end
function image_comparison_tests(pkg::Symbol; skip = [], debug = false, sigma = [1,1], eps = 1e-2)
for i in 1:length(PlotExamples.examples)
function image_comparison_facts(pkg::Symbol;
skip = [], # skip these examples (int index)
only = nothing, # limit to these examples (int index)
debug = false, # print debug information?
sigma = [1,1], # number of pixels to "blur"
eps = 1e-2) # acceptable error (percent)
for i in 1:length(ExamplePlots._examples)
i in skip && continue
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) --> true
if only == nothing || i in only
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
end
end
end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Some files were not shown because too many files have changed in this diff Show More