Compare commits

..

861 Commits

Author SHA1 Message Date
Thomas Breloff 40cbddab29 updated NEWS; export shorthands macro; new example 16 2016-06-08 23:32:03 -04:00
Thomas Breloff 853cda4b80 moved stuff to PlotDocs 2016-06-08 17:34:15 -04:00
Thomas Breloff 91ec0ad077 allow false for color; properly expand extrema for tuple fillrange; make_fillrange_from_ribbon 2016-06-08 09:51:27 -04:00
Thomas Breloff 4be2304ec1 working on arg_desc; violin fix for groups 2016-06-08 00:52:16 -04:00
Tom Breloff d0ee402939 Merge pull request #306 from diegozea/dev
Solve a bug with whisker lengths (#210)
2016-06-07 23:01:29 -04:00
Diego Javier Zea 2d095daddc Solve a bug with whisker lengths (#210) 2016-06-07 23:44:41 -03:00
Thomas Breloff cf4fcf3351 fixed boxplot grouping; cleaned up GroupBy recipe; added arg_descs 2016-06-07 21:12:59 -04:00
Thomas Breloff 42d57fb8c2 working on arg_desc 2016-06-07 18:17:27 -04:00
Thomas Breloff ba13c1528f working on arg_desc 2016-06-07 17:59:30 -04:00
Thomas Breloff 857fb3342a fakedata fix 2016-06-07 17:16:14 -04:00
Thomas Breloff 17189e3125 default_should_widen; symbol in userplot macro; cleanup in recipes 2016-06-07 16:44:15 -04:00
Thomas Breloff d0209d945d widen further; added zorder to pyplot annotations 2016-06-07 12:38:35 -04:00
Tom Breloff 1b6bfa1259 Merge pull request #305 from diegozea/dev
Add notch and outliers to boxplot
2016-06-07 12:09:55 -04:00
Thomas Breloff 4ea813c983 pyplot scatter fix 2016-06-07 12:07:16 -04:00
Diego Javier Zea 71d2af07da Add notch and outliers to boxplot 2016-06-07 13:06:13 -03:00
Thomas Breloff b36f8c701e type recipes 2016-06-07 11:59:38 -04:00
Thomas Breloff d64d3ef101 pgfplots fixes 2016-06-07 01:57:02 -04:00
Thomas Breloff 05fa4a92de fixes in plotly/plotlyjs; smooth primary false 2016-06-07 01:42:33 -04:00
Thomas Breloff 990314cefc fixes for gr markers; add cbar to example 24; turn on gr tests 2016-06-07 01:23:07 -04:00
Thomas Breloff 60d97ad9c9 added density recipe 2016-06-07 00:18:07 -04:00
Thomas Breloff 6bfa31a89f added primary kw for series counting; added sticks recipe; gr_set_font and related fixes 2016-06-06 23:43:06 -04:00
Thomas Breloff 8d8ac10429 step recipes 2016-06-06 18:19:46 -04:00
Thomas Breloff 56f398fb55 histogram2d recipe; handle smoothing generically 2016-06-06 17:55:09 -04:00
Thomas Breloff cf5aed00e2 test fix 2016-06-06 16:12:22 -04:00
Thomas Breloff de616dfdf0 update_min_padding fix; shape support in GR; GR attr fixes; image extrema and fixes; hline/vline recipes; nobigs closes #303 2016-06-06 15:34:51 -04:00
Thomas Breloff 3cf428d7ea pyplot colorbar fix; annotation fix; new contour example; travis fix 2016-06-06 14:06:55 -04:00
Thomas Breloff 29d93ba33e changed axis defaults byletter to match; cleaned up examples; pyplot extrema fixes; commented out gr tests 2016-06-06 12:34:24 -04:00
Thomas Breloff 76c84c7615 attr fixes; allow_fail for nightly travis; series_new cleanup 2016-06-06 01:36:07 -04:00
Thomas Breloff e129c29e2f postpone match logic and add color_or_nothing; update pyplot for attr changes; move some pyplot logic later 2016-06-06 01:19:25 -04:00
Thomas Breloff 52d325b446 Merge remote-tracking branch 'origin/master' into dev 2016-06-05 23:59:06 -04:00
Thomas Breloff 74efd98699 added user_attr field to Plot; fillrange fix; pyplot title fix 2016-06-05 23:58:35 -04:00
Tom Breloff 28effaea36 Merge pull request #298 from dhoegh/fix_animation
Make animation use ImageMagick.jl if it is installed.
2016-06-05 23:16:05 -04:00
Daniel Høegh 6256549f44 Make animation use ImageMagick.jl if it is installed. 2016-06-05 09:31:44 +02:00
Thomas Breloff 2adec2fa7b examples 2016-06-02 20:34:25 -05:00
Thomas Breloff 32e816b713 working on axis limit fixes 2016-06-02 20:22:58 -05:00
Thomas Breloff 6c7b113de5 working on new tests 2016-06-02 17:59:24 -05:00
Thomas Breloff 1d5cce61ac working on switch to PlotReferenceImages 2016-06-02 17:23:40 -05:00
Thomas Breloff 85f91b9075 fix for plotting function; closes #291 2016-06-01 14:45:35 -05:00
Thomas Breloff aa64a0d3ce pyplot color fix 2016-06-01 14:29:36 -05:00
Thomas Breloff e9d95a85b7 proper grid layout in macro; pyplot isx fix 2016-05-30 14:56:32 -05:00
Thomas Breloff 625c92a985 working on 0.5 changes 2016-05-28 11:17:34 -04:00
Thomas Breloff 3cc9425219 working on 0.5 changes -- String 2016-05-28 11:00:19 -04:00
Thomas Breloff 0a86ccb142 working on 0.5 changes 2016-05-28 10:42:41 -04:00
Thomas Breloff ce82e07dc9 Extrema type and link_axis; link keyword, removed old link logic 2016-05-27 22:03:56 -04:00
Thomas Breloff 048c60614c check _axis_defaults in default 2016-05-27 16:31:07 -04:00
Thomas Breloff 148fa6d151 discrete_values handling; pyplot lims/widen; cleanup 2016-05-27 16:23:46 -04:00
Thomas Breloff 088543176f recompute_lengths fix; renamed hist to histogram, hist2d to histogram2d to match methods; fix tests 2016-05-27 15:08:05 -04:00
Thomas Breloff 536746d47e switch order for Surface function constructor; closes #273 2016-05-27 14:38:23 -04:00
Thomas Breloff c15cbad396 shorthands macro; pyplot bar fill fix; userplot macro; nicer error message in convertToAnyVector 2016-05-27 14:25:14 -04:00
Thomas Breloff d3baa58c7e series ordering bug fix 2016-05-27 12:55:29 -04:00
Thomas Breloff 7c885de6c7 improved trickery with layout macro 2016-05-27 12:16:34 -04:00
Thomas Breloff 010b8a382e working on building plot from existing plots 2016-05-27 10:58:45 -04:00
Thomas Breloff 314053af54 gr hist2d fix; closes #253 2016-05-27 09:05:48 -04:00
Thomas Breloff 34a7f8a99c prepared_object; closes #267 2016-05-27 00:19:12 -04:00
Thomas Breloff 87031984d9 widen gr limits; fixes #265 2016-05-27 00:14:22 -04:00
Thomas Breloff 83687f96a5 PLOTS_USE_ATOM_PLOTPANE env var; closes #270 2016-05-26 23:56:11 -04:00
Thomas Breloff f33905ed80 fixes for images/heatmaps/surfaces 2016-05-26 23:47:09 -04:00
Thomas Breloff f91c4d586c html_output_format 2016-05-26 20:57:51 -04:00
Thomas Breloff 77ec4adcad default minpad fix; html_output_format 2016-05-26 17:04:28 -04:00
Thomas Breloff b5a8186d99 working on pgfplots; default minpad calcs; moved subplot/layout init later to allow setting in recipes 2016-05-26 16:01:46 -04:00
Thomas Breloff ed25e554e1 working on pgfplots 2016-05-26 15:02:04 -04:00
Thomas Breloff a388ec71e3 working on pgfplots 2016-05-26 14:18:57 -04:00
Thomas Breloff bde3c2e19d working on pgfplots 2016-05-26 13:47:00 -04:00
Thomas Breloff d1d8d196ba sticks recipe; fixed up unicodeplots backend 2016-05-26 11:19:47 -04:00
Thomas Breloff 7be5aebbc9 gr fixes: polar markers, empty legends, pie labels, scale and flip 2016-05-25 16:52:07 -04:00
Thomas Breloff d15fcb6b24 gr_polyline fixes 2016-05-25 16:01:18 -04:00
Thomas Breloff b3ac38a6f1 working on gr 2016-05-25 15:17:51 -04:00
Thomas Breloff dae9dad2f7 working on GR; series_list and should_add_to_legend; series recipes fix; hist and bar recipes 2016-05-25 13:06:08 -04:00
Thomas Breloff 603dc30bb1 backend callback changes; output callbacks; prepare_output; fixes for pyplot, plotly, plotlyjs; and more 2016-05-24 23:19:51 -04:00
Tom Breloff 71070da13e Merge pull request #276 from spencerlyon2/dev
Fix plotlyjs subplots
2016-05-24 20:48:25 -04:00
Spencer Lyon 8fa1d4eb9b Fix plotlyjs subplots 2016-05-24 17:21:07 -07:00
Thomas Breloff 41f91f9cfb working on GR rebuild 2016-05-24 18:01:20 -04:00
Thomas Breloff 5699f3c6bc begin GR cleanup 2016-05-24 15:22:16 -04:00
Thomas Breloff 300babd6b1 deprecated gadfly/immerse 2016-05-24 14:46:53 -04:00
Thomas Breloff c1baca181c plotly subplot layouts 2016-05-24 14:25:03 -04:00
Thomas Breloff 851fe9f72c plotlyjs fixes 2016-05-24 12:38:52 -04:00
Thomas Breloff cf635cbdd9 renamed plotargs to attr; working on plotly backend 2016-05-24 12:20:03 -04:00
Thomas Breloff abbd8635dd pyplot hist in legend fix; closes #254 2016-05-24 11:03:38 -04:00
Thomas Breloff 2c2218bcb9 layouts fixed 2016-05-24 10:34:02 -04:00
Thomas Breloff bb6c06d3f7 working on layouts 2016-05-24 08:30:46 -04:00
Thomas Breloff 90e22f179e discrete value fixes; margin args; check for fillrange in contourf; skip test 6 2016-05-23 18:15:33 -04:00
Thomas Breloff 0a00d1fbf3 suppress_warnings fix; discrete values fixes 2016-05-23 16:42:24 -04:00
Thomas Breloff 6f0b8d1d7b group fix; ohlc fix 2016-05-23 15:13:20 -04:00
Thomas Breloff ef0d99340a backend template renaming/reorg/cleanup, pyplot fixes 2016-05-23 10:29:35 -04:00
Thomas Breloff d4d388a94b pyplot colorbar labels bbox 2016-05-21 23:03:55 -04:00
Thomas Breloff 7022ce7553 fixes for push/append/set_xy 2016-05-21 10:03:47 -04:00
Thomas Breloff 4a96122067 colorbar layout fixes; process_axis_arg and related fix 2016-05-21 00:04:33 -04:00
Thomas Breloff 862ac3af8a fixes/improvements to annotations; added series_annotations keyword 2016-05-20 11:38:07 -04:00
Thomas Breloff 333c2765fe ohlc recipe and related fixes; removed ohlc-specific code from gadfly and gr 2016-05-20 10:06:15 -04:00
Thomas Breloff 89feb68b7c pyplot lims fix 2016-05-20 08:15:27 -04:00
Thomas Breloff 1b901673fc fixes for guide/dataframes; 3d/polar projections; delayed subplot init; fg_title 2016-05-19 23:45:07 -04:00
Thomas Breloff fb60c244f6 bar_width and bar_edges keywords; small fixes 2016-05-19 17:34:37 -04:00
Thomas Breloff 3cea2df459 fix get_subplot_index; fix pyplot colorbar 2016-05-19 14:00:39 -04:00
Thomas Breloff 1cf514d1e6 merged dev into tb_recipes 2016-05-19 13:03:01 -04:00
Thomas Breloff 65e18a8669 upper bound on RecipesBase in REQUIRE; added NEWS.md; closes #259 2016-05-19 12:36:34 -04:00
Thomas Breloff 3e8f325ddc reorg/cleanup; removed old layouts and subplots; created axes.jl and layouts.jl 2016-05-19 10:42:59 -04:00
Thomas Breloff 0d96c49f4a layout macro; attr rename; getindex; fixes and cleanup 2016-05-18 23:55:03 -04:00
Thomas Breloff bfc3fc1dec titles and sub-layouts 2016-05-18 15:53:00 -04:00
Thomas Breloff 327f235af9 working on subplot/axis arg processing 2016-05-18 14:08:44 -04:00
Thomas Breloff df7fc0c4df fixes; basic layout works 2016-05-17 23:37:47 -04:00
Thomas Breloff 33d9664df5 working on layouts 2016-05-17 21:24:34 -04:00
Thomas Breloff 0d237028e7 redo the bbox logic 2016-05-17 17:41:03 -04:00
Thomas Breloff 80b9115393 fixes 2016-05-17 15:55:54 -04:00
Thomas Breloff 606229a08f trying out measures 2016-05-17 15:45:05 -04:00
Thomas Breloff 2ac17afe30 fixes 2016-05-17 10:33:10 -04:00
Tom Breloff 70f23e695b Merge pull request #252 from pkofod/join
Replace string cats with join() in pgfplots (and more).
2016-05-17 09:09:04 -04:00
Thomas Breloff 3084b0c41c working on arg overhaul 2016-05-17 00:57:42 -04:00
Thomas Breloff b75db9e473 arg defaults 2016-05-16 21:56:27 -04:00
Thomas Breloff c89e9c5f73 refactored and renamed plot defaults into plot,subplot,axis defaults, plus some associated fixes 2016-05-16 20:57:50 -04:00
Thomas Breloff 61107b8577 working on layout 2016-05-16 17:12:45 -04:00
Thomas Breloff 35ff449dc3 working on layout 2016-05-16 15:56:12 -04:00
Thomas Breloff ae1f5b8b06 working on layouts 2016-05-16 14:24:45 -04:00
Thomas Breloff c5bcae1e34 working on subplots 2016-05-16 01:07:33 -04:00
Thomas Breloff e9ab6e7301 started subplots/layouts 2016-05-15 12:32:10 -04:00
Thomas Breloff a6ce2e691d changed add_series to accept Series and push to list automatically; default add_series simplifies; removed old supported.jl 2016-05-15 12:14:18 -04:00
Thomas Breloff bfe04bdd15 changed to _create_backend_figure; started subplot removal 2016-05-15 11:23:27 -04:00
Thomas Breloff 2d0f9f01d5 cleanup 2016-05-14 17:34:44 -04:00
Thomas Breloff 87a967ad9c working on Axis 2016-05-14 00:10:58 -04:00
Thomas Breloff 290b17a5f9 fixes 2016-05-13 22:53:32 -04:00
Thomas Breloff 76572b990b fix gr linetype 2016-05-13 21:00:02 -04:00
Thomas Breloff 54efb48d62 changed linetype to seriestype 2016-05-13 20:55:26 -04:00
Thomas Breloff 83bd780f2a working on Axis type 2016-05-13 16:46:15 -04:00
Thomas Breloff 2ba4ac6d20 working on Axis type 2016-05-13 14:42:11 -04:00
Thomas Breloff 98dc52f124 working on Axis type 2016-05-13 13:45:30 -04:00
Thomas Breloff fbb2f30f3f errorbars, ribbons, and marker_z 2016-05-13 11:58:29 -04:00
Thomas Breloff 8ec3d18339 boxplot, violin, quiver, and line series recipes; plus some fixes 2016-05-13 11:21:32 -04:00
Thomas Breloff 26779cbf4a series recipes 2016-05-13 08:03:28 -04:00
Thomas Breloff 4f429fb536 recipe overhaul; groups, annotations, SliceIt 2016-05-13 00:17:58 -04:00
Thomas Breloff 7e1706f700 working on core recipes 2016-05-12 21:30:52 -04:00
Thomas Breloff d491b29037 working on recipes overhaul 2016-05-12 16:35:57 -04:00
Thomas Breloff cf9b60660d working on recipes overhaul 2016-05-12 14:51:53 -04:00
Thomas Breloff a5e9ad9f19 working on recipes overhaul 2016-05-12 14:00:47 -04:00
Thomas Breloff 6049a9fa0a working on recipes overhaul 2016-05-12 12:31:47 -04:00
Patrick Kofod Mogensen 5196ce5263 Add PGFPlots support for the size kw. 2016-05-12 17:32:54 +02:00
Patrick Kofod Mogensen 9231da4610 Clean up wall of pushes in _pgfplots_get_marker, and lines starting with kwarg. 2016-05-12 17:32:54 +02:00
Patrick Kofod Mogensen 89f8030ba1 Add markerstrokewidth to pgfplots. 2016-05-12 17:32:54 +02:00
Patrick Kofod Mogensen 534f57b227 Replace string cats with join() in pgfplots. 2016-05-12 17:32:54 +02:00
Thomas Breloff 4d3ebf31d4 add series_new.jl 2016-05-12 10:28:04 -04:00
Tom Breloff d778c7922d Merge pull request #255 from jheinen/dev
Fixed some bugs in gr.jl
2016-05-12 10:12:29 -04:00
Josef Heinen 5109c6f72b Fixed some bugs in gr.jl
- Turn off interpolation for heatmaps
- Fixed bug plotting scatter after heatmap (scatter drew to the colorbar
  viewport)
- Don't draw superfluous legends
2016-05-12 15:29:43 +02:00
Thomas Breloff 5005d32afd recipes overhaul; is_installed and dataframes logic; removed requires 2016-05-11 22:12:51 -04:00
Thomas Breloff 88be655dca started recipe reorg 2016-05-11 17:56:18 -04:00
Tom Breloff fe5789d747 Merge pull request #251 from jheinen/dev
Added (native) image support
2016-05-11 10:41:39 -04:00
Josef Heinen 00201b5f9c Added (native) image support 2016-05-11 16:18:03 +02:00
Thomas Breloff 85f7acf9d5 add PyPlot.ioff to init; closes #229 2016-05-11 09:45:44 -04:00
Thomas Breloff 44d1cdc2b2 pgfplots aspect_ratio 2016-05-11 09:18:40 -04:00
Tom Breloff 90c2202f6e Merge pull request #250 from KristofferC/kc/fix_pgfplots_color
Fix bug in some linecolors in PGFPlots
2016-05-11 09:11:13 -04:00
Kristoffer Carlsson d30574de24 workaround a bug in engineering notation for colors in pgfplot 2016-05-11 15:01:17 +02:00
Tom Breloff dec3748fe5 Merge pull request #249 from KristofferC/kc/pgfplots_label
add support for legend and label in pgfplots
2016-05-11 08:51:38 -04:00
Kristoffer Carlsson e8cdff2310 add support for legend and label in pgfplots
also adds some extra kwargs for legend positions
2016-05-11 13:59:32 +02:00
Thomas Breloff a0ca9d675f add_arrows function; plotly cleanup and arrows attempt 2016-05-10 17:22:47 -04:00
Thomas Breloff baf410c712 remove pyplot dash_capstyle option 2016-05-10 14:34:28 -04:00
Thomas Breloff a81af2b449 arrow conveniences 2016-05-10 13:57:38 -04:00
Thomas Breloff 678dde710b arrows with updated quiver recipe; only pyplot so far 2016-05-10 13:40:25 -04:00
Tom Breloff 93a35d8fdc Merge pull request #244 from jheinen/dev
Improved scaling of plots with error bars
2016-05-10 12:21:18 -04:00
Josef Heinen 0878f44b09 Improved scaling of plots with error bars 2016-05-10 18:14:08 +02:00
Thomas Breloff b89ae245ec removed heatmap assert 2016-05-09 22:44:22 -04:00
Thomas Breloff 536da01714 boxplot nan fix; add match_dimensions to pyplot supportedargs 2016-05-09 22:13:53 -04:00
Thomas Breloff a1b991aaeb image fixes and support in pyplot 2016-05-09 15:53:33 -04:00
Thomas Breloff 7bee9a5829 setTicksFromStringVector fixes; travis 2016-05-09 14:36:09 -04:00
Thomas Breloff 17a90e3b00 revamped setTicksFromStringVector; dataframes label fix 2016-05-09 14:00:07 -04:00
Tom Breloff 43ba9b1172 Merge pull request #239 from jheinen/dev
Fix axes offset bug (#221)
2016-05-09 11:28:04 -04:00
Thomas Breloff fdb01046e6 plotly zaxis, tick rotation, 3d axis fix; dataframes recipe fixes 2016-05-09 11:19:20 -04:00
Josef Heinen 09421c9189 Fix axes offset bug (#221) 2016-05-09 17:10:20 +02:00
Thomas Breloff c563204b0a added RecipesBase dep 2016-05-09 09:01:05 -04:00
Thomas Breloff 33b3ee89f3 replaced dataframes with recipes 2016-05-09 08:31:50 -04:00
Tom Breloff 008b61c9f6 Merge pull request #236 from jheinen/dev
Fixed colormap problem
2016-05-09 06:12:55 -04:00
Josef Heinen 7546db4d42 Fixed colormap problem 2016-05-09 11:44:37 +02:00
Thomas Breloff 925243969c attempted colormap fix for gr 2016-05-08 11:02:20 -04:00
Tom Breloff 7bce4a963e Merge pull request #233 from jheinen/dev
gr: support for colormaps
2016-05-08 10:30:40 -04:00
Josef Heinen 42d09a6d80 Working on colormaps 2016-05-08 14:06:11 +02:00
Josef Heinen b6334176e4 Added support for :nbins keyword 2016-05-07 13:24:11 +02:00
Josef Heinen 42a175bd53 Added support for :zlims keyword 2016-05-07 12:45:09 +02:00
Josef Heinen b4fb9af8e4 Fixed a problem with Julia v0.3 2016-05-07 07:47:13 +02:00
Thomas Breloff ed6c9fe432 add is_key_supported definition 2016-05-06 15:17:56 -04:00
Thomas Breloff 7e04aa438f removed RecipesBase from REQUIRE 2016-05-06 15:09:53 -04:00
Thomas Breloff f1679f82c1 remove recipe macro; add dependency on RecipesBase 2016-05-06 14:55:42 -04:00
Thomas Breloff 1808b81d59 recipe fix for empty args in subplot 2016-05-06 11:51:23 -04:00
Thomas Breloff cd25c7acb2 markershape fix; added require option for recipes 2016-05-06 11:39:17 -04:00
Thomas Breloff cf03779c5b handle user keywords properly for recipes 2016-05-06 10:50:54 -04:00
Thomas Breloff d3439f0d7e recipe macro handle curly 2016-05-05 16:58:04 -04:00
Thomas Breloff 2df7f84939 recipe macro 2016-05-05 16:18:56 -04:00
Thomas Breloff 74c76c48d5 working on plotrecipe 2016-05-05 12:22:31 -04:00
Thomas Breloff cdc0d22b01 changed recipe to plotrecipe and improved it 2016-05-05 11:51:50 -04:00
Thomas Breloff 5a520aadc0 removed some debugging 2016-05-05 10:35:04 -04:00
Thomas Breloff ec87489dd4 working on image type; working on ijulia display_dict 2016-05-05 00:13:45 -04:00
Thomas Breloff e30affdfc2 made center calc centroid 2016-05-04 21:36:15 -04:00
Thomas Breloff 66bd2559b9 recipe macro; markershape fix; moved/fixed themes 2016-05-04 16:09:09 -04:00
Thomas Breloff c8d6b1fab0 linewidth fix; kw macro 2016-05-04 14:24:15 -04:00
Thomas Breloff 548c59719b linewidth default 2016-05-04 13:38:08 -04:00
Thomas Breloff 59c1e24371 default_kw and force_kw macros for recipes 2016-05-04 13:24:44 -04:00
Thomas Breloff 3c09921cbd x/y/z ticklabel rotation; new supported graphs using heatmap 2016-05-03 17:14:52 -04:00
Thomas Breloff 00f3d450f9 fix for integer arg in process_inputs 2016-05-03 14:43:34 -04:00
Thomas Breloff e676387c16 shapes change verts to x/y; translate/scale/rotate/center; x/y scale alias fix 2016-05-02 16:37:10 -04:00
Thomas Breloff 2e2e8a2230 move plotargs merge and handlePlotColors before series 2016-05-02 12:16:41 -04:00
Thomas Breloff 8c8ede361e removed plotly tests 2016-04-29 17:00:56 -04:00
Thomas Breloff 672bf05856 travis 2016-04-29 14:03:50 -04:00
Thomas Breloff 67ec31c75a travis 2016-04-29 13:52:22 -04:00
Thomas Breloff 59d13a7810 travis; readme 2016-04-29 13:41:28 -04:00
Thomas Breloff 010a25f4cb travis; readme 2016-04-29 13:29:58 -04:00
Thomas Breloff a0ac7b4a1e travis; readme 2016-04-29 13:02:11 -04:00
Thomas Breloff ab7eb89466 travis; gitter badge 2016-04-29 12:44:05 -04:00
Thomas Breloff 649d362b85 travis install_wkhtmltoimage.sh 2016-04-29 12:20:18 -04:00
Thomas Breloff cb80860d6f travis install_wkhtmltoimage.sh 2016-04-29 12:15:42 -04:00
Thomas Breloff a8ef9e66fc travis install_wkhtmltoimage.sh 2016-04-29 12:05:38 -04:00
Thomas Breloff d27212e0b7 travis 2016-04-29 11:30:47 -04:00
Thomas Breloff 65650a7ae5 travis 2016-04-29 11:26:53 -04:00
Thomas Breloff 6ab5b8eb68 travis 2016-04-29 10:59:10 -04:00
Thomas Breloff c618e0577a travis and tests 2016-04-29 10:49:11 -04:00
Thomas Breloff 0e84c91451 split out supported.jl, added tests for more backends; closes #206 2016-04-29 10:13:41 -04:00
Thomas Breloff 005ce11313 InputWrapper and pyplot surface zcolor 2016-04-28 22:03:52 -04:00
Tom Breloff db118d4f5a Merge pull request #208 from pkofod/newpgf
Further changes to PGFPlots backend.
2016-04-28 15:13:58 -04:00
Patrick Kofod Mogensen c92b30a741 Further changes to PGFPlots backend. 2016-04-28 20:52:56 +02:00
Thomas Breloff d67aec6fec gr fixes and tests; fillrange convertToAnyVector 2016-04-28 12:51:08 -04:00
Tom Breloff ce58f25488 Merge pull request #209 from jheinen/dev
GR - Added polar plots
2016-04-28 11:09:56 -04:00
Josef Heinen e8d77a3c61 Added polar plots 2016-04-28 16:25:32 +02:00
Thomas Breloff d6d7fc1edd gr fix zcolor to marker_z 2016-04-27 12:10:33 -04:00
Thomas Breloff 7ce7f8bfce gr tests 2016-04-27 09:20:19 -04:00
Tom Breloff f0f46e5272 Merge pull request #166 from pkofod/pkm/pgfplots
PGFPlots.jl support
2016-04-27 09:17:45 -04:00
Patrick Kofod Mogensen f9473cc8bc Initial functionality added to PGFPlots backend. 2016-04-27 10:05:48 +02:00
Thomas Breloff 5c7d31157b spy fixes; closes #196 2016-04-26 17:02:16 -04:00
Thomas Breloff 982a512ebd pyplot support for pie charts 2016-04-26 16:01:50 -04:00
Thomas Breloff 5dfd3d2f5d added aspect_ratio keyword and implemented in pyplot 2016-04-26 15:35:26 -04:00
Thomas Breloff 8d6974f67d contours keyword for surface and wireframe plots 2016-04-26 15:09:18 -04:00
Thomas Breloff 8b569e3cd8 contour3d 2016-04-26 14:35:51 -04:00
Thomas Breloff b9d20142a2 pyplot trisurface support 2016-04-26 14:20:07 -04:00
Thomas Breloff 6c9e818abd discrete colorbar for pyplot 2016-04-26 13:19:22 -04:00
Thomas Breloff d2a287d43c gr tests linux_only 2016-04-26 11:59:08 -04:00
Thomas Breloff d6ce2e364f fixes and cleanup: colorbars, fills, polar 2016-04-26 11:18:48 -04:00
Thomas Breloff 36ca485a74 added fg_guide coloring; allow markers for bar/sticks and sticks fixes; legend text color 2016-04-25 16:57:16 -04:00
Thomas Breloff b3230c5671 pyplot shapes 2016-04-25 15:14:54 -04:00
Thomas Breloff ebf490838c pyplot surface, wireframe, heatmap; sorting fixes; default linewidth is :auto 2016-04-25 15:01:24 -04:00
Thomas Breloff 7921cf18b6 pyplot contours 2016-04-25 12:47:35 -04:00
Thomas Breloff 0e0450ced5 gadfly color fixes; pyplot fill_between fix; pyplot hline/vline 2016-04-25 12:24:03 -04:00
Thomas Breloff 096064ac09 subplot layout fix; closes #202 2016-04-25 12:00:43 -04:00
Thomas Breloff 77c2d7d846 subcategories for background/foreground colors, implemented in pyplot; add_theme/set_theme and ggplot2; add_aliases function; nbins renamed bins 2016-04-25 11:37:14 -04:00
Thomas Breloff 40a121198d added weights kw; pyplot hist2d and hexbin 2016-04-24 23:33:51 -04:00
Thomas Breloff 44079a7bf7 added normalize kw, and added to pyplot 2016-04-24 22:47:32 -04:00
Thomas Breloff 50fa013801 working on pyplot refactor; barh added 2016-04-23 09:32:57 -04:00
Thomas Breloff d4ccf0ec62 PLOTS_DEFAULT_BACKEND env variable; closes #200 2016-04-23 09:04:02 -04:00
Thomas Breloff 04842974e7 working on pyplot refactor 2016-04-22 16:46:02 -04:00
Thomas Breloff 6161b08f82 working on pyplot refactor; path/scatter in 2d/3d done 2016-04-22 12:53:40 -04:00
Thomas Breloff b9818a4480 working on seriescolor and pyplot reorgs 2016-04-22 10:44:12 -04:00
Thomas Breloff e2ae22421b working on seriescolor and pyplot reorgs 2016-04-22 10:09:55 -04:00
Thomas Breloff b64677e14a changed kw splatting to passing in KW: _add_series and _create_plot; removed plotly tests 2016-04-22 08:56:54 -04:00
Thomas Breloff c910445634 quiet flag for wkhtmltoimage 2016-04-21 15:10:25 -04:00
Thomas Breloff c4683a754e plotly png generation using wkhtmltoimage 2016-04-20 17:34:55 -04:00
Thomas Breloff 1da8fdb588 plotlyjs travis 2016-04-20 15:35:23 -04:00
Thomas Breloff 4bf8e342dc plotlyjs travis; plotly/plotlyjs polar 2016-04-20 14:44:27 -04:00
Thomas Breloff 18fc50fcbf plotlyjs travis 2016-04-20 12:33:32 -04:00
Thomas Breloff 2fb10b7076 plotlyjs travis 2016-04-20 11:59:17 -04:00
Thomas Breloff 967291c2ef export KW; plotlyjs travis 2016-04-20 11:27:02 -04:00
Thomas Breloff 392ae871d5 plotlyjs travis 2016-04-20 10:57:07 -04:00
Thomas Breloff 27b3070480 Merge remote-tracking branch 'origin/master' into dev 2016-04-20 10:20:55 -04:00
Tom Breloff 325f59e03d Merge pull request #190 from mfalt/master
Better handling of xlims in Gadfly
2016-04-20 10:17:29 -04:00
Thomas Breloff 217ffb36e6 plotlyjs tests and fixes 2016-04-20 10:10:07 -04:00
Mattias Fält 4afad93ff6 Missing changes 2016-04-20 15:51:33 +02:00
Thomas Breloff e8858cb1b7 removed sort in ticks 2016-04-20 09:12:36 -04:00
Mattias Fält 52de31c9a6 Proper implementation of gadfly min/max in Cartesian 2016-04-20 14:37:34 +02:00
Mattias Fält 60660a1f1a Fixed Gadfly axis scale inversion 2016-04-20 10:48:13 +02:00
Thomas Breloff a2ea9db90e added bar_position; fixed orientation handling; pyplot cleanup 2016-04-18 15:12:13 -04:00
Thomas Breloff 236a7dadc6 added matplotlib colormaps; default changed to inferno; pyplot subplot fix 2016-04-13 13:49:03 -04:00
Thomas Breloff 82d2cc943d working on get/set xy/xyz indexing overhaul 2016-04-11 18:19:06 -04:00
Thomas Breloff d70f462899 z axis args; pyplot z axis; major pyplot cleanup; other cleanup/fixes 2016-04-11 16:16:47 -04:00
Thomas Breloff 0a636b5899 polar coords for pyplot 2016-04-11 06:46:28 -04:00
Thomas Breloff e0b2749188 added support for shape linetype in pyplot 2016-04-08 17:10:15 -04:00
Thomas Breloff 2fc973245d added quiver plot/arg; fixed gadfly shapes to allow vector of shapes 2016-04-08 16:05:20 -04:00
Thomas Breloff 9bfcb64542 asymmetric errorbars 2016-04-08 12:06:12 -04:00
Thomas Breloff 61e34b7ef8 ribbons; changed errorbar to yerror and added xerror 2016-04-08 11:52:02 -04:00
Thomas Breloff 3c3078875a errorbars 2016-04-08 10:35:17 -04:00
Thomas Breloff 5293e2c13d sort string ticks 2016-04-07 17:27:12 -04:00
Thomas Breloff fdf3b3f581 added violin plot 2016-04-07 17:05:31 -04:00
Thomas Breloff f3f29fb54f apply_series_recipe framework and boxplot; fix Gadfly scales for tick labels 2016-04-07 15:56:09 -04:00
Thomas Breloff e8ed79a6bb pyplot zlim fixes 2016-03-29 11:01:16 -06:00
Thomas Breloff cca730d927 atom abstractplot 2016-03-29 09:24:23 -06:00
Tom Breloff 0693cb7840 Merge pull request #176 from abelsiqueira/feat/zlim
Implement zlims!
2016-03-29 09:23:07 -06:00
Abel Soares Siqueira 3f1958cce1 Implement zlims! 2016-03-28 22:41:32 -03:00
Thomas Breloff fb708bed90 Atom fixes 2016-03-25 09:23:10 -06:00
Thomas Breloff 1636587a82 surface fix 2016-03-19 19:40:27 -06:00
Thomas Breloff 1f1ccd81bb shapes 2016-03-18 11:38:51 -04:00
Thomas Breloff 5efb0eb582 more Dict to KW renaming 2016-03-17 22:11:29 -04:00
Thomas Breloff be5f71c123 subplot groups; lots of Dict to KW replace 2016-03-17 22:02:50 -04:00
Thomas Breloff a0df6bfc12 groupby overhaul 2016-03-17 18:27:33 -04:00
Thomas Breloff 2ab0dc20d7 working on series reorg 2016-03-17 16:52:09 -04:00
Thomas Breloff 175ce3613a working on series reorg 2016-03-17 15:07:07 -04:00
Thomas Breloff eecb5c3754 started series reorg 2016-03-17 13:38:22 -04:00
Thomas Breloff b34360901f test/REQUIRE 2016-03-17 11:33:18 -04:00
Thomas Breloff 21bbd21ae9 travis 2016-03-17 10:33:39 -04:00
Thomas Breloff 0b403a4c5d changed createKWArgsList to build_series_args and moved into series_args.jl; added Cairo and Fontconfig to test/REQUIRE 2016-03-17 10:08:03 -04:00
Thomas Breloff 1d1e1beca5 pyplot surface fix 2016-03-17 08:59:43 -04:00
Tom Breloff 3d4d844e72 Merge pull request #169 from diegozea/dev
Arc and chord diagram
2016-03-17 08:39:27 -04:00
Diego Javier Zea 1f9aa72bdb clean previous commit 2016-03-17 00:18:13 -03:00
Diego Javier Zea c29f68e35d Arc and chord diagrams 2016-03-17 00:11:41 -03:00
Tom Breloff c7c10e769d Merge pull request #168 from jheinen/dev
GR.jl improvements
2016-03-16 14:55:35 -04:00
Josef Heinen 7264c01b85 Added :heatmap linetype 2016-03-16 18:27:59 +01:00
Josef Heinen 97faa7413f gr: improved subplot layout 2016-03-16 18:27:59 +01:00
Thomas Breloff 7531c48e38 shape linetype; supported in gadfly; gadfly cleanup 2016-03-16 13:12:01 -04:00
Thomas Breloff 16799d8b75 cleanup plotly 2016-03-16 11:38:20 -04:00
Thomas Breloff 901115ed10 working on plotly/interact fix 2016-03-15 13:16:14 -04:00
Tom Breloff 596ca08446 Merge pull request #162 from diegozea/dev
arcdiagram
2016-03-15 11:29:24 -04:00
Thomas Breloff 4d864d8cad working on atom integration 2016-03-14 16:58:01 -04:00
Diego Javier Zea c458a35670 arcdiagram 2016-03-13 16:27:35 -03:00
Thomas Breloff c203bfe5ad working on atom/plotly 2016-03-11 14:59:11 -05:00
Thomas Breloff 8b2a838388 fixed dataframes loading; added dataframes to tests; started atom integration 2016-03-11 13:07:25 -05:00
Thomas Breloff b08212e2f9 more layouts 2016-03-10 23:38:14 -05:00
Thomas Breloff b5f08838b3 renaming: AbstractPlot and AbstractBackend 2016-03-10 23:08:04 -05:00
Thomas Breloff 5501605a1f more cleanup; backends.jl; removed depr dir 2016-03-10 22:47:53 -05:00
Thomas Breloff 7a5197df63 started work on new FlexLayout, some reorg/cleaning 2016-03-10 22:43:02 -05:00
Tom Breloff 09d45aa64b Merge pull request #161 from dlfivefifty/dev
Update GLVisualize
2016-03-10 19:24:24 -05:00
Sheehan Olver 552810359e Merge updated glvisualize 2016-03-11 10:44:51 +11:00
Sheehan Olver a68a6885d0 updated glvisualize 2016-03-11 10:42:55 +11:00
Thomas Breloff b32589f7e7 removed plotly debugging 2016-03-10 16:20:34 -05:00
Thomas Breloff 2e6b8a067d pyplot heatmaps working; ColorGradient fix 2016-03-09 23:34:56 -05:00
Thomas Breloff 581fdfdfe0 pyplot heatmap 2016-03-09 21:55:09 -05:00
Thomas Breloff 8e4ff39738 loosen ColorGradient constructor 2016-03-09 20:31:46 -05:00
Thomas Breloff f568803af2 heatmaps, colorscales, and spy... oh my 2016-03-09 17:48:43 -05:00
Thomas Breloff 6db06857ba changed heatmap to hist2d, see #147 for details 2016-03-09 15:26:30 -05:00
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
Thomas Breloff 42c3827ded 0.3 fix 2015-10-29 13:26:40 -04:00
Thomas Breloff 26e4b4efda back to 0.3; working on fixes 2015-10-29 12:57:07 -04:00
Thomas Breloff 2169ab3bb8 ref imgs 2015-10-29 12:50:25 -04:00
Thomas Breloff 85dad8db88 removed gitattributes 2015-10-29 11:25:08 -04:00
Thomas Breloff 8120c34064 added smooth and opacity args for pyplot; fixes in regressionXY, replaceAliases 2015-10-28 12:14:58 -04:00
Thomas Breloff 1f1d1f70a1 fix for group arg 2015-10-28 01:37:52 -04:00
Thomas Breloff 373d868a17 gadfly color fixes; pyplot grid support 2015-10-28 01:12:20 -04:00
Thomas Breloff 834ba9bc61 fix imgcmp 2015-10-27 23:37:58 -04:00
Thomas Breloff 3ffec5aed9 fixed colors from subplot changes; fix imgcmp; new refimgs 2015-10-27 23:03:30 -04:00
Thomas Breloff ef20c1d684 subplot initargs fix 2015-10-27 22:08:47 -04:00
Thomas Breloff 697a59568c fixes 2015-10-27 20:08:33 -04:00
Thomas Breloff e58fb935b0 several fixes, plus qwt pos/size 2015-10-27 19:25:27 -04:00
Thomas Breloff 044d23f8a5 working on fixing problems with subplots and contours 2015-10-27 18:03:37 -04:00
Thomas Breloff 1604d867c3 cleared out examples markdown 2015-10-27 13:43:49 -04:00
Thomas Breloff 011db481c3 cleaned out examples and img directories 2015-10-27 13:42:29 -04:00
Thomas Breloff c404cdc38a qwt subplot pos/size 2015-10-27 13:38:16 -04:00
Thomas Breloff 20689af7dd alpha kw for colors; pyplot fix, debugshow 2015-10-27 12:40:38 -04:00
Thomas Breloff 9ea0585d71 support for contours in gadfly/immerse/pyplot 2015-10-26 18:07:22 -04:00
Thomas Breloff 614c5f694b readme 2015-10-26 15:58:26 -04:00
Thomas Breloff fa36aae068 readme 2015-10-26 15:52:44 -04:00
Thomas Breloff 3e85232310 readme 2015-10-26 15:46:34 -04:00
Thomas Breloff 894928d7ca fixes, examples, and readme; also deprecated winston 2015-10-26 14:03:06 -04:00
Thomas Breloff afb1486f86 tests and readme 2015-10-26 13:18:22 -04:00
Thomas Breloff 2799bd18e1 moved refimg dirs 2015-10-26 12:44:16 -04:00
Thomas Breloff 43c2a885b9 travis and 0.3 fixes 2015-10-26 12:25:09 -04:00
Thomas Breloff be7feb0eaa travis and readme 2015-10-26 11:43:30 -04:00
Thomas Breloff e3d653a8d9 tests 2015-10-26 11:38:33 -04:00
Thomas Breloff b9f9d8160d working on tests 2015-10-26 11:28:49 -04:00
Thomas Breloff 141b5c604d pyplot test fixes; pyplot ref imgs; travis fix 2015-10-26 10:52:29 -04:00
Thomas Breloff 8a0fc00435 imgcmp and travis 2015-10-26 09:59:26 -04:00
Thomas Breloff a3a8cb9368 nnet 2015-10-26 01:40:12 -04:00
Thomas Breloff 96c66b33a2 nnet 2015-10-26 00:11:43 -04:00
Thomas Breloff 62fad3724f pyplot push and nnet 2015-10-25 17:08:42 -04:00
Thomas Breloff ca2b6c87ef enabled lfs 2015-10-25 13:53:09 -04:00
Thomas Breloff 20348645a3 pyplot fixes 2015-10-25 00:44:18 -04:00
Thomas Breloff a9b39fad64 pyplot gui fixes and background/foreground fixes with writemime 2015-10-25 00:34:20 -04:00
Thomas Breloff 1c556ade57 more subplot fixes 2015-10-24 22:29:27 -04:00
Thomas Breloff e08957f5ec cleanup and fixes for subplot logic 2015-10-24 20:59:42 -04:00
Thomas Breloff e76ded69e6 some fixes for subplots and imgcmp 2015-10-24 16:11:55 -04:00
Thomas Breloff 7e740861d8 palette fixes and working on imgcmp 2015-10-24 15:09:13 -04:00
Thomas Breloff f28e65a26c meetup 2015-10-24 00:00:26 -04:00
Thomas Breloff a29f0c820b nnet 2015-10-23 17:05:35 -04:00
Thomas Breloff b2bc30cfed qwt fix 2015-10-23 15:58:42 -04:00
Thomas Breloff 6ce235bb68 immerse gui fix 2015-10-23 13:53:13 -04:00
Thomas Breloff 479ab989df immerse subplot gui fix; pyplot colorbars; subplot creation fix 2015-10-23 13:26:34 -04:00
Thomas Breloff 8d490b9e52 meetup nnet 2015-10-22 16:53:39 -04:00
Thomas Breloff 949f11a8c9 meetup 2015-10-22 15:10:15 -04:00
Thomas Breloff d4896e1978 improved color palette generation; removed some predefined gradients 2015-10-22 12:16:00 -04:00
Thomas Breloff c4020080b3 nnet 2015-10-22 00:40:41 -04:00
Thomas Breloff 5a68003d16 fixed empty plots 2015-10-21 21:30:05 -04:00
Thomas Breloff 9fcc3cdc24 pre/post processing subplots 2015-10-21 13:52:58 -04:00
Thomas Breloff ee80ce5ae6 subplots and colors 2015-10-21 12:27:13 -04:00
Thomas Breloff 456c4019c4 misc 2015-10-21 01:34:50 -04:00
Thomas Breloff f65627a505 travis; wine 2015-10-21 00:44:48 -04:00
Thomas Breloff 38d1fc15fe travis; wine 2015-10-21 00:29:53 -04:00
Thomas Breloff 5eead5b0fa travis; wine 2015-10-21 00:21:55 -04:00
Thomas Breloff 4223bd57f1 travis; wine 2015-10-21 00:15:11 -04:00
Thomas Breloff 5bfa653858 travis; wine 2015-10-20 23:57:18 -04:00
Thomas Breloff 5342764caf travis 2015-10-20 23:23:38 -04:00
Thomas Breloff 04a44a82c9 tests 2015-10-20 23:07:47 -04:00
Thomas Breloff c28820f39c colors and tests 2015-10-20 17:11:21 -04:00
Thomas Breloff 546955a78b working on colors and tests 2015-10-20 14:49:01 -04:00
Thomas Breloff d1e9cc5800 palettes notebook 2015-10-20 12:55:36 -04:00
Thomas Breloff 4ef2fb9933 palettes notebook 2015-10-20 12:23:45 -04:00
Thomas Breloff d7bc8adf21 palettes notebook 2015-10-20 12:15:13 -04:00
Thomas Breloff b5f44efc69 palettes notebook 2015-10-20 11:56:06 -04:00
Thomas Breloff 5e8abea222 palettes notebook 2015-10-20 11:53:02 -04:00
Thomas Breloff f291454ccb palettes notebook 2015-10-20 10:40:49 -04:00
Thomas Breloff bac6637b46 messing with colors 2015-10-20 08:24:58 -04:00
Thomas Breloff 866ac9fb72 working on test framework 2015-10-19 17:53:17 -04:00
Thomas Breloff 8208f6947f pdf/ps/svg outputs 2015-10-19 14:11:22 -04:00
Thomas Breloff dcd50a7c62 started work on imgcomp tests 2015-10-19 00:31:43 -04:00
Thomas Breloff 781aa86568 started work on imgcomp tests 2015-10-19 00:24:04 -04:00
Thomas Breloff 3facc116c8 gadfly examples 2015-10-18 00:56:38 -04:00
Thomas Breloff 9178c3b087 winston examples 2015-10-18 00:50:30 -04:00
Thomas Breloff 5c6c85a22f qwt fixes and examples 2015-10-18 00:41:04 -04:00
Thomas Breloff b8adb4d229 unicodeplots examples 2015-10-18 00:08:42 -04:00
Thomas Breloff 093118da8b unicodeplots examples 2015-10-17 23:52:07 -04:00
Thomas Breloff 0aa760119f examples 2015-10-17 23:43:52 -04:00
Thomas Breloff 60b3a1583d examples 2015-10-17 23:31:50 -04:00
Thomas Breloff 593c47b938 examples 2015-10-17 23:29:03 -04:00
Thomas Breloff 0f6bb7ce6f examples 2015-10-17 23:10:45 -04:00
Thomas Breloff 048c2541e6 readme 2015-10-17 23:07:35 -04:00
Thomas Breloff f3e7d1a43b examples 2015-10-17 22:43:36 -04:00
Thomas Breloff 5df24d6683 custom markers example; pyplot markers 2015-10-17 22:16:06 -04:00
Thomas Breloff 73779898b7 pyplot fonts and fixes; examples 2015-10-17 16:49:45 -04:00
Thomas Breloff 7200b6adc6 pyplot set/get data; examples 2015-10-17 16:17:18 -04:00
Thomas Breloff d48f15ab4d examples 2015-10-17 15:22:00 -04:00
Thomas Breloff 2747671935 readme 2015-10-17 14:07:53 -04:00
Thomas Breloff d86f24dd35 pyplot fixes 2015-10-17 01:26:58 -04:00
Thomas Breloff 60edccade5 readme 2015-10-16 17:46:20 -04:00
Thomas Breloff 540460cae9 readme 2015-10-16 17:37:30 -04:00
Thomas Breloff df44d86f46 examples and readme 2015-10-16 17:25:54 -04:00
Thomas Breloff c287b446c9 fixes and examples 2015-10-16 17:21:28 -04:00
Thomas Breloff 1db36c05a8 animations 2015-10-16 16:36:40 -04:00
Thomas Breloff 2c884ab5ab animations 2015-10-16 12:03:40 -04:00
Thomas Breloff cd0dfc956d gadfly cleanup 2015-10-16 11:03:34 -04:00
Thomas Breloff 03392a5f03 gadfly cleanup 2015-10-16 10:58:44 -04:00
Thomas Breloff a7da999bd7 Font and tick/guide/legend fonts 2015-10-16 10:52:36 -04:00
Thomas Breloff 47f21b1652 fixes; changed reg to smooth, added loess smoothing in gadfly 2015-10-16 00:47:46 -04:00
Thomas Breloff 7c91d10c79 several fixes after gadfly reorg 2015-10-16 00:21:37 -04:00
Thomas Breloff fac2f5494b gadfly overhaul 2015-10-15 23:11:17 -04:00
Thomas Breloff bfcdb7e840 example 2015-10-15 17:30:44 -04:00
Thomas Breloff 21d55db3b4 slides 2015-10-15 17:19:57 -04:00
Thomas Breloff 18e49888fe jpg 2015-10-15 16:51:48 -04:00
Thomas Breloff 7ba2f61361 0.3 fix 2015-10-15 16:50:57 -04:00
Thomas Breloff 407df158ef PlotText/text for annotations; fixes 2015-10-15 14:46:29 -04:00
Thomas Breloff eab46ba9c4 fixes 2015-10-15 01:34:06 -04:00
Thomas Breloff 39318e5e61 working on shapes 2015-10-14 20:53:44 -04:00
Thomas Breloff ac1ce03fe5 working on shapes overhaul 2015-10-14 20:46:17 -04:00
Thomas Breloff 4fa697ec75 big shapes overhaul; gadfly ShapeGeometry; some reorg and cleanup... still working on it 2015-10-14 18:14:44 -04:00
Thomas Breloff 027961bffa various fixes 2015-10-14 12:11:20 -04:00
Thomas Breloff 7dfcbabe0c wine 2015-10-13 17:35:10 -04:00
Thomas Breloff dfc7658426 misc 2015-10-13 16:51:19 -04:00
Thomas Breloff 04c6726b76 pyplot cleanup 2015-10-13 15:56:14 -04:00
Thomas Breloff 8fdbbe4c16 pyplot subplots 2015-10-13 15:30:25 -04:00
Thomas Breloff 09fceab75b pyplot subplots 2015-10-13 15:02:27 -04:00
Thomas Breloff 8df4c27285 pyplot, corrplot, and nba 2015-10-13 01:16:11 -04:00
Thomas Breloff e38820b74a working on pyplot 2015-10-12 18:16:55 -04:00
Thomas Breloff c052e731f8 fix links to keep separate lims per row/column 2015-10-12 16:42:34 -04:00
Thomas Breloff 3636860262 subplot linkfunc, fixes, cleanup 2015-10-12 14:31:27 -04:00
Thomas Breloff ce7421bef4 immerse fix 2015-10-12 10:42:29 -04:00
Thomas Breloff 23b51c4c3e working on pyplot subplots 2015-10-10 00:57:48 -04:00
Thomas Breloff 48d802fc40 qwt subplots 2015-10-10 00:03:23 -04:00
Thomas Breloff 51e8f3ff6e working on subplots 2015-10-09 23:21:45 -04:00
Thomas Breloff 7917397bf3 working on corrplot and recipes 2015-10-09 17:08:17 -04:00
Thomas Breloff e0c0052b63 working on corrplot and recipes 2015-10-09 17:08:06 -04:00
Thomas Breloff 15a4b50ce4 working on corrplot and recipes 2015-10-09 17:03:54 -04:00
Thomas Breloff a51a8abf27 working on subplots and recipes 2015-10-09 16:00:24 -04:00
Thomas Breloff 45747e3635 working on recipes 2015-10-09 14:35:00 -04:00
Thomas Breloff 64b8e15918 working on subplots and recipes 2015-10-09 13:12:40 -04:00
Thomas Breloff f4b716b255 working on linked subplots 2015-10-08 17:44:00 -04:00
Thomas Breloff 1115ff83bb working on contours 2015-10-08 14:18:49 -04:00
Thomas Breloff c24550c756 0.3 fix gadfly shapes 2015-10-08 14:01:30 -04:00
Thomas Breloff b5cdfe30ea readme and examples 2015-10-08 13:33:14 -04:00
Thomas Breloff a10e594da1 tests 2015-10-08 12:31:33 -04:00
Thomas Breloff 63aee387f0 badges and test fix 2015-10-08 12:05:21 -04:00
Thomas Breloff ab9de1e199 added 0.3 and nightly to travis; force Winston to use gtk 2015-10-08 11:48:54 -04:00
Thomas Breloff e60c463328 0.3 support; require Compat; pyplot scatter colormaps 2015-10-08 11:30:20 -04:00
Thomas Breloff 537d74196b working on contours 2015-10-08 07:49:26 -04:00
Thomas Breloff a8bbbe8582 working on contours 2015-10-08 00:49:30 -04:00
Thomas Breloff 29471a7aac readme 2015-10-07 18:18:44 -04:00
Thomas Breloff 894a4a5567 winston fixes/examples and updated readme 2015-10-07 18:09:32 -04:00
Thomas Breloff f7cd5276f0 fixed qwt and examples 2015-10-07 17:42:08 -04:00
Thomas Breloff 95b8c71083 examples 2015-10-07 17:04:19 -04:00
Thomas Breloff 52c82e6fe2 examples 2015-10-07 16:54:42 -04:00
Thomas Breloff cef1abd6aa readme 2015-10-07 16:29:32 -04:00
Thomas Breloff 91da261128 working on colors/args and examples 2015-10-07 16:04:30 -04:00
Thomas Breloff 1c70346a61 bringing pyplot up to speed 2015-10-07 13:45:38 -04:00
Thomas Breloff 2de017086d working on colors and args 2015-10-07 12:50:07 -04:00
Thomas Breloff d6253c72d4 working on colors, args, and axis flip 2015-10-06 18:19:44 -04:00
Thomas Breloff e5007b6c87 working on colors, args, and axis flip 2015-10-06 17:51:54 -04:00
Thomas Breloff bbc18549b3 working on args 2015-10-06 11:37:45 -05:00
Thomas Breloff b6855b6fba working on args 2015-10-06 10:07:18 -05:00
Thomas Breloff 70db97d576 working on args 2015-10-06 09:49:33 -05:00
Thomas Breloff f632f2f39e working on args 2015-10-06 09:04:57 -05:00
Thomas Breloff b23f968d57 working on axis/line/marker/fill overhaul 2015-10-06 08:45:53 -05:00
Thomas Breloff ea88877a11 working on color schemes 2015-10-05 17:06:52 -05:00
Thomas Breloff 1de3decede working on color schemes 2015-10-05 16:28:43 -05:00
Thomas Breloff 78045fd2ab working on spy and nbins tuple 2015-10-04 21:39:32 -05:00
Thomas Breloff 7c8898158b working on gadfly continuous colors 2015-10-04 16:52:29 -05:00
Thomas Breloff 3fc5f87388 added better error for Winston output_surface 2015-10-04 09:41:42 -05:00
Thomas Breloff 623ca1effc winston log10 scale 2015-10-03 17:18:58 -05:00
Thomas Breloff da05e7fe5e qwt log10 scale 2015-10-03 17:03:13 -05:00
Thomas Breloff f3734d4c64 added pyplot scales 2015-10-03 09:46:02 -05:00
Thomas Breloff 9ab458e109 switched gadfly heatmap to Geom.histogram2d 2015-10-01 12:55:05 -05:00
Thomas Breloff d4c72e6f78 gadfly ribbon 2015-09-30 10:36:00 -04:00
Thomas Breloff 1f58ef5140 don't error on savefig without an ext, use default; closes #32 2015-09-30 09:55:07 -04:00
Thomas Breloff 69d574c587 added scales globally and to gadfly/immerse 2015-09-30 09:18:16 -04:00
Thomas Breloff a027fdded7 autoload dataframes 2015-09-29 14:40:11 -04:00
Thomas Breloff 443df0501d supported graphs 2015-09-29 14:27:18 -04:00
Thomas Breloff d68fe5f80d supported readme 2015-09-29 14:14:13 -04:00
Thomas Breloff ebf868bae3 supported readme 2015-09-29 14:13:46 -04:00
Thomas Breloff 8a9b3286e9 supportedGraphs utils and pngs; removed args/kwargs from defaults 2015-09-29 14:05:24 -04:00
Thomas Breloff a0455561b6 unicode hline/vline; supportGraph utils 2015-09-29 13:46:31 -04:00
Thomas Breloff 518ccf5a74 pyplot hline/vline 2015-09-29 12:20:58 -04:00
Thomas Breloff 54f09c58cb unicodeplots lims 2015-09-29 12:00:48 -04:00
Thomas Breloff 029ad1045a qwt lims/ticks 2015-09-29 11:50:02 -04:00
Thomas Breloff 2f55fb4d84 winston lims 2015-09-29 10:40:46 -04:00
Thomas Breloff add724eee9 working on gadfly ticks 2015-09-29 09:50:53 -04:00
Thomas Breloff 07324ae892 working on gadfly ticks 2015-09-29 09:49:58 -04:00
Thomas Breloff ffc05e971f working on ticks 2015-09-28 23:49:03 -04:00
Thomas Breloff 30f42fd1d4 added lims/ticks for pyplot 2015-09-28 22:49:46 -04:00
Thomas Breloff f284857438 added qwt hline/vline; working on setTicksFromStringVector 2015-09-28 17:56:32 -04:00
Thomas Breloff 06ab514472 qwt annotations and examples 2015-09-28 17:11:43 -04:00
Thomas Breloff 85b65acbe0 readme 2015-09-28 16:48:32 -04:00
Thomas Breloff 4d1d9de22f gitignore 2015-09-28 16:43:04 -04:00
Thomas Breloff a68ec9b191 savefig and png 2015-09-28 16:42:02 -04:00
Thomas Breloff e386636d66 readme 2015-09-28 16:01:48 -04:00
Thomas Breloff cc3311b8eb examples 2015-09-28 15:49:46 -04:00
Thomas Breloff d3d1181769 examples and readme 2015-09-28 15:44:50 -04:00
Thomas Breloff 001abf684c examples 2015-09-28 15:35:45 -04:00
Thomas Breloff 92a65296b5 redid supportedArgs 2015-09-28 15:21:45 -04:00
Thomas Breloff 3a7887d003 working on massive naming overhaul and fixes 2015-09-28 14:58:56 -04:00
Thomas Breloff 3334c4a87a winston annotations 2015-09-28 12:52:44 -04:00
Thomas Breloff 228ce768e0 pyplot annotations and ioff fix 2015-09-28 12:09:52 -04:00
Thomas Breloff eafc1a784c working on annotations 2015-09-28 11:09:45 -04:00
Thomas Breloff fd3a4d0a0e working on annotations 2015-09-28 10:46:53 -04:00
Thomas Breloff 77d679b63b working on handling string input data 2015-09-27 23:46:42 -04:00
Thomas Breloff 730d764c6e gadfly color group 2015-09-25 17:03:57 -04:00
Thomas Breloff 6f1ef82e89 gadfly color groups for line segments 2015-09-25 16:47:17 -04:00
Thomas Breloff d4da910f19 call Gadfly.get_stroke_vector; added getindex/setindex to qwt 2015-09-25 13:33:06 -04:00
Thomas Breloff a0a0773bd2 fix push warning 2015-09-25 09:42:16 -04:00
Thomas Breloff 9ce8d138d5 working on data updating and notebooks 2015-09-25 01:00:22 -04:00
Thomas Breloff 0041b034e0 working on various things 2015-09-24 16:47:30 -04:00
Thomas Breloff d781c437de started real time updates; fixes #29 (pyplot ijulia display) 2015-09-24 13:01:31 -04:00
Thomas Breloff 2fe21b8547 fixes, gadfly star shape, readme example 2015-09-24 00:35:18 -04:00
Thomas Breloff dbc90c9417 working on groups and iris notebook 2015-09-23 23:34:54 -04:00
Thomas Breloff 431d60a58a working on groups and iris notebook 2015-09-23 23:15:15 -04:00
Thomas Breloff fcfcc9a94a working on groups and iris notebook 2015-09-23 17:13:20 -04:00
Thomas Breloff 870fb4e2df working on groups and iris notebook 2015-09-23 17:12:26 -04:00
Thomas Breloff e3612b973f working on groups and iris notebook 2015-09-23 16:48:49 -04:00
Thomas Breloff 75f4ca928f working on auto-labels from dataframes meta info, and started group arg 2015-09-23 15:34:42 -04:00
Thomas Breloff 22fd25b30f readme 2015-09-23 13:36:51 -04:00
Thomas Breloff 610ddb09ff readme and cleanup 2015-09-23 13:33:12 -04:00
Thomas Breloff 33602aca11 fixed tests 2015-09-23 13:03:37 -04:00
Thomas Breloff a207856e99 lims/ticks for gadfly/immerse 2015-09-23 12:45:24 -04:00
Thomas Breloff 80e8b5b5e4 fixes 2015-09-23 11:35:08 -04:00
Thomas Breloff 273996aa91 working on ticks/lims 2015-09-23 00:14:32 -04:00
Thomas Breloff 646b88c5be working on ticks 2015-09-22 23:30:20 -04:00
Thomas Breloff 88cfd82a25 unicodeplots fixes 2015-09-22 17:19:37 -04:00
Thomas Breloff 2f8436be87 winston examples 2015-09-22 17:04:51 -04:00
Thomas Breloff a6237cdda3 qwt examples 2015-09-22 17:02:19 -04:00
Thomas Breloff eb93a767fc pyplot fixes and examples 2015-09-22 16:57:23 -04:00
Thomas Breloff 41852412ca gadfly/immerse fixes and examples 2015-09-22 16:46:54 -04:00
Thomas Breloff 224b2b7323 various fixes; readme 2015-09-22 16:30:40 -04:00
Thomas Breloff ec939f9f9a more display fun 2015-09-22 14:56:37 -04:00
Thomas Breloff eced15b712 working on display/writemime overhaul 2015-09-22 12:54:55 -04:00
Thomas Breloff f8fb473981 reexport Colors; move default backend choice into __init__; fixed pickDefaultBackend 2015-09-22 08:10:30 -04:00
Thomas Breloff f2bcb77cfb trying fgcolor gadfly 2015-09-22 00:04:35 -04:00
Thomas Breloff dc5da28176 initial dataframes support 2015-09-21 23:36:07 -04:00
Thomas Breloff be43e64743 foreground_color fixes and added support in pyplot 2015-09-21 23:04:37 -04:00
Thomas Breloff 454630dace qwt fixes 2015-09-21 22:14:59 -04:00
Thomas Breloff c9df244333 qwt fixes 2015-09-21 17:38:27 -04:00
Thomas Breloff 2649d97d69 readme 2015-09-21 17:31:36 -04:00
Thomas Breloff bcb9ac5501 readme 2015-09-21 17:29:51 -04:00
Thomas Breloff 76d1e26f7d readme 2015-09-21 17:04:20 -04:00
Thomas Breloff ba13ab9926 readme 2015-09-21 16:59:15 -04:00
Thomas Breloff c43b34b67f auto-generated readme 2015-09-21 16:49:45 -04:00
Thomas Breloff 3739c2881b fixed linetype aliases; for qwt as well 2015-09-21 16:18:58 -04:00
Thomas Breloff bc13b81351 working on readme_template; added path linetype and sorting logic for line 2015-09-21 16:03:59 -04:00
Thomas Breloff 86a56e487a working on aliases 2015-09-21 14:38:03 -04:00
Thomas Breloff 031058cd0c cleanup and renaming constants 2015-09-21 12:15:40 -04:00
Thomas Breloff 85040d6104 fix creating empty plot with plot() 2015-09-21 12:05:17 -04:00
Thomas Breloff efbf74b44c working on auto generated color palette 2015-09-21 11:45:37 -04:00
Thomas Breloff 774fc42e8e replaced creation of kw args 2015-09-20 23:48:45 -04:00
Thomas Breloff 692cfe4f52 added srand calls to tests and examples 2015-09-20 22:59:25 -04:00
Thomas Breloff 8b34d4417b gadfly display size and fix: check for line_style 2015-09-20 21:12:56 -04:00
Thomas Breloff c20a7b3c69 added fillto for gadfly/immerse 2015-09-19 17:23:18 -04:00
Thomas Breloff ff6e83c55e working on new plot logic 2015-09-19 14:39:25 -04:00
Thomas Breloff 6aa56fd30f fixed subplot bug 2015-09-19 00:38:50 -04:00
Thomas Breloff f5a6f129dd foreground_color 2015-09-19 00:05:24 -04:00
Thomas Breloff 5405c1d240 working on colors 2015-09-18 17:20:35 -04:00
Thomas Breloff 455f85e230 working on colors, args 2015-09-18 16:53:43 -04:00
Thomas Breloff fa899a67a7 added support for gadfly linestyles... depends on gadfly PR 695 2015-09-18 12:26:18 -04:00
Thomas Breloff 56cf25eebf gadfly shapes 2015-09-18 01:55:16 -04:00
Thomas Breloff 1a490551e6 working on arg aliases and reorg 2015-09-18 01:48:00 -04:00
Thomas Breloff 4514802e35 replacing String with AbstractString 2015-09-17 21:32:27 -04:00
Thomas Breloff a9062b0611 examples 2015-09-17 17:11:25 -04:00
Thomas Breloff eb6b30aab1 markers, fixes, and rerun examples 2015-09-17 17:05:08 -04:00
Thomas Breloff 922abd7ad3 examples 2015-09-17 16:21:13 -04:00
Thomas Breloff c4596dda75 more shape fun... completed gadfly's set 2015-09-17 16:18:48 -04:00
Thomas Breloff 168b77326b fixing markers 2015-09-17 15:44:01 -04:00
Thomas Breloff f674bba861 added gadfly shapes utriangle, dtriangle, and xcross 2015-09-17 15:28:54 -04:00
Thomas Breloff 6b2e65e738 ohlc example 2015-09-17 14:49:37 -04:00
Thomas Breloff 51021c799d accept vectors of tuples; implement ohlc for gadfly with an example 2015-09-17 14:44:29 -04:00
Thomas Breloff 01cb036976 added fillto support for winston 2015-09-17 11:26:26 -04:00
Thomas Breloff ea7867429f added hline/vline support in gadfly 2015-09-17 10:14:13 -04:00
Thomas Breloff c5300cd7be notes 2015-09-17 08:32:32 -04:00
Thomas Breloff ea34c7d226 working on winston and examples 2015-09-16 17:17:05 -04:00
Thomas Breloff 537e04989f working on winston 2015-09-16 16:34:40 -04:00
Thomas Breloff d447c5dc25 moved exports into backend files 2015-09-16 15:11:44 -04:00
Thomas Breloff 73944fc9bf first draft winston 2015-09-16 15:08:50 -04:00
Thomas Breloff 01e994e0f1 regenerate markdown 2015-09-16 14:32:36 -04:00
Thomas Breloff af3f3f436c improving markdown 2015-09-16 14:24:58 -04:00
Thomas Breloff 56e90a266a examples 2015-09-16 14:16:58 -04:00
Thomas Breloff 1fc59ed522 fix ALL_ARGS; unicodeplots examples 2015-09-16 14:01:53 -04:00
Thomas Breloff 3a3b1a6c17 examples 2015-09-16 13:40:23 -04:00
Thomas Breloff 242ce807df examples 2015-09-16 13:32:43 -04:00
Thomas Breloff 734967152c fixed suppported typo 2015-09-16 13:29:51 -04:00
Thomas Breloff 8023e15bb9 examples 2015-09-16 13:17:06 -04:00
Thomas Breloff ceb58a6fe1 supported functions; renamed a few things package to backend 2015-09-16 13:03:37 -04:00
Thomas Breloff ae48bd1abb working on big set of fixes/reorg; better example code, supportedArgs and subplotSupported, change dots to scatter and handle better 2015-09-16 12:07:08 -04:00
Thomas Breloff d27fe2fbad examples 2015-09-16 01:47:17 -04:00
Thomas Breloff 970686efaf supported functions and gadfly shapes 2015-09-16 01:42:47 -04:00
Thomas Breloff 8df46ec0e9 gadfly_shapes.jl 2015-09-16 00:25:51 -04:00
Thomas Breloff 864057a6ed unicode examples 2015-09-16 00:12:14 -04:00
Thomas Breloff 92ca4cb1d1 examples 2015-09-16 00:01:38 -04:00
Thomas Breloff aabf811fe7 working on Immerse subplot support 2015-09-15 23:27:00 -04:00
Thomas Breloff 9b0a645a05 working on immerse subplot window 2015-09-15 17:54:40 -04:00
Thomas Breloff 24b5e7ff09 pushtomaster 2015-09-15 17:11:36 -04:00
Thomas Breloff 48969ecee3 added sticks and sticksHack for Gadfly 2015-09-15 16:49:56 -04:00
Thomas Breloff 6ae0912e0e readme 2015-09-15 13:24:14 -04:00
Thomas Breloff e8062d544d readme 2015-09-15 13:18:49 -04:00
Thomas Breloff 07332aa4ac readme 2015-09-15 13:16:19 -04:00
Thomas Breloff 1e2b3559f2 gadfly marker fixes and examples 2015-09-15 13:08:04 -04:00
Thomas Breloff 8bfaa14edb added backend template 2015-09-15 10:03:56 -04:00
Thomas Breloff d4e87d3fe8 working on gadfly and immerse 2015-09-14 23:44:28 -04:00
Thomas Breloff 460348c0b6 working on gadfly and immerse 2015-09-14 23:28:47 -04:00
Thomas Breloff 264e8c735e working on gadfly markers 2015-09-14 17:27:37 -04:00
Thomas Breloff c4b04e2327 immerse final fixes and examples 2015-09-14 15:30:09 -04:00
Thomas Breloff dc1389bd1a working on immerse 2015-09-14 15:24:18 -04:00
Thomas Breloff 51e38c80d8 working on immerse 2015-09-14 15:08:25 -04:00
Thomas Breloff a33f5fabd1 working on immerse 2015-09-14 14:41:13 -04:00
Thomas Breloff e6c8344970 working on immerse 2015-09-14 13:44:58 -04:00
Thomas Breloff 2207ae6617 working on immerse 2015-09-14 12:35:24 -04:00
Thomas Breloff cdc6707ad3 pyplot bg color 2015-09-14 10:46:33 -04:00
Thomas Breloff 448fdaecbd readme 2015-09-14 00:45:55 -04:00
Thomas Breloff 4aa79aed6f readme 2015-09-14 00:45:00 -04:00
Thomas Breloff c8fcc373f8 examples and readme 2015-09-14 00:28:08 -04:00
Thomas Breloff 1410141b46 examples 2015-09-14 00:16:24 -04:00
Thomas Breloff 76efabb5f3 heatmaps, fixes 2015-09-14 00:15:51 -04:00
Thomas Breloff 36effc6dc4 working on pyplot 2015-09-13 22:20:15 -04:00
Thomas Breloff 8d5412a38f working on pyplot 2015-09-13 21:34:28 -04:00
Thomas Breloff 465b5d20b4 working on pyplot 2015-09-13 18:39:56 -04:00
Thomas Breloff 60a22b1897 working on pyplot 2015-09-13 17:02:03 -04:00
Thomas Breloff 09a685e977 gitignore 2015-09-13 16:36:32 -04:00
Thomas Breloff 31da90865c added args and kwargs to PLOT_DEFAULTS 2015-09-13 14:06:33 -04:00
Thomas Breloff 9ea98bcb56 readme 2015-09-12 22:54:16 -04:00
Thomas Breloff 4f9804d24e readme 2015-09-12 22:48:07 -04:00
Thomas Breloff 0a88518188 readme 2015-09-12 22:38:56 -04:00
Thomas Breloff ccae6373be readme 2015-09-12 22:31:05 -04:00
Thomas Breloff 31e5d07a45 readme 2015-09-12 22:24:44 -04:00
Thomas Breloff 056fee4b28 added parametric plot with example 2015-09-12 22:02:17 -04:00
Thomas Breloff 5a47864d73 readme 2015-09-12 21:46:30 -04:00
Thomas Breloff 1c7da432f1 readme 2015-09-12 21:40:25 -04:00
Thomas Breloff 3d3ceacaab pickDefaultBackend with warning; readme improvements 2015-09-12 21:33:38 -04:00
Thomas Breloff 35df39a44b readme and shorthands for switching plotters 2015-09-12 21:12:18 -04:00
Thomas Breloff c23d6d62e7 examples, fixes, and reorg img dir 2015-09-12 20:47:09 -04:00
Thomas Breloff 243d4a7ac3 working on unicodeplots savepng and examples 2015-09-12 20:28:40 -04:00
Thomas Breloff 50254d06d7 working on unicodeplots savepng and examples 2015-09-12 20:23:36 -04:00
Thomas Breloff 475b46f516 working on unicodeplots 2015-09-12 16:49:02 -04:00
Thomas Breloff f4573f7e87 added unicodeplots to examples 2015-09-12 16:37:34 -04:00
Thomas Breloff 7fb1a4ec0f better error when importing a package that is not installed; xmin/xmax functions example 2015-09-12 16:10:42 -04:00
Thomas Breloff 4299aa0ff8 more ways to plot Funtions 2015-09-12 15:59:45 -04:00
Thomas Breloff 4eb7e3810e unicodeplots 2015-09-12 14:58:15 -04:00
Thomas Breloff 3e7e7e9ac0 working on unicodeplots 2015-09-12 00:57:58 -04:00
Thomas Breloff 9e1058ec0a working on unicodeplots 2015-09-12 00:54:41 -04:00
Thomas Breloff 426a9eb6d3 working on unicodeplots 2015-09-12 00:31:48 -04:00
Thomas Breloff f322b9ac1c working on unicodeplots; added args to Plot; some reorg 2015-09-12 00:24:35 -04:00
Thomas Breloff e13fec08ca readme 2015-09-11 22:12:33 -04:00
86 changed files with 15236 additions and 1654 deletions
+3
View File
@@ -1,3 +1,6 @@
*.jl.cov
*.jl.*.cov
*.jl.mem
.DS_Store
examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
+50 -3
View File
@@ -4,10 +4,57 @@ os:
- linux
- osx
julia:
- 0.4
- release
- nightly
matrix:
allow_failures:
- julia: nightly
# # before install:
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
# # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install wkhtmltopdf; fi
# ref: http://askubuntu.com/a/556672 for the wkhtmltopdf apt repository info
sudo: required
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pwd ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./test/install_wkhtmltoimage.sh ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository -y ppa:pov/wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y wkhtmltopdf ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltopdf -V ; fi
# - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wkhtmltoimage -V ; fi
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltopdf "$@"' | sudo tee /usr/local/bin/wkhtmltopdf.sh >/dev/null
# sudo chmod a+x /usr/local/bin/wkhtmltopdf.sh
# # borrowed from Blink.jl's travis file
# matrix:
# include:
# - os: linux
# julia: 0.4
# env: TESTCMD="xvfb-run julia"
# - os: osx
# julia: 0.4
# env: TESTCMD="julia"
notifications:
email: false
email: true
# uncomment the following lines to override the default test script
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots"); Pkg.add("Gadfly"); Pkg.test("Plots"; coverage=true)'
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
- julia test/travis_commands.jl
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("GR"); Pkg.build("GR")'
# # - julia -e 'Pkg.clone("https://github.com/tbreloff/ImageMagick.jl.git"); Pkg.checkout("ImageMagick","tb_write"); Pkg.build("ImageMagick")'
# - julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
# # - julia -e 'Pkg.clone("https://github.com/JunoLab/Blink.jl.git"); Pkg.build("Blink"); import Blink; Blink.AtomShell.install()'
# # - julia -e 'Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")'
# - julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
#
# # - $TESTCMD -e 'Pkg.test("Plots"; coverage=false)'
# - 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())'
+164
View File
@@ -0,0 +1,164 @@
# Plots.jl NEWS
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.7!
---
## 0.7 (current master/dev)
#### 0.7.0
- Check out [the summary](http://plots.readthedocs.io/en/latest/plots_v0.7/)
- Revamped and simplified internals
- [Recipes, recipes, recipes](https://github.com/JuliaPlots/RecipesBase.jl/issues/6)
- [Layouts and Subplots](https://github.com/tbreloff/Plots.jl/issues/60)
- DataFrames is loaded automatically when installed
- Overhaul to GroupBy mechanic (now offloads to a recipe)
- Replaced much of the argument processing with recipes
- Added series recipes, and began to strip down un-needed backend code. Some recipes:
- line, step, sticks, bar, histogram, histogram2d, boxplot, violin, quiver, errorbars, density, ohlc
- Added `@shorthands` and `@userplot` macros for recipe convenience
- Better handling of errorbars and ribbons
- New Axis type
- Tracks extrema and discrete values
- New `link_axes` functionality
- `linetype` has been renamed `seriestype` (the alias is reversed)
- Many fixes and huge cleanup in GR
- Brand new subplot layout mechanics:
- `@layout` macro
- AbstractLayout, Subplot, GridLayout, and everything related
- Added dependency on Measures.jl
- Computations of axis/guide sizes and precise positioning
- Refactored and compartmentalized default dictionaries for attributes
- Deprecated Gadfly and Immerse backends
- Added `series_annotations` attribute (previously that functionality was merged with `annotations`, which are not series-specific)
- Removed `axis` attribute... currently not supporting twin (right) y axes
- Check for `ENV["PLOTS_USE_ATOM_PLOTPANE"]` and default to false
- Improved backend interface to reduce redundant code. Template updated.
- Added `html_output_format`, primarily for choosing between png and svg output in IJulia.
- Partial support of Julia v0.5
- Switched testing to dump reference images to JuliaPlots/PlotReferenceImages.jl
- Moved docs-specific code to new JuliaPlots/PlotDocs.jl
- Moved example list from ExamplePlots into Plots.
- Added several examples and improved others.
- Many other smaller changes and bug fixes.
---
## Version 0.6
#### 0.6.2
- `linewidth` fixes
- `markershape` fix
- converted center calc to centroid for shapes
- new dependency on [RecipesBase](https://github.com/JuliaPlots/RecipesBase.jl)
- REQUIRE upper limit for RecipesBase: 0.0.1
- GR fixes/improvements (@jheinen)
- support `zlims`, `bins`
- allow Plots colormaps
- other bug fixes
- native image support
- PGFPlots fixes/improvements (@pkofod)
- DataFrames are handled by recipes
- Plotly: zaxis, tick rotation, 3d axis fix
- Improvements in handling discrete data
- Support for image display
- `arrow` keyword and support for adding arrows to paths
- changed quiver recipe to use arrows
- Bug fixes for boxplots, heatmaps, and more
#### 0.6.1
- `rotation` keyword
- improved supported graphs
- subplot bug fix
#### 0.6.0
- `apply_series_recipe` framework for built-in recipes
- [boxplot/violin recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/boxplot.ipynb)
- [errorbar/ribbon recipes](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/errorbars.ipynb)
- [quiver recipe](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/quiver.ipynb)
- `polar` coordinates
- better support for shapes and custom polygons (see [batman](https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb))
- z-axis keywords
- 3D indexing overhaul: `push!`, `append!` support
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
- `typealias KW Dict{Symbol,Any}` used in place of splatting in many places
- png generation for plotly backend using wkhtmltoimage
- `normalize` and `weights` keywords
- background/foreground subcategories for fine-tuning of looks
- `add_theme`/`set_theme` and ggplot2 theme (see [this issue](https://github.com/tbreloff/Plots.jl/issues/201))
- `PLOTS_DEFAULT_BACKEND` environment variable
- `barh` linetype
- support for non-gridded surfaces with pyplot's trisurface
- pyplot surface zcolor
- internal refactor of supported.jl
- `wrap` method to bypass input processing
- `translate`, `scale` and `rotate` methods for coordinates and shapes
- and many more minor fixes and improvements
---
## Version 0.5
#### 0.5.4
- old heatmaps have been renamed to hist2d, and true heatmaps implemented (see https://github.com/tbreloff/Plots.jl/issues/147)
- lots of reorganization and redesign of the internals
- lots of renaming to keep to conventions: AbstractPlot, AbstractBackend, etc
- initial redesign of layouts
- integration with Atom PlotPane
- arc diagram and chord diagram (thanks to @diegozea: see https://github.com/tbreloff/Plots.jl/issues/163)
- work on GR, GLVisualize, and PGFPlots backends (thanks @jheinen @dlfivefifty @pkofod)
- improvements to Plotly setup (thanks @spencerlyon2)
- overhaul to series creation logic and groupby mechanic
- replace Dict with `typealias KW Dict{Symbol,Any}` in many places, also replacing keyword arg splatting
- new `shape` linetype for plotting polygons in plot-coordinates (see https://github.com/tbreloff/ExamplePlots.jl/blob/master/notebooks/batman.ipynb)
- many other fixes
#### 0.5.3
- `@gif` macro with `every`/`when` syntax
- bezier curves and other graph drawing helpers
- added FixedSizeArrays dependency with relevant functionality
- merged lots of improvements to GR (thanks @jheinen)
- `overwrite_figure`/`reuse` arg for reusing the same figure window
- deprecated Qwt, Winston, and Bokeh backends
- improved handling of 3D inputs (call `z=rand(10,10); surface(z)` for example)
- fix IJulia display issue
- lots of progress on PlotlyJS backend
- and many other changes and fixes...
#### 0.5.2
- Added [GR.jl](https://github.com/jheinen/GR.jl) as a backend (unfinished but functional) All credit to @jheinen
- Set defaults within backend calls (i.e. `gadfly(legend=false)`)
- `abline!`; also extrema allows plotting functions without giving x (i.e. `plot(cos, 0, 10); plot!(sin)`) @pkofod @joshday
- Integration with [PlotlyJS.jl](https://github.com/spencerlyon2/PlotlyJS.jl) for using Plotly inside a Blink window @spencerlyon2
- The Plotly backend has been split into my built-in version (`plotly()`) and @spencerlyon2's backend (`plotlyjs()`)
- Revamped backend setup code for easily adding new backends
- New docs (WIP) at http://plots.readthedocs.org/
- Overhaul to `:legend` keyword (see https://github.com/tbreloff/Plots.jl/issues/135)
- New dependency on Requires, allows auto-loading of DataFrames support
- Support for plotting lists of Tuples and FixedSizeArrays
- new `@animate` macro for super simple animations (see https://github.com/tbreloff/Plots.jl/issues/111#issuecomment-181515616)
- allow Function for `:fillrange` and `zcolor` arguments (for example: `scatter(sin, 0:10, marker=15, fill=(cos,0.4), zcolor=sin)`)
- allow vectors of PlotText without x/y coords (for example: `scatter(rand(10), m=20, ann=map(text, 1:10))`)
- Lots and lots of fixes
#### 0.5.1
#### 0.5.0
- `with` function for temporary defaults
- contours
- basic 3D plotting
- preliminary support for Bokeh
- `stroke` and `brush` for more fine-tuned control over visuals
- smarter "magic" arguments: `line`, `marker`
+23 -212
View File
@@ -1,224 +1,35 @@
# Plots
[![Build Status](https://travis-ci.org/tbreloff/Plots.jl.svg?branch=master)](https://travis-ci.org/tbreloff/Plots.jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
<!-- [![Coverage Status](https://coveralls.io/repos/tbreloff/Plots.jl/badge.svg?branch=master)](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
<!-- [![codecov.io](http://codecov.io/github/tbreloff/Plots.jl/coverage.svg?branch=master)](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
Plotting interface and wrapper for several plotting packages.
#### Author: Thomas Breloff (@tbreloff)
Please add wishlist items, bugs, or any other comments/questions to the issues list.
Plots is a plotting API and toolset. My goals with the package are:
## Examples
- **Powerful**. Do more with less. Complex visualizations become easy.
- **Intuitive**. Start generating plots without reading volumes of documentation. Commands should "just work".
- **Concise**. Less code means fewer mistakes and more efficient development/analysis.
- **Flexible**. Produce your favorite plots from your favorite package, but quicker and simpler.
- **Consistent**. Don't commit to one graphics package. Use the same code and access the strengths of all [backends](http://plots.readthedocs.io/en/latest/backends/).
- **Lightweight**. Very few dependencies, since backends are loaded and initialized dynamically.
- [Qwt.jl](docs/qwt_examples.md)
- [Gadfly.jl](docs/gadfly_examples.md)
Use the [preprocessing pipeline](http://plots.readthedocs.io/en/latest/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.
## Installation
First, clone the package, and get any plotting packages you need:
```
Pkg.clone("https://github.com/tbreloff/Plots.jl.git")
Pkg.add("Gadfly") # [optional]
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git") # [optional] requires pyqt and pyqwt
```
## Use
Load it in. The underlying plotting backends are not imported until `plotter()` is called (which happens
on your first call to `plot`). This means that you don't need any backends to be installed when you call `using Plots`.
For now, the default backend is Gadfly.
```
```julia
using Plots
pyplot(reuse=true)
@gif for i in linspace(0,2π,100)
X = Y = linspace(-5,5,40)
surface(X, Y, (x,y) -> sin(x+10sin(i))+cos(y))
end
```
Do a plot in Gadfly, then save a png:
```
plot(rand(10,2); marker = :rect)
savepng(Plots.IMG_DIR * "gadfly1.png")
```
which saves:
![gadfly_plt](img/gadfly1.png)
Do a plot in Qwt, then save a png:
```
plotter!(:qwt) # switches the backend to Qwt
plot(rand(10,2); marker = :rect)
savepng(Plots.IMG_DIR * "qwt1.png")
```
which saves:
![qwt_plt](img/qwt1.png)
## plot and plotter! interface (WIP)
The main plot command. Call `plotter!(:module)` to set the current plotting backend.
Commands are converted into the relevant plotting commands for that package:
```
plotter!(:gadfly)
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
plotter!(: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:
```
plot(args...; kw...) # creates a new plot window, and sets it to be the `currentPlot`
plot!(args...; kw...) # adds to the `currentPlot`
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.
Here are some various args to supply, and the implicit mapping (AVec == AbstractVector and AMat == AbstractMatrix):
```
plot(y::AVec; kw...) # one line... x = 1:length(y)
plot(x::AVec, y::AVec; kw...) # one line (will assert length(x) == length(y))
plot(y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1)
plot(x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
plot(x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y))
plot(x::AVec, f::Function; kw...) # one line, y = f(x)
plot(x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ)
plot(x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ)
plot(y::AVec{AVec}; kw...) # multiple lines, each with x = 1:length(y[i])
plot(x::AVec, y::AVec{AVec}; kw...) # multiple lines, will assert length(x) == length(y[i])
plot(x::AVec{AVec}, y::AVec{AVec}; kw...) # multiple lines, will assert length(x[i]) == length(y[i])
plot(n::Integer; kw...) # n lines, all empty (for updating plots)
# TODO: how do we handle NA values in dataframes?
plot(df::DataFrame; kw...) # one line per DataFrame column, labels == names(df)
plot(df::DataFrame, columns; kw...) # one line per column, but on a subset of column names
```
[TODO] You can swap out `plot` for `subplot`. Each line will go into a separate plot. Use the layout keyword:
```
y = rand(100,3)
subplot(y; layout=(2,2), kw...) # creates 3 lines going into 3 separate plots, laid out on a 2x2 grid (last row is filled with plot #3)
subplot(y; layout=(1,3), kw...) # again 3 plots, all in the same row
subplot(y; layout=[1,[2,3]]) # pass a nested Array to fully specify the layout. here the first plot will take up the first row,
# and the others will share the second row
```
Shorthands:
```
scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :hexagon)
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :hexagon)
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)
```
Some keyword arguments you can set:
```
axis # :left or :right
color # can be a string ("red") or a symbol (:red) or a ColorsTypes.jl Colorant (RGB(1,0,0)) or :auto (which lets the package pick)
label # string or symbol, applies to that line, may go in a legend
width # width of a line
linetype # :line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar
linestyle # :solid, :dash, :dot, :dashdot, :dashdotdot
marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon
markercolor # same choices as `color`, or :match will set the color to be the same as `color`
markersize # size of the marker
nbins # number of bins for heatmap/hexbin and histograms
heatmap_c # color cutoffs for Qwt heatmaps
fillto # fillto value for area plots
title # string or symbol, title of the plot
xlabel # string or symbol, label on the bottom (x) axis
ylabel # string or symbol, label on the left (y) axis
yrightlabel # string or symbol, label on the right (y) axis
reg # true or false, add a regression line for each line
size # (Int,Int), resize the enclosing window
pos # (Int,Int), move the enclosing window to this position
windowtitle # string or symbol, set the title of the enclosing windowtitle
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)
```
If you don't include a keyword argument, these are the defaults:
```
axis = :left
color = :auto
label = automatically generated (y1, y2, ...., or y1 (R), y2 (R) for the right axis)
width = 1
linetype = :line
linestype = :solid
marker = :none
markercolor = :match
markersize = 3
nbins = 100
heatmap_c = (0.15, 0.5)
fillto = nothing
title = ""
xlabel = ""
ylabel = ""
yrightlabel = ""
reg = false
size = (800,600)
pos = (0,0)
windowtitle = ""
screen = 1
show = true
```
When plotting multiple lines, you can give every line the same trait by using the singular, or add an "s" to pluralize.
(yes I know it's not gramatically correct, but it's easy to use and implement)
```
plot(rand(100,2); colors = [:red, RGB(.5,.5,0)], axiss = [:left, :right], width = 5) # note the width=5 is applied to both lines
```
# TODO
- [x] Plot vectors/matrices/functions
- [ ] Plot DataFrames
- [ ] Subplots
- [ ] Histograms
- [ ] 3D plotting
- [ ] Scenes/Drawing
- [ ] Graphs
- [ ] Interactivity (GUIs)
- [x] Gadfly.jl
- [ ] PyPlot.jl
- [ ] Winston.jl
- [ ] Gaston.jl
- [ ] GLPlot.jl
- [x] Qwt.jl
- [ ] Bokeh.jl
- [ ] Plotly.jl
- [ ] GoogleCharts.jl
- [ ] Vega.jl
- [ ] PLplot.jl
- [ ] TextPlots.jl
- [ ] ASCIIPlots.jl
- [ ] Sparklines.jl
- [ ] UnicodePlots.jl
- [ ] Hinton.jl
- [ ] ImageTerm.jl
- [ ] GraphViz.jl
- [ ] TikzGraphs.jl
- [ ] GraphLayout.jl
# Backends
See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
# Author
Thomas Breloff (@tbreloff)
![waves](http://plots.readthedocs.io/en/latest/examples/img/waves.gif)
View the [full documentation](http://plots.readthedocs.io).
+6 -2
View File
@@ -1,4 +1,8 @@
julia 0.4-
julia 0.4
RecipesBase
Colors
FactCheck
Reexport
Compat
FixedSizeArrays
Measures
Vendored Executable
+41
View File
File diff suppressed because one or more lines are too long
-118
View File
@@ -1,118 +0,0 @@
module PlotExamples
using Plots
using Colors
const DOCDIR = Pkg.dir("Plots") * "/docs"
const IMGDIR = Pkg.dir("Plots") * "/img"
doc"""
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
"""
type PlotExample
header::String
desc::String
exprs::Vector{Expr}
end
# the examples we'll run for each
const examples = PlotExample[
PlotExample("Lines",
"A simple line plot of the 3 columns.",
[:(plot(rand(100,3)))]),
PlotExample("Functions",
"Plot multiple functions",
[:(plot(0:0.01:4π, [sin,cos]))]),
PlotExample("Global",
"Change the guides/background without a separate call.",
[:(plot(rand(10); title="TITLE", xlabel="XLABEL", ylabel="YLABEL", background_color = RGB(0.5,0.5,0.5)))]),
PlotExample("Two-axis",
"Use the `axis` or `axiss` arguments.\n\nNote: This is only supported with Qwt right now",
[:(plot(Vector[randn(100), randn(100)*100]; axiss = [:left,:right]))]),
PlotExample("Vectors w/ pluralized args",
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).",
[:(plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8, colors=[:red,:blue]))]),
PlotExample("Build plot in pieces",
"Start with a base plot...",
[:(plot(rand(100)/3; reg=true, fillto=0))]),
PlotExample("",
"and add to it later.",
[:(scatter!(rand(100); markersize=6, color=:blue))]),
PlotExample("Heatmaps",
"",
[:(heatmap(randn(10000),randn(10000); nbins=200))]),
PlotExample("Lots of line types",
"Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar) \nNote: some may not work with all backends",
[:(plot(rand(20,4); linetypes=[:line, :step, :sticks, :dots]))]),
PlotExample("Bar",
"x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)",
[:(bar(randn(1000)))]),
PlotExample("Histogram",
"note: fillto isn't supported on all backends",
[:(histogram(randn(1000); nbins=50, fillto=20))]),
PlotExample("Subplots",
"""
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
number of columns `nc`), or you can set the layout directly with `layout`.
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
""",
[:(subplot(randn(100,5); layout=[1,1,3], linetypes=[:line,:hist,:dots,:step,:bar], nbins=10, legend=false))]),
PlotExample("Adding to subplots",
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
[:(subplot(randn(100,5); n=4))]),
PlotExample("",
"",
[:(subplot!(randn(100,3)))]),
]
function generate_markdown(pkgname::Symbol)
# set up the plotter, and don't show the plots by default
plotter!(pkgname)
plotDefault!(:show, false)
# open the markdown file
md = open("$DOCDIR/$(pkgname)_examples.md", "w")
for (i,example) in enumerate(examples)
try
# run the code
map(eval, example.exprs)
# save the png
imgname = "$(pkgname)_example_$i.png"
savepng("$IMGDIR/$imgname")
# write out the header, description, code block, and image link
write(md, "### $(example.header)\n\n")
write(md, "$(example.desc)\n\n")
write(md, "```julia\n$(join(map(string, example.exprs), "\n"))\n```\n\n")
write(md, "![](../img/$imgname)\n\n")
catch ex
# TODO: put error info into markdown?
warn("Example $pkgname:$i failed with: $ex")
end
#
end
close(md)
end
# run it!
map(generate_markdown, (:qwt, :gadfly))
end # module
-148
View File
@@ -1,148 +0,0 @@
### Lines
A simple line plot of the 3 columns.
```julia
plot(rand(100,3))
```
![](../img/gadfly_example_1.png)
### Functions
Plot multiple functions
```julia
plot(0:0.01:4π,[sin,cos])
```
![](../img/gadfly_example_2.png)
### Global
Change the guides/background without a separate call.
```julia
plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5))
```
![](../img/gadfly_example_3.png)
### Two-axis
Use the `axis` or `axiss` arguments.
Note: This is only supported with Qwt right now
```julia
plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right])
```
![](../img/gadfly_example_4.png)
### Vectors w/ pluralized args
Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).
```julia
plot(Vector[rand(10),rand(20)]; marker=:ellipse,markersize=8,colors=[:red,:blue])
```
![](../img/gadfly_example_5.png)
### Build plot in pieces
Start with a base plot...
```julia
plot(rand(100) / 3; reg=true,fillto=0)
```
![](../img/gadfly_example_6.png)
###
and add to it later.
```julia
scatter!(rand(100); markersize=6,color=:blue)
```
![](../img/gadfly_example_7.png)
### Heatmaps
```julia
heatmap(randn(10000),randn(10000); nbins=200)
```
![](../img/gadfly_example_8.png)
### Lots of line types
Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar)
Note: some may not work with all backends
```julia
plot(rand(20,4); linetypes=[:line,:step,:sticks,:dots])
```
![](../img/gadfly_example_9.png)
### Bar
x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)
```julia
bar(randn(1000))
```
![](../img/gadfly_example_10.png)
### Histogram
note: fillto isn't supported on all backends
```julia
histogram(randn(1000); nbins=50,fillto=20)
```
![](../img/gadfly_example_11.png)
### Subplots
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
number of columns `nc`), or you can set the layout directly with `layout`.
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
```julia
subplot(randn(100,5); layout=[1,1,3],linetypes=[:line,:hist,:dots,:step,:bar],nbins=10,legend=false)
```
![](../img/gadfly_example_12.png)
### Adding to subplots
Note here the automatic grid layout, as well as the order in which new series are added to the plots.
```julia
subplot(randn(100,5); n=4)
```
![](../img/gadfly_example_13.png)
###
```julia
subplot!(randn(100,3))
```
![](../img/gadfly_example_14.png)
-148
View File
@@ -1,148 +0,0 @@
### Lines
A simple line plot of the 3 columns.
```julia
plot(rand(100,3))
```
![](../img/qwt_example_1.png)
### Functions
Plot multiple functions
```julia
plot(0:0.01:4π,[sin,cos])
```
![](../img/qwt_example_2.png)
### Global
Change the guides/background without a separate call.
```julia
plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5))
```
![](../img/qwt_example_3.png)
### Two-axis
Use the `axis` or `axiss` arguments.
Note: This is only supported with Qwt right now
```julia
plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right])
```
![](../img/qwt_example_4.png)
### Vectors w/ pluralized args
Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).
```julia
plot(Vector[rand(10),rand(20)]; marker=:ellipse,markersize=8,colors=[:red,:blue])
```
![](../img/qwt_example_5.png)
### Build plot in pieces
Start with a base plot...
```julia
plot(rand(100) / 3; reg=true,fillto=0)
```
![](../img/qwt_example_6.png)
###
and add to it later.
```julia
scatter!(rand(100); markersize=6,color=:blue)
```
![](../img/qwt_example_7.png)
### Heatmaps
```julia
heatmap(randn(10000),randn(10000); nbins=200)
```
![](../img/qwt_example_8.png)
### Lots of line types
Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar)
Note: some may not work with all backends
```julia
plot(rand(20,4); linetypes=[:line,:step,:sticks,:dots])
```
![](../img/qwt_example_9.png)
### Bar
x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)
```julia
bar(randn(1000))
```
![](../img/qwt_example_10.png)
### Histogram
note: fillto isn't supported on all backends
```julia
histogram(randn(1000); nbins=50,fillto=20)
```
![](../img/qwt_example_11.png)
### Subplots
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
number of columns `nc`), or you can set the layout directly with `layout`.
Note: Gadfly is not very friendly here, and although you can create a plot and save a PNG, I haven't been able to actually display it.
```julia
subplot(randn(100,5); layout=[1,1,3],linetypes=[:line,:hist,:dots,:step,:bar],nbins=10,legend=false)
```
![](../img/qwt_example_12.png)
### Adding to subplots
Note here the automatic grid layout, as well as the order in which new series are added to the plots.
```julia
subplot(randn(100,5); n=4)
```
![](../img/qwt_example_13.png)
###
```julia
subplot!(randn(100,3))
```
![](../img/qwt_example_14.png)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

+4
View File
@@ -0,0 +1,4 @@
git checkout master
git merge --ff-only dev
git push origin master
git checkout dev
+321 -44
View File
@@ -1,76 +1,353 @@
__precompile__()
__precompile__()
module Plots
using Colors
using Compat
using Reexport
@reexport using Colors
# using Requires
using FixedSizeArrays
@reexport using RecipesBase
using Base.Meta
export
plotter,
plot,
subplot,
AbstractPlot,
Plot,
Subplot,
AbstractLayout,
GridLayout,
grid,
EmptyLayout,
@layout,
# RowsLayout,
# FlexLayout,
AVec,
AMat,
KW,
# attr,
# attr!,
plotter!,
plot!,
subplot!,
wrap,
set_theme,
add_theme,
currentPlot,
plotDefault,
scatter,
bar,
histogram,
heatmap,
plot,
plot!,
# subplot,
# subplot!,
currentPlot!,
plotDefault!,
scatter!,
bar!,
histogram!,
heatmap!,
current,
default,
with,
savepng
@userplot,
@shorthands,
# scatter,
# scatter!,
# bar,
# bar!,
# barh,
# barh!,
# histogram,
# histogram!,
# histogram2d,
# histogram2d!,
# density,
# density!,
# heatmap,
# heatmap!,
# hexbin,
# hexbin!,
# sticks,
# sticks!,
# hline,
# hline!,
# vline,
# vline!,
# ohlc,
# ohlc!,
pie,
pie!,
# contour,
# contour!,
# contour3d,
# contour3d!,
# surface,
# surface!,
# wireframe,
# wireframe!,
# path3d,
# path3d!,
plot3d,
plot3d!,
# scatter3d,
# scatter3d!,
# abline!,
# boxplot,
# boxplot!,
# violin,
# violin!,
# quiver,
# quiver!,
title!,
xlabel!,
ylabel!,
xlims!,
ylims!,
zlims!,
xticks!,
yticks!,
annotate!,
xflip!,
yflip!,
xaxis!,
yaxis!,
savefig,
png,
gui,
backend,
backends,
backend_name,
aliases,
dataframes,
Shape,
text,
font,
Axis,
# xaxis,
# yaxis,
# zaxis,
stroke,
brush,
Surface,
OHLC,
arrow,
colorscheme,
ColorScheme,
ColorGradient,
ColorVector,
ColorWrapper,
ColorFunction,
ColorZFunction,
getColor,
getColorZ,
debugplots,
supportedArgs,
supportedAxes,
supportedTypes,
supportedStyles,
supportedMarkers,
subplotSupported,
Animation,
frame,
gif,
@animate,
@gif,
PlotRecipe,
spy,
arcdiagram,
chorddiagram,
# @kw,
# @recipe,
# @plotrecipe,
test_examples,
translate,
translate!,
rotate,
rotate!,
center,
P2,
P3,
BezierCurve,
curve_points,
directed_curve
# ---------------------------------------------------------
const IMG_DIR = Pkg.dir("Plots") * "/img/"
import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height
typealias BBox Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct
# ---------------------------------------------------------
include("types.jl")
include("utils.jl")
# ---------------------------------------------------------
include("qwt.jl")
include("gadfly.jl")
include("plotter.jl")
# ---------------------------------------------------------
include("colors.jl")
include("components.jl")
include("axes.jl")
include("backends.jl")
include("args.jl")
include("themes.jl")
include("plot.jl")
include("subplot.jl")
include("series_args.jl")
include("series_new.jl")
include("layouts.jl")
include("subplots.jl")
include("recipes.jl")
include("animation.jl")
include("output.jl")
include("examples.jl")
include("arg_desc.jl")
# ---------------------------------------------------------
scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :hexagon)
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :hexagon)
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)
# define and export shorthand plotting method definitions
macro shorthands(funcname::Symbol)
funcname2 = Symbol(funcname, "!")
ret = esc(quote
export $funcname, $funcname2
$funcname(args...; kw...) = plot(args...; kw..., seriestype = $(quot(funcname)))
$funcname2(args...; kw...) = plot!(args...; kw..., seriestype = $(quot(funcname)))
end)
# dump(ret,20)
# @show ret
ret
end
@shorthands scatter
@shorthands bar
@shorthands barh
@shorthands histogram
@shorthands histogram2d
@shorthands density
@shorthands heatmap
@shorthands hexbin
@shorthands sticks
@shorthands hline
@shorthands vline
@shorthands ohlc
# @shorthands pie
@shorthands contour
@shorthands contour3d
@shorthands surface
@shorthands wireframe
@shorthands path3d
@shorthands scatter3d
@shorthands boxplot
@shorthands violin
@shorthands quiver
# scatter(args...; kw...) = plot(args...; kw..., seriestype = :scatter)
# scatter!(args...; kw...) = plot!(args...; kw..., seriestype = :scatter)
# bar(args...; kw...) = plot(args...; kw..., seriestype = :bar)
# bar!(args...; kw...) = plot!(args...; kw..., seriestype = :bar)
# barh(args...; kw...) = plot(args...; kw..., seriestype = :barh, orientation = :h)
# barh!(args...; kw...) = plot!(args...; kw..., seriestype = :barh, orientation = :h)
# histogram(args...; kw...) = plot(args...; kw..., seriestype = :histogram)
# histogram!(args...; kw...) = plot!(args...; kw..., seriestype = :histogram)
# histogram2d(args...; kw...) = plot(args...; kw..., seriestype = :histogram2d)
# histogram2d!(args...; kw...) = plot!(args...; kw..., seriestype = :histogram2d)
# density(args...; kw...) = plot(args...; kw..., seriestype = :density)
# density!(args...; kw...) = plot!(args...; kw..., seriestype = :density)
# heatmap(args...; kw...) = plot(args...; kw..., seriestype = :heatmap)
# heatmap!(args...; kw...) = plot!(args...; kw..., seriestype = :heatmap)
# hexbin(args...; kw...) = plot(args...; kw..., seriestype = :hexbin)
# hexbin!(args...; kw...) = plot!(args...; kw..., seriestype = :hexbin)
# sticks(args...; kw...) = plot(args...; kw..., seriestype = :sticks, marker = :ellipse)
# sticks!(args...; kw...) = plot!(args...; kw..., seriestype = :sticks, marker = :ellipse)
# hline(args...; kw...) = plot(args...; kw..., seriestype = :hline)
# hline!(args...; kw...) = plot!(args...; kw..., seriestype = :hline)
# vline(args...; kw...) = plot(args...; kw..., seriestype = :vline)
# vline!(args...; kw...) = plot!(args...; kw..., seriestype = :vline)
# ohlc(args...; kw...) = plot(args...; kw..., seriestype = :ohlc)
# ohlc!(args...; kw...) = plot!(args...; kw..., seriestype = :ohlc)
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
# contour(args...; kw...) = plot(args...; kw..., seriestype = :contour)
# contour!(args...; kw...) = plot!(args...; kw..., seriestype = :contour)
# contour3d(args...; kw...) = plot(args...; kw..., seriestype = :contour3d)
# contour3d!(args...; kw...) = plot!(args...; kw..., seriestype = :contour3d)
# surface(args...; kw...) = plot(args...; kw..., seriestype = :surface)
# surface!(args...; kw...) = plot!(args...; kw..., seriestype = :surface)
# wireframe(args...; kw...) = plot(args...; kw..., seriestype = :wireframe)
# wireframe!(args...; kw...) = plot!(args...; kw..., seriestype = :wireframe)
# path3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
# path3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
# scatter3d(args...; kw...) = plot(args...; kw..., seriestype = :scatter3d)
# scatter3d!(args...; kw...) = plot!(args...; kw..., seriestype = :scatter3d)
# boxplot(args...; kw...) = plot(args...; kw..., seriestype = :boxplot)
# boxplot!(args...; kw...) = plot!(args...; kw..., seriestype = :boxplot)
# violin(args...; kw...) = plot(args...; kw..., seriestype = :violin)
# violin!(args...; kw...) = plot!(args...; kw..., seriestype = :violin)
# quiver(args...; kw...) = plot(args...; kw..., seriestype = :quiver)
# quiver!(args...; kw...) = plot!(args...; kw..., seriestype = :quiver)
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip, kw...)
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
title!(plt::Plot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
xlims!(plt::Plot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::Plot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::Plot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
yticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
xticks!{T<:Real,S<:AbstractString}(plt::Plot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::Plot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
annotate!(plt::Plot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::Plot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
xflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::Plot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::Plot, args...; kw...) = plot!(plt; xaxis = args, kw...)
yaxis!(plt::Plot, args...; kw...) = plot!(plt; yaxis = args, kw...)
# ---------------------------------------------------------
const CURRENT_BACKEND = CurrentBackend(:none)
savepng(args...; kw...) = savepng(currentPlot(), args...; kw...)
savepng(plt::PlottingObject, args...; kw...) = savepng(plt.plotter, plt, args...; kw...)
# setup_dataframes()
function __init__()
setup_ijulia()
# setup_dataframes()
setup_atom()
# add_axis_letter_defaults()
end
# ---------------------------------------------------------
+143
View File
@@ -0,0 +1,143 @@
immutable Animation
dir::Compat.ASCIIString
frames::Vector{Compat.ASCIIString}
end
function Animation()
tmpdir = convert(Compat.ASCIIString, mktempdir())
Animation(tmpdir, Compat.ASCIIString[])
end
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename)
end
# -----------------------------------------------
"Wraps the location of an animated gif so that it can be displayed"
immutable AnimatedGif
filename::Compat.ASCIIString
end
function gif(anim::Animation, fn::Compat.ASCIIString = "tmp.gif"; fps::Integer = 20)
fn = abspath(fn)
try
# high quality
speed = round(Int, 100 / fps)
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
include(file)
end
prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
run(`$(joinpath(prefix, "convert")) -delay $speed -loop 0 $(joinpath(anim.dir, "*.png")) -alpha off $fn`)
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -i $(anim.dir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
end
info("Saved animation to ", fn)
AnimatedGif(fn)
end
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
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
+103
View File
@@ -0,0 +1,103 @@
const _arg_desc = KW(
# series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
:linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area from this to y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:seriescolor`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector. For histogram-types, defines the number of bins, or the edges, of the histogram.",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool. Should normalize histogram types? Trying for area == 1.",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
:background_color => "Color Type. Base color for all backgrounds.",
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
:foreground_color => "Color Type. Base color for all foregrounds.",
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
:window_title => "String. Title of the window.",
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
# subplot args
:title => "String. Subplot title.",
:title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefont => "Font. Font of subplot title.",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:legendfont => "Font. Font of legend items.",
:grid => "Bool. Show the grid lines?",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:projection => "Symbol or String. '3d' or 'polar'",
:aspect_ratio => "Symbol (:equal) or Number (width to height ratio of plot area).",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
# axis args
:guide => "String. Axis guide (label).",
:lims => "NTuple{2,Number}. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?",
:tickfont => "Font. Font of axis tick labels.",
:guidefont => "Font. Font of axis guide (label).",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
)
+1005 -119
View File
File diff suppressed because it is too large Load Diff
+314
View File
@@ -0,0 +1,314 @@
# xaxis(args...; kw...) = Axis(:x, args...; kw...)
# yaxis(args...; kw...) = Axis(:y, args...; kw...)
# zaxis(args...; kw...) = Axis(:z, args...; kw...)
# -------------------------------------------------------------------------
function Axis(sp::Subplot, letter::Symbol, args...; kw...)
# init with values from _plot_defaults
d = KW(
:letter => letter,
# :extrema => (Inf, -Inf),
:extrema => Extrema(),
:discrete_map => Dict(), # map discrete values to discrete indices
:continuous_values => zeros(0),
:use_minor => false,
:show => true, # show or hide the axis? (useful for linked subplots)
)
# get defaults from letter version, unless match
for (k,v) in _axis_defaults
lk = Symbol(letter, k)
lv = _axis_defaults_byletter[lk]
d[k] = (lv == :match ? v : lv)
end
# merge!(d, _axis_defaults)
d[:discrete_values] = []
# update the defaults
update!(Axis(sp, d), args...; kw...)
end
function process_axis_arg!(d::KW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
if typeof(arg) <: Font
d[Symbol(letter,:tickfont)] = arg
d[Symbol(letter,:guidefont)] = arg
elseif arg in _allScales
d[Symbol(letter,:scale)] = arg
elseif arg in (:flip, :invert, :inverted)
d[Symbol(letter,:flip)] = true
elseif T <: AbstractString
d[Symbol(letter,:guide)] = arg
# xlims/ylims
elseif (T <: Tuple || T <: AVec) && length(arg) == 2
sym = typeof(arg[1]) <: Number ? :lims : :ticks
d[Symbol(letter,sym)] = arg
# xticks/yticks
elseif T <: AVec
d[Symbol(letter,:ticks)] = arg
elseif arg == nothing
d[Symbol(letter,:ticks)] = []
elseif typeof(arg) <: Number
d[Symbol(letter,:rotation)] = arg
else
warn("Skipped $(letter)axis arg $arg")
end
end
# update an Axis object with magic args and keywords
function update!(axis::Axis, args...; kw...)
# first process args
d = axis.d
for arg in args
process_axis_arg!(d, arg)
end
# then override for any keywords... only those keywords that already exists in d
for (k,v) in kw
if haskey(d, k)
if k == :discrete_values
# add these discrete values to the axis
for vi in v
discrete_value!(axis, vi)
end
else
d[k] = v
end
end
end
axis
end
# -------------------------------------------------------------------------
Base.show(io::IO, axis::Axis) = dumpdict(axis.d, "Axis", true)
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.d, k)
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.d, v, ks...)
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
Base.extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
# get discrete ticks, or not
function get_ticks(axis::Axis)
ticks = axis[:ticks]
dvals = axis[:discrete_values]
if !isempty(dvals) && ticks == :auto
axis[:continuous_values], dvals
else
ticks
end
end
# -------------------------------------------------------------------------
function expand_extrema!(ex::Extrema, v::Number)
ex.emin = min(v, ex.emin)
ex.emax = max(v, ex.emax)
ex
end
function expand_extrema!(axis::Axis, v::Number)
expand_extrema!(axis[:extrema], v)
end
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX})
ex = axis[:extrema]
ex.emin = min(v[1], ex.emin)
ex.emax = max(v[2], ex.emax)
ex
end
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N})
ex = axis[:extrema]
for vi in v
expand_extrema!(ex, vi)
end
ex
end
function expand_extrema!(sp::Subplot, d::KW)
# first expand for the data
for letter in (:x, :y, :z)
data = d[letter]
axis = sp.attr[Symbol(letter, "axis")]
if eltype(data) <: Number
expand_extrema!(axis, data)
elseif isa(data, Surface) && eltype(data.surf) <: Number
expand_extrema!(axis, data)
elseif data != nothing
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
# @show letter,eltype(data),typeof(data)
d[letter], d[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
end
end
# # expand for fillrange/bar_width
# fillaxis, baraxis = sp.attr[:yaxis], sp.attr[:xaxis]
# if isvertical(d)
# fillaxis, baraxis = baraxis, fillaxis
# end
# expand for fillrange
vert = isvertical(d)
fr = d[:fillrange]
if fr == nothing && d[:seriestype] == :bar
fr = 0.0
end
if fr != nothing
axis = sp.attr[vert ? :yaxis : :xaxis]
if typeof(fr) <: Tuple
for fri in fr
expand_extrema!(axis, fri)
end
else
expand_extrema!(axis, fr)
end
end
# expand for bar_width
if d[:seriestype] == :bar
dsym = vert ? :x : :y
data = d[dsym]
bw = d[:bar_width]
if bw == nothing
bw = d[:bar_width] = mean(diff(data))
end
# @show data bw
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, minimum(data) - 0.5minimum(bw))
end
end
function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
expand_extrema!(sp[:xaxis], (xmin, xmax))
expand_extrema!(sp[:yaxis], (ymin, ymax))
end
# -------------------------------------------------------------------------
# push the limits out slightly
function widen(lmin, lmax)
span = lmax - lmin
# eps = max(1e-16, min(1e-2span, 1e-10))
eps = max(1e-16, 0.03span)
lmin-eps, lmax+eps
end
# figure out if widening is a good idea
function default_should_widen(axis::Axis)
should_widen = false
for series in series_list(axis.sp)
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
should_widen = true
end
end
should_widen
end
# using the axis extrema and limit overrides, return the min/max value for this axis
function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis))
ex = axis[:extrema]
amin, amax = ex.emin, ex.emax
lims = axis[:lims]
if isa(lims, Tuple) && length(lims) == 2
if isfinite(lims[1])
amin = lims[1]
end
if isfinite(lims[2])
amax = lims[2]
end
end
if amax <= amin
amax = amin + 1.0
end
if should_widen
widen(amin, amax)
else
amin, amax
end
end
# -------------------------------------------------------------------------
# these methods track the discrete (categorical) values which correspond to axis continuous values (cv)
# whenever we have discrete values, we automatically set the ticks to match.
# we return (continuous_value, discrete_index)
function discrete_value!(axis::Axis, dv)
cv_idx = get(axis[:discrete_map], dv, -1)
# @show axis[:discrete_map], axis[:discrete_values], dv
if cv_idx == -1
ex = axis[:extrema]
cv = max(0.5, ex.emax + 1.0)
expand_extrema!(axis, cv)
push!(axis[:discrete_values], dv)
push!(axis[:continuous_values], cv)
cv_idx = length(axis[:discrete_values])
axis[:discrete_map][dv] = cv_idx
cv, cv_idx
else
cv = axis[:continuous_values][cv_idx]
cv, cv_idx
end
end
# continuous value... just pass back with axis negative index
function discrete_value!(axis::Axis, cv::Number)
cv, -1
end
# add the discrete value for each item. return the continuous values and the indices
function discrete_value!(axis::Axis, v::AVec)
n = length(v)
cvec = zeros(n)
discrete_indices = zeros(Int, n)
for i=1:n
cvec[i], discrete_indices[i] = discrete_value!(axis, v[i])
end
cvec, discrete_indices
end
# add the discrete value for each item. return the continuous values and the indices
function discrete_value!(axis::Axis, v::AMat)
n,m = size(v)
cmat = zeros(n,m)
discrete_indices = zeros(Int, n, m)
for i=1:n, j=1:m
cmat[i,j], discrete_indices[i,j] = discrete_value!(axis, v[i,j])
end
cmat, discrete_indices
end
function discrete_value!(axis::Axis, v::Surface)
map(Surface, discrete_value!(axis, v.surf))
end
# -------------------------------------------------------------------------
function pie_labels(sp::Subplot, series::Series)
d = series.d
if haskey(d,:x_discrete_indices)
dvals = sp.attr[:xaxis].d[:discrete_values]
[dvals[idx] for idx in d[:x_discrete_indices]]
else
d[:x]
end
end
+190
View File
@@ -0,0 +1,190 @@
immutable NoBackend <: AbstractBackend end
const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :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_backend(s)
str = lowercase(string(s))
sym = Symbol(str)
T = Symbol(string(s) * "Backend")
esc(quote
immutable $T <: AbstractBackend 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_backend Immerse
@init_backend Gadfly
@init_backend PyPlot
@init_backend Qwt
@init_backend UnicodePlots
@init_backend Winston
@init_backend Bokeh
@init_backend Plotly
@init_backend PlotlyJS
@init_backend GR
@init_backend GLVisualize
@init_backend PGFPlots
include("backends/web.jl")
# include("backends/supported.jl")
# ---------------------------------------------------------
# don't do anything as a default
_create_backend_figure(plt::Plot) = nothing
_prepare_plot_object(plt::Plot) = nothing
_initialize_subplot(plt::Plot, sp::Subplot) = nothing
_series_added(plt::Plot, series::Series) = nothing
_series_updated(plt::Plot, series::Series) = nothing
_before_layout_calcs(plt::Plot) = nothing
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
# Set the (left, top, right, bottom) minimum padding around the plot area
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot)
leftpad = 10mm + sp[:left_margin] + guide_padding(sp[:yaxis])
toppad = 2mm + sp[:top_margin] + title_padding(sp)
rightpad = 3mm + sp[:right_margin]
bottompad = 5mm + sp[:bottom_margin] + guide_padding(sp[:xaxis])
# @show (leftpad, toppad, rightpad, bottompad)
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
_update_plot_object(plt::Plot) = nothing
# ---------------------------------------------------------
type CurrentBackend
sym::Symbol
pkg::AbstractBackend
end
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
env_default = get(ENV, "PLOTS_DEFAULT_BACKEND", "")
if env_default != ""
try
Pkg.installed(env_default) # this will error if not installed
sym = Symbol(lowercase(env_default))
if haskey(_backendType, sym)
return backend(sym)
else
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not a valid backend package. Choose from:\n\t",
join(sort(_backends), "\n\t"))
end
catch
warn("You have set PLOTS_DEFAULT_BACKEND=$env_default but it is not installed.")
end
end
# the ordering/inclusion of this package list is my semi-arbitrary guess at
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
for pkgstr in ("PyPlot", "GR", "PlotlyJS", "Immerse", "Gadfly", "UnicodePlots")
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::AbstractBackend)
CURRENT_BACKEND.sym = backend_name(pkg)
warn_on_deprecated_backend(CURRENT_BACKEND.sym)
CURRENT_BACKEND.pkg = pkg
end
function backend(modname::Symbol)
warn_on_deprecated_backend(modname)
CURRENT_BACKEND.sym = modname
CURRENT_BACKEND.pkg = _backend_instance(modname)
end
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
function warn_on_deprecated_backend(bsym::Symbol)
if bsym in _deprecated_backends
warn("Backend $bsym has been deprecated. It may not work as originally intended.")
end
end
# ---------------------------------------------------------
supportedAxes(::AbstractBackend) = [:left]
supportedTypes(::AbstractBackend) = []
supportedStyles(::AbstractBackend) = [:solid]
supportedMarkers(::AbstractBackend) = [:none]
supportedScales(::AbstractBackend) = [:identity]
subplotSupported(::AbstractBackend) = false
stringsSupported(::AbstractBackend) = false
nativeImagesSupported(b::AbstractBackend) = :image in supportedTypes(b)
supportedAxes() = supportedAxes(backend())
supportedTypes() = supportedTypes(backend())
supportedStyles() = supportedStyles(backend())
supportedMarkers() = supportedMarkers(backend())
supportedScales() = supportedScales(backend())
subplotSupported() = subplotSupported(backend())
stringsSupported() = stringsSupported(backend())
nativeImagesSupported() = nativeImagesSupported(backend())
# ---------------------------------------------------------
+209
View File
@@ -0,0 +1,209 @@
# https://github.com/bokeh/Bokeh.jl
supportedArgs(::BokehBackend) = [
# :annotations,
# :axis,
# :background_color,
:linecolor,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
:group,
# :label,
# :layout,
# :legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
# :linealpha,
:markershape,
:markercolor,
:markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :bins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
:size,
:title,
# :window_title,
:x,
# :xguide,
# :xlims,
# :xticks,
:y,
# :yguide,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface,
# :levels,
]
supportedAxes(::BokehBackend) = [:auto, :left]
supportedTypes(::BokehBackend) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline, :contour]
supportedStyles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::BokehBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::BokehBackend) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::BokehBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::BokehBackend; kw...)
@eval begin
warn("Bokeh is no longer supported... many features will likely be broken.")
import Bokeh
export Bokeh
end
end
const _glyphtypes = KW(
: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::KW)
st = d[:seriestype]
mt = d[:markershape]
if st == :scatter && mt == :none
mt = :ellipse
end
# if we have a marker, use that
if st == :scatter || mt != :none
return _glyphtypes[mt]
end
# otherwise return a line
return :Line
end
function get_stroke_vector(linestyle::Symbol)
dash = 12
dot = 3
gap = 2
linestyle == :solid && return Int[]
linestyle == :dash && return Int[dash, gap]
linestyle == :dot && return Int[dot, gap]
linestyle == :dashdot && return Int[dash, gap, dot, gap]
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
error("unsupported linestyle: ", linestyle)
end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::BokehBackend, d::KW)
function _create_backend_figure(plt::Plot{BokehBackend})
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
datacolumns = Bokeh.BokehDataSet[]
tools = Bokeh.tools()
filename = tempname() * ".html"
title = plt.attr[:title]
w, h = plt.attr[:size]
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
# legend = plt.attr[:legend] ? xxxx : nothing
legend = nothing
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
# Plot(bplt, pkg, 0, d, KW[])
end
# function _series_added(::BokehBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{BokehBackend}, series::Series)
bdata = Dict{Symbol, Vector}(:x => collect(series.d[:x]), :y => collect(series.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_object(plt::Plot{BokehBackend}, d::KW)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{BokehBackend}, i::Int)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y]
# end
#
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
# series = plt.o.datacolumns[i].data
# series[:x], series[:y] = xy
# plt
# end
# ----------------------------------------------------------------
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
# TODO: write a png to io
warn("mime png not implemented")
end
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
Bokeh.showplot(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
# # TODO: display/show the subplot
# end
+746
View File
@@ -0,0 +1,746 @@
# https://github.com/dcjones/Gadfly.jl
supportedArgs(::GadflyBackend) = [
:annotations,
:background_color, :foreground_color, :color_palette,
:group, :label, :seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :n, :nc, :nr, :layout, :smooth,
:title, :window_title, :show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
# :z, :zguide, :zlims, :zticks, :zscale, :zflip,
:z,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
]
supportedAxes(::GadflyBackend) = [:auto, :left]
supportedTypes(::GadflyBackend) = [
:none, :line, :path, :steppre, :steppost, :sticks,
:scatter, :histogram2d, :hexbin, :histogram,
:bar, #:box, :violin, :quiver,
:hline, :vline, :contour, :shape
]
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape)
supportedScales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::GadflyBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GadflyBackend; 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::KW)
gplt = Gadfly.Plot()
gplt.mapping = Dict()
gplt.data_source = Gadfly.DataFrames.DataFrame()
# gplt.layers = gplt.layers[1:0]
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xguide]),
Gadfly.Guide.ylabel(d[:yguide]),
Gadfly.Guide.title(d[:title])]
gplt
end
# ---------------------------------------------------------------------------
function getLineGeom(d::KW)
st = d[:seriestype]
xbins, ybins = maketuple(d[:bins])
if st == :hexb
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
elseif st == :histogram2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif st == :histogram
Gadfly.Geom.histogram(bincount = xbins,
orientation = isvertical(d) ? :vertical : :horizontal,
position = d[:bar_position] == :stack ? :stack : :dodge)
elseif st == :path
Gadfly.Geom.path
elseif st in (:bar, :sticks)
Gadfly.Geom.bar
elseif st == :steppost
Gadfly.Geom.step
elseif st == :steppre
Gadfly.Geom.step(direction = :vh)
elseif st == :hline
Gadfly.Geom.hline
elseif st == :vline
Gadfly.Geom.vline
elseif st == :contour
Gadfly.Geom.contour(levels = d[:levels])
# elseif st == :shape
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
nothing
end
end
function get_extra_theme_args(d::KW, k::Symbol)
# gracefully handles old Gadfly versions
extra_theme_args = KW()
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::KW)
st = d[:seriestype]
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
Gadfly.Theme(;
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
line_width = (st == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
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, numlayers::Int, d::KW, geoms...)
gplt = getGadflyContext(plt)
gfargs = vcat(geoms..., getGadflyLineTheme(d))
kwargs = KW()
st = d[:seriestype]
# add a fill?
if d[:fillrange] != nothing && st != :contour
fillmin, fillmax = map(makevec, maketuple(d[:fillrange]))
nmin, nmax = length(fillmin), length(fillmax)
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])]
push!(gfargs, Gadfly.Geom.ribbon)
end
if st in (:hline, :vline)
kwargs[st == :hline ? :yintercept : :xintercept] = d[:y]
else
if st == :sticks
w = 0.01 * mean(diff(d[:x]))
kwargs[:xmin] = d[:x] - w
kwargs[:xmax] = d[:x] + w
elseif st == :contour
kwargs[:z] = d[:z].surf
addGadflyContColorScale(plt, d[:linecolor])
end
kwargs[:x] = d[st == :histogram ? :y : :x]
kwargs[:y] = d[:y]
end
# # add the layer
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
get_shape(sym::Symbol) = _shapes[sym]
get_shape(shape::Shape) = shape
# extract the underlying ShapeGeometry object(s)
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
getMarkerGeom(other) = gadflyshape(get_shape(other))
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
function getMarkerGeom(d::KW)
if d[:seriestype] == :shape
Gadfly.Geom.polygon(fill = true, preserve_order = true)
else
getMarkerGeom(d[:markershape])
end
end
function getGadflyMarkerTheme(d::KW, attr::KW)
c = getColor(d[:markercolor])
α = d[:markeralpha]
if α != nothing
c = RGBA(RGB(c), α)
end
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
Gadfly.Theme(;
default_color = c,
default_point_size = ms,
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
highlight_width = d[:markerstrokewidth] * Gadfly.px,
line_width = d[:markerstrokewidth] * Gadfly.px,
# get_extra_theme_args(d, :markerstrokestyle)...
)
end
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
plt.attr[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = default_gradient()
end
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
end
function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...)
gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d))
kwargs = KW()
# handle continuous color scales for the markers
zcolor = d[:marker_z]
if zcolor != nothing && typeof(zcolor) <: AVec
kwargs[:color] = zcolor
addGadflyContColorScale(plt, d[:markercolor])
end
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
end
# ---------------------------------------------------------------------------
function addToGadflyLegend(plt::Plot, d::KW)
if plt.attr[:legend] != :none && d[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", @compat(AbstractString)[], Color[]))
end
# now add the series to the legend
for guide in gplt.guides
if isa(guide, Gadfly.Guide.ManualColorKey)
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
# since gadfly will call unique(colors), but doesn't also merge the rows that match
# Should ensure from this side that colors which are the same are merged together
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
foundit = false
# extend the label if we found this color
for i in 1:length(guide.colors)
if RGB(c) == guide.colors[i]
guide.labels[i] *= ", " * d[:label]
foundit = true
end
end
# didn't find the color, so add a new entry into the legend
if !foundit
push!(guide.labels, d[:label])
push!(guide.colors, c)
end
end
end
end
end
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
function addGadflySeries!(plt::Plot, d::KW)
layers = Gadfly.Layer[]
gplt = getGadflyContext(plt)
# add a regression line?
# TODO: make more flexible
smooth = getGadflySmoothing(d[:smooth])
# lines
geom = getLineGeom(d)
if geom != nothing
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
smooth = Any[] # don't add a regression for markers too
end
# special handling for ohlc and scatter
st = d[:seriestype]
# if st == :ohlc
# error("Haven't re-implemented after refactoring")
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
elseif st == :scatter && d[:markershape] == :none
d[:markershape] = :ellipse
end
# markers
if d[:markershape] != :none || st == :shape
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...))
end
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
# now save the layers that apply to this series
d[:gadflylayers] = layers
prepend!(gplt.layers, layers)
end
# ---------------------------------------------------------------------------
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
# # colorgroup
# z = d[:z]
# # handle line segments of different colors
# 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...))
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(d[:y])]
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
# colorgroup = [(:linecolor, cs), (:group, grp)]
# ---------------------------------------------------------------------------
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
ticks == :auto && return
# remove the ticks?
if ticks in (:none, false, nothing)
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
end
ttype = ticksType(ticks)
# just the values... put ticks here, but use standard labels
if ttype == :ticks
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
# set the ticks and the labels
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
elseif ttype == :ticks_and_labels
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
# # TODO add xtick_label function (given tick, return label??)
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
# filterGadflyScale(gplt, isx)
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
# labelmap = Dict(zip(ticks...))
# labelfunc = val -> labelmap[val]
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
filterGadflyScale(gplt, isx)
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
push!(gplt.scales, gfunc(labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
end
end
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
function getGadflyScaleFunction(d::KW, isx::Bool)
scalekey = isx ? :xscale : :yscale
hasScaleKey = haskey(d, scalekey)
if hasScaleKey
scale = d[scalekey]
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
end
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
end
function addGadflyLimitsScale(gplt, d::KW, isx::Bool)
gfunc, hasScaleKey, func = getGadflyScaleFunction(d, isx)
# do we want to add min/max limits for the axis?
limsym = isx ? :xlims : :ylims
limargs = Any[]
# map :auto to nothing, otherwise add to limargs
lims = get(d, limsym, :auto)
if lims == :auto
lims = nothing
else
if limsType(lims) == :limits
push!(limargs, (:minvalue, min(lims...)))
push!(limargs, (:maxvalue, max(lims...)))
else
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
end
end
# replace any current scales with this one
if hasScaleKey || !isempty(limargs)
filterGadflyScale(gplt, isx)
push!(gplt.scales, gfunc(; limargs...))
end
lims, func
end
function updateGadflyAxisFlips(gplt, d::KW, xlims, ylims, xfunc, yfunc)
if isa(gplt.coord, Gadfly.Coord.Cartesian)
gplt.coord = Gadfly.Coord.cartesian(
gplt.coord.xvars,
gplt.coord.yvars;
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
xflip = get(d, :xflip, gplt.coord.xflip),
yflip = get(d, :yflip, gplt.coord.yflip),
fixed = gplt.coord.fixed,
aspect_ratio = gplt.coord.aspect_ratio,
raster = gplt.coord.raster
)
else
gplt.coord = Gadfly.Coord.Cartesian(
xflip = get(d, :xflip, false),
yflip = get(d, :yflip, false)
)
end
end
function findGuideAndSet(gplt, t::DataType, args...; kw...) #s::@compat(AbstractString))
for (i,guide) in enumerate(gplt.guides)
if isa(guide, t)
gplt.guides[i] = t(args...; kw...)
end
end
end
function updateGadflyGuides(plt::Plot, d::KW)
gplt = getGadflyContext(plt)
haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title]))
haskey(d, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xguide]))
haskey(d, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:yguide]))
xlims, xfunc = addGadflyLimitsScale(gplt, d, true)
ylims, yfunc = addGadflyLimitsScale(gplt, d, false)
ticks = get(d, :xticks, :auto)
if ticks == :none
_remove_axis(plt, true)
else
addGadflyTicksGuide(gplt, ticks, true)
end
ticks = get(d, :yticks, :auto)
if ticks == :none
_remove_axis(plt, false)
else
addGadflyTicksGuide(gplt, ticks, false)
end
updateGadflyAxisFlips(gplt, d, xlims, ylims, xfunc, yfunc)
end
function updateGadflyPlotTheme(plt::Plot, d::KW)
kwargs = KW()
# colors
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
map(s -> getColor(d[s]), (
:background_color_inside,
:foreground_color_grid,
:foreground_color_text,
:foreground_color_guide,
:foreground_color_legend
))
# # hide the legend?
leg = d[d[:legend] == :none ? :colorbar : :legend]
if leg != :best
kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(d, :grid, true)
kwargs[:grid_color] = gridcolor
end
# fonts
tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont]
getGadflyContext(plt).theme = Gadfly.Theme(;
background_color = insidecolor,
minor_label_color = textcolor,
minor_label_font = tfont.family,
minor_label_font_size = tfont.pointsize * Gadfly.pt,
major_label_color = guidecolor,
major_label_font = gfont.family,
major_label_font_size = gfont.pointsize * Gadfly.pt,
key_title_color = guidecolor,
key_title_font = gfont.family,
key_title_font_size = gfont.pointsize * Gadfly.pt,
key_label_color = legendcolor,
key_label_font = lfont.family,
key_label_font_size = lfont.pointsize * Gadfly.pt,
plot_padding = 1 * Gadfly.mm,
kwargs...
)
end
# ----------------------------------------------------------------
function createGadflyAnnotationObject(x, y, val::@compat(AbstractString))
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, val)
))
end
function createGadflyAnnotationObject(x, y, txt::PlotText)
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
Gadfly.Guide.annotation(Compose.compose(
Compose.context(),
Compose.text(x, y, txt.str, halign, valign, rotations...),
Compose.font(string(txt.font.family)),
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
Compose.stroke(txt.font.color),
Compose.fill(txt.font.color)
))
end
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end
end
# ---------------------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::GadflyBackend, d::KW)
# gplt = createGadflyPlotObject(d)
# Plot(gplt, pkg, 0, d, KW[])
# end
function _create_backend_figure(plt::Plot{GadflyBackend})
createGadflyPlotObject(plt.attr)
end
# plot one data series
# function _series_added(::GadflyBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{GadflyBackend}, series::Series)
# first clear out the temporary layer
gplt = getGadflyContext(plt)
if gplt.layers[1].geom.tag == :remove
gplt.layers = gplt.layers[2:end]
end
addGadflySeries!(plt, series.d)
# push!(plt.seriesargs, d)
# plt
end
function _update_plot_object(plt::Plot{GadflyBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
# ----------------------------------------------------------------
# accessors for x/y data
# TODO: need to save all the layer indices which apply to this series
function getGadflyMappings(plt::Plot, i::Integer)
@assert i > 0 && i <= plt.n
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
end
function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer)
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
# isbefore && return false # wait until after plotting to create the subplots
# subplt.o = nothing
# true
# end
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
# function buildGadflySubplotContext(subplt::Subplot)
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
#
# # add the Plot object to the row
# push!(row, getGadflyContext(subplt.plts[i]))
#
# # add the row
# if c == ncols(subplt.layout, r)
# push!(rows, Gadfly.hstack(row...))
# row = Any[]
# end
# end
#
# # stack the rows
# Gadfly.vstack(rows...)
# end
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
# -------------------------------------------------------------------------
function dowritemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P})
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
end
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.writemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P})
func = getGadflyWriteFunc($mime())
dowritemime(io, func, plt)
end
end
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
setGadflyDisplaySize(plt.attr[:size]...)
display(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
# ctx = buildGadflySubplotContext(subplt)
#
# # taken from Gadfly since I couldn't figure out how to do it directly
#
# filename = string(Gadfly.tempname(), ".html")
# output = open(filename, "w")
#
# plot_output = IOBuffer()
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
# Compose.default_graphic_height, false), ctx)
# plotsvg = takebuf_string(plot_output)
#
# write(output,
# """
# <!DOCTYPE html>
# <html>
# <head>
# <title>Gadfly Plot</title>
# <meta charset="utf-8">
# </head>
# <body>
# <script charset="utf-8">
# $(readall(Compose.snapsvgjs))
# </script>
# <script charset="utf-8">
# $(readall(Gadfly.gadflyjs))
# </script>
# $(plotsvg)
# </body>
# </html>
# """)
# close(output)
# Gadfly.open_file(filename)
# end
+93
View File
@@ -0,0 +1,93 @@
# Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes
immutable ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
new(shape, tag)
end
end
# TODO: add for PR
# const shape = ShapeGeometry
function Gadfly.element_aesthetics(::ShapeGeometry)
[:x, :y, :size, :color]
end
# Generate a form for a shape geometry.
#
# Args:
# geom: shape geometry.
# theme: the plot's theme.
# aes: aesthetics.
#
# Returns:
# A compose Form.
#
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
# TODO: add for PR
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
# element_aesthetics(geom)...)
default_aes = Gadfly.Aesthetics()
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
default_aes.size = Compose.Measure[theme.default_point_size]
aes = Gadfly.inherit(aes, default_aes)
lw_hover_scale = 10
lw_ratio = theme.line_width / aes.size[1]
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
ctx = Compose.compose!(
Compose.context(),
make_polygon(geom, aes.x, aes.y, aes.size),
Compose.fill(aes.color),
Compose.linewidth(theme.highlight_width))
if aes.color_key_continuous != nothing && aes.color_key_continuous
Compose.compose!(ctx,
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
else
Compose.compose!(ctx,
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
for c in aes.color]))
end
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
end
function gadflyshape(sv::Shape)
ShapeGeometry(Any[vertices(sv)])
end
function gadflyshape(sv::AVec{Shape})
ShapeGeometry(Any[vertices(s) for s in sv])
end
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
n = max(length(xs), length(ys), length(rs))
T = Tuple{Compose.Measure, Compose.Measure}
polys = Array(Vector{T}, n)
for i in 1:n
x = Compose.x_measure(xs[mod1(i, length(xs))])
y = Compose.y_measure(ys[mod1(i, length(ys))])
r = rs[mod1(i, length(rs))]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in get_mod(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
# ---------------------------------------------------------------------------------------------
+136
View File
@@ -0,0 +1,136 @@
# [WEBSITE]
supportedArgs(::GLVisualizeBackend) = [
# :annotations,
# :axis,
# :background_color,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
# :group,
# :label,
# :layout,
# :legend,
# :linecolor,
# :linestyle,
:seriestype
# :seriescolor, :seriesalpha,
# :linewidth,
# :linealpha,
# :markershape,
# :markercolor,
# :markersize,
# :markeralpha,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
# :bins,
# :nc,
# :nr,
# :pos,
# :smooth,
# :show,
# :size,
# :title,
# :window_title,
# :x,
# :xguide,
# :xlims,
# :xticks,
# :y,
# :yguide,
# :ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
# :tickfont,
# :guidefont,
# :legendfont,
# :grid,
# :surface
# :levels,
]
supportedAxes(::GLVisualizeBackend) = [:auto, :left]
supportedTypes(::GLVisualizeBackend) = [:surface] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :histogram, :bar, :hline, :vline, :contour]
supportedStyles(::GLVisualizeBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GLVisualizeBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::GLVisualizeBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
subplotSupported(::GLVisualizeBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize
export GLVisualize
end
end
# ---------------------------------------------------------------------------
immutable GLScreenWrapper
window
end
# function _create_plot(pkg::GLVisualizeBackend, d::KW)
function _create_backend_figure(plt::Plot{GLVisualizeBackend})
# TODO: create the window/canvas/context that is the plot within the backend
# TODO: initialize the plot... title, xlabel, bgcolor, etc
# TODO: this should be moved to the display method?
w=GLVisualize.glscreen()
@async GLVisualize.renderloop(w)
GLScreenWrapper(w)
# Plot(GLScreenWrapper(w), pkg, 0, d, KW[])
end
# ----------------------------------------------------------------
function _series_added(plt::Plot{GLVisualizeBackend}, series::Series)
# TODO: add one series to the underlying package
# TODO: this should be moved to the display method?
x, y, z = map(Float32, series.d[:x]), map(Float32, series.d[:y]), map(Float32, series.d[:z].surf)
GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface), plt.o.window)
# plt
end
# When series data is added/changed, this callback can do dynamic updates to the backend object.
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
function _series_updated(plt::Plot{GLVisualizeBackend}, series::Series)
# TODO
end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
function _update_plot_object(plt::Plot{GLVisualizeBackend})
# TODO
end
# ----------------------------------------------------------------
function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
# TODO: write a png to io
end
function _display(plt::Plot{GLVisualizeBackend})
# 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
+1380
View File
File diff suppressed because it is too large Load Diff
+187
View File
@@ -0,0 +1,187 @@
# https://github.com/JuliaGraphics/Immerse.jl
supportedArgs(::ImmerseBackend) = supportedArgs(GadflyBackend())
supportedAxes(::ImmerseBackend) = supportedAxes(GadflyBackend())
supportedTypes(::ImmerseBackend) = supportedTypes(GadflyBackend())
supportedStyles(::ImmerseBackend) = supportedStyles(GadflyBackend())
supportedMarkers(::ImmerseBackend) = supportedMarkers(GadflyBackend())
supportedScales(::ImmerseBackend) = supportedScales(GadflyBackend())
subplotSupported(::ImmerseBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::ImmerseBackend; 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::KW)
w,h = d[:size]
figidx = Immerse.figure(; name = d[:window_title], width = w, height = h)
Immerse.Figure(figidx)
end
# ----------------------------------------------------------------
# create a blank Gadfly.Plot object
# function _create_plot(pkg::ImmerseBackend, d::KW)
# # create the underlying Gadfly.Plot object
# gplt = createGadflyPlotObject(d)
#
# # save both the Immerse.Figure and the Gadfly.Plot
# Plot((nothing,gplt), pkg, 0, d, KW[])
# end
function _create_backend_figure(plt::Plot{ImmerseBackend})
(nothing, createGadflyPlotObject(plt.attr))
end
# # plot one data series
# function _series_added(::ImmerseBackend, plt::Plot, d::KW)
# addGadflySeries!(plt, d)
# push!(plt.seriesargs, d)
# plt
# end
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
addGadflySeries!(plt, series.d)
end
function _update_plot_object(plt::Plot{ImmerseBackend}, d::KW)
updateGadflyGuides(plt, d)
updateGadflyPlotTheme(plt, d)
end
# ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping = getGadflyMappings(plt, i)[1]
mapping[:x], mapping[:y]
end
function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer)
for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy
end
plt
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
# return false
# # isbefore && return false
# end
#
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
# # create the Gtk window with vertical box vsep
# d = getattr(subplt,1)
# w,h = d[:size]
# vsep = Gtk.GtkBoxLeaf(:v)
# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h)
#
# figindices = []
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# for (i,(r,c)) in enumerate(subplt.layout)
# plt = subplt.plts[i]
#
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
#
# # add the plot's box to the row
# push!(row, box)
#
# # create the figure and store the index returned for destruction later
# figidx = Immerse.figure(canvas)
# push!(figindices, figidx)
#
# fig = Immerse.figure(figidx)
# plt.o = (fig, plt.o[2])
#
# # add the row
# if c == ncols(subplt.layout, r)
# row = Gtk.GtkBoxLeaf(:h)
# push!(vsep, row)
# end
#
# end
#
# # destructor... clean up plots
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
#
# subplt.o = win
# true
# end
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
gplt = getGadflyContext(plt)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
end
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
for l in getGadflyContext(plt).layers
_expand_limits(lims, l.mapping[isx ? :x : :y])
end
end
# ----------------------------------------------------------------
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
fig, gplt = plt.o
if fig == nothing
fig = createImmerseFigure(plt.attr)
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
plt.o = (fig, gplt)
end
Immerse.figure(fig.figno; displayfig = false)
display(gplt)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
#
# # if we haven't created the window yet, do it
# if subplt.o == nothing
# showSubplotObject(subplt)
# end
#
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
# for plt in subplt.plts
# fig, gplt = plt.o
# Immerse.figure(fig.figno; displayfig = false)
# display(gplt)
# end
#
# # o is the window... show it
# showall(subplt.o)
# end
+296
View File
@@ -0,0 +1,296 @@
# https://github.com/sisl/PGFPlots.jl
# significant contributions by: @pkofod
supportedArgs(::PGFPlotsBackend) = [
# :annotations,
:background_color, :foreground_color,
:color_palette,
# :background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
# :foreground_color_text, :foreground_color_border,
:group,
:label,
:seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins,
# :bar_width, :bar_edges,
# :n, :nc, :nr,
:layout,
# :smooth,
:title,
# :window_title,
:show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation,
:y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation,
:z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
# :colorbar,
# :marker_z, :levels,
# :xerror, :yerror,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
# :polar,
# :normalize, :weights, :contours,
:aspect_ratio,
# :match_dimensions,
]
supportedAxes(::PGFPlotsBackend) = [:auto, :left]
supportedTypes(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
supportedStyles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
supportedScales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10] # :asinh, :sqrt]
subplotSupported(::PGFPlotsBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
end
end
# --------------------------------------------------------------------------------------
const _pgfplots_linestyles = KW(
:solid => "solid",
:dash => "dashed",
:dot => "dotted",
:dashdot => "dashdotted",
:dashdotdot => "dashdotdotted",
)
const _pgfplots_markers = KW(
:none => "none",
:cross => "+",
:xcross => "x",
:utriangle => "triangle*",
:dtriangle => "triangle*",
:ellipse => "*",
:rect => "square*",
:star5 => "star",
:star6 => "asterisk",
:diamond => "diamond*",
:pentagon => "pentagon*",
)
const _pgfplots_legend_pos = KW(
:bottomleft => "south west",
:bottomright => "south east",
:topright => "north east",
:topleft => "north west",
)
const _pgf_series_extrastyle = KW(
:steppre => "const plot mark right",
:stepmid => "const plot mark mid",
:steppost => "const plot",
:sticks => "ycomb",
:ysticks => "ycomb",
:xsticks => "xcomb",
)
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
function pgf_color(c, a = nothing)
c = getColor(c)
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
a = float(a == nothing ? alpha(c) : a)
cstr, a
end
function pgf_fillstyle(d::KW)
cstr,a = pgf_color(d[:fillcolor], d[:fillalpha])
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d::KW)
cstr,a = pgf_color(d[:linecolor], d[:linealpha])
"""
color = $cstr,
draw opacity=$a,
line width=$(d[:linewidth]),
$(get(_pgfplots_linestyles, d[:linestyle], "solid"))"""
end
function pgf_marker(d::KW)
shape = d[:markershape]
cstr, a = pgf_color(d[:markercolor], d[:markeralpha])
cstr_stroke, a_stroke = pgf_color(d[:markerstrokecolor], d[:markerstrokealpha])
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(0.5 * d[:markersize]),
mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(d[:markerstrokewidth]),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, d[:markerstrokestyle], "solid"))
}"""
end
# --------------------------------------------------------------------------------------
function pgf_series(sp::Subplot, series::Series)
d = series.d
st = d[:seriestype]
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
if d[:fillrange] != nothing
push!(style, pgf_fillstyle(d))
end
# add to legend?
if sp[:legend] != :none && should_add_to_legend(series)
kw[:legendentry] = d[:label]
end
# function args
args = if st == :contour
d[:z].surf, d[:x], d[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
else
d[:x], d[:y]
end
# include additional style, then add to the kw
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
end
kw[:style] = join(style, ',')
# build/return the series object
func = if st == :path3d
PGFPlots.Linear3
elseif st == :scatter
PGFPlots.Scatter
elseif st == :histogram2d
PGFPlots.Histogram2
elseif st == :contour
PGFPlots.Contour
else
PGFPlots.Linear
end
func(args...; kw...)
end
# ----------------------------------------------------------------
function pgf_axis(sp::Subplot, letter)
axis = sp[Symbol(letter,:axis)]
style = []
kw = KW()
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
# scale
scale = axis[:scale]
if scale in (:log2, :ln, :log10)
kw[Symbol(letter,:mode)] = "log"
scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)")
end
# limits
lims = axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
# return the style list and KW args
style, kw
end
# ----------------------------------------------------------------
function _make_pgf_plot!(plt::Plot)
plt.o = PGFPlots.Axis[]
for sp in plt.subplots
# first build the PGFPlots.Axis object
style = ["unbounded coords=jump"]
kw = KW()
# add to style/kw for each axis
for letter in (:x, :y, :z)
if letter != :z || is3d(sp)
axisstyle, axiskw = pgf_axis(sp, letter)
merge!(kw, axiskw)
end
end
# bounding box values are in mm
# note: bb origin is top-left, pgf is bottom-left
bb = bbox(sp)
push!(style, """
xshift = $(left(bb).value)mm,
yshift = $((height(bb) - (bottom(bb))).value)mm,
width = $(width(bb).value)mm,
height = $(height(bb).value)mm,
axis background/.style={fill=$(pgf_color(sp[:background_color_inside])[1])}
""")
if sp[:title] != ""
push!(style, "title = $(sp[:title])")
end
sp[:grid] && push!(style, "grid = major")
if sp[:aspect_ratio] in (1, :equal)
kw[:axisEqual] = "true"
end
legpos = sp[:legend]
if haskey(_pgfplots_legend_pos, legpos)
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
o = PGFPlots.Axis(; style = style, kw...)
# add the series object to the PGFPlots.Axis
for series in series_list(sp)
push!(o, pgf_series(sp, series))
end
# add the PGFPlots.Axis to the list
push!(plt.o, o)
end
end
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
writemime(io, mime, plt.o)
end
function _writemime(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
writemime(io, mime, plt.o)
end
function _display(plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
display(plt.o)
end
+533
View File
@@ -0,0 +1,533 @@
# https://plot.ly/javascript/getting-started
supportedArgs(::PlotlyBackend) = [
:annotations,
:background_color, :foreground_color, :color_palette,
# :background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
# :foreground_color_text, :foreground_color_border,
:group,
:label,
:seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins,
:n, :nc, :nr, :layout,
# :smooth,
:title, :window_title, :show, :size,
:x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation,
:y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation,
:z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation,
:z,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours, :aspect_ratio
]
supportedAxes(::PlotlyBackend) = [:auto, :left]
supportedTypes(::PlotlyBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
:histogram2d, :histogram, :density, :bar, :contour, :surface, :path3d, :scatter3d,
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
supportedStyles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::PlotlyBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
supportedScales(::PlotlyBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PlotlyBackend) = true
stringsSupported(::PlotlyBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::PlotlyBackend; kw...)
@eval begin
import JSON
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
_js_path = Pkg.dir("Plots", "deps", "plotly-latest.min.js")
_js_code = open(@compat(readstring), _js_path, "r")
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
_js_script = """
<script type='text/javascript'>
define('plotly', function(require, exports, module) {
$(_js_code)
});
require(['plotly'], function(Plotly) {
window.Plotly = Plotly;
});
</script>
"""
# if we're in IJulia call setupnotebook to load js and css
if isijulia()
display("text/html", _js_script)
end
# if isatom()
# import Atom
# Atom.@msg evaljs(_js_code)
# end
end
# TODO: other initialization
end
# ----------------------------------------------------------------
function plotlyfont(font::Font, color = font.color)
KW(
:family => font.family,
:size => round(Int, font.pointsize*1.4),
:color => webcolor(color),
)
end
function get_annotation_dict(x, y, val)
KW(
: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), KW(
: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 get_annotation_dict_for_arrow(d::KW, xyprev::Tuple, xy::Tuple, a::Arrow)
# xdiff = xyprev[1] - xy[1]
# ydiff = xyprev[2] - xy[2]
# dist = sqrt(xdiff^2 + ydiff^2)
# KW(
# :showarrow => true,
# :x => xy[1],
# :y => xy[2],
# # :ax => xyprev[1] - xy[1],
# # :ay => xy[2] - xyprev[2],
# # :ax => 0,
# # :ay => -40,
# :ax => 10xdiff / dist,
# :ay => -10ydiff / dist,
# :arrowcolor => webcolor(d[:linecolor], d[:linealpha]),
# :xref => "x",
# :yref => "y",
# :arrowsize => 10a.headwidth,
# # :arrowwidth => a.headlength,
# :arrowwidth => 0.1,
# )
# end
function plotlyscale(scale::Symbol)
if scale == :log10
"log"
else
"-"
end
end
use_axis_field(ticks) = !(ticks in (nothing, :none))
# this method gets the start/end in percentage of the canvas for this axis direction
function plotly_domain(sp::Subplot, letter)
figw, figh = sp.plt[:size]
pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px)
i1,i2 = (letter == :x ? (1,3) : (2,4))
[pcts[i1], pcts[i1]+pcts[i2]]
end
function plotly_axis(axis::Axis, sp::Subplot)
letter = axis[:letter]
# d = axis.d
ax = KW(
:title => axis[:guide],
:showgrid => sp[:grid],
:zeroline => false,
)
# fgcolor = webcolor(axis[:foreground_color])
# tsym = tickssym(letter)
# spidx = sp[:subplot_index]
# d_out[:xaxis] = "x$spidx"
# d_out[:yaxis] = "y$spidx"
if letter in (:x,:y)
ax[:domain] = plotly_domain(sp, letter)
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
end
rot = axis[:rotation]
if rot != 0
ax[:tickangle] = rot
end
if use_axis_field(axis[:ticks])
ax[:titlefont] = plotlyfont(axis[:guidefont], webcolor(axis[:foreground_color_guide]))
ax[:type] = plotlyscale(axis[:scale])
ax[:tickfont] = plotlyfont(axis[:tickfont], webcolor(axis[:foreground_color_text]))
ax[:tickcolor] = webcolor(axis[:foreground_color_border])
ax[:linecolor] = webcolor(axis[:foreground_color_border])
# lims
lims = axis[:lims]
if lims != :auto && limsType(lims) == :limits
ax[:range] = lims
end
# flip
if axis[:flip]
ax[:autorange] = "reversed"
end
# ticks
ticks = axis[:ticks]
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
else
ax[:showticklabels] = false
ax[:showgrid] = false
end
ax
end
# function plotly_layout_json(plt::Plot{PlotlyBackend})
# d = plt
# function plotly_layout(d::KW, seriesargs::AVec{KW})
function plotly_layout(plt::Plot)
d_out = KW()
# # for now, we only support 1 subplot
# if length(plt.subplots) > 1
# warn("Subplots not supported yet")
# end
# sp = plt.subplots[1]
d_out[:width], d_out[:height] = plt[:size]
d_out[:paper_bgcolor] = webcolor(plt[:background_color_outside])
for sp in plt.subplots
sp_out = KW()
spidx = plotly_subplot_index(sp)
# set the fields for the plot
d_out[:title] = sp[:title]
d_out[:titlefont] = plotlyfont(sp[:titlefont], webcolor(sp[:foreground_color_title]))
# # TODO: use subplot positioning logic
# d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20)
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>30)
d_out[:plot_bgcolor] = webcolor(sp[:background_color_inside])
# TODO: x/y axis tick values/labels
# if any(is3d, seriesargs)
if is3d(sp)
d_out[:scene] = KW(
Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp),
Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp),
)
else
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
end
# legend
d_out[:showlegend] = sp[:legend] != :none
if sp[:legend] != :none
d_out[:legend] = KW(
:bgcolor => webcolor(sp[:background_color_legend]),
:bordercolor => webcolor(sp[:foreground_color_legend]),
:font => plotlyfont(sp[:legendfont]),
)
end
# annotations
anns = sp[:annotations]
d_out[:annotations] = if isempty(anns)
KW[]
else
KW[get_annotation_dict(ann...) for ann in anns]
end
# # arrows
# for sargs in seriesargs
# a = sargs[:arrow]
# if sargs[:seriestype] in (:path, :line) && typeof(a) <: Arrow
# add_arrows(sargs[:x], sargs[:y]) do xyprev, xy
# push!(d_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a))
# end
# end
# end
# dumpdict(d_out,"",true)
# @show d_out[:annotations]
if ispolar(sp)
d_out[:direction] = "counterclockwise"
end
d_out
end
d_out
end
function plotly_layout_json(plt::Plot)
JSON.json(plotly_layout(plt))
end
function plotly_colorscale(grad::ColorGradient, alpha = nothing)
[[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)]
end
plotly_colorscale(c, alpha = nothing) = plotly_colorscale(default_gradient(), alpha)
const _plotly_markers = KW(
:rect => "square",
:xcross => "x",
:utriangle => "triangle-up",
:dtriangle => "triangle-down",
:star5 => "star-triangle-up",
:vline => "line-ns",
:hline => "line-ew",
)
function plotly_subplot_index(sp::Subplot)
spidx = sp[:subplot_index]
spidx == 1 ? "" : spidx
end
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
function plotly_series(plt::Plot, series::Series)
d = series.d
sp = d[:subplot]
d_out = KW()
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(sp)
d_out[:xaxis] = "x$spidx"
d_out[:yaxis] = "y$spidx"
x, y = collect(d[:x]), collect(d[:y])
d_out[:name] = d[:label]
st = d[:seriestype]
isscatter = st in (:scatter, :scatter3d)
hasmarker = isscatter || d[:markershape] != :none
hasline = !isscatter
# set the "type"
if st 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 st == :bar
d_out[:type] = "bar"
d_out[:x], d_out[:y] = x, y
elseif st == :histogram2d
d_out[:type] = "histogram2d"
d_out[:x], d_out[:y] = x, y
if isa(d[:bins], Tuple)
xbins, ybins = d[:bins]
else
xbins = ybins = d[:bins]
end
d_out[:nbinsx] = xbins
d_out[:nbinsy] = ybins
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
elseif st in (:histogram, :density)
d_out[:type] = "histogram"
isvert = isvertical(d)
d_out[isvert ? :x : :y] = y
d_out[isvert ? :nbinsx : :nbinsy] = d[:bins]
if st == :density
d_out[:histogramnorm] = "probability density"
end
elseif st == :heatmap
d_out[:type] = "heatmap"
# d_out[:x], d_out[:y] = x, y
# d_out[:z] = d[:z].surf
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
elseif st == :contour
d_out[:type] = "contour"
# d_out[:x], d_out[:y] = x, y
# d_out[:z] = d[:z].surf
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
# d_out[:showscale] = d[:colorbar] != :none
d_out[:ncontours] = d[:levels]
d_out[:contours] = KW(:coloring => d[:fillrange] != nothing ? "fill" : "lines")
d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha])
elseif st in (:surface, :wireframe)
d_out[:type] = "surface"
# d_out[:x], d_out[:y] = x, y
# d_out[:z] = d[:z].surf
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
elseif st == :pie
d_out[:type] = "pie"
d_out[:labels] = pie_labels(sp, series)
d_out[:values] = y
d_out[:hoverinfo] = "label+percent+name"
elseif st 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: seriestype $st isn't supported.")
return KW()
end
# add "marker"
if hasmarker
d_out[:marker] = KW(
:symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])),
:opacity => d[:markeralpha],
:size => 2 * d[:markersize],
:color => webcolor(d[:markercolor], d[:markeralpha]),
:line => KW(
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
:width => d[:markerstrokewidth],
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if d[:marker_z] != nothing
# d_out[:marker][:color] = d[:marker_z]
# d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor], d[:markeralpha])
# d_out[:showscale] = true
grad = ColorGradient(d[:markercolor], alpha=d[:markeralpha])
zmin, zmax = extrema(d[:marker_z])
d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:marker_z]]
end
end
# add "line"
if hasline
d_out[:line] = KW(
:color => webcolor(d[:linecolor], d[:linealpha]),
:width => d[:linewidth],
:shape => if st == :steppre
"vh"
elseif st == :steppost
"hv"
else
"linear"
end,
:dash => string(d[:linestyle]),
# :dash => "solid",
)
end
# convert polar plots x/y to theta/radius
if ispolar(d[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x))
d_out[:r] = pop!(d_out, :y)
end
d_out
end
# get a list of dictionaries, each representing the series params
function plotly_series_json(plt::Plot)
JSON.json(map(series -> plotly_series(plt, series), plt.series_list))
end
# ----------------------------------------------------------------
function html_head(plt::Plot{PlotlyBackend})
"<script src=\"$(Pkg.dir("Plots","deps","plotly-latest.min.js"))\"></script>"
end
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
if style == nothing
w, h = plt[:size]
style = "width:$(w)px;height:$(h)px;"
end
uuid = Base.Random.uuid4()
html = """
<div id=\"$(uuid)\" style=\"$(style)\"></div>
<script>
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
</script>
"""
html
end
function js_body(plt::Plot{PlotlyBackend}, uuid)
js = """
PLOT = document.getElementById('$(uuid)');
Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
"""
end
# ----------------------------------------------------------------
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
writemime_png_from_html(io, plt)
end
function _writemime(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
end
# function Base.display(::PlotsDisplay, plt::Plot{PlotlyBackend})
function _display(plt::Plot{PlotlyBackend})
standalone_html_window(plt)
end
+187
View File
@@ -0,0 +1,187 @@
# https://github.com/spencerlyon2/PlotlyJS.jl
supportedArgs(::PlotlyJSBackend) = [
:annotation,
# :axis,
:background_color,
:color_palette,
:fillrange,
:fillcolor,
:fillalpha,
:foreground_color,
:group,
:label,
:layout,
:legend,
:seriescolor, :seriesalpha,
:linecolor,
:linestyle,
:seriestype,
:linewidth,
:linealpha,
:markershape,
:markercolor,
:markersize,
:markeralpha,
:markerstrokewidth,
:markerstrokecolor,
:markerstrokestyle,
:n,
:bins,
:nc,
:nr,
# :pos,
# :smooth,
:show,
:size,
:title,
:window_title,
:x,
:xguide,
:xlims,
:xticks,
:y,
:yguide,
:ylims,
# :yrightlabel,
:yticks,
:xscale,
:yscale,
:xflip,
:yflip,
:z,
:marker_z,
:tickfont,
:guidefont,
:legendfont,
:grid,
:levels,
:xerror,
:yerror,
:ribbon,
:quiver,
:orientation,
:polar,
]
supportedAxes(::PlotlyJSBackend) = [:auto, :left]
supportedTypes(::PlotlyJSBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
:histogram2d, :histogram, :density, :bar, :contour, :surface, :path3d, :scatter3d,
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
supportedStyles(::PlotlyJSBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::PlotlyJSBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
supportedScales(::PlotlyJSBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PlotlyJSBackend) = true
stringsSupported(::PlotlyJSBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::PlotlyJSBackend; kw...)
@eval begin
import PlotlyJS
export PlotlyJS
end
for (mime, fmt) in PlotlyJS._mimeformats
# mime == "image/png" && continue # don't use plotlyjs's writemime for png
@eval Base.writemime(io::IO, m::MIME{Symbol($mime)}, p::Plot{PlotlyJSBackend}) = writemime(io, m, p.o)
end
# override IJulia inline display
if isijulia()
IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
end
end
# ---------------------------------------------------------------------------
# function _create_plot(pkg::PlotlyJSBackend, d::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, KW[])
# end
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
PlotlyJS.plot()
end
function _series_added(plt::Plot{PlotlyJSBackend}, series::Series)
syncplot = plt.o
pdict = plotly_series(plt, series)
typ = pop!(pdict, :type)
gt = PlotlyJS.GenericTrace(typ; pdict...)
PlotlyJS.addtraces!(syncplot, gt)
end
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y))
PlotlyJS.restyle!(
plt.o,
findfirst(plt.series_list, series),
KW(xsym => (series.d[:x],), ysym => (series.d[:y],))
)
end
# ----------------------------------------------------------------
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot_object(plt::Plot{PlotlyJSBackend})
pdict = plotly_layout(plt)
syncplot = plt.o
w,h = plt[:size]
# DD(pdict)
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{PlotlyJSBackend}, i::Int)
# d = plt.seriesargs[i]
# d[:x], d[:y]
# end
# function setxy!{X,Y}(plt::Plot{PlotlyJSBackend}, xy::Tuple{X,Y}, i::Integer)
# d = plt.seriesargs[i]
# ispolar = get(plt.attr, :polar, false)
# xsym = ispolar ? :t : :x
# ysym = ispolar ? :r : :y
# d[xsym], d[ysym] = xy
# # TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
# PlotlyJS.restyle!(plt.o, i, KW(xsym=>(d[xsym],), ysym=>(d[ysym],)))
# plt
# end
# ----------------------------------------------------------------
# function _update_min_padding!(sp::Subplot{PlotlyBackend})
# sp.minpad = plotly_minpad(sp)
# end
# function plotlyjs_finalize(plt::Plot)
# plotly_finalize(plt)
# PlotlyJS.relayout!(plt.o, plotly_layout(plt))
# end
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
tmpfn = tempname() * "png"
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
function _display(plt::Plot{PlotlyJSBackend})
# plotlyjs_finalize(plt)
display(plt.o)
end
File diff suppressed because it is too large Load Diff
+333
View File
@@ -0,0 +1,333 @@
# https://github.com/tbreloff/Qwt.jl
supportedArgs(::QwtBackend) = [
:annotations,
:axis,
:background_color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
:foreground_color,
:group,
:label,
:layout,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
:markershape,
:markercolor,
:markersize,
:n,
:bins,
:nc,
:nr,
:pos,
:smooth,
:show,
:size,
:title,
:window_title,
:x,
:xguide,
:xlims,
:xticks,
:y,
:yguide,
:ylims,
:yrightlabel,
:yticks,
:xscale,
:yscale,
]
supportedTypes(::QwtBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline]
supportedMarkers(::QwtBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supportedScales(::QwtBackend) = [:identity, :log10]
subplotSupported(::QwtBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::QwtBackend; kw...)
@eval begin
warn("Qwt is no longer supported... many features will likely be broken.")
import Qwt
export Qwt
end
end
# -------------------------------
@compat const _qwtAliases = KW(
:bins => :heatmap_n,
:fillrange => :fillto,
:linewidth => :width,
:markershape => :marker,
:hexbin => :heatmap,
:path => :line,
:steppost => :step,
:steppre => :stepinverted,
:star5 => :star1,
:star8 => :star2,
)
function fixcolors(d::KW)
for (k,v) in d
if typeof(v) <: ColorScheme
d[k] = getColor(v)
end
end
end
function replaceQwtAliases(d, s)
if haskey(_qwtAliases, d[s])
d[s] = _qwtAliases[d[s]]
end
end
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
d = KW(kw)
st = d[:seriestype]
if st == :scatter
d[:seriestype] = :none
if d[:markershape] == :none
d[:markershape] = :ellipse
end
elseif st in (:hline, :vline)
addLineMarker(plt, d)
d[:seriestype] = :none
d[:markershape] = :ellipse
d[:markersize] = 1
if st == :vline
d[:x], d[:y] = d[:y], d[:x]
end
elseif !iscreating && st == :bar
d = barHack(; kw...)
elseif !iscreating && st == :histogram
d = barHack(; histogramHack(; kw...)...)
end
replaceQwtAliases(d, :seriestype)
replaceQwtAliases(d, :markershape)
for k in keys(d)
if haskey(_qwtAliases, k)
d[_qwtAliases[k]] = d[k]
end
end
d[:x] = collect(d[:x])
d[:y] = collect(d[:y])
d
end
# function _create_plot(pkg::QwtBackend, d::KW)
function _create_backend_figure(plt::Plot{QwtBackend})
fixcolors(plt.attr)
dumpdict(plt.attr,"\n\n!!! plot")
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
# plt = Plot(o, pkg, 0, d, KW[])
# plt
end
# function _series_added(::QwtBackend, plt::Plot, d::KW)
function _series_added(plt::Plot{QwtBackend}, series::Series)
d = adjustQwtKeywords(plt, false; series.d...)
fixcolors(d)
dumpdict(d,"\n\n!!! plot!")
Qwt.oplot(plt.o; d...)
# push!(plt.seriesargs, d)
# plt
end
# ----------------------------------------------------------------
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
lims = get(d, isx ? :xlims : :ylims, nothing)
ticks = get(d, isx ? :xticks : :yticks, nothing)
w = plt.o.widget
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
if typeof(lims) <: @compat(Union{Tuple,AVec}) && length(lims) == 2
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, lims...)
end
if typeof(ticks) <: Range
if isx
plt.o.autoscale_x = false
else
plt.o.autoscale_y = false
end
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
elseif !(ticks in (nothing, :none, :auto))
warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
end
# change the scale
scalesym = isx ? :xscale : :yscale
if haskey(d, scalesym)
scaletype = d[scalesym]
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
scaletype in supportedScales() || warn("Unsupported scale type: ", scaletype)
end
end
function _update_plot_object(plt::Plot{QwtBackend}, d::KW)
haskey(d, :title) && Qwt.title(plt.o, d[:title])
haskey(d, :xguide) && Qwt.xlabel(plt.o, d[:xguide])
haskey(d, :yguide) && Qwt.ylabel(plt.o, d[:yguide])
updateLimsAndTicks(plt, d, true)
updateLimsAndTicks(plt, d, false)
end
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
end
# ----------------------------------------------------------------
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
for yi in d[:y]
marker = Qwt.QWT.QwtPlotMarker()
ishorizontal = (d[:seriestype] == :hline)
marker[:setLineStyle](ishorizontal ? 1 : 2)
marker[ishorizontal ? :setYValue : :setXValue](yi)
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
marker[:attach](plt.o.widget)
end
# marker[:setValue](x, y)
# marker[:setLabel](Qwt.QWT.QwtText(val))
# marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
qwttext = Qwt.QWT.QwtText(val.str)
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
marker[:setLabel](qwttext)
marker[:attach](plt.o.widget)
end
function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
marker = Qwt.QWT.QwtPlotMarker()
marker[:setValue](x, y)
marker[:setLabel](Qwt.QWT.QwtText(val))
marker[:attach](plt.o.widget)
end
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createQwtAnnotation(plt, ann...)
end
end
# ----------------------------------------------------------------
# accessors for x/y data
function getxy(plt::Plot{QwtBackend}, i::Int)
series = plt.o.lines[i]
series.x, series.y
end
function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer)
series = plt.o.lines[i]
series.x, series.y = xy
plt
end
# -------------------------------
# savepng(::QwtBackend, plt::AbstractPlot, fn::@compat(AbstractString), args...) = Qwt.savepng(plt.o, fn)
# -------------------------------
# # create the underlying object (each backend will do this differently)
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
# isbefore && return false
# i = 0
# rows = Any[]
# row = Any[]
# for (i,(r,c)) in enumerate(subplt.layout)
# push!(row, subplt.plts[i].o)
# if c == ncols(subplt.layout, r)
# push!(rows, Qwt.hsplitter(row...))
# row = Any[]
# end
# end
# # for rowcnt in subplt.layout.rowcounts
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
# # i += rowcnt
# # end
# subplt.o = Qwt.vsplitter(rows...)
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
# true
# end
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
for series in plt.o.lines
_expand_limits(lims, isx ? series.x : series.y)
end
end
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
end
# ----------------------------------------------------------------
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
write(io, readall("/tmp/dfskjdhfkh.png"))
end
# function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
# write(io, readall("/tmp/dfskjdhfkh.png"))
# end
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
Qwt.refresh(plt.o)
Qwt.showwidget(plt.o)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
# for plt in subplt.plts
# Qwt.refresh(plt.o)
# end
# Qwt.showwidget(subplt.o)
# end
+75
View File
@@ -0,0 +1,75 @@
# TODO: find/replace all [PkgName] with CamelCase
# [ADD BACKEND WEBSITE]
function _initialize_backend(::[PkgName]Backend; kw...)
@eval begin
import [PkgName]
export [PkgName]
# todo: other initialization that needs to be eval-ed
end
# todo: other initialization
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{[PkgName]Backend})
nothing
end
# this is called early in the pipeline, use it to make the plot current or something
function _prepare_plot_object(plt::Plot{[PkgName]Backend})
end
# Set up the subplot within the backend object.
function _initialize_subplot(plt::Plot{[PkgName]Backend}, sp::Subplot{[PkgName]Backend})
end
# ---------------------------------------------------------------------------
# Add one series to the underlying backend object.
function _series_added(plt::Plot{[PkgName]Backend}, series::Series)
end
# When series data is added/changed, this callback can do dynamic updates to the backend object.
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
function _series_updated(plt::Plot{[PkgName]Backend}, series::Series)
end
# ---------------------------------------------------------------------------
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{[PkgName]Backend})
end
# Set the (left, top, right, bottom) minimum padding around the plot area
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{[PkgName]Backend})
sp.minpad = (20mm, 5mm, 2mm, 10mm)
end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
function _update_plot_object(plt::Plot{[PkgName]Backend})
end
# ----------------------------------------------------------------
# Write a png to io. You could define methods for:
# "application/eps" => "eps",
# "image/eps" => "eps",
# "application/pdf" => "pdf",
# "image/png" => "png",
# "application/postscript" => "ps",
# "image/svg+xml" => "svg"
function _writemime(io::IO, ::MIME"image/png", plt::Plot{[PkgName]Backend})
end
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{[PkgName]Backend})
end
+332
View File
@@ -0,0 +1,332 @@
# https://github.com/Evizero/UnicodePlots.jl
supportedArgs(::UnicodePlotsBackend) = [
# :annotations,
# :args,
# :axis,
# :background_color,
# :linecolor,
# :fill,
# :foreground_color,
:group,
# :heatmap_c,
# :kwargs,
:label,
# :layout,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
# :linewidth,
:markershape,
# :markercolor,
# :markersize,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
:bins,
# :nc,
# :nr,
# :pos,
# :reg,
# :ribbon,
:show,
:size,
:title,
:window_title,
:x,
:xguide,
:xlims,
# :xticks,
:y,
:yguide,
:ylims,
# :yrightlabel,
# :yticks,
# :xscale,
# :yscale,
# :xflip,
# :yflip,
# :z,
]
supportedAxes(::UnicodePlotsBackend) = [:auto, :left]
supportedTypes(::UnicodePlotsBackend) = [
:path, :steppre, :steppost, :scatter,
:histogram2d, :hline, :vline
]
supportedStyles(::UnicodePlotsBackend) = [:auto, :solid]
supportedMarkers(::UnicodePlotsBackend) = [:none, :auto, :ellipse]
supportedScales(::UnicodePlotsBackend) = [:identity]
subplotSupported(::UnicodePlotsBackend) = true
# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupportedArgs(pkg::UnicodePlotsBackend, d::KW) = nothing
# --------------------------------------------------------------------------------------
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
# convert_size_from_pixels(sz) =
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot)
plt.o = []
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xlim = axis_limits(xaxis)
ylim = axis_limits(yaxis)
# make vectors
xlim = [xlim[1], xlim[2]]
ylim = [ylim[1], ylim[2]]
# we set x/y to have a single point, since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
x = Float64[xlim[1]]
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
width, height = plt[:size]
o = UnicodePlots.Plot(x, y;
width = width,
height = height,
title = sp[:title],
xlim = xlim,
ylim = ylim
)
# set the axis labels
UnicodePlots.xlabel!(o, xaxis[:guide])
UnicodePlots.ylabel!(o, yaxis[:guide])
# now use the ! functions to add to the plot
for series in series_list(sp)
addUnicodeSeries!(o, series.d, sp[:legend] != :none, xlim, ylim)
end
# save the object
push!(plt.o, o)
end
end
# # do all the magic here... build it all at once, since we need to know about all the series at the very beginning
# function rebuildUnicodePlot!(plt::Plot)
#
# # figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
# sargs = plt.seriesargs
# iargs = plt.attr
#
# # get the x/y limits
# if get(iargs, :xlims, :auto) == :auto
# xlim = [Inf, -Inf]
# for d in sargs
# _expand_limits(xlim, d[:x])
# end
# else
# xmin, xmax = iargs[:xlims]
# xlim = [xmin, xmax]
# end
#
# if get(iargs, :ylims, :auto) == :auto
# ylim = [Inf, -Inf]
# for d in sargs
# _expand_limits(ylim, d[:y])
# end
# else
# ymin, ymax = iargs[:ylims]
# ylim = [ymin, ymax]
# end
#
# # we set x/y to have a single point, since we need to create the plot with some data.
# # since this point is at the bottom left corner of the plot, it shouldn't actually be shown
# x = Float64[xlim[1]]
# y = Float64[ylim[1]]
#
# # create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
# width, height = iargs[:size]
# o = UnicodePlots.Plot(x, y; width = width,
# height = height,
# title = iargs[:title],
# # labels = iargs[:legend],
# xlim = xlim,
# ylim = ylim)
#
# # set the axis labels
# UnicodePlots.xlabel!(o, iargs[:xguide])
# UnicodePlots.ylabel!(o, iargs[:yguide])
#
# # now use the ! functions to add to the plot
# for d in sargs
# addUnicodeSeries!(o, d, iargs[:legend] != :none, xlim, ylim)
# end
#
# # save the object
# plt.o = o
# end
# add a single series
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = d[:seriestype]
# handle hline/vline separately
if st in (:hline,:vline)
for yi in d[:y]
if st == :hline
UnicodePlots.lineplot!(o, xlim, [yi,yi])
else
UnicodePlots.lineplot!(o, [yi,yi], ylim)
end
end
return
# elseif st == :bar
# UnicodePlots.barplot!(o, d[:x], d[:y])
# return
# elseif st == :histogram
# UnicodePlots.histogram!(o, d[:y], bins = d[:bins])
# return
elseif st == :histogram2d
UnicodePlots.densityplot!(o, d[:x], d[:y])
return
end
stepstyle = :post
if st == :path
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
elseif st == :steppost
func = UnicodePlots.stairs!
elseif st == :steppre
func = UnicodePlots.stairs!
stepstyle = :pre
else
error("Linestyle $st 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[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# add the series
func(o, x, y; color = color, name = label, style = stepstyle)
end
# function handlePlotColors(::UnicodePlotsBackend, d::KW)
# # TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette
# d[:color_palette] = [RGB(0,0,0)]
# end
# -------------------------------
# function _create_plot(pkg::UnicodePlotsBackend, d::KW)
# plt = Plot(nothing, pkg, 0, d, KW[])
function _create_backend_figure(plt::Plot{UnicodePlotsBackend})
# do we want to give a new default size?
# if !haskey(plt.attr, :size) || plt.attr[:size] == default(:size)
# plt.attr[:size] = (60,20)
# end
w, h = plt[:size]
plt.attr[:size] = div(w, 10), div(h, 20)
plt.attr[:color_palette] = [RGB(0,0,0)]
nothing
# plt
end
# function _series_added(plt::Plot{UnicodePlotsBackend}, series::Series)
# d = series.d
# # TODO don't need these once the "bar" series recipe is done
# if d[:seriestype] in (:sticks, :bar)
# d = barHack(; d...)
# elseif d[:seriestype] == :histogram
# d = barHack(; histogramHack(; d...)...)
# end
# # push!(plt.seriesargs, d)
# # plt
# end
#
#
# function _update_plot_object(plt::Plot{UnicodePlotsBackend}, d::KW)
# for k in (:title, :xguide, :yguide, :xlims, :ylims)
# if haskey(d, k)
# plt.attr[k] = d[k]
# end
# end
# end
# -------------------------------
# since this is such a hack, it's only callable using `png`... should error during normal `writemime`
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
fn = addExtension(fn, "png")
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# @osx_only begin
@compat @static if is_apple()
# BEGIN HACK
# wait while the plot gets drawn
sleep(0.5)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
run(`screencapture -R50,600,700,420 $fn`)
# END HACK (phew)
return
end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end
# -------------------------------
# we don't do very much for subplots... just stack them vertically
# function _create_subplot(subplt::Subplot{UnicodePlotsBackend}, isbefore::Bool)
# isbefore && return false
# true
# end
function _display(plt::Plot{UnicodePlotsBackend})
rebuildUnicodePlot!(plt)
map(show, plt.o)
nothing
end
# function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend})
# for plt in subplt.plts
# gui(plt)
# end
# end
+66
View File
@@ -0,0 +1,66 @@
# 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::AbstractPlot; title::AbstractString = get(plt.attr, :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)
@compat @static if is_apple()
return run(`open $(filename)`)
end
@compat @static if is_linux()
return run(`xdg-open $(filename)`)
end
@compat @static if is_windows()
return run(`$(ENV["COMSPEC"]) /c start $(filename)`)
end
warn("Unknown OS... cannot open browser window.")
end
function write_temp_html(plt::AbstractPlot)
html = standalone_html(plt; title = plt.attr[:window_title])
filename = string(tempname(), ".html")
output = open(filename, "w")
write(output, html)
close(output)
filename
end
function standalone_html_window(plt::AbstractPlot)
filename = write_temp_html(plt)
open_browser_window(filename)
end
# uses wkhtmltopdf/wkhtmltoimage: http://wkhtmltopdf.org/downloads.html
function html_to_png(html_fn, png_fn, w, h)
run(`wkhtmltoimage -f png -q --width $w --height $h --disable-smart-width $html_fn $png_fn`)
end
function writemime_png_from_html(io::IO, plt::AbstractPlot)
# write html to a temporary file
html_fn = write_temp_html(plt)
# convert that html file to a temporary png file using wkhtmltoimage
png_fn = tempname() * ".png"
w, h = plt.attr[:size]
html_to_png(html_fn, png_fn, w, h)
# now read that file data into io
pngdata = readall(png_fn)
write(io, pngdata)
end
+307
View File
@@ -0,0 +1,307 @@
# https://github.com/nolta/Winston.jl
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
supportedArgs(::WinstonBackend) = [
:annotations,
# :args,
# :axis,
# :background_color,
:linecolor,
:color_palette,
:fillrange,
:fillcolor,
# :foreground_color,
:group,
# :heatmap_c,
# :kwargs,
:label,
# :layout,
:legend,
:seriescolor, :seriesalpha,
:linestyle,
:seriestype,
:linewidth,
:markershape,
:markercolor,
:markersize,
# :markerstrokewidth,
# :markerstrokecolor,
# :markerstrokestyle,
# :n,
:bins,
# :nc,
# :nr,
# :pos,
:smooth,
# :ribbon,
:show,
:size,
:title,
:window_title,
:x,
:xguide,
:xlims,
# :xticks,
:y,
:yguide,
:ylims,
# :yrightlabel,
# :yticks,
:xscale,
:yscale,
# :xflip,
# :yflip,
# :z,
]
supportedAxes(::WinstonBackend) = [:auto, :left]
supportedTypes(::WinstonBackend) = [:none, :line, :path, :sticks, :scatter, :histogram, :bar]
supportedStyles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::WinstonBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supportedScales(::WinstonBackend) = [:identity, :log10]
subplotSupported(::WinstonBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::WinstonBackend; kw...)
@eval begin
# ENV["WINSTON_OUTPUT"] = "gtk"
warn("Winston is no longer supported... many features will likely be broken.")
import Winston, Gtk
export Winston, Gtk
end
end
# ---------------------------------------------------------------------------
## dictionaries for conversion of Plots.jl names to Winston ones.
@compat const winston_linestyle = KW(:solid=>"solid",
:dash=>"dash",
:dot=>"dotted",
:dashdot=>"dotdashed"
)
@compat const winston_marker = KW(:none=>".",
:rect => "square",
:ellipse=>"circle",
:diamond=>"diamond",
:utriangle=>"triangle",
:dtriangle=>"down-triangle",
:cross => "plus",
:xcross => "cross",
:star5 => "asterisk"
)
function _before_update(plt::Plot{WinstonBackend})
Winston.ghf(plt.o)
end
# ---------------------------------------------------------------------------
function _create_backend_figure(plt::Plot{WinstonBackend})
Winston.FramedPlot(
title = plt.attr[:title],
xlabel = plt.attr[:xguide],
ylabel = plt.attr[:yguide]
)
end
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
function addRegressionLineWinston(d::KW, wplt)
xs, ys = regressionXY(d[:x], d[:y])
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
end
function getWinstonItems(plt::Plot)
if isa(plt.o, Winston.FramedPlot)
wplt = plt.o
window, canvas = nothing, nothing
else
window, canvas, wplt = plt.o
end
window, canvas, wplt
end
function _series_added(plt::Plot{WinstonBackend}, series::Series)
d = series.d
window, canvas, wplt = getWinstonItems(plt)
# until we call it normally, do the hack
if d[:seriestype] == :bar
d = barHack(;d...)
end
e = KW()
e[:color] = getColor(d[:linecolor])
e[:linewidth] = d[:linewidth]
e[:kind] = winston_linestyle[d[:linestyle]]
e[:symbolkind] = winston_marker[d[:markershape]]
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
e[:symbolsize] = d[:markersize] / 5
# pos # (Int,Int), move the enclosing window to this position
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
if d[:seriestype] == :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
elseif d[:seriestype] == :path
x, y = d[:x], d[:y]
Winston.add(wplt, Winston.Curve(x, y; e...))
fillrange = d[:fillrange]
if fillrange != nothing
if isa(fillrange, AbstractVector)
y2 = fillrange
else
y2 = Float64[fillrange for yi in y]
end
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(d[:fillcolor])))
end
elseif d[:seriestype] == :scatter
if d[:markershape] == :none
d[:markershape] = :ellipse
end
# elseif d[:seriestype] == :step
# fn = Winston.XXX
# elseif d[:seriestype] == :stepinverted
# fn = Winston.XXX
elseif d[:seriestype] == :sticks
Winston.add(wplt, Winston.Stems(d[:x], d[:y]; e...))
# elseif d[:seriestype] == :dots
# fn = Winston.XXX
# elseif d[:seriestype] == :histogram2d
# fn = Winston.XXX
# elseif d[:seriestype] == :hexbin
# fn = Winston.XXX
elseif d[:seriestype] == :histogram
hst = hist(d[:y], d[:bins])
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
# elseif d[:seriestype] == :bar
# # fn = Winston.XXX
else
error("seriestype $(d[:seriestype]) not supported by Winston.")
end
# markershape
if d[:markershape] != :none
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
end
# optionally add a regression line
d[:smooth] && d[:seriestype] != :histogram && addRegressionLineWinston(d, wplt)
# push!(plt.seriesargs, d)
# plt
end
# ----------------------------------------------------------------
@compat const _winstonNames = KW(
:xlims => :xrange,
:ylims => :yrange,
:xscale => :xlog,
:yscale => :ylog,
)
function _update_plot_object(plt::Plot{WinstonBackend}, d::KW)
window, canvas, wplt = getWinstonItems(plt)
for k in (:xguide, :yguide, :title, :xlims, :ylims)
if haskey(d, k)
Winston.setattr(wplt, string(get(_winstonNames, k, k)), d[k])
end
end
for k in (:xscale, :yscale)
if haskey(d, k)
islogscale = d[k] == :log10
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
end
end
end
# ----------------------------------------------------------------
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::@compat(AbstractString))
Winston.text(x, y, val)
end
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns
createWinstonAnnotationObject(plt, ann...)
end
end
# ----------------------------------------------------------------
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
# end
# ----------------------------------------------------------------
function addWinstonLegend(plt::Plot, wplt)
if plt.attr[:legend] != :none
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
end
end
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
addWinstonLegend(plt, wplt)
writemime(io, "image/png", wplt)
end
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
window, canvas, wplt = getWinstonItems(plt)
if window == nothing
if Winston.output_surface != :gtk
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
end
# initialize window
w,h = plt.attr[:size]
canvas = Gtk.GtkCanvasLeaf()
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
plt.o = (window, canvas, wplt)
end
addWinstonLegend(plt, wplt)
Winston.display(canvas, wplt)
Gtk.showall(window)
end
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
# # TODO: display/show the Subplot object
# end
File diff suppressed because it is too large Load Diff
+373
View File
@@ -0,0 +1,373 @@
abstract ColorScheme
getColor(scheme::ColorScheme) = getColor(scheme, 1)
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme{T<:Colorant}(cs::AVec{T}; kw...) = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
# --------------------------------------------------------------
convertColor(c::AbstractString) = parse(Colorant, c)
convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
function convertColor(c, α::Real)
c = convertColor(c)
RGBA(RGB(c), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::@compat(Void)) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
# --------------------------------------------------------------
function darken(c, v=0.1)
rgba = convert(RGBA, c)
r = max(0, min(rgba.r - v, 1))
g = max(0, min(rgba.g - v, 1))
b = max(0, min(rgba.b - v, 1))
RGBA(r,g,b,rgba.alpha)
end
function lighten(c, v=0.3)
darken(c, -v)
end
# --------------------------------------------------------------
const _rainbowColors = [colorant"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)]
const _gradients = KW(
:blues => [colorant"lightblue", colorant"darkblue"],
:reds => [colorant"lightpink", colorant"darkred"],
:greens => [colorant"lightgreen", colorant"darkgreen"],
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
:rainbow => _rainbowColors,
:lightrainbow => map(lighten, _rainbowColors),
:darkrainbow => map(darken, _rainbowColors),
:darktest => _testColors,
:lighttest => map(c -> lighten(c, 0.3), _testColors),
)
function register_gradient_colors{C<:Colorant}(name::Symbol, colors::AVec{C})
_gradients[name] = colors
end
include("color_gradients.jl")
default_gradient() = ColorGradient(:inferno)
# --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
immutable ColorGradient <: ColorScheme
colors::Vector
values::Vector
function ColorGradient{S<:Real}(cs::AVec, 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)
# 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:0; kw...)
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s]
if vals == 0:0
vals = linspace(0, 1, length(cs))
end
ColorGradient(cs, vals; kw...)
end
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
# ColorGradient(map(convertColor, cs), vals; kw...)
# end
function ColorGradient(grad::ColorGradient; alpha = nothing)
ColorGradient(convertColor(grad.colors, alpha), grad.values)
end
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
function getColorZ(gradient::ColorGradient, z::Real)
cs = gradient.colors
vs = gradient.values
n = length(cs)
@assert n > 0 && n == length(vs)
# can we just return the first color?
if z <= vs[1] || n == 1
return cs[1]
end
# find the bounding colors and interpolate
for i in 2:n
if z <= vs[i]
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
end
end
# if we get here, return the last color
cs[end]
end
getColorVector(gradient::ColorGradient) = gradient.colors
# for 0.3
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
rgb1 = RGBA(c1)
rgb2 = RGBA(c2)
r = interpolate(rgb1.r, rgb2.r, w)
g = interpolate(rgb1.g, rgb2.g, w)
b = interpolate(rgb1.b, rgb2.b, w)
a = interpolate(rgb1.alpha, rgb2.alpha, w)
RGBA(r, g, b, a)
end
function interpolate(v1::Real, v2::Real, w::Real)
(1-w) * v1 + w * v2
end
# --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant"
immutable ColorFunction <: ColorScheme
f::Function
end
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant"
immutable ColorZFunction <: ColorScheme
f::Function
end
getColorZ(scheme::ColorFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
immutable ColorVector <: ColorScheme
v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
getColorVector(scheme::ColorVector) = scheme.v
# --------------------------------------------------------------
"Wraps a single color"
immutable ColorWrapper <: ColorScheme
c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
# --------------------------------------------------------------
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
# move closer to lighter/darker depending on background value
function adjustAway(val, bgval, vmin=0., vmax=100.)
if bgval < 0.5 * (vmax+vmin)
tmp = max(val, bgval)
return 0.5 * (tmp + max(tmp, vmax))
else
tmp = min(val, bgval)
return 0.5 * (tmp + min(tmp, vmin))
end
end
# borrowed from http://stackoverflow.com/a/1855903:
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
isdark(c::Colorant) = lightnessLevel(c) < 0.5
islight(c::Colorant) = !isdark(c)
function convertHexToRGB(h::Unsigned)
mask = 0x0000FF
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
end
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
const _masterColorList = [
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
]
const _allColors = map(convertHexToRGB, _masterColorList)
const _darkColors = filter(isdark, _allColors)
const _lightColors = filter(islight, _allColors)
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
const _defaultNumColors = 17
# --------------------------------------------------------------
# Methods to automatically generate gradients for color selection based on
# background color and a short list of seed colors
# here are some magic constants that could be changed if you really want
const _lightness_darkbg = [80.0]
const _lightness_lightbg = [60.0]
const _lch_c_const = [60]
function adjust_lch(color, l, c)
lch = convert(LCHab, color)
convert(RGB, LCHab(l, c, lch.h))
end
function lightness_from_background(bgcolor)
bglight = convert(LCHab, bgcolor).l
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
end
function gradient_from_list(cs)
zvalues = Plots.get_zvalues(length(cs))
indices = sortperm(zvalues)
sorted_colors = map(RGBA, cs[indices])
sorted_zvalues = zvalues[indices]
ColorGradient(sorted_colors, sorted_zvalues)
end
function generate_colorgradient(bgcolor = colorant"white";
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
lightness = lightness_from_background(bgcolor),
chroma = _lch_c_const[1],
n = _defaultNumColors)
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
colors = distinguishable_colors(n,
seed_colors,
lchoices=Float64[lightness],
cchoices=Float64[chroma],
hchoices=linspace(0, 340, 20)
)[2:end]
gradient_from_list(colors)
end
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
grad = if palette == :auto
generate_colorgradient(bgcolor)
else
ColorGradient(palette)
end
zrng = get_zvalues(numcolors)
RGBA[getColorZ(grad, z) for z in zrng]
end
function get_color_palette{C<:Colorant}(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
palette
end
# ----------------------------------------------------------------------------------
function getpctrange(n::Int)
n > 0 || error()
n == 1 && return zeros(1)
zs = [0.0, 1.0]
for i in 3:n
sorted = sort(zs)
diffs = diff(sorted)
widestj = 0
widest = 0.0
for (j,d) in enumerate(diffs)
if d > widest
widest = d
widestj = j
end
end
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
end
zs
end
function get_zvalues(n::Int)
offsets = getpctrange(ceil(Int,n/4)+1)/4
offsets = vcat(offsets[1], offsets[3:end])
zvalues = Float64[]
for offset in offsets
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
end
vcat(zvalues[1], 1.0, zvalues[2:n-1])
end
# ----------------------------------------------------------------------------------
make255(x) = round(Int, 255 * x)
function webcolor(c::Color)
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
end
function webcolor(c::TransparentColor)
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
end
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
webcolor(c) = webcolor(convertColor(c))
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
# ----------------------------------------------------------------------------------
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
function getSeriesRGBColor(c, sp::Subplot, n::Int)
if c == :auto
c = autopick(sp[:color_palette], n)
end
# c should now be a subtype of ColorScheme
colorscheme(c)
end
+486
View File
@@ -0,0 +1,486 @@
typealias P2 FixedSizeArrays.Vec{2,Float64}
typealias P3 FixedSizeArrays.Vec{3,Float64}
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
nanpush!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P3}, b) = (push!(a, P3(NaN,NaN,NaN)); append!(a, b))
compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : angle)
# -------------------------------------------------------------
immutable Shape
x::AVec
y::AVec
end
Shape(verts::AVec) = Shape(unzip(verts)...)
get_xs(shape::Shape) = shape.x
get_ys(shape::Shape) = shape.y
vertices(shape::Shape) = collect(zip(shape.x, shape.y))
function shape_coords(shape::Shape)
shape.x, shape.y
end
function shape_coords(shapes::AVec{Shape})
length(shapes) == 0 && return zeros(0), zeros(0)
xs = map(get_xs, shapes)
ys = map(get_ys, shapes)
x, y = map(copy, shape_coords(shapes[1]))
for shape in shapes[2:end]
nanappend!(x, shape.x)
nanappend!(y, shape.y)
end
x, y
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
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
from_polar(angle, dist) = P2(dist*cos(angle), dist*sin(angle))
function makearrowhead(angle; h = 2.0, w = 0.4)
tip = from_polar(angle, h)
Shape(P2[(0,0), from_polar(angle - 0.5π, w) - tip,
from_polar(angle + 0.5π, w) - tip, (0,0)])
end
const _shapes = KW(
: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
# -----------------------------------------------------------------------
# uses the centroid calculation from https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
function center(shape::Shape)
x, y = shape_coords(shape)
n = length(x)
A, Cx, Cy = 0.0, 0.0, 0.0
for i=1:n
ip1 = i==n ? 1 : i+1
A += x[i] * y[ip1] - x[ip1] * y[i]
end
A *= 0.5
for i=1:n
ip1 = i==n ? 1 : i+1
m = (x[i] * y[ip1] - x[ip1] * y[i])
Cx += (x[i] + x[ip1]) * m
Cy += (y[i] + y[ip1]) * m
end
Cx / 6A, Cy / 6A
end
function Base.scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
sx, sy = shape_coords(shape)
cx, cy = c
for i=1:length(sx)
sx[i] = (sx[i] - cx) * x + cx
sy[i] = (sy[i] - cy) * y + cy
end
shape
end
function Base.scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
shapecopy = deepcopy(shape)
scale!(shape, x, y, c)
end
function translate!(shape::Shape, x::Real, y::Real = x)
sx, sy = shape_coords(shape)
for i=1:length(sx)
sx[i] += x
sy[i] += y
end
shape
end
function translate(shape::Shape, x::Real, y::Real = x)
shapecopy = deepcopy(shape)
translate!(shape, x, y)
end
function rotate_x(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
(x - centerx) * cos(Θ) - (y - centery) * sin(Θ) + centerx
end
function rotate_y(x::Real, y::Real, Θ::Real, centerx::Real, centery::Real)
(y - centery) * cos(Θ) + (x - centerx) * sin(Θ) + centery
end
function rotate(x::Real, y::Real, θ::Real, c = center(shape))
cx, cy = c
rotate_x(x, y, Θ, cx, cy), rotate_y(x, y, Θ, cx, cy)
end
function rotate!(shape::Shape, Θ::Real, c = center(shape))
x, y = shape_coords(shape)
cx, cy = c
for i=1:length(x)
x[i] = rotate_x(x[i], y[i], Θ, cx, cy)
y[i] = rotate_y(x[i], y[i], Θ, cx, cy)
end
shape
end
function rotate(shape::Shape, Θ::Real, c = center(shape))
shapecopy = deepcopy(shape)
rotate!(shapecopy, Θ, c)
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 <: Symbol || T <: 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::AbstractString
font::Font
end
PlotText(str) = PlotText(string(str), font())
text(t::PlotText) = t
function text(str, args...)
PlotText(string(str), font(args...))
end
annotations(::Void) = []
annotations(anns::AVec) = anns
annotations(anns) = Any[anns]
# -----------------------------------------------------------------------
# -----------------------------------------------------------------------
immutable Stroke
width
color
alpha
style
end
function stroke(args...; alpha = nothing)
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 <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
end
elseif allAlphas(arg)
alpha = arg
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)
size = nothing
color = nothing
for arg in args
T = typeof(arg)
if T <: Colorant
color = arg
elseif T <: Symbol || T <: AbstractString
try
color = parse(Colorant, string(arg))
end
elseif allAlphas(arg)
alpha = arg
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
# -----------------------------------------------------------------------
abstract AbstractSurface
"represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface
surf::M
end
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for yi in y, xi in x])
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))
Base.eltype(surf::Surface) = eltype(surf.surf)
function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema]
for vi in surf.surf
expand_extrema!(ex, vi)
end
ex
end
"For the case of representing a surface as a function of x/y... can possibly avoid allocations."
immutable SurfaceFunction <: AbstractSurface
f::Function
end
# -----------------------------------------------------------------------
# style is :open or :closed (for now)
immutable Arrow
style::Symbol
headlength::Float64
headwidth::Float64
end
function arrow(args...)
style = :simple
headlength = 0.3
headwidth = 0.3
setlength = false
for arg in args
T = typeof(arg)
if T == Symbol
style = arg
elseif T <: Number
# first we apply to both, but if there's more, then only change width after the first number
headwidth = Float64(arg)
if !setlength
headlength = headwidth
end
setlength = true
elseif T <: Tuple && length(arg) == 2
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
else
warn("Skipped arrow arg $arg")
end
end
Arrow(style, headlength, headwidth)
end
# allow for do-block notation which gets called on every valid start/end pair which
# we need to draw an arrow
function add_arrows(func::Function, x::AVec, y::AVec)
for i=2:length(x)
xyprev = (x[i-1], y[i-1])
xy = (x[i], y[i])
if ok(xyprev) && ok(xy)
if i==length(x) || !ok(x[i+1], y[i+1])
# add the arrow from xyprev to xy
func(xyprev, xy)
end
end
end
end
# -----------------------------------------------------------------------
type BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T}
end
@compat function (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
+63
View File
@@ -0,0 +1,63 @@
# TODO:
"""
- load Contours.jl similar to DataFrames
- method to build grid from x/y/z vectors
- method to wrap contours creation
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
"""
# # ----------------------------------------------------------
# # ----------------------------------------------------------
# immutable Vertex
# x::Float64
# y::Float64
# z::Float64
# end
# immutable Edge
# v::Vertex
# u::Vertex
# end
# # ----------------------------------------------------------
# # one rectangle's z-values and the center vertex
# # z is ordered: topleft, topright, bottomright, bottomleft
# immutable GridRect
# z::Vector{Float64}
# center::Vertex
# data::Vector{Vertex}
# end
# type Grid
# xs::Vector{Float64}
# ys::Vector{Float64}
# rects::Matrix{GridRect}
# end
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
# vs = sort(v)
# end
# # the goal here is to create the vertical and horizontal partitions
# # which define the grid, so that the data is somewhat evenly split
# function bucketData(x, y, z)
# end
# function buildGrid(x, y, z)
# # create
# end
+342
View File
@@ -0,0 +1,342 @@
"""
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
"""
type PlotExample
header::AbstractString
desc::AbstractString
exprs::Vector{Expr}
end
# the _examples we'll run for each
const _examples = PlotExample[
PlotExample("Lines",
"A simple line plot of the columns.",
[:(begin
plot(Plots.fakedata(50,5), w=3)
end)]
),
PlotExample("Functions, adding data, and animations",
"Plot multiple functions. You can also put the function first, or use the form `plot(f, xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data: `x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with `push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the animation.",
[:(begin
p = plot([sin,cos], zeros(0), leg=false)
anim = Animation()
for x in linspace(0, 10π, 100)
push!(p, x, Float64[sin(x), cos(x)])
frame(anim)
end
end)]
),
PlotExample("Parametric plots",
"Plot function pair (x(u), y(u)).",
[:(begin
plot(sin, x->sin(2x), 0, 2π, line=4, leg=false, fill=(0,:orange))
end)]
),
PlotExample("Colors",
"Access predefined palettes (or build your own with the `colorscheme` method). Line/marker colors are auto-generated from the plot's palette, unless overridden. Set the `z` argument to turn on series gradients.",
[:(begin
y = rand(100)
plot(0:10:100,rand(11,4),lab="lines",w=3,palette=:grays,fill=(0,:auto), α=0.6)
scatter!(y, zcolor=abs(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs(y-0.5)+4, lab="grad")
end)]
),
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!`",
[:(begin
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)
end)]
),
# PlotExample("Two-axis",
# "Use the `axis` arguments.",
# [
# :(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
# ]),
PlotExample("Images",
"Plot an image. y-axis is set to flipped",
[:(begin
import Images
img = Images.load(Pkg.dir("PlotReferenceImages","Plots","pyplot","0.7.0","ref1.png"))
plot(img)
end)]
),
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.",
[:(begin
ys = Vector[rand(10), rand(20)]
plot(ys, color=[:black :orange], line=(:dot,4), marker=([:hex :d],12,0.8,stroke(3,:gray)))
end)]
),
PlotExample("Build plot in pieces",
"Start with a base plot...",
[:(begin
plot(rand(100)/3, reg=true, fill=(0,:green))
end)]
),
PlotExample("",
"and add to it later.",
[:(begin
scatter!(rand(100), markersize=6, c=:orange)
end)]
),
PlotExample("Histogram2D",
"",
[:(begin
histogram2d(randn(10000), randn(10000), nbins=20)
end)]
),
PlotExample("Line types",
"",
[:(begin
linetypes = [:path :steppre :steppost :sticks :scatter]
n = length(linetypes)
x = Vector[sort(rand(20)) for i in 1:n]
y = rand(20,n)
plot(x, y, line=(linetypes,3), lab=map(string,linetypes), ms=15)
end)]
),
PlotExample("Line styles",
"",
[:(begin
styles = setdiff(supportedStyles(), [:auto])'
plot(cumsum(randn(20,length(styles)),1), style=:auto, label=map(string,styles), w=5)
end)]
),
PlotExample("Marker types",
"",
[:(begin
markers = setdiff(supportedMarkers(), [:none,:auto,Shape])'
n = length(markers)
x = linspace(0,10,n+2)[2:end-1]
y = repmat(reverse(x)', n, 1)
scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen, xlim=(0,10), ylim=(0,10))
end)]
),
PlotExample("Bar",
"x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)",
[:(begin
bar(randn(99))
end)]
),
PlotExample("Histogram",
"",
[:(begin
histogram(randn(1000), nbins=20)
end)]
),
PlotExample("Subplots",
"""
Use the `layout` keyword, and optionally the convenient `@layout` macro to generate arbitrarily complex subplot layouts.
""",
[:(begin
l = @layout([a{0.1h}; b [c;d e]])
plot(randn(100,5), layout=l, t=[:line :histogram :scatter :steppre :bar], leg=false, ticks=nothing, border=false)
end)]
),
PlotExample("Adding to subplots",
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
[:(begin
plot(Plots.fakedata(100,10), layout=4, palette=[:grays :blues :heat :lightrainbow], bg_inside=[:orange :pink :darkblue :black])
end)]
),
PlotExample("",
"",
[:(begin
srand(111)
plot!(Plots.fakedata(100,10))
end)]
),
PlotExample("Open/High/Low/Close",
"Create an OHLC chart. Pass in a list of (open,high,low,close) tuples as your `y` argument. This uses recipes to first convert the tuples to OHLC objects, and subsequently create a :path series with the appropriate line segments.",
[:(begin
n=20
hgt=rand(n)+1
bot=randn(n)
openpct=rand(n)
closepct=rand(n)
y = OHLC[(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]
ohlc(y)
end)]
),
PlotExample("Annotations",
"The `annotations` keyword is used for text annotations in data-coordinates. Pass in a tuple (x,y,text) or a vector of annotations. `annotate!(ann)` is shorthand for `plot!(; annotation=ann)`. Series annotations are used for annotating individual data points. They require only the annotation... x/y values are computed. A `PlotText` object can be build with the method `text(string, attr...)`, which wraps font and color attributes.",
[:(begin
y = rand(10)
plot(y, annotations = (3,y[3],text("this is #3",:left)), leg=false)
annotate!([(5, y[5], text("this is #5",16,:red,:center)), (10, y[10], text("this is #10",:right,20,"courier"))])
scatter!(linspace(2,8,6), rand(6), marker=(50,0.2,:orange), series_annotations = ["series","annotations","map","to","series",text("data",:green)])
end)]
),
PlotExample("Custom Markers",
"A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and the size is expected to be rougly the area of the unit circle.",
[:(begin
verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)]
x = 0.1:0.2:0.9
y = 0.7rand(5)+0.15
plot(x, y, line = (3,:dash,:lightblue), marker = (Shape(verts),30,RGBA(0,0,0,0.2)),
bg=:pink, fg=:darkblue, xlim = (0,1), ylim=(0,1), leg=false)
end)]
),
PlotExample("Contours",
"Any value for fill works here. We first build a filled contour from a function, then an unfilled contour from a matrix.",
[:(begin
x = 1:0.5:20
y = 1:0.5:10
f(x,y) = (3x+y^2)*abs(sin(x)+cos(y))
X = repmat(x', length(y), 1)
Y = repmat(y, 1, length(x))
Z = map(f, X, Y)
p1 = contour(x, y, f, fill=true)
p2 = contour(x, y, Z)
plot(p1, p2)
end)]
# [:(begin
# x = 1:0.3:20
# y = x
# f(x,y) = sin(x)+cos(y)
# contour(x, y, f, fill=true)
# end)]
),
PlotExample("Pie",
"",
[:(begin
x = ["Nerds", "Hackers", "Scientists"]
y = [0.4, 0.35, 0.25]
pie(x, y, title="The Julia Community", l=0.5)
end)]
),
PlotExample("3D",
"",
[:(begin
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, cbar=true, w=5)
plot!(zeros(n),zeros(n),1:n, w=10)
end)]
),
PlotExample("DataFrames",
"Plot using DataFrame column symbols.",
[:(begin
import RDatasets
iris = RDatasets.dataset("datasets", "iris")
scatter(iris, :SepalLength, :SepalWidth, group=:Species,
title = "My awesome plot", xlabel = "Length", ylabel = "Width",
marker = (0.5, [:+ :h :star7], 12), bg=RGB(.2,.2,.2))
end)]
),
PlotExample("Groups and Subplots",
"",
[:(begin
group = rand(map(i->"group $i",1:4),100)
plot(rand(100), layout=@layout([a b;c]), group=group, n=3, linetype=[:bar :scatter :steppre])
end)]
),
PlotExample("Polar Plots",
"",
[:(begin
Θ = linspace(0,1.5π,100)
r = abs(0.1randn(100)+sin(3Θ))
plot(Θ, r, proj=:polar, m=2)
end)]
),
PlotExample("Heatmap, categorical axes, and aspect_ratio",
"",
[:(begin
xs = [string("x",i) for i=1:10]
ys = [string("y",i) for i=1:4]
z = float((1:4)*(1:10)')
heatmap(xs, ys, z, aspect_ratio=1)
end)]
),
PlotExample("Layouts, margins, label rotation, title location",
"",
[:(begin
plot(rand(100,6),layout=@layout([a b; c]),title=["A" "B" "C"],
title_location=:left, left_margin=[20mm 0mm],
bottom_margin=50px, xrotation=60)
end)]
),
PlotExample("Boxplot and Violin series recipes",
"",
[:(begin
import RDatasets
singers = RDatasets.dataset("lattice", "singer")
violin(singers, :VoicePart, :Height, marker = (0.2, :blue, stroke(0)))
boxplot!(singers, :VoicePart, :Height, marker = (0.3, :orange, stroke(2)))
end)]
)
]
# ---------------------------------------------------------------------------------
# make and display one plot
function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
Plots._debugMode.on = debug
info("Testing plot: $pkgname:$idx:$(_examples[idx].header)")
backend(pkgname)
backend()
map(eval, _examples[idx].exprs)
plt = current()
if disp
gui(plt)
end
plt
end
# generate all plots and create a dict mapping idx --> plt
function test_examples(pkgname::Symbol; debug = false, disp = true)
Plots._debugMode.on = debug
plts = Dict()
for i in 1:length(_examples)
try
plt = test_examples(pkgname, i, debug=debug, disp=disp)
plts[i] = plt
catch ex
# TODO: put error info into markdown?
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
end
end
plts
end
-134
View File
@@ -1,134 +0,0 @@
# https://github.com/dcjones/Gadfly.jl
immutable GadflyPackage <: PlottingPackage end
# create a blank Gadfly.Plot object
function plot(pkg::GadflyPackage; kw...)
@eval import DataFrames
plt = Gadfly.Plot()
plt.mapping = Dict()
plt.data_source = DataFrames.DataFrame()
plt.layers = plt.layers[1:0]
# add the title, axis labels, and theme
d = Dict(kw)
plt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]),
Gadfly.Guide.ylabel(d[:ylabel]),
Gadfly.Guide.title(d[:title])]
# add the legend?
if d[:legend]
unshift!(plt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
end
plt.theme = Gadfly.Theme(background_color = (haskey(d, :background_color) ? d[:background_color] : colorant"white"))
Plot(plt, pkg, 0)
end
function getGeomFromLineType(linetype::Symbol, nbins::Int)
linetype == :line && return Gadfly.Geom.line
linetype == :dots && return Gadfly.Geom.point
linetype == :bar && return Gadfly.Geom.bar
linetype == :step && return Gadfly.Geom.step
linetype == :hist && return Gadfly.Geom.histogram(bincount=nbins)
linetype == :none && return Gadfly.Geom.point # change this? are we usually pairing no line with scatterplots?
linetype == :sticks && return Gadfly.Geom.bar
error("linetype $linetype not currently supported with Gadfly")
end
function getGeoms(linetype::Symbol, marker::Symbol, nbins::Int)
geoms = []
# handle heatmaps (hexbins) specially
if linetype in (:heatmap,:hexbin)
push!(geoms, Gadfly.Geom.hexbin(xbincount=nbins, ybincount=nbins))
else
# for other linetypes, get the correct Geom
push!(geoms, getGeomFromLineType(linetype, nbins))
# for any marker, add Geom.point
if marker != :none
push!(geoms, Gadfly.Geom.point)
end
end
geoms
end
# plot one data series
function plot!(::GadflyPackage, plt::Plot; kw...)
d = Dict(kw)
gfargs = []
# add the Geoms
append!(gfargs, getGeoms(d[:linetype], d[:marker], d[:nbins]))
# set color, line width, and point size
theme = Gadfly.Theme(default_color = d[:color],
line_width = d[:width] * Gadfly.px,
default_point_size = d[:markersize] * Gadfly.px)
push!(gfargs, theme)
# add a regression line?
if d[:reg]
push!(gfargs, Gadfly.Geom.smooth(method=:lm))
end
# for histograms, set x=y
x = d[d[:linetype] == :hist ? :y : :x]
# add to the legend
if length(plt.o.guides) > 0 && isa(plt.o.guides[1], Gadfly.Guide.ManualColorKey)
push!(plt.o.guides[1].labels, d[:label])
push!(plt.o.guides[1].colors, d[:color])
end
if d[:axis] != :left
warn("Gadly only supports one y axis")
end
# add the layer to the Gadfly.Plot
prepend!(plt.o.layers, Gadfly.layer(unique(gfargs)...; x = x, y = d[:y]))
plt
end
function Base.display(::GadflyPackage, plt::Plot)
display(plt.o)
end
# -------------------------------
function savepng(::GadflyPackage, plt::PlottingObject, fn::String;
w = 6 * Gadfly.inch,
h = 4 * Gadfly.inch)
Gadfly.draw(Gadfly.PNG(fn, w, h), plt.o)
end
# -------------------------------
# # create the underlying object (each backend will do this differently)
# o = buildSubplotObject(plts, pkg, layout)
function buildSubplotObject!(::GadflyPackage, subplt::Subplot)
i = 0
rows = []
for rowcnt in subplt.layout.rowcounts
push!(rows, Gadfly.hstack([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
i += rowcnt
end
subplt.o = Gadfly.vstack(rows...)
end
function Base.display(::GadflyPackage, subplt::Subplot)
display(subplt.o)
end
+674
View File
@@ -0,0 +1,674 @@
# NOTE: (0,0) is the top-left !!!
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
const _cbar_width = 5mm
@compat Base.:.*(m::Measure, n::Number) = m * n
@compat Base.:.*(n::Number, m::Measure) = m * n
@compat Base.:-(m::Measure, a::AbstractArray) = map(ai -> m - ai, a)
@compat Base.:-(a::AbstractArray, m::Measure) = map(ai -> ai - m, a)
Base.zero(::Type{typeof(mm)}) = 0mm
Base.one(::Type{typeof(mm)}) = 1mm
Base.typemin(::typeof(mm)) = -Inf*mm
Base.typemax(::typeof(mm)) = Inf*mm
Base.convert{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs
# @compat Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
# @compat Base.:+(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (1 + m1.value))
# @compat Base.:-(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 - m2.value))
# @compat Base.:-(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * (m1.value - 1))
@compat Base.:*(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * m2.value)
@compat Base.:*(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value * m1.value)
@compat Base.:/(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value / m2.value)
@compat Base.:/(m1::Length{:pct}, m2::AbsoluteLength) = AbsoluteLength(m2.value / m1.value)
Base.zero(::Type{typeof(pct)}) = 0pct
Base.one(::Type{typeof(pct)}) = 1pct
Base.typemin(::typeof(pct)) = 0pct
Base.typemax(::typeof(pct)) = 1pct
const defaultbox = BoundingBox(0mm, 0mm, 0mm, 0mm)
left(bbox::BoundingBox) = bbox.x0[1]
top(bbox::BoundingBox) = bbox.x0[2]
right(bbox::BoundingBox) = left(bbox) + width(bbox)
bottom(bbox::BoundingBox) = top(bbox) + height(bbox)
Base.size(bbox::BoundingBox) = (width(bbox), height(bbox))
# @compat Base.:*{T,N}(m1::Length{T,N}, m2::Length{T,N}) = Length{T,N}(m1.value * m2.value)
ispositive(m::Measure) = m.value > 0
# union together bounding boxes
@compat function Base.:+(bb1::BoundingBox, bb2::BoundingBox)
# empty boxes don't change the union
ispositive(width(bb1)) || return bb2
ispositive(height(bb1)) || return bb2
ispositive(width(bb2)) || return bb1
ispositive(height(bb2)) || return bb1
l = min(left(bb1), left(bb2))
t = min(top(bb1), top(bb2))
r = max(right(bb1), right(bb2))
b = max(bottom(bb1), bottom(bb2))
BoundingBox(l, t, r-l, b-t)
end
# this creates a bounding box in the parent's scope, where the child bounding box
# is relative to the parent
function crop(parent::BoundingBox, child::BoundingBox)
l = left(parent) + left(child)
t = top(parent) + top(child)
w = width(child)
h = height(child)
BoundingBox(l, t, w, h)
end
# convert a bounding box from absolute coords to percentages...
# returns an array of percentages of figure size: [left, bottom, width, height]
function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
mms = Float64[f(bb).value for f in (left,bottom,width,height)]
if flipy
mms[2] = figh.value - mms[2] # flip y when origin in bottom-left
end
mms ./ Float64[figw.value, figh.value, figw.value, figh.value]
end
function Base.show(io::IO, bbox::BoundingBox)
print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
end
# -----------------------------------------------------------
# AbstractLayout
Base.show(io::IO, layout::AbstractLayout) = print(io, "$(typeof(layout))$(size(layout))")
# this is the available area for drawing everything in this layout... as percentages of total canvas
bbox(layout::AbstractLayout) = layout.bbox
bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
# layouts are recursive, tree-like structures, and most will have a parent field
Base.parent(layout::AbstractLayout) = layout.parent
parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
# NOTE: these should be implemented for subplots in each backend!
# they represent the minimum size of the axes and guides
min_padding_left(layout::AbstractLayout) = 0mm
min_padding_top(layout::AbstractLayout) = 0mm
min_padding_right(layout::AbstractLayout) = 0mm
min_padding_bottom(layout::AbstractLayout) = 0mm
padding_w(layout::AbstractLayout) = left_padding(layout) + right_padding(layout)
padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
_update_position!(layout::AbstractLayout) = nothing
update_child_bboxes!(layout::AbstractLayout) = nothing
width(layout::AbstractLayout) = width(layout.bbox)
height(layout::AbstractLayout) = height(layout.bbox)
plotarea(layout::AbstractLayout) = defaultbox
plotarea!(layout::AbstractLayout, bbox::BoundingBox) = nothing
attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
attr!(layout::AbstractLayout, v, k::Symbol) = (layout.attr[k] = v)
hasattr(layout::AbstractLayout, k::Symbol) = haskey(layout.attr, k)
leftpad(layout::AbstractLayout) = 0mm
toppad(layout::AbstractLayout) = 0mm
rightpad(layout::AbstractLayout) = 0mm
bottompad(layout::AbstractLayout) = 0mm
# -----------------------------------------------------------
# RootLayout
# this is the parent of the top-level layout
immutable RootLayout <: AbstractLayout end
Base.parent(::RootLayout) = nothing
parent_bbox(::RootLayout) = defaultbox
bbox(::RootLayout) = defaultbox
# -----------------------------------------------------------
# EmptyLayout
# contains blank space
type EmptyLayout <: AbstractLayout
parent::AbstractLayout
bbox::BoundingBox
attr::KW # store label, width, and height for initialization
# label # this is the label that the subplot will take (since we create a layout before initialization)
end
EmptyLayout(parent = RootLayout(); kw...) = EmptyLayout(parent, defaultbox, KW(kw))
Base.size(layout::EmptyLayout) = (0,0)
Base.length(layout::EmptyLayout) = 0
Base.getindex(layout::EmptyLayout, r::Int, c::Int) = nothing
_update_min_padding!(layout::EmptyLayout) = nothing
# -----------------------------------------------------------
# GridLayout
# nested, gridded layout with optional size percentages
type GridLayout <: AbstractLayout
parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox
grid::Matrix{AbstractLayout} # Nested layouts. Each position is a AbstractLayout, which allows for arbitrary recursion
widths::Vector{Measure}
heights::Vector{Measure}
attr::KW
end
grid(args...; kw...) = GridLayout(args...; kw...)
function GridLayout(dims...;
parent = RootLayout(),
widths = zeros(dims[2]),
heights = zeros(dims[1]),
kw...)
grid = Matrix{AbstractLayout}(dims...)
layout = GridLayout(
parent,
(20mm, 5mm, 2mm, 10mm),
defaultbox,
grid,
Measure[w*pct for w in widths],
Measure[h*pct for h in heights],
# convert(Vector{Float64}, widths),
# convert(Vector{Float64}, heights),
KW(kw))
fill!(grid, EmptyLayout(layout))
layout
end
Base.size(layout::GridLayout) = size(layout.grid)
Base.length(layout::GridLayout) = length(layout.grid)
Base.getindex(layout::GridLayout, r::Int, c::Int) = layout.grid[r,c]
function Base.setindex!(layout::GridLayout, v, r::Int, c::Int)
layout.grid[r,c] = v
end
leftpad(layout::GridLayout) = layout.minpad[1]
toppad(layout::GridLayout) = layout.minpad[2]
rightpad(layout::GridLayout) = layout.minpad[3]
bottompad(layout::GridLayout) = layout.minpad[4]
# leftpad, toppad, rightpad, bottompad
function _update_min_padding!(layout::GridLayout)
map(_update_min_padding!, layout.grid)
layout.minpad = (
maximum(map(leftpad, layout.grid[:,1])),
maximum(map(toppad, layout.grid[1,:])),
maximum(map(rightpad, layout.grid[:,end])),
maximum(map(bottompad, layout.grid[end,:]))
)
end
function _update_position!(layout::GridLayout)
map(_update_position!, layout.grid)
end
function recompute_lengths(v)
# dump(v)
tot = 0pct
cnt = 0
for vi in v
if vi == 0pct
cnt += 1
else
tot += vi
end
end
leftover = 1.0pct - tot
if cnt > 1 && leftover.value <= 0
error("Not enough length left over in layout! v = $v, cnt = $cnt, leftover = $leftover")
end
# now fill in the blanks
Measure[(vi == 0pct ? leftover / cnt : vi) for vi in v]
end
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
function update_child_bboxes!(layout::GridLayout)
nr, nc = size(layout)
# create a matrix for each minimum padding direction
_update_min_padding!(layout)
minpad_left = map(leftpad, layout.grid)
minpad_top = map(toppad, layout.grid)
minpad_right = map(rightpad, layout.grid)
minpad_bottom = map(bottompad, layout.grid)
# @show minpad_left minpad_top minpad_right minpad_bottom
# get the max horizontal (left and right) padding over columns,
# and max vertical (bottom and top) padding over rows
# TODO: add extra padding here
pad_left = maximum(minpad_left, 1)
pad_top = maximum(minpad_top, 2)
pad_right = maximum(minpad_right, 1)
pad_bottom = maximum(minpad_bottom, 2)
# @show pad_left pad_top pad_right pad_bottom
# scale this up to the total padding in each direction
total_pad_horizontal = sum(pad_left + pad_right)
total_pad_vertical = sum(pad_top + pad_bottom)
# @show total_pad_horizontal total_pad_vertical
# now we can compute the total plot area in each direction
total_plotarea_horizontal = width(layout) - total_pad_horizontal
total_plotarea_vertical = height(layout) - total_pad_vertical
# @show total_plotarea_horizontal total_plotarea_vertical
# recompute widths/heights
layout.widths = recompute_lengths(layout.widths)
layout.heights = recompute_lengths(layout.heights)
# @show layout.widths layout.heights
# normalize widths/heights so they sum to 1
# denom_w = sum(layout.widths)
# denom_h = sum(layout.heights)
# @show layout.widths layout.heights denom_w, denom_h
# we have all the data we need... lets compute the plot areas and set the bounding boxes
for r=1:nr, c=1:nc
child = layout[r,c]
# get the top-left corner of this child... the first one is top-left of the parent (i.e. layout)
child_left = (c == 1 ? left(layout.bbox) : right(layout[r, c-1].bbox))
child_top = (r == 1 ? top(layout.bbox) : bottom(layout[r-1, c].bbox))
# compute plot area
plotarea_left = child_left + pad_left[c]
plotarea_top = child_top + pad_top[r]
plotarea_width = total_plotarea_horizontal * layout.widths[c]
plotarea_height = total_plotarea_vertical * layout.heights[r]
plotarea!(child, BoundingBox(plotarea_left, plotarea_top, plotarea_width, plotarea_height))
# compute child bbox
child_width = pad_left[c] + plotarea_width + pad_right[c]
child_height = pad_top[r] + plotarea_height + pad_bottom[r]
bbox!(child, BoundingBox(child_left, child_top, child_width, child_height))
# recursively update the child's children
update_child_bboxes!(child)
end
end
# ----------------------------------------------------------------------
calc_num_subplots(layout::AbstractLayout) = 1
function calc_num_subplots(layout::GridLayout)
tot = 0
for l in layout.grid
tot += calc_num_subplots(l)
end
tot
end
function compute_gridsize(numplts::Int, nr::Int, nc::Int)
# figure out how many rows/columns we need
if nr < 1
if nc < 1
nr = round(Int, sqrt(numplts))
nc = ceil(Int, numplts / nr)
else
nr = ceil(Int, numplts / nc)
end
else
nc = ceil(Int, numplts / nr)
end
nr, nc
end
# ----------------------------------------------------------------------
# constructors
# pass the layout arg through
function layout_args(d::KW)
layout_args(get(d, :layout, default(:layout)))
end
function layout_args(d::KW, n_override::Integer)
layout, n = layout_args(get(d, :layout, n_override))
if n != n_override
error("When doing layout, n != n_override. You're probably trying to force existing plots into a layout that doesn't fit them.")
end
layout, n
end
function layout_args(n::Integer)
nr, nc = compute_gridsize(n, -1, -1)
GridLayout(nr, nc), n
end
function layout_args{I<:Integer}(sztup::NTuple{2,I})
nr, nc = sztup
GridLayout(nr, nc), nr*nc
end
function layout_args{I<:Integer}(sztup::NTuple{3,I})
n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n
end
# compute number of subplots
function layout_args(layout::GridLayout)
# recursively get the size of the grid
n = calc_num_subplots(layout)
layout, n
end
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
# # pass the layout arg through
# function build_layout(d::KW)
# build_layout(get(d, :layout, default(:layout)))
# end
#
# function build_layout(n::Integer)
# nr, nc = compute_gridsize(n, -1, -1)
# build_layout(GridLayout(nr, nc), n)
# end
#
# function build_layout{I<:Integer}(sztup::NTuple{2,I})
# nr, nc = sztup
# build_layout(GridLayout(nr, nc))
# end
#
# function build_layout{I<:Integer}(sztup::NTuple{3,I})
# n, nr, nc = sztup
# nr, nc = compute_gridsize(n, nr, nc)
# build_layout(GridLayout(nr, nc), n)
# end
#
# # compute number of subplots
# function build_layout(layout::GridLayout)
# # recursively get the size of the grid
# n = calc_num_subplots(layout)
# build_layout(layout, n)
# end
function build_layout(args...)
layout, n = layout_args(args...)
build_layout(layout, n)
end
# n is the number of subplots
function build_layout(layout::GridLayout, n::Integer)
nr, nc = size(layout)
subplots = Subplot[]
spmap = SubplotMap()
i = 0
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
sp = Subplot(backend(), parent=layout)
layout[r,c] = sp
push!(subplots, sp)
spmap[attr(l,:label,gensym())] = sp
if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l,:width)
end
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l,:height)
end
i += 1
elseif isa(l, GridLayout)
# sub-grid
l, sps, m = build_layout(l, n-i)
append!(subplots, sps)
merge!(spmap, m)
i += length(sps)
end
i >= n && break # only add n subplots
end
layout, subplots, spmap
end
# build a layout from a list of existing Plot objects
# TODO... much of the logic overlaps with the method above... can we merge?
function build_layout(layout::GridLayout, numsp::Integer, plts::AVec{Plot})
nr, nc = size(layout)
subplots = Subplot[]
spmap = SubplotMap()
i = 0
for r=1:nr, c=1:nc
l = layout[r,c]
if isa(l, EmptyLayout) && !get(l.attr, :blank, false)
plt = shift!(plts) # grab the first plot out of the list
layout[r,c] = plt.layout
append!(subplots, plt.subplots)
merge!(spmap, plt.spmap)
if get(l.attr, :width, :auto) != :auto
layout.widths[c] = attr(l,:width)
end
if get(l.attr, :height, :auto) != :auto
layout.heights[r] = attr(l,:height)
end
i += length(plt.subplots)
elseif isa(l, GridLayout)
# sub-grid
l, sps, m = build_layout(l, numsp-i, plts)
append!(subplots, sps)
merge!(spmap, m)
i += length(sps)
end
i >= numsp && break # only add n subplots
end
layout, subplots, spmap
end
# ----------------------------------------------------------------------
# @layout macro
function add_layout_pct!(kw::KW, v::Expr, idx::Integer, nidx::Integer)
# dump(v)
# something like {0.2w}?
if v.head == :call && v.args[1] == :*
num = v.args[2]
if length(v.args) == 3 && isa(num, Number)
units = v.args[3]
if units == :h
return kw[:h] = num*pct
elseif units == :w
return kw[:w] = num*pct
elseif units in (:pct, :px, :mm, :cm, :inch)
idx == 1 && (kw[:w] = v)
(idx == 2 || nidx == 1) && (kw[:h] = v)
# return kw[idx == 1 ? :w : :h] = v
end
end
end
error("Couldn't match layout curly (idx=$idx): $v")
end
function add_layout_pct!(kw::KW, v::Number, idx::Integer)
# kw[idx == 1 ? :w : :h] = v*pct
idx == 1 && (kw[:w] = v*pct)
(idx == 2 || nidx == 1) && (kw[:h] = v*pct)
end
isrow(v) = isa(v, Expr) && v.head in (:hcat,:row)
iscol(v) = isa(v, Expr) && v.head == :vcat
rowsize(v) = isrow(v) ? length(v.args) : 1
function create_grid(expr::Expr)
# cellsym = gensym(:cell)
# @show expr
if iscol(expr)
create_grid_vcat(expr)
# rowsizes = map(rowsize, expr.args)
# rmin, rmax = extrema(rowsizes)
# if rmin > 0 && rmin == rmax
# # we have a grid... build the whole thing
# # note: rmin is the number of columns
# nr = length(expr.args)
# nc = rmin
#
# :(let cell = GridLayout($nr, $nc)
# $([:(cell[$r,$c] = $(create_grid(expr.args[r], c))) for r=1:nr, c=1:nc]...)
# for r=1:nr
# layout = $(create_grid(expr.args[r])
# cell[r,]
# $([:($cellsym[$r,1] = $(create_grid(expr.args[r]))) for r=1:length(expr.args)]...)
# $cellsym
# end)
# else
# # otherwise just build one row at a time
# :(let
# $cellsym = GridLayout($(length(expr.args)), 1)
# $([:($cellsym[$i,1] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
# $cellsym
# end)
# end
elseif isrow(expr)
:(let cell = GridLayout(1, $(length(expr.args)))
$([:(cell[1,$i] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
# :(let
# $cellsym = GridLayout(1, $(length(expr.args)))
# $([:($cellsym[1,$i] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
# $cellsym
# end)
elseif expr.head == :curly
create_grid_curly(expr)
else
# if it's something else, just return that (might be an existing layout?)
expr
end
end
function create_grid_vcat(expr::Expr)
rowsizes = map(rowsize, expr.args)
rmin, rmax = extrema(rowsizes)
# @show rmin, rmax
if rmin > 0 && rmin == rmax
# we have a grid... build the whole thing
# note: rmin is the number of columns
nr = length(expr.args)
nc = rmin
# @show nr, nc
body = Expr(:block)
for r=1:nr
arg = expr.args[r]
# @show r, arg
if isrow(arg)
for (c,item) in enumerate(arg.args)
push!(body.args, :(cell[$r,$c] = $(create_grid(item))))
end
else
push!(body.args, :(cell[$r,1] = $(create_grid(arg))))
end
end
# @show body
:(let cell = GridLayout($nr, $nc)
$body
cell
end)
# :(let cell = GridLayout($nr, $nc)
# $([:(cell[$r,$c] = $(create_grid(expr.args[r], c))) for r=1:nr, c=1:nc]...)
# for r=1:nr
# layout = $(create_grid(expr.args[r])
# cell[r,]
# $([:($cellsym[$r,1] = $(create_grid(expr.args[r]))) for r=1:length(expr.args)]...)
# $cellsym
# end)
else
# otherwise just build one row at a time
:(let cell = GridLayout($(length(expr.args)), 1)
$([:(cell[$i,1] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
cell
end)
# :(let
# $cellsym = GridLayout($(length(expr.args)), 1)
# $([:($cellsym[$i,1] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
# $cellsym
# end)
end
end
function create_grid_curly(expr::Expr)
s = expr.args[1]
kw = KW()
for (i,arg) in enumerate(expr.args[2:end])
add_layout_pct!(kw, arg, i, length(expr.args)-1)
end
# @show kw
:(EmptyLayout(label = $(QuoteNode(s)), width = $(get(kw, :w, QuoteNode(:auto))), height = $(get(kw, :h, QuoteNode(:auto)))))
end
function create_grid(s::Symbol)
:(EmptyLayout(label = $(QuoteNode(s)), blank = $(s == :_)))
end
macro layout(mat::Expr)
create_grid(mat)
end
# -------------------------------------------------------------------------
# make all reference the same axis extrema/values
function link_axes!(axes::Axis...)
a1 = axes[1]
for i=2:length(axes)
a2 = axes[i]
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
a2[k] = a1[k]
end
end
end
# for some vector or matrix of layouts, filter only the Subplots and link those axes
function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
subplots = filter(l -> isa(l, Subplot), a)
axes = [sp.attr[axissym] for sp in subplots]
link_axes!(axes...)
end
# don't do anything for most layout types
function link_axes!(l::AbstractLayout, link::Symbol)
end
# process a GridLayout, recursively linking axes according to the link symbol
function link_axes!(layout::GridLayout, link::Symbol)
nr, nc = size(layout)
if link in (:x, :both)
for c=1:nc
link_axes!(layout.grid[:,c], :xaxis)
end
end
if link in (:y, :both)
for r=1:nr
link_axes!(layout.grid[r,:], :yaxis)
end
end
if link == :all
link_axes!(layout.grid, :xaxis)
link_axes!(layout.grid, :yaxis)
end
for l in layout.grid
link_axes!(l, link)
end
end
+225
View File
@@ -0,0 +1,225 @@
defaultOutputFormat(plt::Plot) = "png"
function png(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "png")
io = open(fn, "w")
writemime(io, MIME("image/png"), plt)
close(io)
end
png(fn::AbstractString) = png(current(), fn)
function svg(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "svg")
io = open(fn, "w")
writemime(io, MIME("image/svg+xml"), plt)
close(io)
end
svg(fn::AbstractString) = svg(current(), fn)
function pdf(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "pdf")
io = open(fn, "w")
writemime(io, MIME("application/pdf"), plt)
close(io)
end
pdf(fn::AbstractString) = pdf(current(), fn)
function ps(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "ps")
io = open(fn, "w")
writemime(io, MIME("application/postscript"), plt)
close(io)
end
ps(fn::AbstractString) = ps(current(), fn)
function tex(plt::Plot, fn::AbstractString)
fn = addExtension(fn, "tex")
io = open(fn, "w")
writemime(io, MIME("application/x-tex"), plt)
close(io)
end
tex(fn::AbstractString) = tex(current(), fn)
# ----------------------------------------------------------------
@compat const _savemap = Dict(
"png" => png,
"svg" => svg,
"pdf" => pdf,
"ps" => ps,
"tex" => tex,
)
function getExtension(fn::AbstractString)
pieces = split(fn, ".")
length(pieces) > 1 || error("Can't extract file extension: ", fn)
ext = pieces[end]
haskey(_savemap, ext) || error("Invalid file extension: ", fn)
ext
end
function addExtension(fn::AbstractString, ext::AbstractString)
try
oldext = getExtension(fn)
if oldext == ext
return fn
else
return "$fn.$ext"
end
catch
return "$fn.$ext"
end
end
function savefig(plt::Plot, fn::AbstractString)
# get the extension
local ext
try
ext = getExtension(fn)
catch
# if we couldn't extract the extension, add the default
ext = defaultOutputFormat(plt)
fn = addExtension(fn, ext)
end
# save it
func = get(_savemap, ext) do
error("Unsupported extension $ext with filename ", fn)
end
func(plt, fn)
end
savefig(fn::AbstractString) = savefig(current(), fn)
# ---------------------------------------------------------
gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
function Base.display(::PlotsDisplay, plt::Plot)
prepare_output(plt)
_display(plt)
end
# override the REPL display to open a gui window
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
# ---------------------------------------------------------
const _mimeformats = Dict(
"application/eps" => "eps",
"image/eps" => "eps",
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg"
)
const _best_html_output_type = KW(
:pyplot => :png,
)
# a backup for html... passes to svg or png depending on the html_output_format arg
function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
if output_type == :png
# info("writing png to html output")
print(io, "<img src=\"data:image/png;base64,", base64encode(writemime, MIME("image/png"), plt), "\" />")
elseif output_type == :svg
# info("writing svg to html output")
writemime(io, MIME("image/svg+xml"), plt)
else
error("only png or svg allowed. got: $output_type")
end
end
# for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats)
@eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
prepare_output(plt)
_writemime(io, m, plt)
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
# print(io, "<img src=\"data:image/png;base64,", base64(writemime, MIME("image/png"), plt), "\" />")
# end
# elseif fmt == "svg"
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
# writemime(io, MIME("image/svg+xml"), plt)
# end
# else
# error("only png or svg allowed. got: $fmt")
# end
# end
#
# html_output_format("svg")
# ---------------------------------------------------------
# IJulia
# ---------------------------------------------------------
const _ijulia_output = Compat.ASCIIString["text/html"]
function setup_ijulia()
# override IJulia inline display
if isijulia()
@eval begin
import IJulia
export set_ijulia_output
function set_ijulia_output(mimestr::AbstractString)
# info("Setting IJulia output format to $mimestr")
global _ijulia_output
_ijulia_output[1] = mimestr
end
function IJulia.display_dict(plt::Plot)
global _ijulia_output
Dict{Compat.ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
end
end
set_ijulia_output("text/html")
end
end
# ---------------------------------------------------------
# Atom PlotPane
# ---------------------------------------------------------
function setup_atom()
# @require Atom begin
if isatom() && get(ENV, "PLOTS_USE_ATOM_PLOTPANE", false) in (true, 1, "1", "true", "yes")
# @eval import Atom, Media
@eval import Atom
# connects the render function
for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
Atom.Media.media(Plot{T}, Atom.Media.Plot)
end
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
# Atom.displaysize(::Plot) = (535, 379)
# Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))"
# this is like "display"... sends an html div with the plot to the PlotPane
function Atom.Media.render(pane::Atom.PlotPane, plt::Plot)
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
end
# function Atom.Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
# html = Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
# end
end
end
+457 -357
View File
@@ -1,414 +1,514 @@
type CurrentPlot
nullableplot::Nullable{PlottingObject}
nullableplot::Nullable{AbstractPlot}
end
const CURRENT_PLOT = CurrentPlot(Nullable{PlottingObject}())
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
function currentPlot()
if isplotnull()
error("No current plot/subplot")
end
get(CURRENT_PLOT.nullableplot)
function current()
if isplotnull()
error("No current plot/subplot")
end
get(CURRENT_PLOT.nullableplot)
end
currentPlot!(plot::PlottingObject) = (CURRENT_PLOT.nullableplot = Nullable(plot))
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(plot))
# ---------------------------------------------------------
Base.string(plt::Plot) = "Plot{$(plt.plotter) n=$(plt.n)}"
Base.string(plt::Plot) = "Plot{$(plt.backend) n=$(plt.n)}"
Base.print(io::IO, plt::Plot) = print(io, string(plt))
Base.show(io::IO, plt::Plot) = print(io, string(plt))
getplot(plt::Plot) = plt
getattr(plt::Plot, idx::Int = 1) = plt.attr
convertSeriesIndex(plt::Plot, n::Int) = n
# ---------------------------------------------------------
doc"""
The main plot command. Call `plotter!(:module)` to set the current plotting backend.
Commands are converted into the relevant plotting commands for that package:
```
plotter!(:gadfly)
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
plotter!(: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:
```
plot(args...; kw...) # creates a new plot window, and sets it to be the currentPlot
plot!(args...; kw...) # adds to the `currentPlot`
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
```
There are lots of ways to pass in data... just try it and it will likely work as expected.
When you pass in matrices, it splits by columns. See the documentation for more info.
Some keyword arguments you can set:
```
axis # :left or :right
color # can be a string ("red") or a symbol (:red) or a ColorsTypes.jl Colorant (RGB(1,0,0)) or :auto (which lets the package pick)
label # string or symbol, applies to that line, may go in a legend
width # width of a line
linetype # :line, :step, :stepinverted, :sticks, :dots, :none, :heatmap
linestyle # :solid, :dash, :dot, :dashdot, :dashdotdot
marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon
markercolor # same choices as `color`
markersize # size of the marker
nbins # number of bins for heatmap/hexbin and histograms
heatmap_c # color cutoffs for Qwt heatmaps
fillto # fillto value for area plots
title # string or symbol, title of the plot
xlabel # string or symbol, label on the bottom (x) axis
ylabel # string or symbol, label on the left (y) axis
yrightlabel # string or symbol, label on the right (y) axis
reg # true or false, add a regression line for each line
size # (Int,Int), resize the enclosing window
pos # (Int,Int), move the enclosing window to this position
windowtitle # string or symbol, set the title of the enclosing windowtitle
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)
```
When plotting multiple lines, you can give every line the same trait by using the singular, or add an "s" to pluralize.
(yes I know it's not gramatically correct, but it's easy to use and implement)
```
plot(rand(100,2); colors = [:red, RGB(.5,.5,0)], axiss = [:left, :right], width = 5) # note the width=5 is applied to both lines
```
"""
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
```
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`
```
# -------------------------
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
When you pass in matrices, it splits by columns. See the documentation for more info.
"""
# this creates a new plot with args/kw and sets it to be the current plot
function plot(args...; kw...)
plt = plot(plotter(); getPlotKeywordArgs(kw, 1, 0)...) # create a new, blank plot
plot!(plt, args...; kw...) # add to it
d = KW(kw)
preprocessArgs!(d)
# create an empty Plot then process
plt = Plot()
# plt.user_attr = d
_plot!(plt, d, args...)
end
# this adds to the current plot
# build a new plot from existing plots
# note: we split into plt1 and plts_tail so we can dispatch correctly
function plot(plt1::Plot, plts_tail::Plot...; kw...)
d = KW(kw)
preprocessArgs!(d)
# build our plot vector from the args
n = length(plts_tail) + 1
plts = Array(Plot, n)
plts[1] = plt1
for (i,plt) in enumerate(plts_tail)
plts[i+1] = plt
end
# compute the layout
layout = layout_args(d, n)[1]
num_sp = sum([length(p.subplots) for p in plts])
# create a new plot object, with subplot list/map made of existing subplots.
# note: we create a new backend figure for this new plot object
# note: all subplots and series "belong" to this new plot...
plt = Plot()
# TODO: build the user_attr dict by creating "Any matrices" for the args of each subplot
# TODO: replace this with proper processing from a merged user_attr KW
# update plot args, first with existing plots, then override with d
for p in plts
_update_plot_args(plt, p.attr)
plt.n += p.n
end
_update_plot_args(plt, d)
# pass new plot to the backend
plt.o = _create_backend_figure(plt)
plt.init = true
# create the layout and initialize the subplots
plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts))
for (idx, sp) in enumerate(plt.subplots)
_initialize_subplot(plt, sp)
serieslist = series_list(sp)
sp.plt = plt
sp.attr[:subplot_index] = idx
for series in serieslist
push!(plt.series_list, series)
_series_added(plt, series)
end
end
# finish up
current(plt)
if get(d, :show, default(:show))
gui()
end
plt
end
# this adds to the current plot, or creates a new plot if none are current
function plot!(args...; kw...)
plot!(currentPlot(), args...; kw...)
end
# not allowed:
function plot!(subplt::Subplot, args...; kw...)
error("Can't call plot! on a Subplot!")
local plt
try
plt = current()
catch
return plot(args...; kw...)
end
plot!(current(), args...; kw...)
end
# this adds to a specific plot... most plot commands will flow through here
function plot!(plt::Plot, args...; kw...)
# # increment n if we're going directly to the package's plot method
# if length(args) == 0
# plt.n += 1
# end
# plot!(plt.plotter, plt, args...; kw...)
kwList = createKWargsList(plt, args...; kw...)
for (i,d) in enumerate(kwList)
plt.n += 1
plot!(plt.plotter, plt; d...)
end
currentPlot!(plt)
# do we want to show it?
d = Dict(kw)
if haskey(d, :show) && d[:show]
display(plt)
end
plt
d = KW(kw)
preprocessArgs!(d)
# merge!(plt.user_attr, d)
_plot!(plt, d, args...)
end
# show/update the plot
function Base.display(plt::PlottingObject)
display(plt.plotter, plt)
function strip_first_letter(s::Symbol)
str = string(s)
str[1:1], Symbol(str[2:end])
end
# -------------------------
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
function _apply_series_recipe(plt::Plot, d::KW)
st = d[:seriestype]
# @show st
if st in supportedTypes()
# getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes
sp = d[:subplot]
sp_idx = get_subplot_index(plt, sp)
_update_subplot_args(plt, sp, d, sp_idx)
# change to a 3d projection for this subplot?
if is3d(st)
sp.attr[:projection] = "3d"
end
# initialize now that we know the first series type
if !haskey(sp.attr, :init)
_initialize_subplot(plt, sp)
sp.attr[:init] = true
end
# adjust extrema and discrete info
if st == :image
w, h = size(d[:z])
expand_extrema!(sp[:xaxis], (0,w))
expand_extrema!(sp[:yaxis], (0,h))
sp[:yaxis].d[:flip] = true
elseif !(st in (:pie, :histogram, :histogram2d))
expand_extrema!(sp, d)
end
# add the series!
warnOnUnsupportedArgs(plt.backend, d)
warnOnUnsupported(plt.backend, d)
series = Series(d)
push!(plt.series_list, series)
# @show series
_series_added(plt, series)
doc"Build a vector of dictionaries which hold the keyword arguments for a call to plot!"
else
# get a sub list of series for this seriestype
datalist = try
RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
catch
warn("Exception during apply_recipe(Val{$st}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))")
rethrow()
end
# no args... 1 series
function createKWargsList(plt::PlottingObject; kw...)
d = Dict(kw)
@assert haskey(d, :y)
if !haskey(d, :x)
d[:x] = 1:length(d[:y])
end
[getPlotKeywordArgs(d, 1, plt.n + 1)]
# assuming there was no error, recursively apply the series recipes
for data in datalist
if isa(data, RecipeData)
_apply_series_recipe(plt, data.d)
else
warn("Unhandled recipe: $(data)")
break
end
end
end
end
# create one series where y is vectors of numbers
function createKWargsList{T<:Real}(plt::PlottingObject, y::AVec{T}; kw...)
d = getPlotKeywordArgs(kw, 1, plt.n + 1)
d[:x] = 1:length(y)
d[:y] = y
[d]
# this is the core plotting function. recursively apply recipes to build
# a list of series KW dicts.
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
function _plot!(plt::Plot, d::KW, args...)
# d = plt.user_attr
d[:plot_object] = plt
# the grouping mechanism is a recipe on a GroupBy object
# we simply add the GroupBy object to the front of the args list to allow
# the recipe to be applied
if haskey(d, :group)
args = (extractGroupArgs(d[:group], args...), args...)
end
# for plotting recipes, swap out the args and update the parameter dictionary
# we are keeping a queue of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue
# for processing.
kw_list = KW[]
still_to_process = isempty(args) ? [] : [RecipeData(copy(d), args)]
while !isempty(still_to_process)
# grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes)
next_series = shift!(still_to_process)
for recipedata in RecipesBase.apply_recipe(next_series.d, next_series.args...)
# recipedata should be of type RecipeData. if it's not then the inputs must not have been fully processed by recipes
if !(typeof(recipedata) <: RecipeData)
error("Inputs couldn't be processed... expected RecipeData but got: $recipedata")
end
if isempty(recipedata.args)
# when the arg tuple is empty, that means there's nothing left to recursively
# process... finish up and add to the kw_list
kw = recipedata.d
_add_markershape(kw)
# if there was a grouping, filter the data here
_filter_input_data!(kw)
# map marker_z if it's a Function
if isa(get(kw, :marker_z, nothing), Function)
# TODO: should this take y and/or z as arguments?
kw[:marker_z] = map(kw[:marker_z], kw[:x])
end
# convert a ribbon into a fillrange
if get(kw, :ribbon, nothing) != nothing
make_fillrange_from_ribbon(kw)
end
# add the plot index
plt.n += 1
kw[:series_plotindex] = plt.n
# check that the backend will support the command and add it to the list
warnOnUnsupportedScales(plt.backend, kw)
push!(kw_list, kw)
# handle error bars by creating new recipedata data... these will have
# the same recipedata index as the recipedata they are copied from
for esym in (:xerror, :yerror)
if get(d, esym, nothing) != nothing
# we make a copy of the KW and apply an errorbar recipe
errkw = copy(kw)
errkw[:seriestype] = esym
errkw[:label] = ""
errkw[:primary] = false
push!(kw_list, errkw)
end
end
# handle smoothing by adding a new series
if get(d, :smooth, false)
x, y = kw[:x], kw[:y]
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
sx = [minimum(x), maximum(x)]
sy = β * sx + α
push!(kw_list, merge(copy(kw), KW(
:seriestype => :path,
:x => sx,
:y => sy,
:fillrange => nothing,
:label => "",
:primary => false,
)))
# don't allow something else to handle it
d[:smooth] = false
end
else
# args are non-empty, so there's still processing to do... add it back to the queue
push!(still_to_process, recipedata)
end
end
end
# merge in anything meant for plot/subplot
for kw in kw_list
for (k,v) in kw
for defdict in (_plot_defaults, _subplot_defaults)
if haskey(defdict, k)
d[k] = pop!(kw, k)
end
end
# if haskey(_plot_defaults, k) || haskey(_subplot_defaults, k)
# d[k] = v
# end
end
end
# TODO: init subplots here
_update_plot_args(plt, d)
if !plt.init
plt.o = _create_backend_figure(plt)
# create the layout and subplots from the inputs
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
for (idx,sp) in enumerate(plt.subplots)
sp.plt = plt
sp.attr[:subplot_index] = idx
end
plt.init = true
end
# just in case the backend needs to set up the plot (make it current or something)
_prepare_plot_object(plt)
# first apply any args for the subplots
for (idx,sp) in enumerate(plt.subplots)
_update_subplot_args(plt, sp, d, idx, remove_pair = false)
end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
# this is it folks!
# TODO: we probably shouldn't use i for tracking series index, but rather explicitly track it in recipes
for (i,kw) in enumerate(kw_list)
# if !(get(kw, :seriestype, :none) in (:xerror, :yerror))
# plt.n += 1
# end
command_idx = kw[:series_plotindex] - kw_list[1][:series_plotindex] + 1
# get the Subplot object to which the series belongs
sp = get(kw, :subplot, :auto)
sp = if sp == :auto
mod1(i,length(plt.subplots))
else
slice_arg(sp, i)
end
sp = kw[:subplot] = get_subplot(plt, sp)
idx = get_subplot_index(plt, sp)
# strip out series annotations (those which are based on series x/y coords)
# and add them to the subplot attr
sp_anns = annotations(sp[:annotations])
anns = annotations(pop!(kw, :series_annotations, []))
if length(anns) > 0
x, y = kw[:x], kw[:y]
nx, ny, na = map(length, (x,y,anns))
n = max(nx, ny, na)
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
end
sp.attr[:annotations] = vcat(sp_anns, anns)
# we update subplot args in case something like the color palatte is part of the recipe
_update_subplot_args(plt, sp, kw, idx)
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, sp, command_idx)
# now we have a fully specified series, with colors chosen. we must recursively handle
# series recipes, which dispatch on seriestype. If a backend does not natively support a seriestype,
# we check for a recipe that will convert that series type into one made up of lower-level components.
# For example, a histogram is just a bar plot with binned data, a bar plot is really a filled step plot,
# and a step plot is really just a path. So any backend that supports drawing a path will implicitly
# be able to support step, bar, and histogram plots (and any recipes that use those components).
_apply_series_recipe(plt, kw)
end
# # everything is processed, time to compute the layout bounding boxes
# _before_layout_calcs(plt)
# w, h = plt.attr[:size]
# plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
# update_child_bboxes!(plt.layout)
#
# # TODO just need to pass plt... and we should do all non-series updates here
# _update_plot_object(plt)
current(plt)
# note: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
# # do we want to show it?
# if haskey(d, :show) && d[:show]
if get(d, :show, default(:show))
gui()
end
plt
end
# create one series where x/y are vectors of numbers
function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec{S}; kw...)
@assert length(x) == length(y)
d = getPlotKeywordArgs(kw, 1, plt.n + 1)
d[:x] = x
d[:y] = y
[d]
function _replace_linewidth(d::KW)
# get a good default linewidth... 0 for surface and heatmaps
if get(d, :linewidth, :auto) == :auto
d[:linewidth] = (get(d, :seriestype, :path) in (:surface,:heatmap,:image) ? 0 : 1)
end
end
# create m series, 1 for each column of y
function createKWargsList(plt::PlottingObject, y::AMat; kw...)
n,m = size(y)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = 1:n
d[:y] = y[:,i]
push!(ret, d)
end
ret
# we're getting ready to display/output. prep for layout calcs, then update
# the plot object after
function prepare_output(plt::Plot)
_before_layout_calcs(plt)
w, h = plt.attr[:size]
plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
update_child_bboxes!(plt.layout)
_update_plot_object(plt)
end
# create m series, 1 for each column of y
function createKWargsList(plt::PlottingObject, x::AVec, y::AMat; kw...)
n,m = size(y)
@assert length(x) == n
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = x
d[:y] = y[:,i]
push!(ret, d)
end
ret
function prepared_object(plt::Plot)
prepare_output(plt)
plt.o
end
# create m series, 1 for each column of y
function createKWargsList(plt::PlottingObject, x::AMat, y::AMat; kw...)
@assert size(x) == size(y)
n,m = size(y)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = x[:,i]
d[:y] = y[:,i]
push!(ret, d)
end
ret
end
# --------------------------------------------------------------------
# create 1 series, y = f(x)
function createKWargsList(plt::PlottingObject, x::AVec, f::Function; kw...)
d = getPlotKeywordArgs(kw, 1, plt.n + 1)
d[:x] = x
d[:y] = map(f, x)
[d]
end
# create m series, y = f(x), 1 for each column of x
function createKWargsList(plt::PlottingObject, x::AMat, f::Function; kw...)
n,m = size(x)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = x[:,i]
d[:y] = map(f, d[:x])
push!(ret, d)
end
ret
end
# create m series, 1 for each item in y (assumes vectors of something other than numbers... functions? vectors?)
function createKWargsList(plt::PlottingObject, y::AVec; kw...)
m = length(y)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = 1:length(y[i])
d[:y] = y[i]
push!(ret, d)
end
ret
end
function getyvec(x::AVec, y::AVec)
@assert length(x) == length(y)
y
end
getyvec(x::AVec, f::Function) = map(f, x)
getyvec(x, y) = error("Couldn't create yvec from types: x ($(typeof(x))), y ($(typeof(y)))")
# same, but given an x to use for all series
function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec; kw...)
m = length(y)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = x
d[:y] = getyvec(x, y[i])
push!(ret, d)
end
ret
end
# same, but m series of (x[i],y[i])
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec; kw...)
@assert length(x) == length(y)
m = length(y)
ret = []
for i in 1:m
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = x[i]
d[:y] = getyvec(x[i], y[i])
push!(ret, d)
end
ret
end
# n empty series
function createKWargsList(plt::PlottingObject, n::Integer; kw...)
ret = []
for i in 1:n
d = getPlotKeywordArgs(kw, i, plt.n + i)
d[:x] = zeros(0)
d[:y] = zeros(0)
push!(ret, d)
end
ret
end
# TODO: handle DataFrames (might have NAs!)
# -------------------------
# # most calls should flow through here now... we create a Dict with the keyword args for each series, and plot them
# function plot!(pkg::PlottingPackage, plt::Plot, args...; kw...)
# kwList = createKWargsList(plt, args...; kw...)
# for (i,d) in enumerate(kwList)
# plt.n += 1
# plot!(pkg, plt; d...)
# end
# plt
# function get_indices(orig, labels)
# Int[findnext(labels, l, 1) for l in orig]
# end
# -------------------------
# # These methods are various ways to add to an existing plot
# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, y::AVec{T}; kw...)
# plt.n += 1
# # plot!(pkg, plt; x = 1:length(y), y = y, getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!{T<:Real,S<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec{S}; kw...) # one line (will assert length(x) == length(y))
# @assert length(x) == length(y)
# plt.n += 1
# plot!(pkg, plt; x=x, y=y, getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!(pkg::PlottingPackage, plt::Plot, y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1)
# n,m = size(y)
# for i in 1:m
# plt.n += 1
# plot!(pkg, plt; x = 1:n, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
# n,m = size(y)
# for i in 1:m
# @assert length(x) == n
# plt.n += 1
# plot!(pkg, plt; x = x, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y))
# @assert size(x) == size(y)
# for i in 1:size(x,2)
# plt.n += 1
# plot!(pkg, plt; x = x[:,i], y = y[:,i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, f::Function; kw...) # one line, y = f(x)
# plt.n += 1
# plot!(pkg, plt; x = x, y = map(f,x), getPlotKeywordArgs(kw, 1, plt)...)
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ)
# for i in 1:size(x,2)
# xi = x[:,i]
# plt.n += 1
# plot!(pkg, plt; x = xi, y = map(f, xi), getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# # function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ)
# # for i in 1:length(fs)
# # plt.n += 1
# # plot!(pkg, plt; x = x, y = map(fs[i], x), getPlotKeywordArgs(kw, i, plt)...)
# # end
# # plt
# # end
# function plot!(pkg::PlottingPackage, plt::Plot, y::AVec; kw...) # multiple lines, each with x = 1:length(y[i])
# for i in 1:length(y)
# plt.n += 1
# plot!(pkg, plt; x = 1:length(y[i]), y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# end
# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec; kw...) # multiple lines, will assert length(x) == length(y[i])
# for i in 1:length(y)
# if typeof(y[i]) <: AbstractVector
# @assert length(x) == length(y[i])
# plt.n += 1
# plot!(pkg, plt; x = x, y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# elseif typeof(y[i]) == Function
# plt.n += 1
# plot!(pkg, plt; x = x, y = map(y[i], x), getPlotKeywordArgs(kw, 1, plt)...)
# # TODO: remove?? this is the old way of handling discrete data... should be
# # replaced by the Axis type and logic
# function setTicksFromStringVector(plt::Plot, d::KW, di::KW, letter)
# sym = Symbol(letter)
# ticksym = Symbol(letter * "ticks")
# pargs = plt.attr
# v = di[sym]
#
# # do we really want to do this?
# typeof(v) <: AbstractArray || return
# isempty(v) && return
# trueOrAllTrue(_ -> typeof(_) <: AbstractString, v) || return
#
# # compute the ticks and labels
# ticks, labels = if ticksType(pargs[ticksym]) == :ticks_and_labels
# # extend the existing ticks and labels. only add to labels if they're new!
# ticks, labels = pargs[ticksym]
# newlabels = filter(_ -> !(_ in labels), unique(v))
# newticks = if isempty(ticks)
# collect(1:length(newlabels))
# else
# maximum(ticks) + collect(1:length(newlabels))
# end
# ticks = vcat(ticks, newticks)
# labels = vcat(labels, newlabels)
# ticks, labels
# else
# # create new ticks and labels
# newlabels = unique(v)
# collect(1:length(newlabels)), newlabels
# end
#
# d[ticksym] = ticks, labels
# plt.attr[ticksym] = ticks, labels
#
# # add an origsym field so that later on we can re-compute the x vector if ticks change
# origsym = Symbol(letter * "orig")
# di[origsym] = v
# di[sym] = get_indices(v, labels)
#
# # loop through existing plt.seriesargs and adjust indices if there is an origsym key
# for sargs in plt.seriesargs
# if haskey(sargs, origsym)
# # TODO: might need to call the setindex function instead to trigger a plot update for some backends??
# sargs[sym] = get_indices(sargs[origsym], labels)
# end
# end
# end
# plt
# end
# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec; kw...) # multiple lines, will assert length(x[i]) == length(y[i])
# @assert length(x) == length(y)
# for i in 1:length(x)
# @assert length(x[i]) == length(y[i])
# plt.n += 1
# plot!(pkg, plt; x = x[i], y = y[i], getPlotKeywordArgs(kw, i, plt)...)
# end
# plt
# --------------------------------------------------------------------
# --------------------------------------------------------------------
# function Base.copy(plt::Plot)
# backend(plt.backend)
# plt2 = plot(; plt.attr...)
# for sargs in plt.seriesargs
# sargs = filter((k,v) -> haskey(_series_defaults,k), sargs)
# plot!(plt2; sargs...)
# end
# plt2
# end
# function plot!(pkg::PlottingPackage, plt::Plot, n::Integer; kw...) # n lines, all empty (for updating plots)
# for i in 1:n
# plt.n += 1
# plot(pkg, plt, x = zeros(0), y = zeros(0), getPlotKeywordArgs(kw, i, plt)...)
# end
# end
# -------------------------
# # this is the core method... add to a plot object using kwargs, with args already converted into kwargs
# function plot!(pkg::PlottingPackage, plt::Plot; kw...)
# plot!(pl, plt; kw...)
# end
# --------------------------------------------------------------------
-64
View File
@@ -1,64 +0,0 @@
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")
Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented")
# ---------------------------------------------------------
const AVAILABLE_PACKAGES = [:qwt, :gadfly]
const INITIALIZED_PACKAGES = Set{Symbol}()
type CurrentPackage
sym::Symbol
pkg::PlottingPackage
end
# const CURRENT_PACKAGE = CurrentPackage(:qwt, QwtPackage())
const CURRENT_PACKAGE = CurrentPackage(:gadfly, GadflyPackage())
doc"""
Returns the current plotting package name. Initializes package on first call.
"""
function plotter()
currentPackageSymbol = CURRENT_PACKAGE.sym
if !(currentPackageSymbol in INITIALIZED_PACKAGES)
# initialize
print("[Plots.jl] Initializing package: $CURRENT_PACKAGE... ")
if currentPackageSymbol == :qwt
@eval import Qwt
elseif currentPackageSymbol == :gadfly
@eval import Gadfly
else
error("Unknown plotter $currentPackageSymbol. Choose from: $AVAILABLE_PACKAGES")
end
push!(INITIALIZED_PACKAGES, currentPackageSymbol)
println("done.")
end
CURRENT_PACKAGE.pkg
end
doc"""
Set the plot backend. Choose from: :qwt, :gadfly
"""
function plotter!(modname)
# set the PlottingPackage
if modname == :qwt
CURRENT_PACKAGE.pkg = QwtPackage()
elseif modname == :gadfly
CURRENT_PACKAGE.pkg = GadflyPackage()
else
error("Unknown plotter $modname. Choose from: $AVAILABLE_PACKAGES")
end
# update the symbol
CURRENT_PACKAGE.sym = modname
# return the package
CURRENT_PACKAGE.pkg
end
-67
View File
@@ -1,67 +0,0 @@
# https://github.com/tbreloff/Qwt.jl
immutable QwtPackage <: PlottingPackage end
# -------------------------------
function adjustQwtKeywords(iscreating::Bool; kw...)
d = Dict(kw)
d[:heatmap_n] = d[:nbins]
if d[:linetype] == :hexbin
d[:linetype] = :heatmap
elseif d[:linetype] == :dots
d[:linetype] = :none
d[:marker] = :hexagon
elseif !iscreating && d[:linetype] == :bar
return barHack(; kw...)
elseif !iscreating && d[:linetype] == :hist
return barHack(; histogramHack(; kw...)...)
end
d
end
function plot(pkg::QwtPackage; kw...)
kw = adjustQwtKeywords(true; kw...)
plt = Plot(Qwt.plot(zeros(0,0); kw..., show=false), pkg, 0)
plt
end
function plot!(::QwtPackage, plt::Plot; kw...)
kw = adjustQwtKeywords(false; kw...)
Qwt.oplot(plt.o; kw...)
end
function Base.display(::QwtPackage, plt::Plot)
Qwt.refresh(plt.o)
Qwt.showwidget(plt.o)
end
# -------------------------------
savepng(::QwtPackage, plt::PlottingObject, fn::String, args...) = Qwt.savepng(plt.o, fn)
# -------------------------------
# # create the underlying object (each backend will do this differently)
# o = buildSubplotObject(plts, pkg, layout)
function buildSubplotObject!(::QwtPackage, subplt::Subplot)
i = 0
rows = []
for rowcnt in subplt.layout.rowcounts
push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
i += rowcnt
end
subplt.o = Qwt.vsplitter(rows...)
end
function Base.display(::QwtPackage, subplt::Subplot)
for plt in subplt.plts
Qwt.refresh(plt.o)
end
Qwt.showwidget(subplt.o)
end
+1095
View File
File diff suppressed because it is too large Load Diff
+550
View File
@@ -0,0 +1,550 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :heatmap, :surface, :wireframe, :contour3d), get(d, :seriestype, :none))
# missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
# numeric matrix
function convertToAnyVector{T<:Number}(v::AMat{T}, d::KW)
if all3D(d)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# other matrix... vector of columns
function convertToAnyVector(m::AMat, d::KW)
Any[begin
v = vec(m[:,i])
length(v) == 1 ? v[1] : v
end for i=1:size(m,2)], nothing
end
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
# surface
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
# # vector of OHLC
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW)
if all(x -> typeof(x) <: Number, v)
# all real numbers wrap the whole vector as one item
Any[convert(Vector{Float64}, v)], nothing
else
# something else... treat each element as an item
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
# Any[vi for vi in v], nothing
end
end
convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing
function convertToAnyVector(args...)
error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))")
end
# --------------------------------------------------------------------
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
# result in that array being shared. push!, etc will add too many items to that array
compute_x(x::Void, y::Void, z) = 1:size(z,1)
compute_x(x::Void, y, z) = 1:size(y,1)
compute_x(x::Function, y, z) = map(x, y)
compute_x(x, y, z) = copy(x)
# compute_y(x::Void, y::Function, z) = error()
compute_y(x::Void, y::Void, z) = 1:size(z,2)
compute_y(x, y::Function, z) = map(y, x)
compute_y(x, y, z) = copy(y)
compute_z(x, y, z::Function) = map(z, x, y)
compute_z(x, y, z::AbstractMatrix) = Surface(z)
compute_z(x, y, z::Void) = nothing
compute_z(x, y, z) = copy(z)
nobigs(v::AVec{BigFloat}) = map(Float64, v)
nobigs(v::AVec{BigInt}) = map(Int64, v)
nobigs(v) = v
@noinline function compute_xyz(x, y, z)
x = compute_x(x,y,z)
y = compute_y(x,y,z)
z = compute_z(x,y,z)
nobigs(x), nobigs(y), nobigs(z)
end
# not allowed
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# --------------------------------------------------------------------
# # create n=max(mx,my) series arguments. the shorter list is cycled through
# # note: everything should flow through this
# function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter)
# x, y, z = map(sym -> pop!(kw, sym, nothing), (:x, :y, :z))
# if nothing == x == y == z
# return [], nothing, nothing
# end
#
# xs, xmeta = convertToAnyVector(x, kw)
# ys, ymeta = convertToAnyVector(y, kw)
# zs, zmeta = convertToAnyVector(z, kw)
#
# fr = pop!(kw, :fillrange, nothing)
# fillranges, _ = if typeof(fr) <: Number
# ([fr],nothing)
# else
# convertToAnyVector(fr, kw)
# end
#
# mx = length(xs)
# my = length(ys)
# mz = length(zs)
# ret = Any[]
# for i in 1:max(mx, my, mz)
#
# # try to set labels using ymeta
# d = copy(kw)
# if !haskey(d, :label) && ymeta != nothing
# if isa(ymeta, Symbol)
# d[:label] = string(ymeta)
# elseif isa(ymeta, AVec{Symbol})
# d[:label] = string(ymeta[mod1(i,length(ymeta))])
# end
# end
#
# # build the series arg dict
# numUncounted = pop!(d, :numUncounted, 0)
# commandIndex = i + numUncounted
# n = plt.n + i
#
# dumpdict(d, "before getSeriesArgs")
# d = getSeriesArgs(plt.backend, getattr(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n)
# dumpdict(d, "after getSeriesArgs")
#
# d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)])
# st = d[:seriestype]
#
# # for seriestype `line`, need to sort by x values
# if st == :line
# # order by x
# indices = sortperm(d[:x])
# d[:x] = d[:x][indices]
# d[:y] = d[:y][indices]
# d[:seriestype] = :path
# end
#
# # special handling for missing x in box plot... all the same category
# if st == :box && xs[mod1(i,mx)] == nothing
# d[:x] = ones(Int, length(d[:y]))
# end
#
# # map functions to vectors
# if isa(d[:marker_z], Function)
# d[:marker_z] = map(d[:marker_z], d[:x])
# end
#
# # @show fillranges
# d[:fillrange] = fillranges[mod1(i,length(fillranges))]
# if isa(d[:fillrange], Function)
# d[:fillrange] = map(d[:fillrange], d[:x])
# end
#
# # handle error bars
# for esym in (:xerror, :yerror)
# if get(d, esym, nothing) != nothing
# # we make a copy of the KW and apply an errorbar recipe
# append!(ret, apply_series_recipe(copy(d), Val{esym}))
# end
# end
#
# # handle ribbons
# if get(d, :ribbon, nothing) != nothing
# rib = d[:ribbon]
# d[:fillrange] = (d[:y] - rib, d[:y] + rib)
# end
#
# # handle quiver plots
# # either a series of velocity vectors are passed in (`:quiver` keyword),
# # or we just add arrows to the path
#
# # if st == :quiver
# # d[:seriestype] = st = :path
# # d[:linewidth] = 0
# # end
# if get(d, :quiver, nothing) != nothing
# append!(ret, apply_series_recipe(copy(d), Val{:quiver}))
# elseif st == :quiver
# d[:seriestype] = st = :path
# d[:arrow] = arrow()
# end
#
# # now that we've processed a given series... optionally split into
# # multiple dicts through a recipe (for example, a box plot is split into component
# # parts... polygons, lines, and scatters)
# # note: we pass in a Val type (i.e. Val{:box}) so that we can dispatch on the seriestype
# kwlist = apply_series_recipe(d, Val{st})
# append!(ret, kwlist)
#
# # # add it to our series list
# # push!(ret, d)
# end
#
# ret, xmeta, ymeta
# end
#
#
# # --------------------------------------------------------------------
# # process_inputs
# # --------------------------------------------------------------------
#
# # These methods take a plot and the keyword arguments, and processes the input
# # arguments (x/y/z, group, etc), populating the KW dict with appropriate values.
#
# # --------------------------------------------------------------------
# # 0 arguments
# # --------------------------------------------------------------------
#
# # don't do anything
# function process_inputs(plt::AbstractPlot, d::KW)
# end
#
# # --------------------------------------------------------------------
# # 1 argument
# # --------------------------------------------------------------------
#
# function process_inputs(plt::AbstractPlot, d::KW, n::Integer)
# # d[:x], d[:y], d[:z] = zeros(0), zeros(0), zeros(0)
# d[:x] = d[:y] = d[:z] = n
# end
#
# # no special handling... assume x and z are nothing
# function process_inputs(plt::AbstractPlot, d::KW, y)
# d[:y] = y
# end
#
# # matrix... is it z or y?
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, mat::AMat{T})
# if all3D(d)
# n,m = size(mat)
# d[:x], d[:y], d[:z] = 1:n, 1:m, mat
# else
# d[:y] = mat
# end
# end
#
# # images - grays
# function process_inputs{T<:Gray}(plt::AbstractPlot, d::KW, mat::AMat{T})
# d[:seriestype] = :image
# n,m = size(mat)
# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat)
# # handle images... when not supported natively, do a hack to use heatmap machinery
# if !nativeImagesSupported()
# d[:seriestype] = :heatmap
# d[:yflip] = true
# d[:z] = Surface(convert(Matrix{Float64}, mat.surf))
# d[:fillcolor] = ColorGradient([:black, :white])
# end
# end
#
# # images - colors
# function process_inputs{T<:Colorant}(plt::AbstractPlot, d::KW, mat::AMat{T})
# d[:seriestype] = :image
# n,m = size(mat)
# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat)
# # handle images... when not supported natively, do a hack to use heatmap machinery
# if !nativeImagesSupported()
# d[:yflip] = true
# imageHack(d)
# end
# end
#
#
# # plotting arbitrary shapes/polygons
# function process_inputs(plt::AbstractPlot, d::KW, shape::Shape)
# d[:x], d[:y] = shape_coords(shape)
# d[:seriestype] = :shape
# end
# function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape})
# d[:x], d[:y] = shape_coords(shapes)
# d[:seriestype] = :shape
# end
# function process_inputs(plt::AbstractPlot, d::KW, shapes::AMat{Shape})
# x, y = [], []
# for j in 1:size(shapes, 2)
# tmpx, tmpy = shape_coords(vec(shapes[:,j]))
# push!(x, tmpx)
# push!(y, tmpy)
# end
# d[:x], d[:y] = x, y
# d[:seriestype] = :shape
# end
#
#
# # function without range... use the current range of the x-axis
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs)
# process_inputs(plt, d, f, xmin(plt), xmax(plt))
# end
#
# # --------------------------------------------------------------------
# # 2 arguments
# # --------------------------------------------------------------------
#
# function process_inputs(plt::AbstractPlot, d::KW, x, y)
# d[:x], d[:y] = x, y
# end
#
# # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in)
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, x)
# @assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
# process_inputs(plt, d, x, f)
# end
#
# # --------------------------------------------------------------------
# # 3 arguments
# # --------------------------------------------------------------------
#
# # no special handling... just pass them through
# function process_inputs(plt::AbstractPlot, d::KW, x, y, z)
# d[:x], d[:y], d[:z] = x, y, z
# end
#
# # 3d line or scatter
# function process_inputs(plt::AbstractPlot, d::KW, x::AVec, y::AVec, zvec::AVec)
# # default to path3d if we haven't set a 3d seriestype
# st = get(d, :seriestype, :none)
# if st == :scatter
# d[:seriestype] = :scatter3d
# elseif !(st in _3dTypes)
# d[:seriestype] = :path3d
# end
# d[:x], d[:y], d[:z] = x, y, zvec
# end
#
# # surface-like... function
# function process_inputs{TX,TY}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zf::Function)
# x = TX <: Number ? sort(x) : x
# y = TY <: Number ? sort(y) : y
# # x, y = sort(x), sort(y)
# d[:z] = Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
# d[:x], d[:y] = x, y
# end
#
# # surface-like... matrix grid
# function process_inputs{TX,TY,TZ}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zmat::AMat{TZ})
# # @assert size(zmat) == (length(x), length(y))
# # if TX <: Number && !issorted(x)
# # idx = sortperm(x)
# # x, zmat = x[idx], zmat[idx, :]
# # end
# # if TY <: Number && !issorted(y)
# # idx = sortperm(y)
# # y, zmat = y[idx], zmat[:, idx]
# # end
# d[:x], d[:y], d[:z] = x, y, Surface{Matrix{TZ}}(zmat)
# if !like_surface(get(d, :seriestype, :none))
# d[:seriestype] = :contour
# end
# end
#
# # surfaces-like... general x, y grid
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, x::AMat{T}, y::AMat{T}, zmat::AMat{T})
# @assert size(zmat) == size(x) == size(y)
# # d[:x], d[:y], d[:z] = Any[x], Any[y], Surface{Matrix{Float64}}(zmat)
# d[:x], d[:y], d[:z] = map(Surface{Matrix{Float64}}, (x, y, zmat))
# if !like_surface(get(d, :seriestype, :none))
# d[:seriestype] = :contour
# end
# end
#
#
# # --------------------------------------------------------------------
# # Parametric functions
# # --------------------------------------------------------------------
#
# # special handling... xmin/xmax with function(s)
# function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, xmin::Number, xmax::Number)
# width = get(plt.attr, :size, (100,))[1]
# x = linspace(xmin, xmax, width)
# process_inputs(plt, d, x, f)
# end
#
# # special handling... xmin/xmax with parametric function(s)
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
# process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, linspace(umin, umax, numPoints))
#
# # special handling... 3D parametric function(s)
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
# process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
# process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, fz, linspace(umin, umax, numPoints))
#
#
# # --------------------------------------------------------------------
# # Lists of tuples and FixedSizeArrays
# # --------------------------------------------------------------------
#
# # if we get an unhandled tuple, just splat it in
# function process_inputs(plt::AbstractPlot, d::KW, tup::Tuple)
# process_inputs(plt, d, tup...)
# end
#
# # (x,y) tuples
# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::AVec{Tuple{R1,R2}})
# process_inputs(plt, d, unzip(xy)...)
# end
# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2})
# process_inputs(plt, d, [xy[1]], [xy[2]])
# end
#
# # (x,y,z) tuples
# function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{Tuple{R1,R2,R3}})
# process_inputs(plt, d, unzip(xyz)...)
# end
# function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::Tuple{R1,R2,R3})
# process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
# end
#
# # 2D FixedSizeArrays
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}})
# process_inputs(plt, d, unzip(xy)...)
# end
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T})
# process_inputs(plt, d, [xy[1]], [xy[2]])
# end
#
# # 3D FixedSizeArrays
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}})
# process_inputs(plt, d, unzip(xyz)...)
# end
# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::FixedSizeArrays.Vec{3,T})
# process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
# end
#
# # --------------------------------------------------------------------
# # handle grouping
# # --------------------------------------------------------------------
#
# # function process_inputs(plt::AbstractPlot, d::KW, groupby::GroupBy, args...)
# # ret = Any[]
# # error("unfinished after series reorg")
# # for (i,glab) in enumerate(groupby.groupLabels)
# # # TODO: don't automatically overwrite labels
# # kwlist, xmeta, ymeta = process_inputs(plt, d, args...,
# # idxfilter = groupby.groupIds[i],
# # label = string(glab),
# # numUncounted = length(ret)) # we count the idx from plt.n + numUncounted + i
# # append!(ret, kwlist)
# # end
# # ret, nothing, nothing # TODO: handle passing meta through
# # end
# --------------------------------------------------------------------
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
# --------------------------------------------------------------------
# function setup_dataframes()
# @require DataFrames begin
# # @eval begin
# # import DataFrames
#
# DFS = Union{Symbol, AbstractArray{Symbol}}
#
# function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, dfs::DFS)
# if isa(dfs, Symbol)
# get!(d, Symbol(letter * "label"), string(dfs))
# collect(df[dfs])
# else
# get!(d, :label, reshape(dfs, 1, length(dfs)))
# Any[collect(df[s]) for s in dfs]
# end
# end
#
# function handle_group(df::DataFrames.AbstractDataFrame, d::KW)
# if haskey(d, :group)
# g = d[:group]
# if isa(g, Symbol)
# d[:group] = collect(df[g])
# end
# end
# end
#
# @recipe function plot(df::DataFrames.AbstractDataFrame, sy::DFS)
# handle_group(df, d)
# handle_dfs(df, d, "y", sy)
# end
#
# @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS)
# handle_group(df, d)
# x = handle_dfs(df, d, "x", sx)
# y = handle_dfs(df, d, "y", sy)
# x, y
# end
#
# @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS, sz::DFS)
# handle_group(df, d)
# x = handle_dfs(df, d, "x", sx)
# y = handle_dfs(df, d, "y", sy)
# z = handle_dfs(df, d, "z", sz)
# x, y, z
# end
#
# # get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg]
# # get_data(df::DataFrames.AbstractDataFrame, arg) = arg
# #
# # function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...)
# # # d[:dataframe] = df
# # process_inputs(plt, d, map(arg -> get_data(df, arg), args)...)
# # end
# #
# # # expecting the column name of a dataframe that was passed in... anything else should error
# # function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
# # if haskey(df, s)
# # return extractGroupArgs(df[s])
# # else
# # error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
# # end
# # end
#
# # function getDataFrameFromKW(d::KW)
# # get(d, :dataframe) do
# # error("Missing dataframe argument!")
# # end
# # end
#
# # # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
# # convertToAnyVector(s::Symbol, d::KW) = Any[getDataFrameFromKW(d)[s]], s
# # convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
#
# end
# end
+392
View File
@@ -0,0 +1,392 @@
# we are going to build recipes to do the processing and splitting of the args
function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
pkg = plt.backend
globalIndex = d[:series_plotindex]
# add default values to our dictionary, being careful not to delete what we just added!
for (k,v) in _series_defaults
slice_arg!(d, d, k, v, commandIndex, remove_pair = false)
end
# this is how many series belong to this subplot
plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list)
if get(d, :primary, true)
plotIndex += 1
end
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
# update color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp, plotIndex)
# update colors
for csym in (:linecolor, :markercolor, :fillcolor)
d[csym] = if d[csym] == :match
if has_black_border_for_default(d[:seriestype]) && csym == :linecolor
:black
else
d[:seriescolor]
end
else
getSeriesRGBColor(d[csym], sp, plotIndex)
end
end
# update markerstrokecolor
c = d[:markerstrokecolor]
c = if c == :match
sp[:foreground_color_subplot]
else
getSeriesRGBColor(c, sp, plotIndex)
end
d[:markerstrokecolor] = c
# update alphas
for asym in (:linealpha, :markeralpha, :markerstrokealpha, :fillalpha)
if d[asym] == nothing
d[asym] = d[:seriesalpha]
end
end
# scatter plots don't have a line, but must have a shape
if d[:seriestype] in (:scatter, :scatter3d)
d[:linewidth] = 0
if d[:markershape] == :none
d[:markershape] = :ellipse
end
end
# set label
label = d[:label]
label = (label == "AUTO" ? "y$globalIndex" : label)
d[:label] = label
_replace_linewidth(d)
d
end
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# instead of process_inputs:
# ensure we dispatch to the slicer
immutable SliceIt end
# the catch-all recipes
@recipe function f(::Type{SliceIt}, x, y, z)
# @show "HERE", typeof((x,y,z))
xs, _ = convertToAnyVector(x, d)
ys, _ = convertToAnyVector(y, d)
zs, _ = convertToAnyVector(z, d)
fr = pop!(d, :fillrange, nothing)
fillranges, _ = if typeof(fr) <: Number
([fr],nothing)
else
convertToAnyVector(fr, d)
end
mf = length(fillranges)
# @show zs
mx = length(xs)
my = length(ys)
mz = length(zs)
# ret = Any[]
for i in 1:max(mx, my, mz)
# add a new series
di = copy(d)
xi, yi, zi = xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]
# @show i, typeof((xi, yi, zi))
di[:x], di[:y], di[:z] = compute_xyz(xi, yi, zi)
# @show i, typeof((di[:x], di[:y], di[:z]))
# handle fillrange
fr = fillranges[mod1(i,mf)]
di[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr
# @show i, di[:x], di[:y], di[:z]
push!(series_list, RecipeData(di, ()))
end
nothing # don't add a series for the main block
end
# this is the default "type recipe"... just pass the object through
@recipe f{T}(::Type{T}, v::T) = v
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
# handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z)
did_replace = false
newx = _apply_type_recipe(d, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
y === newy || (did_replace = true)
newz = _apply_type_recipe(d, z)
z === newz || (did_replace = true)
if did_replace
newx, newy, newz
else
SliceIt, x, y, z
end
end
@recipe function f(x, y)
did_replace = false
newx = _apply_type_recipe(d, x)
x === newx || (did_replace = true)
newy = _apply_type_recipe(d, y)
y === newy || (did_replace = true)
if did_replace
newx, newy
else
SliceIt, x, y, nothing
end
end
@recipe function f(y)
newy = _apply_type_recipe(d, y)
if y !== newy
newy
else
SliceIt, nothing, y, nothing
end
end
# @recipe f(x, y, z) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), apply_recipe(typeof(z), z)
# @recipe f(x, y) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), nothing
# @recipe f(y) = SliceIt, nothing, apply_recipe(typeof(y), y), nothing
# # pass these through to the slicer
# @recipe f(x, y, z) = SliceIt, x, y, z
# @recipe f(x, y) = SliceIt, x, y, nothing
# @recipe f(y) = SliceIt, nothing, y, nothing
# # --------------------------------------------------------------------
# # 1 argument
# # --------------------------------------------------------------------
@recipe f(n::Integer) = n, n, n
# return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f{T<:Number}(mat::AMat{T})
if all3D(d)
n,m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
SliceIt, nothing, mat, nothing
end
end
# # images - grays
@recipe function f{T<:Gray}(mat::AMat{T})
if nativeImagesSupported()
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
end
end
# # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T})
if nativeImagesSupported()
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
z, d[:fillcolor] = replace_image_with_heatmap(mat)
SliceIt, 1:m, 1:n, Surface(z)
end
end
#
# # plotting arbitrary shapes/polygons
@recipe function f(shape::Shape)
seriestype := :shape
shape_coords(shape)
end
@recipe function f(shapes::AVec{Shape})
seriestype := :shape
shape_coords(shapes)
end
@recipe function f(shapes::AMat{Shape})
for j in 1:size(shapes,2)
# create one series for each column
# @series shape_coords(vec(shapes[:,j]))
di = copy(d)
push!(series_list, RecipeData(di, shape_coords(vec(shapes[:,j]))))
end
nothing # don't create a series for the main block
end
#
#
# # function without range... use the current range of the x-axis
@recipe function f(f::FuncOrFuncs)
plt = d[:plot_object]
f, xmin(plt), xmax(plt)
end
#
# # --------------------------------------------------------------------
# # 2 arguments
# # --------------------------------------------------------------------
#
#
# # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in)
@recipe function f(f::FuncOrFuncs, x)
@assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
x, f
end
#
# # --------------------------------------------------------------------
# # 3 arguments
# # --------------------------------------------------------------------
#
#
# # 3d line or scatter
@recipe function f(x::AVec, y::AVec, z::AVec)
st = get(d, :seriestype, :none)
if st == :scatter
d[:seriestype] = :scatter3d
elseif !is3d(st)
d[:seriestype] = :path3d
end
SliceIt, x, y, z
end
@recipe function f(x::AMat, y::AMat, z::AMat)
st = get(d, :seriestype, :none)
if size(x) == size(y) == size(z)
if !is3d(st)
seriestype := :path3d
end
end
SliceIt, x, y, z
end
#
# # surface-like... function
@recipe function f(x::AVec, y::AVec, zf::Function)
# x = X <: Number ? sort(x) : x
# y = Y <: Number ? sort(y) : y
SliceIt, x, y, Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
end
#
# # surface-like... matrix grid
@recipe function f(x::AVec, y::AVec, z::AMat)
if !like_surface(get(d, :seriestype, :none))
d[:seriestype] = :contour
end
SliceIt, x, y, Surface(z)
end
#
#
# # --------------------------------------------------------------------
# # Parametric functions
# # --------------------------------------------------------------------
#
# # special handling... xmin/xmax with parametric function(s)
@recipe f(f::FuncOrFuncs, xmin::Number, xmax::Number) = linspace(xmin, xmax, 100), f
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f(fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n)
#
# # special handling... 3D parametric function(s)
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec)
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPointsn = 200)
fx, fy, fz, linspace(umin, umax, numPoints)
end
#
#
# # --------------------------------------------------------------------
# # Lists of tuples and FixedSizeArrays
# # --------------------------------------------------------------------
#
# # if we get an unhandled tuple, just splat it in
@recipe f(tup::Tuple) = tup
#
# # (x,y) tuples
@recipe f{R1<:Number,R2<:Number}(xy::AVec{Tuple{R1,R2}}) = unzip(xy)
@recipe f{R1<:Number,R2<:Number}(xy::Tuple{R1,R2}) = [xy[1]], [xy[2]]
#
# # (x,y,z) tuples
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::AVec{Tuple{R1,R2,R3}}) = unzip(xyz)
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(d,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
#
# # 2D FixedSizeArrays
@recipe f{T<:Number}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = unzip(xy)
@recipe f{T<:Number}(xy::FixedSizeArrays.Vec{2,T}) = [xy[1]], [xy[2]]
#
# # 3D FixedSizeArrays
@recipe f{T<:Number}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = unzip(xyz)
@recipe f{T<:Number}(xyz::FixedSizeArrays.Vec{3,T}) = [xyz[1]], [xyz[2]], [xyz[3]]
#
# # --------------------------------------------------------------------
# # handle grouping
# # --------------------------------------------------------------------
# @recipe function f(groupby::GroupBy, args...)
# for (i,glab) in enumerate(groupby.groupLabels)
# # create a new series, with the label of the group, and an idxfilter (to be applied in slice_and_dice)
# # TODO: use @series instead
# @show i, glab, groupby.groupIds[i]
# di = copy(d)
# get!(di, :label, string(glab))
# get!(di, :idxfilter, groupby.groupIds[i])
# push!(series_list, RecipeData(di, args))
# end
# nothing
# end
# split the group into 1 series per group, and set the label and idxfilter for each
@recipe function f(groupby::GroupBy, args...)
for (i,glab) in enumerate(groupby.groupLabels)
@series begin
label --> string(glab)
idxfilter --> groupby.groupIds[i]
args
end
end
end
-124
View File
@@ -1,124 +0,0 @@
# create a layout directly
SubplotLayout(rowcounts::AbstractVector{Int}) = SubplotLayout(sum(rowcounts), rowcounts)
# create a layout given counts... nr/nc == -1 implies we figure out a good number automatically
function SubplotLayout(numplts::Int, nr::Int, nc::Int)
# figure out how many rows/columns we need
if nr == -1
if nc == -1
nr = round(Int, sqrt(numplts))
nc = ceil(Int, numplts / nr)
else
nr = ceil(Int, numplts / nc)
end
else
nc = ceil(Int, numplts / nr)
end
# create the rowcounts vector
i = 0
rowcounts = Int[]
for r in 1:nr
cnt = min(nc, numplts - i)
push!(rowcounts, cnt)
i += cnt
end
SubplotLayout(numplts, rowcounts)
end
Base.length(layout::SubplotLayout) = layout.numplts
# ------------------------------------------------------------
Base.string(subplt::Subplot) = "Subplot{$(subplt.plotter) p=$(subplt.p) n=$(subplt.n)}"
Base.print(io::IO, subplt::Subplot) = print(io, string(subplt))
Base.show(io::IO, subplt::Subplot) = print(io, string(subplt))
getplot(subplt::Subplot) = subplt.plts[mod1(subplt.n, subplt.p)]
# ------------------------------------------------------------
doc"""
Create a series of plots:
```
y = rand(100,3)
subplot(y; n = 3) # create an automatic grid, and let it figure out the nr/nc... will put plots 1 and 2 on the first row, and plot 3 by itself on the 2nd row
subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows to 1 (so there are n columns)
subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns to 1 (so there are n rows)
subplot(y; layout = [1, 2]) # explicit layout by row... plot #1 goes by itself in the first row, plots 2 and 3 split the 2nd row (note the n kw is unnecessary)
```
"""
function subplot(args...; kw...)
d = Dict(kw)
# figure out the layout
if haskey(d, :layout)
layout = SubplotLayout(d[:layout])
else
if !haskey(d, :n)
error("You must specify either layout or n when creating a subplot: ", d)
end
layout = SubplotLayout(d[:n], get(d, :nr, -1), get(d, :nc, -1))
end
# initialize the individual plots
pkg = plotter()
kw0 = getPlotKeywordArgs(kw, 1, 0)
plts = Plot[plot(pkg; kw0..., show=false) for i in 1:length(layout)]
# create the object and do the plotting
subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout)
subplot!(subplt, args...; kw...)
subplt
end
doc"""
Adds to a subplot.
"""
# current subplot
function subplot!(args...; kw...)
subplot!(currentPlot(), args...; kw...)
end
# not allowed:
function subplot!(plt::Plot, args...; kw...)
error("Can't call subplot! on a Plot!")
end
# # this adds to a specific subplot... most plot commands will flow through here
function subplot!(subplt::Subplot, args...; kw...)
kwList = createKWargsList(subplt, args...; kw...)
for (i,d) in enumerate(kwList)
subplt.n += 1
plt = getplot(subplt) # get the Plot object where this series will be drawn
plot!(plt; d...)
end
# create the underlying object (each backend will do this differently)
buildSubplotObject!(subplt.plotter, subplt)
# set this to be current
currentPlot!(subplt)
# do we want to show it?
d = Dict(kw)
if haskey(d, :show) && d[:show]
draw(subplt)
end
subplt
end
+46
View File
@@ -0,0 +1,46 @@
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout())
Subplot{T}(
parent,
(20mm, 5mm, 2mm, 10mm),
defaultbox,
defaultbox,
KW(),
nothing,
nothing
)
end
plotarea(sp::Subplot) = sp.plotarea
plotarea!(sp::Subplot, bbox::BoundingBox) = (sp.plotarea = bbox)
Base.size(sp::Subplot) = (1,1)
Base.length(sp::Subplot) = 1
Base.getindex(sp::Subplot, r::Int, c::Int) = sp
leftpad(sp::Subplot) = sp.minpad[1]
toppad(sp::Subplot) = sp.minpad[2]
rightpad(sp::Subplot) = sp.minpad[3]
bottompad(sp::Subplot) = sp.minpad[4]
get_subplot(plt::Plot, sp::Subplot) = sp
get_subplot(plt::Plot, i::Integer) = plt.subplots[i]
get_subplot(plt::Plot, k) = plt.spmap[k]
get_subplot(series::Series) = series.d[:subplot]
get_subplot_index(plt::Plot, idx::Integer) = idx
get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots)
series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
function should_add_to_legend(series::Series)
!(series.d[:label] == "" || series.d[:seriestype] in (
:hexbin,:histogram2d,:hline,:vline,
:contour,:contour3d,:surface,:wireframe,
:heatmap,:path3d,:scatter3d, :pie, :image
))
end
# ----------------------------------------------------------------------
+65
View File
@@ -0,0 +1,65 @@
const _invisible = RGBA(0,0,0,0)
const _themes = KW(
:default => KW(
:bg => :white,
:bglegend => :match,
:bginside => :match,
:bgoutside => :match,
:fg => :auto,
:fglegend => :match,
:fggrid => :match,
:fgaxis => :match,
:fgtext => :match,
:fgborder => :match,
:fgguide => :match,
)
)
function add_theme(sym::Symbol, theme::KW)
_themes[sym] = theme
end
# add a new theme, using an existing theme as the base
function add_theme(sym::Symbol;
base = :default, # start with this theme
bg = _themes[base][:bg],
bglegend = _themes[base][:bglegend],
bginside = _themes[base][:bginside],
bgoutside = _themes[base][:bgoutside],
fg = _themes[base][:fg],
fglegend = _themes[base][:fglegend],
fggrid = _themes[base][:fggrid],
fgaxis = _themes[base][:fgaxis],
fgtext = _themes[base][:fgtext],
fgborder = _themes[base][:fgborder],
fgguide = _themes[base][:fgguide],
kw...)
_themes[sym] = merge(KW(
:bg => bg,
:bglegend => bglegend,
:bginside => bginside,
:bgoutside => bgoutside,
:fg => fg,
:fglegend => fglegend,
:fggrid => fggrid,
:fgaxis => fgaxis,
:fgtext => fgtext,
:fgborder => fgborder,
:fgguide => fgguide,
), KW(kw))
end
add_theme(:ggplot2,
bglegend = _invisible,
bginside = :lightgray,
fg = :white,
fglegend = _invisible,
fgtext = :gray,
fgguide = :black
)
function set_theme(sym::Symbol)
default(; _themes[sym]...)
end
+81 -17
View File
@@ -1,28 +1,92 @@
# TODO: I declare lots of types here because of the lacking ability to do forward declarations in current Julia
# I should move these to the relevant files when something like "extern" is implemented
typealias AVec AbstractVector
typealias AMat AbstractMatrix
typealias KW Dict{Symbol,Any}
abstract PlottingObject
abstract PlottingPackage
immutable PlotsDisplay <: Display end
type Plot <: PlottingObject
o # the underlying object
plotter::PlottingPackage
n::Int # number of series
abstract AbstractBackend
abstract AbstractPlot{T<:AbstractBackend}
abstract AbstractLayout
# -----------------------------------------------------------
immutable InputWrapper{T}
obj::T
end
wrap{T}(obj::T) = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false
# -----------------------------------------------------------
# a single subplot
type Subplot{T<:AbstractBackend} <: AbstractLayout
parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox # the canvas area which is available to this subplot
plotarea::BoundingBox # the part where the data goes
attr::KW # args specific to this subplot
o # can store backend-specific data... like a pyplot ax
plt # the enclosing Plot object (can't give it a type because of no forward declarations)
end
# -----------------------------------------------------------
type SubplotLayout
numplts::Int
rowcounts::AbstractVector{Int}
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis
sp::Subplot
d::KW
end
type Extrema
emin::Float64
emax::Float64
end
Extrema() = Extrema(Inf, -Inf)
type Subplot <: PlottingObject
o # the underlying object
plts::Vector{Plot} # the individual plots
plotter::PlottingPackage
p::Int # number of plots
n::Int # number of series
layout::SubplotLayout
end
# -----------------------------------------------------------
typealias SubplotMap Dict{Any, Subplot}
# -----------------------------------------------------------
type Series
d::KW
end
attr(series::Series, k::Symbol) = series.d[k]
attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
# -----------------------------------------------------------
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type
n::Int # number of series
attr::KW # arguments for the whole plot
user_attr::KW # raw arg inputs (after aliases). these are used as the input dict in `_plot!`
series_list::Vector{Series} # arguments for each series
o # the backend's plot object
subplots::Vector{Subplot}
spmap::SubplotMap # provide any label as a map to a subplot
layout::AbstractLayout
init::Bool
end
function Plot()
Plot(backend(), 0, KW(), KW(), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout(), false)
end
# TODO: make a decision... should plt[1] return the first subplot or the first series??
# Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
Base.getindex(plt::Plot, s::Symbol) = plt.spmap[s]
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
attr(plt::Plot, k::Symbol) = plt.attr[k]
attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
# -----------------------------------------------------------------------
+590 -13
View File
@@ -1,7 +1,7 @@
calcMidpoints(edges::AbstractVector) = Float64[0.5 * (edges[i] + edges[i+1]) for i in 1:length(edges)-1]
doc"Make histogram-like bins of data"
"Make histogram-like bins of data"
function binData(data, nbins)
lo, hi = extrema(data)
edges = collect(linspace(lo, hi, nbins+1))
@@ -14,31 +14,31 @@ function binData(data, nbins)
edges, midpoints, buckets, counts
end
doc"""
"""
A hacky replacement for a histogram when the backend doesn't support histograms directly.
Convert it into a bar chart with the appropriate x/y values.
"""
function histogramHack(; kw...)
d = Dict(kw)
d = KW(kw)
# we assume that the y kwarg is set with the data to be binned, and nbins is also defined
edges, midpoints, buckets, counts = binData(d[:y], d[:nbins])
edges, midpoints, buckets, counts = binData(d[:y], d[:bins])
d[:x] = midpoints
d[:y] = float(counts)
d[:linetype] = :bar
d[:fillto] = d[:fillto] == nothing ? 0.0 : d[:fillto]
d[:seriestype] = :bar
d[:fillrange] = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
d
end
doc"""
"""
A hacky replacement for a bar graph when the backend doesn't support bars directly.
Convert it into a line chart with fillto set.
Convert it into a line chart with fillrange set.
"""
function barHack(; kw...)
d = Dict(kw)
d = KW(kw)
midpoints = d[:x]
heights = d[:y]
fillto = d[:fillto] == nothing ? 0.0 : d[:fillto]
fillrange = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
# estimate the edges
dists = diff(midpoints) * 0.5
@@ -59,13 +59,590 @@ function barHack(; kw...)
for i in 1:length(heights)
e1, e2 = edges[i:i+1]
append!(x, [e1, e1, e2, e2])
append!(y, [fillto, heights[i], heights[i], fillto])
append!(y, [fillrange, heights[i], heights[i], fillrange])
end
d[:x] = x
d[:y] = y
d[:linetype] = :line
d[:fillto] = fillto
d[:seriestype] = :path
d[:fillrange] = fillrange
d
end
"""
A hacky replacement for a sticks graph when the backend doesn't support sticks directly.
Convert it into a line chart that traces the sticks, and a scatter that sets markers at the points.
"""
function sticksHack(; kw...)
dLine = KW(kw)
dScatter = copy(dLine)
# these are the line vertices
x = Float64[]
y = Float64[]
fillrange = dLine[:fillrange] == nothing ? 0.0 : dLine[:fillrange]
# calculate the vertices
yScatter = dScatter[:y]
for (i,xi) in enumerate(dScatter[:x])
yi = yScatter[i]
for j in 1:3 push!(x, xi) end
append!(y, [fillrange, yScatter[i], fillrange])
end
# change the line args
dLine[:x] = x
dLine[:y] = y
dLine[:seriestype] = :path
dLine[:markershape] = :none
dLine[:fillrange] = nothing
# change the scatter args
dScatter[:seriestype] = :none
dLine, dScatter
end
function regressionXY(x, y)
# regress
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
# make a line segment
regx = [minimum(x), maximum(x)]
regy = β * regx + α
regx, regy
end
function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
@show T, size(z)
n, m = size(z)
# idx = 0
colors = ColorGradient(vec(z))
newz = reshape(linspace(0, 1, n*m), n, m)
newz, colors
# newz = zeros(n, m)
# for i=1:n, j=1:m
# push!(colors, T(z[i,j]...))
# newz[i,j] = idx / (n*m-1)
# idx += 1
# end
# newz, ColorGradient(colors)
end
function imageHack(d::KW)
:heatmap in supportedTypes() || error("Neither :image or :heatmap are supported!")
d[:seriestype] = :heatmap
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
end
# ---------------------------------------------------------------
# ------------------------------------------------------------------------------------
nop() = nothing
notimpl() = error("This has not been implemented yet")
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
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
"duplicate a single value, or pass the 2-tuple through"
maketuple(x::Real) = (x,x)
maketuple{T,S}(x::@compat(Tuple{T,S})) = x
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs]
unzip{X,Y}(xy::AVec{Tuple{X,Y}}) = [t[1] for t in xy], [t[2] for t in xy]
unzip{X,Y,Z}(xyz::AVec{Tuple{X,Y,Z}}) = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip{X,Y,U,V}(xyuv::AVec{Tuple{X,Y,U,V}}) = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip{T}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = T[t[1] for t in xy], T[t[2] for t in xy]
unzip{T}(xy::FixedSizeArrays.Vec{2,T}) = T[xy[1]], T[xy[2]]
unzip{T}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip{T}(xyz::FixedSizeArrays.Vec{3,T}) = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip{T}(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
try
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
lims[2] = max(lims[2], e2)
# catch err
# warn(err)
end
nothing
end
# if the type exists in a list, replace the first occurence. otherwise add it to the end
function addOrReplace(v::AbstractVector, t::DataType, args...; kw...)
for (i,vi) in enumerate(v)
if isa(vi, t)
v[i] = t(args...; kw...)
return
end
end
push!(v, t(args...; kw...))
return
end
function replaceType(vec, val)
filter!(x -> !isa(x, typeof(val)), vec)
push!(vec, val)
end
function replaceAlias!(d::KW, k::Symbol, aliases::KW)
if haskey(aliases, k)
d[aliases[k]] = pop!(d, k)
end
end
function replaceAliases!(d::KW, aliases::KW)
ks = collect(keys(d))
for k in ks
replaceAlias!(d, k, aliases)
# if haskey(aliases, k)
# d[aliases[k]] = d[k]
# delete!(d, k)
# end
end
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)))
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec)
vmin, vmax = extrema(v)
extra = 0.5 * (vmax-vmin) / (length(v)-1)
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
end
function fakedata(sz...)
y = zeros(sz...)
for r in 2:size(y,1)
y[r,:] = 0.95 * vec(y[r-1,:]) + randn(size(y,2))
end
y
end
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false: true
catch
false
end
end
istuple(::Tuple) = true
istuple(::Any) = false
isvector(::AVec) = true
isvector(::Any) = false
ismatrix(::AMat) = true
ismatrix(::Any) = false
isscalar(::Real) = true
isscalar(::Any) = false
isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
# 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
limsType{T<:Real,S<:Real}(lims::@compat(Tuple{T,S})) = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
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)))
nanpush!(a::AbstractVector, b) = (push!(a, NaN); push!(a, b))
nanappend!(a::AbstractVector, b) = (push!(a, NaN); append!(a, b))
# given an array of discrete values, turn it into an array of indices of the unique values
# returns the array of indices (znew) and a vector of unique values (vals)
function indices_and_unique_values(z::AbstractArray)
vals = sort(unique(z))
vmap = Dict([(v,i) for (i,v) in enumerate(vals)])
newz = map(zi -> vmap[zi], z)
newz, vals
end
# this is a helper function to determine whether we need to transpose a surface matrix.
# it depends on whether the backend matches rows to x (transpose_on_match == true) or vice versa
# for example: PyPlot sends rows to y, so transpose_on_match should be true
function transpose_z(d::KW, z, transpose_on_match::Bool = true)
if d[:match_dimensions] == transpose_on_match
z'
else
z
end
end
function ok(x::Number, y::Number, z::Number = 0)
isfinite(x) && isfinite(y) && isfinite(z)
end
ok(tup::Tuple) = ok(tup...)
# compute one side of a fill range from a ribbon
function make_fillrange_side(y, rib)
frs = zeros(length(y))
for (i, (yi, ri)) in enumerate(zip(y, cycle(rib)))
frs[i] = yi + ri
end
frs
end
# turn a ribbon into a fillrange
function make_fillrange_from_ribbon(kw::KW)
y, rib = kw[:y], kw[:ribbon]
rib = wraptuple(rib)
rib1, rib2 = -first(rib), last(rib)
kw[:ribbon] = nothing
kw[:fillrange] = make_fillrange_side(y, rib1), make_fillrange_side(y, rib2)
end
# ---------------------------------------------------------------
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=:histogram) do
plot(rand(10))
plot(rand(10))
end
```
"""
function with(f::Function, args...; kw...)
newdefs = KW(kw)
if :canvas in args
newdefs[:xticks] = nothing
newdefs[:yticks] = nothing
newdefs[:grid] = false
newdefs[:legend] = false
end
# dict to store old and new keyword args for anything that changes
olddefs = KW()
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 = :seriestype
# 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
# ---------------------------------------------------------------
# ---------------------------------------------------------------
type DebugMode
on::Bool
end
const _debugMode = DebugMode(false)
function debugplots(on = true)
_debugMode.on = on
end
debugshow(x) = show(x)
debugshow(x::AbstractArray) = print(summary(x))
function dumpdict(d::KW, prefix = "", alwaysshow = false)
_debugMode.on || alwaysshow || return
println()
if prefix != ""
println(prefix, ":")
end
for k in sort(collect(keys(d)))
@printf("%14s: ", k)
debugshow(d[k])
println()
end
println()
end
DD(d::KW, prefix = "") = dumpdict(d, prefix, true)
function dumpcallstack()
error() # well... you wanted the stacktrace, didn't you?!?
end
# ---------------------------------------------------------------
# ---------------------------------------------------------------
# used in updating an existing series
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + maximum(v))
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v)
# -------------------------------------------------------
# NOTE: backends should implement the following methods to get/set the x/y/z data objects
tovec(v::AbstractVector) = v
tovec(v::Void) = zeros(0)
function getxy(plt::Plot, i::Integer)
d = plt.series_list[i].d
tovec(d[:x]), tovec(d[:y])
end
function getxyz(plt::Plot, i::Integer)
d = plt.series_list[i].d
tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
end
function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer)
series = plt.series_list[i]
series.d[:x], series.d[:y] = xy
sp = series.d[:subplot]
expand_extrema!(sp.attr[:xaxis], xy[1])
expand_extrema!(sp.attr[:yaxis], xy[2])
_series_updated(plt, series)
end
function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
series = plt.series_list[i]
series.d[:x], series.d[:y], series.d[:z] = xyz
sp = series.d[:subplot]
expand_extrema!(sp.attr[:xaxis], xy[1])
expand_extrema!(sp.attr[:yaxis], xy[2])
expand_extrema!(sp.attr[:zaxis], xy[3])
_series_updated(plt, series)
end
# -------------------------------------------------------
# indexing notation
Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = setxy!(plt, xy, i)
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = setxyz!(plt, xyz, i)
# -------------------------------------------------------
# push/append for one series
# push value to first series
Base.push!(plt::Plot, y::Real) = push!(plt, 1, y)
Base.push!(plt::Plot, x::Real, y::Real) = push!(plt, 1, x, y)
Base.push!(plt::Plot, x::Real, y::Real, z::Real) = push!(plt, 1, x, y, z)
# y only
function Base.push!(plt::Plot, i::Integer, y::Real)
xdata, ydata = getxy(plt, i)
setxy!(plt, (extendSeriesByOne(xdata), extendSeriesData(ydata, y)), i)
plt
end
function Base.append!(plt::Plot, i::Integer, y::AVec)
xdata, ydata = plt[i]
if !isa(xdata, UnitRange{Int})
error("Expected x is a UnitRange since you're trying to push a y value only")
end
plt[i] = (extendSeriesByOne(xdata, length(y)), extendSeriesData(ydata, y))
plt
end
# x and y
function Base.push!(plt::Plot, i::Integer, x::Real, y::Real)
xdata, ydata = getxy(plt, i)
setxy!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y)), i)
plt
end
function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec)
@assert length(x) == length(y)
xdata, ydata = getxy(plt, i)
setxy!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y)), i)
plt
end
# x, y, and z
function Base.push!(plt::Plot, i::Integer, x::Real, y::Real, z::Real)
# @show i, x, y, z
xdata, ydata, zdata = getxyz(plt, i)
# @show xdata, ydata, zdata
setxyz!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y), extendSeriesData(zdata, z)), i)
plt
end
function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec, z::AVec)
@assert length(x) == length(y) == length(z)
xdata, ydata, zdata = getxyz(plt, i)
setxyz!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y), extendSeriesData(zdata, z)), i)
plt
end
# tuples
Base.push!{X,Y}(plt::Plot, xy::Tuple{X,Y}) = push!(plt, 1, xy...)
Base.push!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}) = push!(plt, 1, xyz...)
Base.push!{X,Y}(plt::Plot, i::Integer, xy::Tuple{X,Y}) = push!(plt, i, xy...)
Base.push!{X,Y,Z}(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) = push!(plt, i, xyz...)
# -------------------------------------------------------
# push/append for all series
# push y[i] to the ith series
function Base.push!(plt::Plot, y::AVec)
ny = length(y)
for i in 1:plt.n
push!(plt, i, y[mod1(i,ny)])
end
plt
end
# push y[i] to the ith series
# same x for each series
function Base.push!(plt::Plot, x::Real, y::AVec)
push!(plt, [x], y)
end
# push (x[i], y[i]) to the ith series
function Base.push!(plt::Plot, x::AVec, y::AVec)
nx = length(x)
ny = length(y)
for i in 1:plt.n
push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)])
end
plt
end
# push (x[i], y[i], z[i]) to the ith series
function Base.push!(plt::Plot, x::AVec, y::AVec, z::AVec)
nx = length(x)
ny = length(y)
nz = length(z)
for i in 1:plt.n
push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)], z[mod1(i,nz)])
end
plt
end
# ---------------------------------------------------------------
# Some conversion functions
# note: I borrowed these conversion constants from Compose.jl's Measure
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(series.d[:x]) for series in plt.series_list])
"Largest x in plot"
xmax(plt::Plot) = maximum([maximum(series.d[:x]) for series in plt.series_list])
"Extrema of x-values in plot"
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
+16
View File
@@ -0,0 +1,16 @@
julia 0.4
RecipesBase
Colors
Reexport
Measures
FactCheck
Images
PyPlot
@osx QuartzImageIO
GR
DataFrames
RDatasets
VisualRegressionTests
UnicodePlots
Glob
+100
View File
@@ -0,0 +1,100 @@
using VisualRegressionTests
# using ExamplePlots
import DataFrames, RDatasets
# don't let pyplot use a gui... it'll crash
# note: Agg will set gui -> :none in PyPlot
ENV["MPLBACKEND"] = "Agg"
try
@eval import PyPlot
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
end
using Plots, FactCheck
using Glob
default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.7.0"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
Plots._debugMode.on = debug
example = Plots._examples[idx]
info("Testing plot: $pkg:$idx:$(example.header)")
backend(pkg)
backend()
# ensure consistent results
srand(1234)
# reference image directory setup
# refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
refdir = Pkg.dir("PlotReferenceImages", "Plots", string(pkg))
fn = "ref$idx.png"
# firgure out version info
G = glob(relpath(refdir) * "/*")
# @show refdir fn G
versions = map(fn -> VersionNumber(split(fn,"/")[end]), G)
versions = reverse(sort(versions))
# @show refdir fn versions
reffn = nothing
newdir = joinpath(refdir, string(_current_plots_version))
newfn = joinpath(newdir, fn)
for v in versions
try
tmpfn = joinpath(refdir, string(v), fn)
# @show "trying", tmpfn
f = open(tmpfn)
reffn = tmpfn
end
end
# now we have the fn (if any)... do the comparison
# @show reffn
if reffn == nothing
reffn = newfn
end
# @show reffn
# return
# test function
func = (fn, idx) -> begin
map(eval, example.exprs)
png(fn)
end
try
run(`mkdir -p $newdir`)
catch err
display(err)
end
# reffn = joinpath(refdir, "ref$idx.png")
# the test
vtest = VisualTest(func, reffn, idx)
test_images(vtest, popup=popup, sigma=sigma, eps=eps, newfn = newfn)
end
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(Plots._examples)
i in skip && continue
if only == nothing || i in only
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
end
end
end
+22
View File
@@ -0,0 +1,22 @@
#!/bin/sh
set -ex
# sudo add-apt-repository -y ppa:pov/wkhtmltopdf
sudo apt-get -qq update
# sudo apt-get install -y wkhtmltopdf
sudo apt-get install -y xfonts-75dpi
wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
wkhtmltoimage http://www.google.com test.png
ls
wkhtmltopdf -V
wkhtmltoimage -V
# echo 'exec xvfb-run -a -s "-screen 0 640x480x16" wkhtmltoimage "$@"' | sudo tee /usr/local/bin/wkhtmltoimage.sh >/dev/null
# sudo chmod a+x /usr/local/bin/wkhtmltoimage.sh
# export DISPLAY=:99.0
# sh -e /etc/init.d/xvfb start
# sleep 3 # give xvfb some time to start
+76 -63
View File
@@ -1,78 +1,91 @@
module PlotsTests
using Plots
using FactCheck
include("imgcomp.jl")
# don't actually show the plots
plotDefault!(:show, false)
srand(1234)
default(show=false, reuse=true)
img_eps = 5e-2
# facts("Gadfly") do
# @fact gadfly() --> Plots.GadflyBackend()
# @fact backend() --> Plots.GadflyBackend()
#
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
# @fact plot(Int[1,2,3], rand(3)) --> not(nothing)
# @fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
# @fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
#
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# end
# note: we wrap in a try block so that the tests only run if we have the backend installed
try
Pkg.installed("Gadfly")
facts("Gadfly") do
@fact plotter!(:gadfly) --> Plots.GadflyPackage()
@fact plotter() --> Plots.GadflyPackage()
@fact typeof(plot(1:10)) --> Plot
facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
# plot(x::AVec, y::AVec; kw...) # one line (will assert length(x) == length(y))
@fact plot(Int[1,2,3], rand(3)) --> not(nothing)
@fact_throws plot(1:5, 1:4)
# plot(x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
@fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
@fact_throws(plot!(rand(10), rand(9,2)))
# plot(x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y))
@fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
@fact_throws plot!(rand(10,3), rand(10,2))
# plot(x::AVec, y::AVec{AVec}; kw...) # multiple lines, will assert length(x) == length(y[i])
# plot(x::AVec{AVec}, y::AVec{AVec}; kw...) # multiple lines, will assert length(x[i]) == length(y[i])
# plot(n::Integer; kw...) # n lines, all empty (for updating plots)
end
image_comparison_facts(:pyplot, skip=[30], eps=img_eps)
end
# note: we wrap in a try block so that the tests only run if we have the backend installed
try
Pkg.installed("Qwt")
facts("Qwt") do
@fact plotter!(:qwt) --> Plots.QwtPackage()
@fact plotter() --> Plots.QwtPackage()
@fact typeof(plot(1:10)) --> Plot
facts("GR") do
@fact gr() --> Plots.GRBackend()
@fact backend() --> Plots.GRBackend()
# plot(y::AVec; kw...) # one line... x = 1:length(y)
@fact plot(1:10) --> not(nothing)
@fact length(currentPlot().o.lines) --> 1
# plot(x::AVec, f::Function; kw...) # one line, y = f(x)
@fact plot(1:10, sin) --> not(nothing)
@fact currentPlot().o.lines[1].y --> sin(collect(1:10))
# plot(x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ)
@fact plot(rand(10,2), sin) --> not(nothing)
@fact length(currentPlot().o.lines) --> 2
# plot(y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1)
@fact plot!(rand(10,2)) --> not(nothing)
@fact length(currentPlot().o.lines) --> 4
# plot(x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ)
@fact plot(1:10, Function[sin,cos]) --> not(nothing)
@fact currentPlot().o.lines[1].y --> sin(collect(1:10))
@fact currentPlot().o.lines[2].y --> cos(collect(1:10))
# plot(y::AVec{AVec}; kw...) # multiple lines, each with x = 1:length(y[i])
@fact plot([11:20 ; rand(10)]) --> not(nothing)
@fact currentPlot().o.lines[1].x[4] --> 4
@fact currentPlot().o.lines[1].y[4] --> 14
end
@linux_only image_comparison_facts(:gr, skip=[30], eps=img_eps)
end
facts("Plotly") do
@fact plotly() --> Plots.PlotlyBackend()
@fact backend() --> Plots.PlotlyBackend()
# # until png generation is reliable on OSX, just test on linux
# @linux_only image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
end
# facts("Immerse") do
# @fact immerse() --> Plots.ImmerseBackend()
# @fact backend() --> Plots.ImmerseBackend()
#
# # as long as we can plot anything without error, it should be the same as Gadfly
# image_comparison_facts(:immerse, only=[1], eps=img_eps)
# end
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
#
# # as long as we can plot anything without error, it should be the same as Plotly
# image_comparison_facts(:plotlyjs, only=[1], eps=img_eps)
# end
facts("UnicodePlots") do
@fact unicodeplots() --> Plots.UnicodePlotsBackend()
@fact backend() --> Plots.UnicodePlotsBackend()
# lets just make sure it runs without error
@fact isa(plot(rand(10)), Plot) --> true
end
facts("Axes") do
p = plot()
axis = p.subplots[1][:xaxis]
@fact typeof(axis) --> Axis
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
@fact extrema(axis) --> (0.5,1.5)
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i=1:5])
Plots.discrete_value!(axis, ["x$i" for i=0:2])
@fact extrema(axis) --> (0.5, 7.5)
end
FactCheck.exitstatus()
end # module
-21
View File
@@ -1,21 +0,0 @@
function testplot_line1()
plot(rand(100,3))
end
function testplot_fn1()
plot(0:0.01:4π, [sin,cos])
end
function testplot_guides1()
plot(rand(10); title="TITLE", xlabel="XLABEL", ylabel="YLABEL", background_color=:red)
end
function testplot_points1()
plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8)
end
function testplot_points2()
plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8, markercolors=[:red,:blue])
end
+27
View File
@@ -0,0 +1,27 @@
# Pkg.clone(pwd())
# Pkg.build("Plots")
Pkg.clone("ImageMagick")
Pkg.build("ImageMagick")
Pkg.clone("GR")
Pkg.build("GR")
# Pkg.clone("https://github.com/JuliaPlots/RecipesBase.jl.git")
# Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
# Pkg.clone("https://github.com/JunoLab/Blink.jl.git")
# Pkg.build("Blink")
# import Blink
# Blink.AtomShell.install()
# Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")
Pkg.checkout("RecipesBase")
Pkg.clone("VisualRegressionTests")
ENV["PYTHON"] = ""
Pkg.add("PyPlot")
Pkg.build("PyPlot")
Pkg.test("Plots"; coverage=false)