Compare commits

...

136 Commits

Author SHA1 Message Date
Thomas Breloff dcab8e3ac2 travis fix 2016-07-12 13:14:53 -04:00
Thomas Breloff 1ad9a7e176 fix fillrange for shape; travis fix 2016-07-12 12:53:03 -04:00
Thomas Breloff f1bd7ab1dc travis fix 2016-07-12 11:53:37 -04:00
Thomas Breloff 79399913d7 NEWS, bumped version; travis fixes; added warnings for moved recipes 2016-07-12 11:23:04 -04:00
Thomas Breloff 4a2e88a81c switched Colors dep for PlotUtils dep; removed DataFrames, boxplot, violin, density and added StatPlots to tests 2016-07-12 10:45:58 -04:00
Thomas Breloff 8d5b748b09 gr heatmap fix; pipeline reorg 2016-07-10 23:26:52 -04:00
Thomas Breloff b2dba8af73 split plot into pipeline 2016-07-10 22:59:05 -04:00
Thomas Breloff c258bc49c3 gr trisurface; closes #387 2016-07-10 22:07:00 -04:00
Thomas Breloff e3e2a354e7 reorg of update_subplot_args; add back recipe, DataFrames; random type stability fixes 2016-07-10 18:12:49 -04:00
Thomas Breloff 32c1c31139 working on _plot organization; switch alias dicts to Dict{Symbol,Symbol}; other type stability changes 2016-07-10 15:50:29 -04:00
Thomas Breloff b8b5a33833 margin default to 1mm 2016-07-09 14:54:44 -04:00
Thomas Breloff 5407fa73f8 plotly redesign for splitting shapes 2016-07-09 13:30:39 -04:00
Thomas Breloff 1cb0c0071b improvements to layout padding; handle axis attr better; fix histogram2d 2016-07-09 12:40:27 -04:00
Thomas Breloff a456ac4c90 pyplot line segments fixes; curves remove line_z logic 2016-07-08 14:36:02 -04:00
Thomas Breloff 71b48427c5 pyplot line segments fix; bar fixes 2016-07-08 13:09:36 -04:00
Thomas Breloff ec06a01b6c pgf fixes 2016-07-08 11:21:26 -04:00
Thomas Breloff e3ccc34a2c ensure_gradient; plotly fixes 2016-07-08 10:12:48 -04:00
Thomas Breloff 396721568f color fixes; add PlotUtils to travis_commands 2016-07-08 09:17:39 -04:00
Thomas Breloff e53ab85745 color fixes; pyplot shape iteration; KernelDensity in travis and warning; attribute accessors 2016-07-07 21:46:34 -04:00
Thomas Breloff 4d99b37def working on colors overhaul; fix for rationals in plotly; closes #382 2016-07-07 14:40:09 -04:00
Thomas Breloff 2e24da3dcd update matrix of Shapes recipe 2016-07-07 09:36:03 -04:00
Thomas Breloff 0cc1bd2dc6 sample ticks if too many discrete values; use get_ticks in plotly to fix discrete ticks; allow ticks==false in pyplot; closes #356 2016-07-06 16:51:54 -04:00
Thomas Breloff aec162c50e fix for discrete bars; closes #365 2016-07-06 16:22:11 -04:00
Thomas Breloff d5e9340f8f bar fix for horizontal orientation 2016-07-06 16:10:01 -04:00
Thomas Breloff 6fe87c4c69 bar_width support in bar and boxplot; close the shape for bar plots; closes #366; closes #377 2016-07-06 15:55:38 -04:00
Tom Breloff 85f0a87213 Merge pull request #372 from anowacki/rainbow_palette
Switch blue and violet in rainbow colour palette.
2016-07-05 10:22:03 -04:00
Thomas Breloff 853f85be2e bug fix for passing vectors to bins; closes #375 2016-07-05 10:18:48 -04:00
Andy Nowacki a7448e3a1d Switch blue and violet in rainbow color palette. 2016-07-04 17:43:25 +01:00
Thomas Breloff 521e753183 string fix; iter_segments change to use unused and skip initial NaNs; working on glvisualize shape type 2016-07-01 17:23:25 -04:00
Thomas Breloff 9193941fd0 version bump; NEWS 2016-07-01 09:01:38 -04:00
Tom Breloff f56c6effe4 Merge pull request #368 from jheinen/dev
Added iTerm2 inline display support for gr
2016-07-01 08:09:34 -04:00
Josef Heinen 4cfcb239c1 Added iTerm2 inline display support for gr
Example:
--------
    using Plots
    gr(display_type=:inline)
    plot(Plots.fakedata(50,5), w=3)
2016-07-01 14:03:16 +02:00
Thomas Breloff a4be274718 pyplot display hack 2016-06-30 21:05:32 -04:00
Thomas Breloff 120f861a27 surface fixes for mis-typed matrices; getindex for Series 2016-06-30 14:08:05 -04:00
Thomas Breloff 7e56d85b83 args fix 2016-06-29 21:58:07 -04:00
Thomas Breloff 20af495581 added display_type and extra_kwargs plot attributes 2016-06-29 16:34:06 -04:00
Thomas Breloff bf94c48225 pyplot fix; new flexible logic for DataFrames 2016-06-29 16:22:16 -04:00
Thomas Breloff 27a68333b1 readme 2016-06-29 14:51:24 -04:00
Thomas Breloff 63f18dd26a vector of seriestypes fix; pycall changed strings to symbols 2016-06-29 14:45:33 -04:00
Thomas Breloff 4ea787743e added contourf; getindex for plt/sp; plot/plot! on a Subplot; fix for pyplot zorder 2016-06-29 13:53:22 -04:00
Thomas Breloff 3a4b881576 switched docs url 2016-06-29 12:31:01 -04:00
Thomas Breloff f087594331 switched docs url 2016-06-29 12:23:42 -04:00
Thomas Breloff 5491e40fd1 bump version; img_eps; remove gr 30 test; attempted fixes for appveyor 2016-06-28 18:04:40 -04:00
Tom Breloff 4b690ec9ad Merge pull request #361 from jheinen/dev
gr: allow simple formulas or LaTeX equations
2016-06-28 10:03:23 -04:00
Josef Heinen 9fecb03b5f gr: allow simple formulas or LaTeX equations 2016-06-28 15:35:32 +02:00
Thomas Breloff de6e3d46ec appveyor fix 2016-06-27 21:49:45 -04:00
Thomas Breloff 3006a26500 revert precompile; add appveyor; gr fixes for markersize, shapes, and legend entries; add GR to tests again; recipe fixes and cleanup 2016-06-27 21:43:57 -04:00
Thomas Breloff 6ffed9387c snoop and precompile; bumped version 2016-06-27 16:52:50 -04:00
Thomas Breloff 558627e7a9 NEWS 2016-06-27 14:02:01 -04:00
Thomas Breloff 4b276f977c revert pyplot heatmap change 2016-06-27 12:25:45 -04:00
Thomas Breloff 99fe4f615d show arg fix; add image to all3D 2016-06-27 12:09:08 -04:00
Thomas Breloff 928c306803 dpi fixes 2016-06-27 10:06:40 -04:00
Thomas Breloff a3eddf8ba7 dpi support for pyplot 2016-06-27 09:20:42 -04:00
Thomas Breloff 78e0ae31af removed chorddiagram 2016-06-26 12:37:06 -04:00
Thomas Breloff 1a90ce0950 recoded boxplot recipe to match violin approach; switched marker to line/fill for shape seriestype: ref #347 2016-06-26 11:36:09 -04:00
Thomas Breloff 2465b3eb5a fallback warnings for missing _writemime and _display 2016-06-26 11:08:06 -04:00
Thomas Breloff 16a2e34e95 writemime fix for Interact; working on glvisualize 2016-06-26 10:34:34 -04:00
Thomas Breloff 5c52d68091 working on glvisualize 2016-06-25 18:06:27 -04:00
Thomas Breloff 1a2e180f4f working on glvisualize 2016-06-25 17:00:45 -04:00
Thomas Breloff 9048053669 working on glvisualize 2016-06-25 10:56:51 -04:00
Thomas Breloff 69b69714cb working on glvisualize 2016-06-24 12:15:21 -04:00
Thomas Breloff 1ecd9f9e19 working on glvisualize 2016-06-24 11:52:33 -04:00
Thomas Breloff 2bca9ca9ec square link 2016-06-24 11:00:28 -04:00
Thomas Breloff d66028ed0d glvisualize: support for path/path3d with or without markers, 3d markers are spheres 2016-06-23 17:00:08 -04:00
Thomas Breloff 1cf33044bc scatter and scatter3d support in glvisualize 2016-06-23 14:59:04 -04:00
Thomas Breloff 2c138c8355 readme 2016-06-22 13:22:25 -04:00
Thomas Breloff 73ffcb9bc1 changed convertToAnyVector AMat so that all matrices use the version previously for numbers; violin cleanup 2016-06-22 13:20:09 -04:00
Thomas Breloff 730025e144 recoded violin; removed try/catch around apply_recipe; default values for xtick/ytick in GR 2016-06-22 11:45:30 -04:00
Thomas Breloff 91aa1d718a animations: use tmp.gif for ijulia, remove prefix from convert call; closes #346 2016-06-22 11:01:00 -04:00
Thomas Breloff f881bfc4fc add Segments; pyplot: switch bar/hist/hist2d to recipes and path fix; change bar to shape; removed GR from tests 2016-06-20 23:11:23 -04:00
Thomas Breloff e76c3fff69 refactored gr markers fixing bugs and enabling features; clear subplot/axis args from d in _plot 2016-06-20 19:51:03 -04:00
Thomas Breloff 9f168071ff subplot attributes fixes 2016-06-20 15:11:25 -04:00
Thomas Breloff b6652b7619 improvements to bbox construction and inset subplots 2016-06-20 10:13:03 -04:00
Thomas Breloff f6d501f69e plot recipe fixes 2016-06-20 00:11:06 -04:00
Thomas Breloff 4c052cb3b3 colors cgrad and getindex 2016-06-19 11:25:25 -04:00
Thomas Breloff ea8ccf38db plot recipe fixes 2016-06-18 22:30:47 -04:00
Thomas Breloff cf12ff8070 plot logic cleanup; added plot recipes 2016-06-18 09:33:34 -04:00
Thomas Breloff b7a95244db handle seriestype aliases; handle vector of seriestypes; hvline_limits; added cycle for InputWrapper; turn on GR tests for OSX 2016-06-18 00:14:20 -04:00
Tom Breloff 4c884651a8 Merge pull request #343 from jheinen/dev
Added suport for marker borders
2016-06-18 00:02:42 -04:00
Thomas Breloff e9eca577aa plotlyjs supported_scales; violin check 2016-06-17 15:31:01 -04:00
Josef Heinen cff78b477c Added suport for marker borders 2016-06-17 20:21:07 +02:00
Tom Breloff b232410d25 Merge pull request #338 from jheinen/dev
use temporary files when generating MIME files
2016-06-17 08:09:53 -04:00
Josef Heinen 5ff338d4ac use temporary files when generating MIME files 2016-06-17 09:34:10 +02:00
Thomas Breloff a5ceea153d bump plots version 0.7.3 2016-06-16 21:00:25 -04:00
Thomas Breloff f3544dc826 plotlyjs png fix; NEWS update for 0.7.2 2016-06-16 20:58:44 -04:00
Thomas Breloff b0bc68ae8a orientation aliases dir/direction; removed native support for sticks/hline/vline in pyplot; commented out arcdiagram 2016-06-16 17:31:10 -04:00
Thomas Breloff c38e947dc6 animation default file tempname; raised group warning to 100; check for empty vec in axis; use command_idx for slicing; move deletion of smooth outside loop 2016-06-16 10:03:01 -04:00
Thomas Breloff ec826fc8ce moved series_annotations into series recipe processing; change pyplot clf to fig clear 2016-06-16 00:48:35 -04:00
Thomas Breloff e5c4f782a5 anynan isfinite; error on reusing layout 2016-06-15 15:36:36 -04:00
Thomas Breloff a5ddebf44d curves fix 2016-06-15 13:02:31 -04:00
Thomas Breloff 38804898c5 iter_segments and curve series type 2016-06-15 12:52:36 -04:00
Thomas Breloff 2bd67f3519 pyplot 3d line segments 2016-06-15 02:15:51 -04:00
Thomas Breloff c8ed611c9c unicodeplots cleanup: ijulia output fixes, ascii canvas 2016-06-15 01:45:13 -04:00
Thomas Breloff 3d7d8caa82 moved pyplot methods _series_added and _initialize_subplot into the display pipeline 2016-06-14 18:02:44 -04:00
Thomas Breloff f64108523c line_z arg and pyplot implementation 2016-06-14 15:39:21 -04:00
Tom Breloff a7493504ed Merge pull request #334 from jheinen/dev
conserve user defined GR workstation type
2016-06-14 13:31:40 -04:00
Josef Heinen bc5293b5a4 conserve user defined GR workstation type 2016-06-14 18:03:03 +02:00
Thomas Breloff c4bdc5b856 NEWS.md 2016-06-14 00:27:22 -04:00
Thomas Breloff b5b4023056 axis link arg; change those subplot/axis args set in kwlist to apply just to its own subplot; markerstrokealpha matches markeralpha 2016-06-14 00:10:26 -04:00
Thomas Breloff 0e598cc51d resolve relative coords for inset subplots 2016-06-13 17:46:19 -04:00
Thomas Breloff 9fd09924eb _shape_keys for consistent shape ordering 2016-06-13 16:57:26 -04:00
Thomas Breloff 10d218089f working on glvisualize 2016-06-13 16:15:45 -04:00
Thomas Breloff 1ba0d198a7 rename ellipse to circle; cleanup glvisualize 2016-06-13 15:59:51 -04:00
Thomas Breloff c44132d29d merge_with_base_supported updates 2016-06-13 15:45:35 -04:00
Thomas Breloff a018a2c07a series type dependencies and cleanup; bbox anchors in construction; fix for insets 2016-06-13 14:53:28 -04:00
Thomas Breloff 266d2efde5 inset_subplots; GR log axes fix 2016-06-13 12:27:48 -04:00
Thomas Breloff 3b33b054d3 plotly hover and scattergl 2016-06-13 11:04:56 -04:00
Thomas Breloff 1140b51e91 PLOTS_DEFAULTS and removed pyplot finalizer 2016-06-13 09:42:50 -04:00
Thomas Breloff 9d25c8fcd4 added PLOTS_DEFAULTS env var; check isfinite in axis_limits 2016-06-13 09:27:49 -04:00
Thomas Breloff e8ade18d47 code and utils for plotly shapes 2016-06-13 01:45:53 -04:00
Thomas Breloff ed243f4e3e added hover attribute and desc; fixed plotly title location; already_warned check 2016-06-13 00:15:28 -04:00
Thomas Breloff e0af4b7925 pyplot log scale fix; plotly title as annotation, title_location, hover placeholder 2016-06-12 23:48:18 -04:00
Thomas Breloff 80e53adbd8 getting plotly/plotlyjs up to speed 2016-06-12 21:03:11 -04:00
Thomas Breloff 36a29357a3 only widen axis limits for identity scale; closes #326 2016-06-12 20:22:57 -04:00
Thomas Breloff 5bb9aceaac pyplot log scale threshold fix; imgcomp fix to filter out higher versions 2016-06-12 13:06:15 -04:00
Thomas Breloff 02d893b316 big cleanup: changed camelcase to underscores; removed supportedAxes; changed pyplot methods to be py_ which matches gr_/plotly_/etc convention 2016-06-12 12:34:41 -04:00
Thomas Breloff b1850e58f4 gr cleanup commented code; bump version in imgcomp 2016-06-12 11:35:24 -04:00
Thomas Breloff f1e566dddc fix scale aliases 2016-06-12 11:00:42 -04:00
Thomas Breloff 2f60da33b7 changed pyplot log scale to symlog; #326 2016-06-12 10:28:41 -04:00
Thomas Breloff b0456d155a allow nothing for colorbar; gr fixes: marker_z colors, check colorbar arg 2016-06-11 15:55:55 -04:00
Tom Breloff 5f57a48996 Merge pull request #322 from jheinen/dev
Fixed GR output problem
2016-06-11 15:54:00 -04:00
Josef Heinen bc9d137001 Fixed GR output problem 2016-06-11 11:11:57 +02:00
Thomas Breloff 483946787a big GR refactor: axes drawing and cleanup; convert_to_polar and GR polar fill; should_add_to_legend fix; rename get_mod to Base.cycle 2016-06-11 02:03:46 -04:00
Thomas Breloff b165f233a8 animation fix; gr transparency 2016-06-10 16:17:30 -04:00
Thomas Breloff 3b325b2482 pyplot figure finalizer; accept 2-len AVec for limits (#289); sleep/skip/only options in test_examples 2016-06-10 10:04:33 -04:00
Tom Breloff 2dd480a3a6 Merge pull request #313 from jheinen/dev
Improved GR output
2016-06-10 08:56:53 -04:00
Josef Heinen df33ed40d6 Improved GR output
- slightly reduced the nominal marker size
- use character height as line spacing criterion when plotting legends
- use GR surface function for filled contours
- avoid calling GR setwindow/adjust* functions with Inf arguments
- corrected bounding box for legend
2016-06-10 13:39:57 +02:00
Thomas Breloff cf4d78c87c added clims attribute and support it in pyplot 2016-06-10 01:25:34 -04:00
Thomas Breloff 8007d0dd6a smarter cleanup of dicts; layout fixes: split out update_min_padding and added minimum_perimeter logic; check for nonempty axes when linking; add subplot processing and linking when combining plots 2016-06-10 00:16:13 -04:00
Thomas Breloff d7098f77c2 pgfplots display popup 2016-06-09 17:31:06 -04:00
Thomas Breloff 514284e784 pyplot display fixes for #308; setxyz fix; generic png conversion from pdf; pgfplots pdf output 2016-06-09 17:13:16 -04:00
Thomas Breloff 2a3029edb4 add build.jl 2016-06-09 12:08:36 -04:00
Thomas Breloff 45a1ed69d4 removed plotly-latest.min.js and added build.jl which downloads it; fix for quiver_using_hack; working on pyplot display behavior 2016-06-09 11:44:05 -04:00
Thomas Breloff 7248d8d7ce several fixes for type recipes; collect/zmin fixes in pgfplots; scatter3d recipe 2016-06-09 01:48:43 -04:00
Tom Breloff fa84401866 Merge pull request #310 from diegozea/dev
Add trim kw arg to violin and density
2016-06-09 01:45:43 -04:00
Diego Javier Zea 910b94c5fd Add trim kw arg to violin and density 2016-06-09 02:38:19 -03:00
49 changed files with 4274 additions and 4216 deletions
+1
View File
@@ -4,3 +4,4 @@
.DS_Store
examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
+118 -3
View File
@@ -7,11 +7,126 @@
---
## 0.7 (current master/dev)
## 0.8 (current master/dev)
#### 0.8.0
- added dependency on PlotUtils
- BREAKING: removed DataFrames support (now in StatPlots.jl)
- BREAKING: removed boxplot/violin/density recipes (now in StatPlots.jl)
- GR:
- inline iterm2 support
- trisurface support
- heatmap fix
- PyPlot:
- ijulia display fix
- GLVisualize:
- first try with shapes
- iter_segments improvements
- bar_width support
- horizontal bars
- improve tick display
- better shape handling in pyplot, plotly
- improved padding calcs
- internal reorg of _plots method, add pipeline.jl
---
## 0.7
#### 0.7.5
- GR: LaTeX support
- Changed docs url to juliaplots.github.io
- added `contourf` seriestype
- allow `plt[1]` to return first Subplot
- allow `sp[1]` to return the first Series of the Subplot
- `series[k]` now passes through to `series.d[k]`
- allow calling `plot!(sp, ...)` to update a target Subplot
- PyPlot: zorder fix
- new DataFrames logic/recipe: more flexible/robust and allow Symbols for:
- `(:fillrange, :line_z, :marker_z, :markersize, :ribbon, :weights, :xerror, :yerror)`
- new `display_type` and `extra_kwargs` plot attributes
- surface fix
#### 0.7.4
- added snooped precompiles, but left commented out
- GR fixes: markersize, shapes, legends
- fixes to recipes
- turned on Appveyor
#### 0.7.3
- rebuild violin and boxplot recipes
- "plot recipes"
- `cgrad` method for easy color gradient creation
- improvements to inset subplots
- Segments and iter_segments for NaN-separated vectors
- `bar` recipe now creates a `shape` series
- writemime fix for Interact.jl
- `link = :square` option
- !!! set `shape` attributes with line/fill, NOT marker/markerstroke !!!
- basic DPI support
- moved chorddiagram to PlotRecipes
- GR:
- use temp files for img output
- basic support for marker strokes and other marker fixes
- PyPlot:
- Switch to recipes for bar, histogram, histogram2d
- GLVisualize
- subplots
- path/scatter and path3d/scatter3d
- initial drawing of axes
- many smaller fixes and improvements
#### 0.7.2
- line_z arg for multicolored line segments
- pyplot
- line_z (2d and 3d)
- pushed all fig updates into display pipeline
- remove native sticks/hline/vline in favor of recipes
- unicodeplots cleanup, ijulia fixes, ascii canvas
- `curves` series type
- `iter_segments` iterator
- moved arcdiagram out and into PlotRecipes (thanks @diegozea)
- several other fixes/checks
#### 0.7.1
- inset (floating) subplots
- change: when setting subplot/axis args from user recipes, they should apply only to their own subplot
- trim for violin/boxplot
- scatter3d recipe
- removed plotly.js in favor of build.jl download
- improvements/fixes to pgfplots backend
- improvements/fixes to plotly/plotlyjs backends
- titles are annotations and properly placed with title_position
- hover attribute
- shapes (almost)
- scattergl
- minimum perimeter logic in layout calc... fixed misaligned subplots
- new clims attribute
- more options for test_examples
- GR refactor
- added transparency
- moved axis/grid logic out of series loop
- generalized 3d and polar projections
- renamed get_mod to Base.cycle
- pyplot log scale fixes
- PLOTS_DEFAULTS environment var processing
- rename :ellipse to :circle, :ellipse is now an alias
- supported args/types cleanup
- seriestype dependency methods and `@deps` macro
- bbox `h_anchor`/`v_anchor`
- new axis arg: `:link` is a list of subplots to link axes with
- cleanup/simplification of glvisualize backend
#### 0.7.0
- Check out [the summary](http://plots.readthedocs.io/en/latest/plots_v0.7/)
- Check out [the summary](http://juliaplots.github.io/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)
@@ -143,7 +258,7 @@
- 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/
- New docs (WIP) at http://juliaplots.github.io/
- 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
+5 -18
View File
@@ -12,24 +12,11 @@
Plots is a plotting API and toolset. My goals with the package are:
- **Powerful**. Do more with less. Complex visualizations become easy.
- **Intuitive**. Start generating plots without reading volumes of documentation. Commands should "just work".
- **Intuitive**. Stop reading so much 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.
- **Consistent**. Don't commit to one graphics package, use the same code everywhere.
- **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
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.
```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
```
![waves](http://plots.readthedocs.io/en/latest/examples/img/waves.gif)
View the [full documentation](http://plots.readthedocs.io).
View the [full documentation](http://juliaplots.github.io).
+1 -1
View File
@@ -1,7 +1,7 @@
julia 0.4
RecipesBase
Colors
PlotUtils
Reexport
Compat
FixedSizeArrays
+10 -15
View File
@@ -1,14 +1,11 @@
environment:
matrix:
- JULIAVERSION: "julialang/bin/winnt/x86/0.3/julia-0.3-latest-win32.exe"
- JULIAVERSION: "julialang/bin/winnt/x64/0.3/julia-0.3-latest-win64.exe"
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
branches:
only:
- master
- /release-.*/
# Releases
- JULIAVERSION: "stable/win32"
- JULIAVERSION: "stable/win64"
# Nightlies
- JULIAVERSION: "download/win32"
- JULIAVERSION: "download/win64"
notifications:
- provider: Email
@@ -18,17 +15,15 @@ notifications:
install:
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$("http://s3.amazonaws.com/"+$env:JULIAVERSION),
"C:\projects\julia-binary.exe")
- ps: (new-object net.webclient).DownloadFile($("http://status.julialang.org/"+$env:JULIAVERSION), "C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo();
Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
- C:\projects\julia\bin\julia -e "versioninfo(); Pkg.clone(pwd(), \"Plots\"); Pkg.build(\"Plots\")"
test_script:
- C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"Plots\")"
# - C:\projects\julia\bin\julia -e "Pkg.test(\"Plots\")"
- C:\projects\julia\bin\julia -e "include(Pkg.dir(\"Plots\", \"test\", \"travis_commands.jl\"))"
+8
View File
@@ -0,0 +1,8 @@
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
if !isfile(local_fn)
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
end
-41
View File
File diff suppressed because one or more lines are too long
+42 -132
View File
@@ -1,15 +1,16 @@
__precompile__()
__precompile__()
module Plots
using Compat
using Reexport
@reexport using Colors
# @reexport using Colors
# using Requires
using FixedSizeArrays
@reexport using RecipesBase
using Base.Meta
@reexport using PlotUtils
export
AbstractPlot,
@@ -19,14 +20,12 @@ export
GridLayout,
grid,
EmptyLayout,
bbox,
plotarea,
@layout,
# RowsLayout,
# FlexLayout,
AVec,
AMat,
KW,
# attr,
# attr!,
wrap,
set_theme,
@@ -34,8 +33,6 @@ export
plot,
plot!,
# subplot,
# subplot!,
current,
default,
@@ -43,53 +40,11 @@ export
@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!,
@@ -119,33 +74,30 @@ export
text,
font,
Axis,
# xaxis,
# yaxis,
# zaxis,
stroke,
brush,
Surface,
OHLC,
arrow,
Segments,
colorscheme,
ColorScheme,
ColorGradient,
ColorVector,
ColorWrapper,
ColorFunction,
ColorZFunction,
getColor,
getColorZ,
# colorscheme,
# ColorScheme,
# ColorGradient,
# ColorVector,
# ColorWrapper,
# ColorFunction,
# ColorZFunction,
# getColor,
# getColorZ,
debugplots,
supportedArgs,
supportedAxes,
supportedTypes,
supportedStyles,
supportedMarkers,
subplotSupported,
supported_args,
supported_types,
supported_styles,
supported_markers,
is_subplot_supported,
Animation,
frame,
@@ -153,16 +105,10 @@ export
@animate,
@gif,
PlotRecipe,
spy,
arcdiagram,
chorddiagram,
# @kw,
# @recipe,
# @plotrecipe,
test_examples,
iter_segments,
translate,
translate!,
@@ -178,23 +124,22 @@ export
# ---------------------------------------------------------
import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
typealias BBox Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
# ---------------------------------------------------------
include("types.jl")
include("utils.jl")
include("colors.jl")
include("components.jl")
include("axes.jl")
include("backends.jl")
include("args.jl")
include("themes.jl")
include("plot.jl")
include("series_args.jl")
include("series_new.jl")
include("pipeline.jl")
include("series.jl")
include("layouts.jl")
include("subplots.jl")
include("recipes.jl")
@@ -209,14 +154,11 @@ include("arg_desc.jl")
# define and export shorthand plotting method definitions
macro shorthands(funcname::Symbol)
funcname2 = Symbol(funcname, "!")
ret = esc(quote
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
@@ -231,8 +173,8 @@ end
@shorthands hline
@shorthands vline
@shorthands ohlc
# @shorthands pie
@shorthands contour
@shorthands contourf
@shorthands contour3d
@shorthands surface
@shorthands wireframe
@@ -241,53 +183,12 @@ end
@shorthands boxplot
@shorthands violin
@shorthands quiver
@shorthands curves
# 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...)
@@ -340,15 +241,24 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
const CURRENT_BACKEND = CurrentBackend(:none)
# setup_dataframes()
function __init__()
setup_ijulia()
# setup_dataframes()
setup_atom()
# add_axis_letter_defaults()
if haskey(ENV, "PLOTS_DEFAULTS")
for (k,v) in eval(parse(ENV["PLOTS_DEFAULTS"]))
default(k, v)
end
end
end
# ---------------------------------------------------------
# if VERSION >= v"0.4.0-dev+5512"
# include("precompile.jl")
# _precompile_()
# end
# ---------------------------------------------------------
end # module
+4 -4
View File
@@ -24,7 +24,7 @@ immutable AnimatedGif
filename::Compat.ASCIIString
end
function gif(anim::Animation, fn::Compat.ASCIIString = "tmp.gif"; fps::Integer = 20)
function gif(anim::Animation, fn = (isijulia() ? "tmp.gif" : tempname()*".gif"); fps::Integer = 20)
fn = abspath(fn)
try
@@ -35,8 +35,8 @@ function gif(anim::Animation, fn::Compat.ASCIIString = "tmp.gif"; fps::Integer =
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`)
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
run(`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
@@ -56,7 +56,7 @@ 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())>\" />")
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />")
end
+8 -1
View File
@@ -27,7 +27,8 @@ const _arg_desc = KW(
: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.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
: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)",
@@ -45,6 +46,7 @@ const _arg_desc = KW(
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
# plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
@@ -59,6 +61,10 @@ const _arg_desc = KW(
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
# subplot args
:title => "String. Subplot title.",
@@ -74,6 +80,7 @@ const _arg_desc = KW(
: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)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
: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.",
+323 -159
View File
@@ -1,6 +1,6 @@
const _keyAliases = KW()
const _keyAliases = Dict{Symbol,Symbol}()
function add_aliases(sym::Symbol, aliases::Symbol...)
for alias in aliases
@@ -11,10 +11,20 @@ function add_aliases(sym::Symbol, aliases::Symbol...)
end
end
function add_non_underscore_aliases!(aliases::Dict{Symbol,Symbol})
for (k,v) in aliases
s = string(k)
if '_' in s
aliases[Symbol(replace(s, "_", ""))] = v
end
end
end
# ------------------------------------------------------------
const _allAxes = [:auto, :left, :right]
const _axesAliases = KW(
const _axesAliases = Dict{Symbol,Symbol}(
:a => :auto,
:l => :left,
:r => :right
@@ -29,7 +39,7 @@ const _allTypes = vcat([
:contour, :pie, :shape, :image
], _3dTypes)
@compat const _typeAliases = KW(
@compat const _typeAliases = Dict{Symbol,Symbol}(
:n => :none,
:no => :none,
:l => :line,
@@ -61,15 +71,19 @@ const _allTypes = vcat([
:imagesc => :image,
:hist => :histogram,
:hist2d => :histogram2d,
:bezier => :curves,
:bezier_curves => :curves,
)
add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :density)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contour3d, :heatmap, :surface, :wireframe, :image)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
is3d(seriestype::Symbol) = seriestype in _3dTypes
is3d(series::Series) = is3d(series.d)
is3d(d::KW) = trueOrAllTrue(is3d, d[:seriestype])
is3d(d::KW) = trueOrAllTrue(is3d, Symbol(d[:seriestype]))
is3d(sp::Subplot) = string(sp.attr[:projection]) == "3d"
ispolar(sp::Subplot) = string(sp.attr[:projection]) == "polar"
@@ -78,7 +92,7 @@ ispolar(series::Series) = ispolar(series.d[:subplot])
# ------------------------------------------------------------
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
@compat const _styleAliases = KW(
@compat const _styleAliases = Dict{Symbol,Symbol}(
:a => :auto,
:s => :solid,
:d => :dash,
@@ -86,13 +100,14 @@ const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
:ddd => :dashdotdot,
)
const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
@compat const _markerAliases = KW(
const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes))))
@compat const _markerAliases = Dict{Symbol,Symbol}(
:n => :none,
:no => :none,
:a => :auto,
:circle => :ellipse,
:c => :ellipse,
:ellipse => :circle,
:c => :circle,
:circ => :circle,
:square => :rect,
:sq => :rect,
:r => :rect,
@@ -128,7 +143,7 @@ const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
)
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
@compat const _scaleAliases = KW(
@compat const _scaleAliases = Dict{Symbol,Symbol}(
:none => :identity,
:log => :log10,
)
@@ -162,6 +177,7 @@ const _series_defaults = KW(
:y => nothing,
:z => nothing, # depth for contour, surface, etc
:marker_z => nothing, # value for color scale
:line_z => nothing,
:levels => 15,
:orientation => :vertical,
:bar_position => :overlay, # for bar plots and histograms: could also be stack (stack up) or dodge (side by side)
@@ -181,6 +197,7 @@ const _series_defaults = KW(
:series_annotations => [], # a list of annotations which apply to the coordinates of this series
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
# one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points
)
@@ -197,6 +214,11 @@ const _plot_defaults = KW(
:link => :none,
:overwrite_figure => true,
:html_output_format => :auto,
:inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are
# the parent layout and the relative bounding box of inset subplots
:dpi => DPI, # dots per inch for images, etc
:display_type => :auto,
:extra_kwargs => KW(),
)
@@ -214,12 +236,13 @@ const _subplot_defaults = KW(
:color_palette => :auto,
:legend => :best,
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
:grid => true,
:annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal
:margin => 2mm,
:margin => 1mm,
:left_margin => :match,
:top_margin => :match,
:right_margin => :match,
@@ -234,6 +257,7 @@ const _axis_defaults = KW(
:scale => :identity,
:rotation => 0,
:flip => false,
:link => [],
:tickfont => font(8),
:guidefont => font(11),
:foreground_color_axis => :match, # axis border/tick colors,
@@ -254,6 +278,7 @@ const _suppress_warnings = Set{Symbol}([
:plot_object,
:primary,
:smooth,
:relative_bbox,
])
# add defaults for the letter versions
@@ -266,6 +291,7 @@ for letter in (:x,:y,:z)
:scale,
:rotation,
:flip,
:link,
:tickfont,
:guidefont,
:foreground_color_axis,
@@ -289,10 +315,10 @@ const _all_defaults = KW[
]
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
supportedArgs(::AbstractBackend) = error("supportedArgs not defined") #_all_args
supportedArgs() = supportedArgs(backend())
supported_args(::AbstractBackend) = error("supported_args not defined") #_all_args
supported_args() = supported_args(backend())
RecipesBase.is_key_supported(k::Symbol) = (k in supportedArgs())
RecipesBase.is_key_supported(k::Symbol) = (k in supported_args())
# -----------------------------------------------------------------------------
@@ -304,7 +330,7 @@ autopick(notarr, idx::Integer) = notarr
autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
autopick_ignore_none_auto(notarr, idx::Integer) = notarr
function aliasesAndAutopick(d::KW, sym::Symbol, aliases::KW, options::AVec, plotIndex::Int)
function aliasesAndAutopick(d::KW, sym::Symbol, aliases::Dict{Symbol,Symbol}, options::AVec, plotIndex::Int)
if d[sym] == :auto
d[sym] = autopick_ignore_none_auto(options, plotIndex)
elseif haskey(aliases, d[sym])
@@ -312,7 +338,7 @@ function aliasesAndAutopick(d::KW, sym::Symbol, aliases::KW, options::AVec, plot
end
end
function aliases(aliasMap::KW, val)
function aliases(aliasMap::Dict{Symbol,Symbol}, val)
sortedkeys(filter((k,v)-> v==val, aliasMap))
end
@@ -367,7 +393,8 @@ add_aliases(:linestyle, :style, :s, :ls)
add_aliases(:marker, :m, :mark)
add_aliases(:markershape, :shape)
add_aliases(:markersize, :ms, :msize)
add_aliases(:marker_z, :markerz, :zcolor)
add_aliases(:marker_z, :markerz, :zcolor, :mz)
add_aliases(:line_z, :linez, :zline, :lz)
add_aliases(:fill, :f, :area)
add_aliases(:fillrange, :fillrng, :frange, :fillto, :fill_between)
add_aliases(:group, :g, :grouping)
@@ -388,14 +415,13 @@ add_aliases(:zticks, :ztick)
add_aliases(:zrotation, :zrot, :zr)
add_aliases(:legend, :leg, :key)
add_aliases(:colorbar, :cb, :cbar, :colorkey)
add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits)
add_aliases(:smooth, :regression, :reg)
add_aliases(:levels, :nlevels, :nlev, :levs)
add_aliases(:size, :windowsize, :wsize)
add_aliases(:window_title, :windowtitle, :wtitle)
add_aliases(:show, :gui, :display)
add_aliases(:color_palette, :palette)
# add_aliases(:linkx, :xlink)
# add_aliases(:linky, :ylink)
add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse)
add_aliases(:xerror, :xerr, :xerrorbar)
add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
@@ -408,6 +434,8 @@ add_aliases(:projection, :proj)
add_aliases(:title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation)
add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir)
add_aliases(:inset_subplots, :inset, :floating)
# add all pluralized forms to the _keyAliases dict
@@ -470,7 +498,8 @@ function handleColors!(d::KW, arg, csym::Symbol)
if arg == :auto
d[csym] = :auto
else
c = colorscheme(arg)
# c = colorscheme(arg)
c = plot_color(arg)
d[csym] = c
end
return true
@@ -491,13 +520,13 @@ function processLineArg(d::KW, arg)
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[:linewidth] = arg.width)
arg.color == nothing || (d[:linecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.color == nothing || (d[:linecolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:linealpha] = arg.alpha)
arg.style == nothing || (d[:linestyle] = arg.style)
elseif typeof(arg) <: Brush
arg.size == nothing || (d[:fillrange] = arg.size)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows)
@@ -530,13 +559,13 @@ function processMarkerArg(d::KW, arg)
elseif typeof(arg) <: Stroke
arg.width == nothing || (d[:markerstrokewidth] = arg.width)
arg.color == nothing || (d[:markerstrokecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.color == nothing || (d[:markerstrokecolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:markerstrokealpha] = arg.alpha)
arg.style == nothing || (d[:markerstrokestyle] = arg.style)
elseif typeof(arg) <: Brush
arg.size == nothing || (d[:markersize] = arg.size)
arg.color == nothing || (d[:markercolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.color == nothing || (d[:markercolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:markeralpha] = arg.alpha)
# linealpha
@@ -556,14 +585,15 @@ end
function processFillArg(d::KW, arg)
fr = get(d, :fillrange, 0)
if typeof(arg) <: Brush
arg.size == nothing || (d[:fillrange] = arg.size)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.size == nothing || (fr = arg.size)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
# fillrange function
elseif allFunctions(arg)
d[:fillrange] = arg
fr = arg
# fillalpha
elseif allAlphas(arg)
@@ -571,8 +601,10 @@ function processFillArg(d::KW, arg)
elseif !handleColors!(d, arg, :fillcolor)
d[:fillrange] = arg
fr = arg
end
d[:fillrange] = fr
return
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
@@ -622,7 +654,7 @@ function preprocessArgs!(d::KW)
if haskey(d, :markershape)
d[:markershape] = _replace_markershape(d[:markershape])
elseif anymarker
d[:markershape_to_add] = :ellipse # add it after _apply_recipe
d[:markershape_to_add] = :circle # add it after _apply_recipe
end
# handle fill
@@ -659,21 +691,13 @@ function preprocessArgs!(d::KW)
d[:colorbar] = convertLegendValue(d[:colorbar])
end
# # handle subplot links
# if haskey(d, :link)
# l = d[:link]
# if isa(l, Bool)
# d[:linkx] = l
# d[:linky] = l
# elseif isa(l, Function)
# d[:linkx] = true
# d[:linky] = true
# d[:linkfunc] = l
# else
# warn("Unhandled/invalid link $l. Should be a Bool or a function mapping (row,column) -> (linkx, linky), where linkx/y can be Bool or Void (nothing)")
# end
# delete!(d, :link)
# end
# warnings for moved recipes
st = get(d, :seriestype, :path)
if st in (:boxplot, :violin, :density) && !isdefined(Main, :StatPlots)
warn("seriestype $st has been moved to StatPlots. To use: \`Pkg.add(\"StatPlots\"); using StatPlots\`")
end
return
end
# -----------------------------------------------------------------------------
@@ -689,7 +713,7 @@ end
function extractGroupArgs(v::AVec, args...)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 20
if n > 100
warn("You created n=$n groups... Is that intended?")
end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
@@ -723,37 +747,46 @@ end
# -----------------------------------------------------------------------------
function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW)
const _already_warned = Set()
function warnOnUnsupported_args(pkg::AbstractBackend, d::KW)
for k in sortedkeys(d)
k in supportedArgs(pkg) && continue
k in supported_args(pkg) && continue
k in _suppress_warnings && continue
if d[k] != default(k)
warn("Keyword argument $k not supported with $pkg. Choose from: $(supportedArgs(pkg))")
if !((pkg, k) in _already_warned)
push!(_already_warned, (pkg,k))
warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_args(pkg))")
end
end
end
end
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supportedMarkers(pkg)
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supportedMarkers(pkg)
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supported_markers(pkg)
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
_markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
(d[:seriestype] == :none
|| d[:seriestype] in supportedTypes(pkg)
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))"))
(d[:linestyle] in supportedStyles(pkg)
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
|| d[:seriestype] in supported_types(pkg)
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_types(pkg))"))
(d[:linestyle] in supported_styles(pkg)
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))"))
(d[:markershape] == :none
|| _markershape_supported(pkg, d[:markershape])
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))"))
end
function warnOnUnsupportedScales(pkg::AbstractBackend, d::KW)
for k in (:xscale, :yscale)
if haskey(d, k)
d[k] in supportedScales(pkg) || warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supportedScales(pkg))")
function warnOnUnsupported_scales(pkg::AbstractBackend, d::KW)
for k in (:xscale, :yscale, :zscale)
if haskey(d, k)
v = d[k]
v = get(_scaleAliases, v, v)
if !(v in supported_scales(pkg))
warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
end
end
end
end
end
@@ -771,6 +804,7 @@ function convertLegendValue(val::Symbol)
end
end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none
# -----------------------------------------------------------------------------
@@ -790,9 +824,9 @@ slice_arg(v, idx) = v
# given an argument key (k), we want to extract the argument value for this index.
# matrices are sliced by column, otherwise we
# if nothing is set (or container is empty), return the default or the existing value.
function slice_arg!(d_in::KW, d_out::KW, k::Symbol, default_value, idx::Int = 1; new_key::Symbol = k, remove_pair::Bool = true)
v = get(d_in, k, get(d_out, new_key, default_value))
d_out[new_key] = if haskey(d_in, k) && typeof(v) <: AMat && !isempty(v)
function slice_arg!(d_in::KW, d_out::KW, k::Symbol, default_value, idx::Int, remove_pair::Bool)
v = get(d_in, k, get(d_out, k, default_value))
d_out[k] = if haskey(d_in, k) && typeof(v) <: AMat && !isempty(v)
slice_arg(v, idx)
else
v
@@ -800,6 +834,7 @@ function slice_arg!(d_in::KW, d_out::KW, k::Symbol, default_value, idx::Int = 1;
if remove_pair
delete!(d_in, k)
end
return
end
# -----------------------------------------------------------------------------
@@ -811,7 +846,7 @@ end
# d[k] = if v == :match
# match_color
# elseif v == nothing
# colorscheme(RGBA(0,0,0,0))
# plot_color(RGBA(0,0,0,0))
# else
# v
# end
@@ -820,10 +855,13 @@ end
function color_or_nothing!(d::KW, k::Symbol)
v = d[k]
d[k] = if v == nothing || v == false
colorscheme(RGBA(0,0,0,0))
RGBA{Float64}(0,0,0,0)
elseif v != :match
plot_color(v)
else
v
end
return
end
# -----------------------------------------------------------------------------
@@ -892,128 +930,254 @@ function Base.getindex(axis::Axis, k::Symbol)
end
end
function Base.getindex(series::Series, k::Symbol)
series.d[k]
end
Base.setindex!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
Base.setindex!(sp::Subplot, v, k::Symbol) = (sp.attr[k] = v)
Base.setindex!(axis::Axis, v, k::Symbol) = (axis.d[k] = v)
Base.setindex!(series::Series, v, k::Symbol) = (series.d[k] = v)
Base.get(plt::Plot, k::Symbol, v) = get(plt.attr, k, v)
Base.get(sp::Subplot, k::Symbol, v) = get(sp.attr, k, v)
Base.get(axis::Axis, k::Symbol, v) = get(axis.d, k, v)
Base.get(series::Series, k::Symbol, v) = get(series.d, k, v)
# -----------------------------------------------------------------------------
# update attr from an input dictionary
function _update_plot_args(plt::Plot, d_in::KW)
pargs = plt.attr
for (k,v) in _plot_defaults
slice_arg!(d_in, pargs, k, v)
slice_arg!(d_in, plt.attr, k, v, 1, true)
end
# handle colors
bg = convertColor(pargs[:background_color])
fg = pargs[:foreground_color]
bg = plot_color(plt.attr[:background_color])
fg = plt.attr[:foreground_color]
if fg == :auto
fg = isdark(bg) ? colorant"white" : colorant"black"
end
pargs[:background_color] = bg
pargs[:foreground_color] = convertColor(fg)
# color_or_match!(pargs, :background_color_outside, bg)
color_or_nothing!(pargs, :background_color_outside)
plt.attr[:background_color] = bg
plt.attr[:foreground_color] = plot_color(fg)
color_or_nothing!(plt.attr, :background_color_outside)
end
# -----------------------------------------------------------------------------
# update a subplots args and axes
function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::Integer; remove_pair = true)
pargs = plt.attr
spargs = sp.attr
anns = pop!(sp.attr, :annotations, [])
# grab those args which apply to this subplot
for (k,v) in _subplot_defaults
slice_arg!(d_in, spargs, k, v, subplot_index, remove_pair = remove_pair)
end
function _update_subplot_periphery(sp::Subplot, anns::AVec)
# extend annotations
sp.attr[:annotations] = vcat(anns, sp[:annotations])
# handle legend/colorbar
spargs[:legend] = convertLegendValue(spargs[:legend])
spargs[:colorbar] = convertLegendValue(spargs[:colorbar])
if spargs[:colorbar] == :legend
spargs[:colorbar] = spargs[:legend]
sp.attr[:legend] = convertLegendValue(sp.attr[:legend])
sp.attr[:colorbar] = convertLegendValue(sp.attr[:colorbar])
if sp.attr[:colorbar] == :legend
sp.attr[:colorbar] = sp.attr[:legend]
end
return
end
function _update_subplot_colors(sp::Subplot)
# background colors
# bg = color_or_match!(spargs, :background_color_subplot, pargs[:background_color])
color_or_nothing!(spargs, :background_color_subplot)
bg = sp[:background_color_subplot]
spargs[:color_palette] = get_color_palette(spargs[:color_palette], bg, 30)
# color_or_match!(spargs, :background_color_legend, bg)
color_or_nothing!(spargs, :background_color_legend)
# color_or_match!(spargs, :background_color_inside, bg)
color_or_nothing!(spargs, :background_color_inside)
color_or_nothing!(sp.attr, :background_color_subplot)
bg = plot_color(sp[:background_color_subplot])
sp.attr[:color_palette] = get_color_palette(sp.attr[:color_palette], bg, 30)
color_or_nothing!(sp.attr, :background_color_legend)
color_or_nothing!(sp.attr, :background_color_inside)
# foreground colors
# fg = color_or_match!(spargs, :foreground_color_subplot, pargs[:foreground_color])
color_or_nothing!(spargs, :foreground_color_subplot)
# color_or_match!(spargs, :foreground_color_legend, fg)
color_or_nothing!(spargs, :foreground_color_legend)
# color_or_match!(spargs, :foreground_color_grid, fg)
color_or_nothing!(spargs, :foreground_color_grid)
# color_or_match!(spargs, :foreground_color_title, fg)
color_or_nothing!(spargs, :foreground_color_title)
color_or_nothing!(sp.attr, :foreground_color_subplot)
color_or_nothing!(sp.attr, :foreground_color_legend)
color_or_nothing!(sp.attr, :foreground_color_grid)
color_or_nothing!(sp.attr, :foreground_color_title)
return
end
# for k in (:left_margin, :top_margin, :right_margin, :bottom_margin)
# if spargs[k] == :match
# spargs[k] = spargs[:margin]
# end
# end
function _update_axis(plt::Plot, sp::Subplot, d_in::KW, letter::Symbol, subplot_index::Int)
# get (maybe initialize) the axis
axis = get_axis(sp, letter)
_update_axis(axis, d_in, letter, subplot_index)
# convert a bool into auto or nothing
if isa(axis[:ticks], Bool)
axis[:ticks] = axis[:ticks] ? :auto : nothing
end
_update_axis_colors(axis)
_update_axis_links(plt, axis, letter)
return
end
function _update_axis(axis::Axis, d_in::KW, letter::Symbol, subplot_index::Int)
# grab magic args (for example `xaxis = (:flip, :log)`)
args = wraptuple(get(d_in, Symbol(letter, :axis), ()))
# build the KW of arguments from the letter version (i.e. xticks --> ticks)
kw = KW()
for (k,v) in _axis_defaults
# first get the args without the letter: `tickfont = font(10)`
# note: we don't pop because we want this to apply to all axes! (delete after all have finished)
if haskey(d_in, k)
kw[k] = slice_arg(d_in[k], subplot_index)
end
# then get those args that were passed with a leading letter: `xlabel = "X"`
lk = Symbol(letter, k)
if haskey(d_in, lk)
kw[k] = slice_arg(d_in[lk], subplot_index)
end
end
# update the axis
update!(axis, args...; kw...)
return
end
function _update_axis_colors(axis::Axis)
# # update the axis colors
color_or_nothing!(axis.d, :foreground_color_axis)
color_or_nothing!(axis.d, :foreground_color_border)
color_or_nothing!(axis.d, :foreground_color_guide)
color_or_nothing!(axis.d, :foreground_color_text)
return
end
function _update_axis_links(plt::Plot, axis::Axis, letter::Symbol)
# handle linking here. if we're passed a list of
# other subplots to link to, link them together
link = axis[:link]
if !isempty(link)
for other_sp in link
other_sp = get_subplot(plt, other_sp)
link_axes!(axis, get_axis(other_sp, letter))
end
axis.d[:link] = []
end
return
end
# update a subplots args and axes
function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::Int, remove_pair::Bool)
anns = pop!(sp.attr, :annotations, [])
# grab those args which apply to this subplot
for (k,v) in _subplot_defaults
slice_arg!(d_in, sp.attr, k, v, subplot_index, remove_pair)
end
_update_subplot_periphery(sp, anns)
_update_subplot_colors(sp)
for letter in (:x, :y, :z)
# get (maybe initialize) the axis
axissym = Symbol(letter, :axis)
axis = if haskey(spargs, axissym)
spargs[axissym]
else
spargs[axissym] = Axis(sp, letter)
end
# grab magic args (for example `xaxis = (:flip, :log)`)
args = wraptuple(get(d_in, axissym, ()))
# build the KW of arguments from the letter version (i.e. xticks --> ticks)
kw = KW()
# DD(d_in, "d_in before")
for (k,v) in _axis_defaults
# first get the args without the letter: `tickfont = font(10)`
# note: we don't pop because we want this to apply to all axes! (delete after all have finished)
if haskey(d_in, k)
kw[k] = slice_arg(d_in[k], subplot_index)
end
# then get those args that were passed with a leading letter: `xlabel = "X"`
lk = Symbol(letter, k)
if haskey(d_in, lk)
kw[k] = slice_arg(pop!(d_in, lk), subplot_index)
end
end
# update the axis
update!(axis, args...; kw...)
# # update the axis colors
# color_or_match!(axis.d, :foreground_color_axis, fg)
color_or_nothing!(axis.d, :foreground_color_axis)
# color_or_match!(axis.d, :foreground_color_border, fg)
color_or_nothing!(axis.d, :foreground_color_border)
# color_or_match!(axis.d, :foreground_color_guide, fg)
color_or_nothing!(axis.d, :foreground_color_guide)
# color_or_match!(axis.d, :foreground_color_text, fg)
color_or_nothing!(axis.d, :foreground_color_text)
# TODO: need to handle linking here?
end
# now we can get rid of the axis keys without a letter
for k in keys(_axis_defaults)
delete!(d_in, k)
_update_axis(plt, sp, d_in, letter, subplot_index)
end
end
# -----------------------------------------------------------------------------
function has_black_border_for_default(st::Symbol)
like_histogram(st) || st in (:hexbin, :bar)
like_histogram(st) || st in (:hexbin, :bar, :shape)
end
# 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
plot_color(c, α)
end
function ensure_gradient!(d::KW, csym::Symbol, asym::Symbol)
if !isa(d[csym], ColorGradient)
d[csym] = cgrad(alpha = d[asym])
end
end
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
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, 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, supported_styles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex)
# update alphas
for asym in (:linealpha, :markeralpha, :fillalpha)
if d[asym] == nothing
d[asym] = d[:seriesalpha]
end
end
if d[:markerstrokealpha] == nothing
d[:markerstrokealpha] = d[:markeralpha]
end
# update series color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], d[:seriesalpha], sp, plotIndex)
# update other colors
for s in (:line, :marker, :fill)
csym, asym = Symbol(s,:color), Symbol(s,:alpha)
d[csym] = if d[csym] == :match
plot_color(if has_black_border_for_default(d[:seriestype]) && s == :line
sp[:foreground_color_subplot]
else
d[:seriescolor]
end, d[asym])
else
getSeriesRGBColor(d[csym], d[asym], sp, plotIndex)
end
end
# update markerstrokecolor
d[:markerstrokecolor] = if d[:markerstrokecolor] == :match
plot_color(sp[:foreground_color_subplot], d[:markerstrokealpha])
else
getSeriesRGBColor(d[:markerstrokecolor], d[:markerstrokealpha], sp, plotIndex)
end
# if marker_z or line_z are set, ensure we have a gradient
if d[:marker_z] != nothing
ensure_gradient!(d, :markercolor, :markeralpha)
end
if d[:line_z] != nothing
ensure_gradient!(d, :linecolor, :linealpha)
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] = :circle
end
end
# set label
label = d[:label]
label = (label == "AUTO" ? "y$globalIndex" : label)
d[:label] = label
_replace_linewidth(d)
d
end
+38 -11
View File
@@ -32,6 +32,15 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
update!(Axis(sp, d), args...; kw...)
end
function get_axis(sp::Subplot, letter::Symbol)
axissym = Symbol(letter, :axis)
if haskey(sp.attr, axissym)
sp.attr[axissym]
else
sp.attr[axissym] = Axis(sp, letter)
end::Axis
end
function process_axis_arg!(d::KW, arg, letter = "")
T = typeof(arg)
arg = get(_scaleAliases, arg, arg)
@@ -91,6 +100,12 @@ function update!(axis::Axis, args...; kw...)
end
end
end
# replace scale aliases
if haskey(_scaleAliases, d[:scale])
d[:scale] = _scaleAliases[d[:scale]]
end
axis
end
@@ -107,7 +122,14 @@ function get_ticks(axis::Axis)
ticks = axis[:ticks]
dvals = axis[:discrete_values]
if !isempty(dvals) && ticks == :auto
axis[:continuous_values], dvals
cv, dv = axis[:continuous_values], dvals
# TODO: better/smarter cutoff values for sampling ticks
if length(cv) > 30
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
cv[rng], dv[rng]
else
cv, dv
end
else
ticks
end
@@ -144,16 +166,18 @@ function expand_extrema!(sp::Subplot, d::KW)
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
if eltype(data) <: Number || (isa(data, Surface) && all(di -> isa(di, Number), data.surf))
if !(eltype(data) <: Number)
# huh... must have been a mis-typed surface? lets swap it out
data = d[letter] = Surface(Matrix{Float64}(data.surf))
end
expand_extrema!(axis, data)
elseif data != nothing
# TODO: need more here... gotta track the discrete reference value
# as well as any coord offset (think of boxplot shape coords... they all
# correspond to the same x-value)
# @show letter,eltype(data),typeof(data)
d[letter], d[Symbol(letter,"_discrete_indices")] = discrete_value!(axis, data)
expand_extrema!(axis, d[letter])
end
end
@@ -213,12 +237,15 @@ function widen(lmin, lmax)
lmin-eps, lmax+eps
end
# figure out if widening is a good idea
# figure out if widening is a good idea. if there's a scale set it's too tricky,
# so lazy out and don't widen
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
if axis[:scale] == :identity
for series in series_list(axis.sp)
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
should_widen = true
end
end
end
should_widen
@@ -229,7 +256,7 @@ 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 (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
if isfinite(lims[1])
amin = lims[1]
end
@@ -237,7 +264,7 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
amax = lims[2]
end
end
if amax <= amin
if amax <= amin && isfinite(amin)
amax = amin + 1.0
end
if should_widen
+71 -19
View File
@@ -57,13 +57,26 @@ _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
# TODO: this should account for both tick font and the size/length/rotation of tick labels
function tick_padding(axis::Axis)
ptsz = axis[:tickfont].pointsize * pt
if axis[:ticks] in (nothing,false)
0mm
elseif axis[:letter] == :x
2mm + ptsz
else
8mm
end
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)
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])
# TODO: something different when `is3d(sp) == true`
leftpad = tick_padding(sp[:yaxis]) + sp[:left_margin] + guide_padding(sp[:yaxis])
toppad = sp[:top_margin] + title_padding(sp)
rightpad = sp[:right_margin]
bottompad = tick_padding(sp[:xaxis]) + sp[:bottom_margin] + guide_padding(sp[:xaxis])
# @show (leftpad, toppad, rightpad, bottompad)
sp.minpad = (leftpad, toppad, rightpad, bottompad)
end
@@ -169,22 +182,61 @@ 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)
supported_types(::AbstractBackend) = []
supported_styles(::AbstractBackend) = [:solid]
supported_markers(::AbstractBackend) = [:none]
supported_scales(::AbstractBackend) = [:identity]
is_subplot_supported(::AbstractBackend) = false
is_string_supported(::AbstractBackend) = false
nativeImagesSupported(b::AbstractBackend) = :image in supported_types(b)
supportedAxes() = supportedAxes(backend())
supportedTypes() = supportedTypes(backend())
supportedStyles() = supportedStyles(backend())
supportedMarkers() = supportedMarkers(backend())
supportedScales() = supportedScales(backend())
subplotSupported() = subplotSupported(backend())
stringsSupported() = stringsSupported(backend())
supported_types() = supported_types(backend())
supported_styles() = supported_styles(backend())
supported_markers() = supported_markers(backend())
supported_scales() = supported_scales(backend())
is_subplot_supported() = is_subplot_supported(backend())
is_string_supported() = is_string_supported(backend())
nativeImagesSupported() = nativeImagesSupported(backend())
# ---------------------------------------------------------
# these are args which every backend supports because they're not used in the backend code
const _base_supported_args = [
:color_palette,
:background_color, :background_color_subplot,
:foreground_color, :foreground_color_subplot,
:group,
:seriestype,
:seriescolor, :seriesalpha,
:smooth,
:xerror, :yerror,
:subplot,
:x, :y, :z,
:show, :size,
:margin,
:left_margin,
:right_margin,
:top_margin,
:bottom_margin,
:html_output_format,
:layout,
:link,
:primary,
:series_annotations,
:subplot_index,
:discrete_values,
:projection,
]
function merge_with_base_supported(v::AVec)
v = vcat(v, _base_supported_args)
for vi in v
if haskey(_axis_defaults, vi)
for letter in (:x,:y,:z)
push!(v, Symbol(letter,vi))
end
end
end
v
end
+9 -10
View File
@@ -2,7 +2,7 @@
# https://github.com/bokeh/Bokeh.jl
supportedArgs(::BokehBackend) = [
supported_args(::BokehBackend) = merge_with_base_supported([
# :annotations,
# :axis,
# :background_color,
@@ -58,13 +58,12 @@ supportedArgs(::BokehBackend) = [
# :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
])
supported_types(::BokehBackend) = [:path, :scatter]
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::BokehBackend) = [:identity, :ln]
is_subplot_supported(::BokehBackend) = false
# --------------------------------------------------------------------------------------
@@ -81,7 +80,7 @@ end
const _glyphtypes = KW(
:ellipse => :Circle,
:circle => :Circle,
:rect => :Square,
:diamond => :Diamond,
:utriangle => :Triangle,
@@ -100,7 +99,7 @@ function bokeh_glyph_type(d::KW)
st = d[:seriestype]
mt = d[:markershape]
if st == :scatter && mt == :none
mt = :ellipse
mt = :circle
end
# if we have a marker, use that
+12 -14
View File
@@ -2,7 +2,7 @@
# https://github.com/dcjones/Gadfly.jl
supportedArgs(::GadflyBackend) = [
supported_args(::GadflyBackend) = merge_with_base_supported([
:annotations,
:background_color, :foreground_color, :color_palette,
:group, :label, :seriestype,
@@ -15,7 +15,6 @@ supportedArgs(::GadflyBackend) = [
: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,
@@ -23,18 +22,17 @@ supportedArgs(::GadflyBackend) = [
: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
])
supported_types(::GadflyBackend) = [
:path,
:scatter, :hexbin,
:bar,
: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
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
is_subplot_supported(::GadflyBackend) = true
# --------------------------------------------------------------------------------------
@@ -303,7 +301,7 @@ function addGadflySeries!(plt::Plot, d::KW)
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
d[:markershape] = :circle
end
# markers
+1 -1
View File
@@ -84,7 +84,7 @@ function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray,
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)]
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
end
Gadfly.polygon(polys, geom.tag)
end
+290 -107
View File
@@ -2,135 +2,318 @@
# [WEBSITE]
supportedArgs(::GLVisualizeBackend) = [
supported_args(::GLVisualizeBackend) = merge_with_base_supported([
# :annotations,
# :axis,
# :background_color,
# :color_palette,
# :fillrange,
# :fillcolor,
# :fillalpha,
# :foreground_color,
# :group,
# :background_color_legend, :background_color_inside, :background_color_outside,
# :foreground_color_grid, :foreground_color_legend, :foreground_color_title,
# :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
# :label,
# :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,
# :linecolor, :linestyle, :linewidth, :linealpha,
# :markershape, :markercolor, :markersize, :markeralpha,
# :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
# :fillrange, :fillcolor, :fillalpha,
# :bins, :bar_width, :bar_edges, :bar_position,
# :title, :title_location, :titlefont,
# :window_title,
# :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
# :guide, :lims, :ticks, :scale, :flip, :rotation,
# :tickfont, :guidefont, :legendfont,
# :grid, :legend, :colorbar,
# :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
# :polar,
# :normalize, :weights,
# :contours, :aspect_ratio,
# :match_dimensions,
# :clims,
# :inset_subplots,
])
supported_types(::GLVisualizeBackend) = [:surface, :scatter, :scatter3d, :path, :path3d, :shape]
supported_styles(::GLVisualizeBackend) = [:auto, :solid]
supported_markers(::GLVisualizeBackend) = vcat([:none, :auto, :circle], collect(keys(_gl_marker_map)))
supported_scales(::GLVisualizeBackend) = [:identity]
is_subplot_supported(::GLVisualizeBackend) = true
# --------------------------------------------------------------------------------------
function _initialize_backend(::GLVisualizeBackend; kw...)
@eval begin
import GLVisualize
export GLVisualize
end
@eval begin
import GLVisualize, GeometryTypes, GLAbstraction, GLWindow
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0
export GLVisualize
# # TODO: remove this when PlotUtils is registered
# import PlotUtils
end
end
# ---------------------------------------------------------------------------
immutable GLScreenWrapper
window
end
# function _create_plot(pkg::GLVisualizeBackend, d::KW)
# initialize the figure/window
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
# init a screen
screen = if isdefined(GLVisualize, :ROOT_SCREEN)
GLVisualize.ROOT_SCREEN
else
s = GLVisualize.glscreen()
@async GLVisualize.renderloop(s)
s
end
empty!(screen)
screen
end
# 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[])
# ---------------------------------------------------------------------------
# size as a percentage of the window size
function gl_relative_size(plt::Plot{GLVisualizeBackend}, msize::Number)
winsz = min(plt[:size]...)
Float32(msize / winsz)
end
const _gl_marker_map = KW(
:rect => '■',
:star5 => '★',
:diamond => '◆',
:hexagon => '⬢',
:cross => '✚',
:xcross => '❌',
:utriangle => '▲',
:dtriangle => '▼',
:pentagon => '⬟',
:octagon => '⯄',
:star4 => '✦',
:star6 => '✶',
:star8 => '✷',
:vline => '┃',
:hline => '━',
)
# create a marker/shape type
function gl_marker(shape::Symbol, msize::Number, _3d::Bool)
GeometryTypes.HyperSphere((_3d ? Point3f0 : Point2f0)(0), msize)
end
gl_color(c::RGBA{Float32}) = c
# convert to RGBA
function gl_color(c, a=nothing)
@show c, a
c = convertColor(c, a)
@show c
RGBA{Float32}(c)
end
function gl_viewport(bb, rect)
l, b, bw, bh = bb
rw, rh = rect.w, rect.h
GLVisualize.SimpleRectangle(
round(Int, rect.x + rw * l),
round(Int, rect.y + rh * b),
round(Int, rw * bw),
round(Int, rh * bh)
)
end
gl_make_points(x, y) = Point2f0[Point2f0(x[i], y[i]) for i=1:length(x)]
gl_make_points(x, y, z) = Point3f0[Point3f0(x[i], y[i], z[i]) for i=1:length(x)]
function gl_draw_lines_2d(x, y, color, linewidth, sp_screen)
color = gl_color(color)
thickness = Float32(linewidth)
for rng in iter_segments(x, y)
n = length(rng)
n < 2 && continue
pts = gl_make_points(x[rng], y[rng])
@show pts, n
viz = GLVisualize.visualize(
pts,
n==2 ? :linesegment : :lines,
color = color,
thickness = thickness
)
GLVisualize.view(viz, sp_screen, camera=:orthographic_pixel)
end
end
function gl_draw_lines_3d(x, y, z, color, linewidth, sp_screen)
color = gl_color(color)
thickness = Float32(linewidth)
for rng in iter_segments(x, y, z)
n = length(rng)
n < 2 && continue
pts = gl_make_points(x[rng], y[rng], z[rng])
viz = GLVisualize.visualize(
pts,
n==2 ? :linesegment : :lines,
color=color,
thickness = thickness
)
GLVisualize.view(viz, sp_screen, camera=:perspective)
end
end
function gl_annotate(sp::Subplot{GLVisualizeBackend}, x, y, txt::PlotText)
end
function gl_draw_axes_2d(sp::Subplot{GLVisualizeBackend})
sp_screen = sp.o
xaxis = sp[:xaxis]
xmin, xmax = axis_limits(xaxis)
yaxis = sp[:yaxis]
ymin, ymax = axis_limits(yaxis)
# x axis
xsegs, ysegs = Segments(), Segments()
ticksz = 0.03*(ymax-ymin)
push!(xsegs, [xmin,xmax]); push!(ysegs, [ymin,ymin])
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
push!(xsegs, [tick,tick]); push!(ysegs, [ymin,ymin+ticksz])
# TODO: add the ticklabel
end
gl_draw_lines_2d(xsegs.pts, ysegs.pts, xaxis[:foreground_color_border], 1, sp_screen)
# y axis
xsegs, ysegs = Segments(), Segments()
push!(xsegs, [xmin,xmin]); push!(ysegs, [ymin,ymax])
for tick in PlotUtils.optimize_ticks(xmin, xmax)[1]
push!(xsegs, [xmin,xmin+ticksz]); push!(ysegs, [tick,tick])
# TODO: add the ticklabel
end
gl_draw_lines_2d(xsegs.pts, ysegs.pts, yaxis[:foreground_color_border], 1, sp_screen)
end
# ---------------------------------------------------------------------------
# draw everything
function gl_display(plt::Plot{GLVisualizeBackend})
screen = plt.o
sw, sh = plt[:size]
sw, sh = sw*px, sh*px
for (name, sp) in plt.spmap
_3d = is3d(sp)
camera = _3d ? :perspective : :orthographic_pixel
# camera = :perspective
# initialize the sub-screen for this subplot
# note: we create a lift function to update the size on resize
rel_bbox = bbox_to_pcts(bbox(sp), sw, sh)
f = rect -> gl_viewport(rel_bbox, rect)
sp_screen = GLVisualize.Screen(
screen,
name = name,
area = GLVisualize.const_lift(f, screen.area)
)
sp.o = sp_screen
if !is3d(sp)
# gl_draw_axes_2d(sp)
end
# loop over the series and add them to the subplot
for series in series_list(sp)
d = series.d
st = d[:seriestype]
x, y = map(Float32, d[:x]), map(Float32, d[:y])
msize = gl_relative_size(plt, d[:markersize])
if st == :surface
# TODO: can pass just the ranges and surface
ismatrix(x) || (x = repmat(x', length(y), 1))
ismatrix(y) || (y = repmat(y, 1, length(x)))
z = transpose_z(d, map(Float32, d[:z].surf), false)
viz = GLVisualize.visualize((x, y, z), :surface)
GLVisualize.view(viz, sp_screen, camera = camera)
else
# paths, scatters, and shape
_3d && (z = map(Float32, d[:z]))
# paths?
lw = d[:linewidth]
if lw > 0
c = gl_color(d[:linecolor], d[:linealpha])
if _3d
gl_draw_lines_3d(x, y, z, c, lw, sp_screen)
else
gl_draw_lines_2d(x, y, c, lw, sp_screen)
end
end
# markers?
if st in (:scatter, :scatter3d) || d[:markershape] != :none
extrakw = KW()
c = gl_color(d[:markercolor], d[:markeralpha])
# get the marker
shape = d[:markershape]
shape = get(_gl_marker_map, shape, shape)
marker = if isa(shape, Char)
# extrakw[:scale] = Vec2f0(_3d ? 0.6*d[:markersize] : msize)
extrakw[:scale] = Vec2f0(msize)
shape
else
gl_marker(d[:markershape], msize, _3d)
end
if !_3d
extrakw[:billboard] = true
end
points = _3d ? gl_make_points(x,y,z) : gl_make_points(x,y)
viz = GLVisualize.visualize(
(marker, points);
color = c,
extrakw...
)
GLVisualize.view(viz, sp_screen, camera = camera)
# TODO: might need to switch to these forms later?
# GLVisualize.visualize((marker ,(x, y, z)))
#GLVisualize.visualize((marker , map(Point3f0, zip(x, y, z),
# billboard=true
#))
end
if st == :shape
for rng in iter_segments(x, y)
pts = Point2f0[Point2f0(x[i], y[i]) for i in rng]
@show pts
mesh = GeometryTypes.GLNormalMesh(pts)
@show mesh
if !isempty(GeometryTypes.faces(mesh))
viz = GLVisualize.visualize(
mesh,
color = gl_color(d[:fillcolor], d[:fillalpha])
)
GLVisualize.view(viz, sp_screen, camera = camera)
end
end
end
end
end
GLAbstraction.center!(sp_screen, camera)
end
# TODO: render one frame at a time? (no renderloop)
# GLWindow.render_frame(screen)
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
gl_display(plt)
end
# ----------------------------------------------------------------
function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
# TODO: write a png to io
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
+397 -820
View File
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -1,13 +1,12 @@
# 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
supported_args(::ImmerseBackend) = supported_args(GadflyBackend())
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
is_subplot_supported(::ImmerseBackend) = true
# --------------------------------------------------------------------------------------
+68 -45
View File
@@ -2,39 +2,28 @@
# significant contributions by: @pkofod
supportedArgs(::PGFPlotsBackend) = [
supported_args(::PGFPlotsBackend) = merge_with_base_supported([
# :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,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
: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,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
# :colorbar,
# :marker_z, :levels,
# :xerror, :yerror,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
@@ -42,23 +31,22 @@ supportedArgs(::PGFPlotsBackend) = [
# :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
])
supported_types(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
supported_styles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
supported_markers(::PGFPlotsBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
supported_scales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10]
is_subplot_supported(::PGFPlotsBackend) = false
# --------------------------------------------------------------------------------------
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
end
@eval begin
import PGFPlots
export PGFPlots
end
end
@@ -78,7 +66,7 @@ const _pgfplots_markers = KW(
:xcross => "x",
:utriangle => "triangle*",
:dtriangle => "triangle*",
:ellipse => "*",
:circle => "*",
:rect => "square*",
:star5 => "star",
:star6 => "asterisk",
@@ -106,20 +94,18 @@ const _pgf_series_extrastyle = KW(
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
function pgf_color(c, a = nothing)
c = getColor(c)
function pgf_color(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
cstr, alpha(c)
end
function pgf_fillstyle(d::KW)
cstr,a = pgf_color(d[:fillcolor], d[:fillalpha])
cstr,a = pgf_color(d[:fillcolor])
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d::KW)
cstr,a = pgf_color(d[:linecolor], d[:linealpha])
cstr,a = pgf_color(d[:linecolor])
"""
color = $cstr,
draw opacity=$a,
@@ -129,8 +115,8 @@ 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])
cstr, a = pgf_color(d[:markercolor])
cstr_stroke, a_stroke = pgf_color(d[:markerstrokecolor])
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(0.5 * d[:markersize]),
@@ -145,7 +131,6 @@ end
# --------------------------------------------------------------------------------------
function pgf_series(sp::Subplot, series::Series)
d = series.d
st = d[:seriestype]
@@ -173,6 +158,18 @@ function pgf_series(sp::Subplot, series::Series)
d[:x], d[:y]
end
# PGFPlots can't handle non-Vector?
args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
collect(a)
else
a
end, args)
# for (i,a) in enumerate(args)
# if typeof(a) <: AbstractVector && typeof(a) != Vector
# args[i] = collect(a)
# end
# end
# include additional style, then add to the kw
if haskey(_pgf_series_extrastyle, st)
push!(style, _pgf_series_extrastyle[st])
@@ -216,9 +213,12 @@ function pgf_axis(sp::Subplot, letter)
end
# limits
lims = axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
# TODO: support zlims
if letter != :z
lims = axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2]
end
# return the style list and KW args
style, kw
@@ -281,16 +281,39 @@ end
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
writemime(io, mime, plt.o)
_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)
function _writemime(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
# prepare the object
pgfplt = PGFPlots.plot(plt.o)
# save a pdf
fn = tempname()*".pdf"
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
# read it into io
write(io, readall(open(fn)))
# cleanup
PGFPlots.cleanup(plt.o)
end
function _display(plt::Plot{PGFPlotsBackend})
_make_pgf_plot!(plt)
display(plt.o)
# prepare the object
_make_pgf_plot!(plt)
pgfplt = PGFPlots.plot(plt.o)
# save an svg
fn = string(tempname(), ".svg")
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
# show it
open_browser_window(fn)
# cleanup
PGFPlots.cleanup(plt.o)
end
+205 -158
View File
@@ -1,49 +1,48 @@
# https://plot.ly/javascript/getting-started
supportedArgs(::PlotlyBackend) = [
supported_args(::PlotlyBackend) = merge_with_base_supported([
: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,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_legend, :foreground_color_guide,
# :foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:foreground_color_title,
:label,
:seriestype,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
: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,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :levels,
:xerror, :yerror,
:ribbon, :quiver,
:orientation,
# :overwrite_figure,
:polar,
# :normalize, :weights, :contours, :aspect_ratio
]
:normalize, :weights,
# :contours, :aspect_ratio,
:hover,
:inset_subplots,
])
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
supported_types(::PlotlyBackend) = [
:path, :scatter, :bar, :pie, :heatmap,
:contour, :surface, :path3d, :scatter3d, :shape, :scattergl,
]
supported_styles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supported_markers(::PlotlyBackend) = [
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
]
supported_scales(::PlotlyBackend) = [:identity, :log10]
is_subplot_supported(::PlotlyBackend) = true
is_string_supported(::PlotlyBackend) = true
# --------------------------------------------------------------------------------------
@@ -85,28 +84,28 @@ end
# ----------------------------------------------------------------
function plotlyfont(font::Font, color = font.color)
function plotly_font(font::Font, color = font.color)
KW(
:family => font.family,
:size => round(Int, font.pointsize*1.4),
:color => webcolor(color),
:color => rgba_string(color),
)
end
function get_annotation_dict(x, y, val)
function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
KW(
:text => val,
:xref => "x",
:xref => xref,
:x => x,
:yref => "y",
:yref => xref,
: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),
function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper")
merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW(
:font => plotly_font(ptxt.font),
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
:rotation => ptxt.font.rotation,
@@ -127,7 +126,7 @@ end
# # :ay => -40,
# :ax => 10xdiff / dist,
# :ay => -10ydiff / dist,
# :arrowcolor => webcolor(d[:linecolor], d[:linealpha]),
# :arrowcolor => rgba_string(d[:linecolor]),
# :xref => "x",
# :yref => "y",
# :arrowsize => 10a.headwidth,
@@ -136,7 +135,7 @@ end
# )
# end
function plotlyscale(scale::Symbol)
function plotly_scale(scale::Symbol)
if scale == :log10
"log"
else
@@ -144,7 +143,6 @@ function plotlyscale(scale::Symbol)
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)
@@ -157,19 +155,12 @@ 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))"
@@ -180,12 +171,12 @@ function plotly_axis(axis::Axis, sp::Subplot)
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])
if !(axis[:ticks] in (nothing, :none))
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
ax[:tickcolor] = rgba_string(axis[:foreground_color_border])
ax[:linecolor] = rgba_string(axis[:foreground_color_border])
# lims
lims = axis[:lims]
@@ -199,7 +190,7 @@ function plotly_axis(axis::Axis, sp::Subplot)
end
# ticks
ticks = axis[:ticks]
ticks = get_ticks(axis)
if ticks != :auto
ttype = ticksType(ticks)
if ttype == :ticks
@@ -218,34 +209,37 @@ function plotly_axis(axis::Axis, sp::Subplot)
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]
w, h = plt[:size]
d_out[:width], d_out[:height] = w, h
d_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20)
d_out[:width], d_out[:height] = plt[:size]
d_out[:paper_bgcolor] = webcolor(plt[:background_color_outside])
d_out[:annotations] = KW[]
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]))
# add an annotation for the title... positioned horizontally relative to plotarea,
# but vertically just below the top of the subplot bounding box
if sp[:title] != ""
bb = plotarea(sp)
tpos = sp[:title_location]
xmm = if tpos == :left
left(bb)
elseif tpos == :right
right(bb)
else
0.5 * (left(bb) + right(bb))
end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title])
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont)))
end
# # 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])
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
# TODO: x/y axis tick values/labels
@@ -265,19 +259,14 @@ function plotly_layout(plt::Plot)
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]),
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
)
end
# annotations
anns = sp[:annotations]
d_out[:annotations] = if isempty(anns)
KW[]
else
KW[get_annotation_dict(ann...) for ann in anns]
end
append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]])
# # arrows
# for sargs in seriesargs
@@ -288,8 +277,6 @@ function plotly_layout(plt::Plot)
# end
# end
# end
# dumpdict(d_out,"",true)
# @show d_out[:annotations]
if ispolar(sp)
d_out[:direction] = "counterclockwise"
@@ -298,6 +285,11 @@ function plotly_layout(plt::Plot)
d_out
end
# turn off hover if nothing's using it
if all(series -> series.d[:hover] in (false,:none), plt.series_list)
d_out[:hovermode] = "none"
end
d_out
end
@@ -306,10 +298,11 @@ function plotly_layout_json(plt::Plot)
end
function plotly_colorscale(grad::ColorGradient, alpha = nothing)
[[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)]
function plotly_colorscale(grad::ColorGradient, α)
[[grad.values[i], rgb_string(grad.colors[i])] for i in 1:length(grad.colors)]
end
plotly_colorscale(c, alpha = nothing) = plotly_colorscale(default_gradient(), alpha)
plotly_colorscale(c, α) = plotly_colorscale(cgrad(alpha=α), α)
# plotly_colorscale(c, alpha = nothing) = plotly_colorscale(cgrad(), alpha)
const _plotly_markers = KW(
:rect => "square",
@@ -327,88 +320,81 @@ function plotly_subplot_index(sp::Subplot)
end
# the Shape contructor will automatically close the shape. since we need it closed,
# we split by NaNs and then construct/destruct the shapes to get the closed coords
function plotly_close_shapes(x, y)
xs, ys = nansplit(x), nansplit(y)
for i=1:length(xs)
shape = Shape(xs[i], ys[i])
xs[i], ys[i] = shape_coords(shape)
end
nanvcat(xs), nanvcat(ys)
end
plotly_data(v) = collect(v)
plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v)
# 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]
st = series[:seriestype]
if st == :shape
return plotly_series_shapes(plt, series)
end
sp = series[: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"
d_out[:showlegend] = should_add_to_legend(series)
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
x, y = plotly_data(series[:x]), plotly_data(series[:y])
d_out[:name] = series[:label]
isscatter = st in (:scatter, :scatter3d, :scattergl)
hasmarker = isscatter || series[:markershape] != :none
hasline = st in (:path, :path3d)
# set the "type"
if st in (:line, :path, :scatter, :steppre, :steppost)
d_out[:type] = "scatter"
if st in (:path, :scatter, :scattergl)
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
d_out[:mode] = if hasmarker
hasline ? "lines+markers" : "markers"
else
hasline ? "lines" : "none"
end
if d[:fillrange] == true || d[:fillrange] == 0
if series[:fillrange] == true || series[: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])")
d_out[:fillcolor] = rgba_string(series[:fillcolor])
elseif !(series[:fillrange] in (false, nothing))
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(series[: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
d_out[:orientation] = isvertical(series) ? "v" : "h"
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])
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[: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])
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
# d_out[:showscale] = series[:colorbar] != :none
d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[: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])
d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
elseif st == :pie
d_out[:type] = "pie"
@@ -424,7 +410,7 @@ function plotly_series(plt::Plot, series::Series)
hasline ? "lines" : "none"
end
d_out[:x], d_out[:y] = x, y
d_out[:z] = collect(d[:z])
d_out[:z] = plotly_data(series[:z])
else
warn("Plotly: seriestype $st isn't supported.")
@@ -434,32 +420,32 @@ function plotly_series(plt::Plot, series::Series)
# 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]),
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
# :opacity => series[:markeralpha],
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:line => KW(
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
:width => d[:markerstrokewidth],
:color => rgba_string(series[:markerstrokecolor]),
:width => series[: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]]
d_out[:marker][:color] = if series[:marker_z] == nothing
rgba_string(series[:markercolor])
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
grad = series[:markercolor]
zmin, zmax = extrema(series[:marker_z])
[rgba_string(grad[(zi - zmin) / (zmax - zmin)]) for zi in series[:marker_z]]
end
end
# add "line"
if hasline
d_out[:line] = KW(
:color => webcolor(d[:linecolor], d[:linealpha]),
:width => d[:linewidth],
:color => rgba_string(series[:linecolor]),
:width => series[:linewidth],
:shape => if st == :steppre
"vh"
elseif st == :steppost
@@ -467,23 +453,85 @@ function plotly_series(plt::Plot, series::Series)
else
"linear"
end,
:dash => string(d[:linestyle]),
:dash => string(series[:linestyle]),
# :dash => "solid",
)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
[d_out]
end
function plotly_series_shapes(plt::Plot, series::Series)
d_outs = []
# TODO: create a d_out for each polygon
# x, y = series[:x], series[:y]
# these are the axes that the series should be mapped to
spidx = plotly_subplot_index(series[:subplot])
base_d = KW()
base_d[:xaxis] = "x$spidx"
base_d[:yaxis] = "y$spidx"
base_d[:name] = series[:label]
# base_d[:legendgroup] = series[:label]
x, y = plotly_data(series[:x]), plotly_data(series[:y])
for (i,rng) in enumerate(iter_segments(x,y))
length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill
d_out = merge(base_d, KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
:y => vcat(y[rng], y[rng[1]]),
:fill => "tozeroy",
:fillcolor => rgba_string(cycle(series[:fillcolor], i)),
))
if series[:markerstrokewidth] > 0
d_out[:line] = KW(
:color => rgba_string(cycle(series[:linecolor], i)),
:width => series[:linewidth],
:dash => string(series[:linestyle]),
)
end
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
plotly_polar!(d_out, series)
plotly_hover!(d_out, cycle(series[:hover], i))
push!(d_outs, d_out)
end
d_outs
end
function plotly_polar!(d_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(d[:subplot])
if ispolar(series[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x))
d_out[:r] = pop!(d_out, :y)
end
end
d_out
function plotly_hover!(d_out::KW, hover)
# hover text
if hover in (:none, false)
d_out[:hoverinfo] = "none"
elseif hover != nothing
d_out[:hoverinfo] = "text"
d_out[:text] = hover
end
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))
slist = []
for series in plt.series_list
append!(slist, plotly_series(plt, series))
end
JSON.json(slist)
# JSON.json(map(series -> plotly_series(plt, series), plt.series_list))
end
# ----------------------------------------------------------------
@@ -523,11 +571,10 @@ 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})
function _writemime(io::IO, ::MIME"image/svg+xml", 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
+21 -130
View File
@@ -1,79 +1,13 @@
# 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
supported_args(::PlotlyJSBackend) = supported_args(PlotlyBackend())
supported_types(::PlotlyJSBackend) = supported_types(PlotlyBackend())
supported_styles(::PlotlyJSBackend) = supported_styles(PlotlyBackend())
supported_markers(::PlotlyJSBackend) = supported_markers(PlotlyBackend())
supported_scales(::PlotlyJSBackend) = supported_scales(PlotlyBackend())
is_subplot_supported(::PlotlyJSBackend) = true
is_string_supported(::PlotlyJSBackend) = true
# --------------------------------------------------------------------------------------
@@ -83,30 +17,14 @@ function _initialize_backend(::PlotlyJSBackend; kw...)
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
# # 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()
@@ -115,10 +33,12 @@ 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)
pdicts = plotly_series(plt, series)
for pdict in pdicts
typ = pop!(pdict, :type)
gt = PlotlyJS.GenericTrace(typ; pdict...)
PlotlyJS.addtraces!(syncplot, gt)
end
end
function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series)
@@ -133,55 +53,26 @@ 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/svg+xml", plt::Plot{PlotlyJSBackend})
writemime(io, MIME("text/html"), plt.o)
end
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
tmpfn = tempname() * "png"
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
+448 -504
View File
File diff suppressed because it is too large Load Diff
+10 -33
View File
@@ -2,52 +2,29 @@
# https://github.com/tbreloff/Qwt.jl
supportedArgs(::QwtBackend) = [
supported_args(::QwtBackend) = merge_with_base_supported([
: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
:guide, :lims, :ticks, :scale,
])
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
supported_scales(::QwtBackend) = [:identity, :log10]
is_subplot_supported(::QwtBackend) = true
# --------------------------------------------------------------------------------------
@@ -95,13 +72,13 @@ function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
if st == :scatter
d[:seriestype] = :none
if d[:markershape] == :none
d[:markershape] = :ellipse
d[:markershape] = :circle
end
elseif st in (:hline, :vline)
addLineMarker(plt, d)
d[:seriestype] = :none
d[:markershape] = :ellipse
d[:markershape] = :circle
d[:markersize] = 1
if st == :vline
d[:x], d[:y] = d[:y], d[:x]
@@ -184,7 +161,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
# 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)
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
end
end
+3 -3
View File
@@ -19,9 +19,9 @@ 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
# # 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})
+64 -233
View File
@@ -1,86 +1,46 @@
# https://github.com/Evizero/UnicodePlots.jl
supportedArgs(::UnicodePlotsBackend) = [
# :annotations,
# :args,
# :axis,
# :background_color,
# :linecolor,
# :fill,
# :foreground_color,
:group,
# :heatmap_c,
# :kwargs,
supported_args(::UnicodePlotsBackend) = merge_with_base_supported([
:label,
# :layout,
:legend,
:seriescolor, :seriesalpha,
: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
:guide, :lims,
])
supported_types(::UnicodePlotsBackend) = [
:path, :scatter,
:histogram2d
]
supportedStyles(::UnicodePlotsBackend) = [:auto, :solid]
supportedMarkers(::UnicodePlotsBackend) = [:none, :auto, :ellipse]
supportedScales(::UnicodePlotsBackend) = [:identity]
subplotSupported(::UnicodePlotsBackend) = true
supported_styles(::UnicodePlotsBackend) = [:auto, :solid]
supported_markers(::UnicodePlotsBackend) = [:none, :auto, :circle]
supported_scales(::UnicodePlotsBackend) = [:identity]
is_subplot_supported(::UnicodePlotsBackend) = true
# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupportedArgs(pkg::UnicodePlotsBackend, d::KW) = nothing
warnOnUnsupported_args(pkg::UnicodePlotsBackend, d::KW) = nothing
# --------------------------------------------------------------------------------------
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
@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]
@@ -98,12 +58,14 @@ function rebuildUnicodePlot!(plt::Plot)
# 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;
canvas_type = isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
o = UnicodePlots.Plot(x, y, canvas_type;
width = width,
height = height,
title = sp[:title],
xlim = xlim,
ylim = ylim
ylim = ylim,
border = isijulia() ? :ascii : :solid
)
# set the axis labels
@@ -120,213 +82,82 @@ function rebuildUnicodePlot!(plt::Plot)
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
if 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
if st == :path
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
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] : ""
# 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
# 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)
# add the series
func(o, x, y; color = color, name = label)
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")
fn = addExtension(fn, "png")
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# 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
# @osx_only begin
@compat @static if is_apple()
# BEGIN HACK
# wait while the plot gets drawn
sleep(0.5)
# 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`)
# 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
# END HACK (phew)
return
end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
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})
function _update_plot_object(plt::Plot{UnicodePlotsBackend})
w, h = plt[:size]
plt.attr[:size] = div(w, 10), div(h, 20)
plt.attr[:color_palette] = [RGB(0,0,0)]
rebuildUnicodePlot!(plt)
end
function _writemime(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
map(show, plt.o)
nothing
end
function _display(plt::Plot{UnicodePlotsBackend})
map(show, plt.o)
nothing
end
# function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend})
# for plt in subplt.plts
# gui(plt)
# end
# end
+10 -45
View File
@@ -3,64 +3,29 @@
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
supportedArgs(::WinstonBackend) = [
supported_args(::WinstonBackend) = merge_with_base_supported([
: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
:guide, :lims, :scale,
])
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
supported_scales(::WinstonBackend) = [:identity, :log10]
is_subplot_supported(::WinstonBackend) = false
# --------------------------------------------------------------------------------------
@@ -87,7 +52,7 @@ end
@compat const winston_marker = KW(:none=>".",
:rect => "square",
:ellipse=>"circle",
:circle=>"circle",
:diamond=>"diamond",
:utriangle=>"triangle",
:dtriangle=>"down-triangle",
@@ -170,7 +135,7 @@ function _series_added(plt::Plot{WinstonBackend}, series::Series)
elseif d[:seriestype] == :scatter
if d[:markershape] == :none
d[:markershape] = :ellipse
d[:markershape] = :circle
end
# elseif d[:seriestype] == :step
+42 -6
View File
@@ -12,8 +12,15 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang
# -------------------------------------------------------------
immutable Shape
x::AVec
y::AVec
x::Vector{Float64}
y::Vector{Float64}
# function Shape(x::AVec, y::AVec)
# # if x[1] != x[end] || y[1] != y[end]
# # new(vcat(x, x[1]), vcat(y, y[1]))
# # else
# new(x, y)
# end
# end
end
Shape(verts::AVec) = Shape(unzip(verts)...)
@@ -93,8 +100,29 @@ function makearrowhead(angle; h = 2.0, w = 0.4)
from_polar(angle + 0.5π, w) - tip, (0,0)])
end
const _shape_keys = Symbol[
:circle,
:rect,
:star5,
:diamond,
:hexagon,
:cross,
:xcross,
:utriangle,
:dtriangle,
:pentagon,
:heptagon,
:octagon,
:star4,
:star6,
:star7,
:star8,
:vline,
:hline,
]
const _shapes = KW(
:ellipse => makeshape(20),
:circle => makeshape(20),
:rect => makeshape(4, offset=-0.25),
:diamond => makeshape(4),
:utriangle => makeshape(3),
@@ -218,7 +246,14 @@ function font(args...)
for arg in args
T = typeof(arg)
if arg == :center
if T == Font
family = arg.family
pointsize = arg.pointsize
halign = arg.halign
valign = arg.valign
rotation = arg.rotation
color = arg.color
elseif arg == :center
halign = :hcenter
valign = :vcenter
elseif arg in (:hcenter, :left, :right)
@@ -253,6 +288,7 @@ end
PlotText(str) = PlotText(string(str), font())
text(t::PlotText) = t
text(str::AbstractString, f::Font) = PlotText(str, f)
function text(str, args...)
PlotText(string(str), font(args...))
end
@@ -363,8 +399,8 @@ 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)
Base.copy(surf::Surface) = Surface{typeof(surf.surf)}(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T)
function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema]
+46 -4
View File
@@ -1,10 +1,38 @@
abstract ColorScheme
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
export
cgrad
cgrad() = default_gradient()
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
colors = ColorGradient(arg, alpha=alpha).colors
values = if values != nothing
values
elseif scale in (:log, :log10)
log10(linspace(1,10,30))
elseif scale == :log2
log2(linspace(1,2,30))
elseif scale == :ln
log(linspace(1,pi,30))
elseif scale in (:exp, :exp10)
(exp10(linspace(0,1,30)) - 1) / 9
else
linspace(0, 1, length(colors))
end
ColorGradient(colors, values)
end
# --------------------------------------------------------------
getColor(scheme::ColorScheme) = getColor(scheme, 1)
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
@@ -23,13 +51,15 @@ convertColor(c::Symbol) = parse(Colorant, string(c))
convertColor(c::Colorant) = c
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
convertColor(c::ColorScheme) = c
convertColor(v::Void) = RGBA(0,0,0,0)
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
function convertColor(c, α::Real)
c = convertColor(c)
RGBA(RGB(c), α)
RGBA(RGB(getColor(c)), α)
end
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
convertColor(c, α::@compat(Void)) = convertColor(c)
convertColor(c, α::Void) = convertColor(c)
# backup... try to convert
getColor(c) = convertColor(c)
@@ -49,7 +79,7 @@ end
# --------------------------------------------------------------
const _rainbowColors = [colorant"blue", colorant"purple", colorant"green", colorant"orange", colorant"red"]
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
@@ -101,6 +131,12 @@ immutable ColorGradient <: ColorScheme
end
end
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
@@ -119,6 +155,11 @@ function ColorGradient(grad::ColorGradient; alpha = nothing)
ColorGradient(convertColor(grad.colors, alpha), grad.values)
end
# anything else just gets the default gradient
function ColorGradient(cw; alpha=nothing)
ColorGradient(default_gradient(), alpha=alpha)
end
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
function getColorZ(gradient::ColorGradient, z::Real)
@@ -180,7 +221,7 @@ immutable ColorZFunction <: ColorScheme
f::Function
end
getColorZ(scheme::ColorFunction, z::Real) = scheme.f(z)
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# --------------------------------------------------------------
@@ -206,6 +247,7 @@ ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Color
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
convertColor(c::ColorWrapper, α::Void) = c.c
# --------------------------------------------------------------
+99
View File
@@ -0,0 +1,99 @@
# 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, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), 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
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
Any[Surface(v)]
else
Any[v[:,i] for i in 1:size(v,2)]
end, 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!")
# --------------------------------------------------------------------
+15 -14
View File
@@ -115,15 +115,17 @@ PlotExample("Line types",
PlotExample("Line styles",
"",
[:(begin
styles = setdiff(supportedStyles(), [:auto])'
plot(cumsum(randn(20,length(styles)),1), style=:auto, label=map(string,styles), w=5)
styles = filter(s -> s in supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])'
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles))
end)]
),
PlotExample("Marker types",
"",
[:(begin
markers = setdiff(supportedMarkers(), [:none,:auto,Shape])'
markers = filter(m -> m in supported_markers(), Plots._shape_keys)'
n = length(markers)
x = linspace(0,10,n+2)[2:end-1]
y = repmat(reverse(x)', n, 1)
@@ -219,12 +221,6 @@ PlotExample("Contours",
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",
@@ -264,7 +260,7 @@ 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])
plot(rand(100), layout=@layout([a b;c]), group=group, linetype=[:bar :scatter :steppre])
end)]
),
@@ -301,8 +297,8 @@ 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)))
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
end)]
)
@@ -325,11 +321,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
end
# generate all plots and create a dict mapping idx --> plt
function test_examples(pkgname::Symbol; debug = false, disp = true)
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
skip = [], only = nothing)
Plots._debugMode.on = debug
plts = Dict()
for i in 1:length(_examples)
only != nothing && !(i in only) && continue
i in skip && continue
try
plt = test_examples(pkgname, i, debug=debug, disp=disp)
plts[i] = plt
@@ -337,6 +335,9 @@ function test_examples(pkgname::Symbol; debug = false, disp = true)
# TODO: put error info into markdown?
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
end
if sleep != nothing
Base.sleep(sleep)
end
end
plts
end
+136 -99
View File
@@ -5,6 +5,8 @@
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm
@compat Base.:.*(m::Measure, n::Number) = m * n
@@ -70,6 +72,16 @@ function crop(parent::BoundingBox, child::BoundingBox)
BoundingBox(l, t, w, h)
end
# convert x,y coordinates from absolute coords to percentages...
# returns x_pct, y_pct
function xy_mm_to_pcts(x::AbsoluteLength, y::AbsoluteLength, figw, figh, flipy = true)
xmm, ymm = x.value, y.value
if flipy
ymm = figh.value - ymm # flip y when origin in bottom-left
end
xmm / figw.value, ymm / figh.value
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)
@@ -89,6 +101,48 @@ end
Base.show(io::IO, layout::AbstractLayout) = print(io, "$(typeof(layout))$(size(layout))")
make_measure_hor(n::Number) = n * w
make_measure_hor(m::Measure) = m
make_measure_vert(n::Number) = n * h
make_measure_vert(m::Measure) = m
function bbox(x, y, w, h, oarg1::Symbol, originargs::Symbol...)
oargs = vcat(oarg1, originargs...)
orighor = :left
origver = :top
for oarg in oargs
if oarg in (:left, :right)
orighor = oarg
elseif oarg in (:top, :bottom)
origver = oarg
else
warn("Unused origin arg in bbox construction: $oarg")
end
end
bbox(x, y, w, h; h_anchor = orighor, v_anchor = origver)
end
# create a new bbox
function bbox(x, y, width, height; h_anchor = :left, v_anchor = :top)
x = make_measure_hor(x)
y = make_measure_vert(y)
width = make_measure_hor(width)
height = make_measure_vert(height)
left = if h_anchor == :left
x
else
1w - x - width
end
top = if v_anchor == :top
y
else
1h - y - height
end
BoundingBox(left, top, width, height)
end
# 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)
@@ -97,25 +151,23 @@ bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
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))
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, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
_update_position!(layout::AbstractLayout) = nothing
update_child_bboxes!(layout::AbstractLayout) = nothing
left(layout::AbstractLayout) = left(bbox(layout))
top(layout::AbstractLayout) = top(bbox(layout))
right(layout::AbstractLayout) = right(bbox(layout))
bottom(layout::AbstractLayout) = bottom(bbox(layout))
width(layout::AbstractLayout) = width(bbox(layout))
height(layout::AbstractLayout) = height(bbox(layout))
width(layout::AbstractLayout) = width(layout.bbox)
height(layout::AbstractLayout) = height(layout.bbox)
plotarea(layout::AbstractLayout) = defaultbox
plotarea!(layout::AbstractLayout, bbox::BoundingBox) = nothing
# pass these through to the bbox methods if there's no plotarea
plotarea(layout::AbstractLayout) = bbox(layout)
plotarea!(layout::AbstractLayout, bb::BoundingBox) = bbox!(layout, bb)
attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
@@ -204,6 +256,12 @@ rightpad(layout::GridLayout) = layout.minpad[3]
bottompad(layout::GridLayout) = layout.minpad[4]
# here's how this works... first we recursively "update the minimum padding" (which
# means to calculate the minimum size needed from the edge of the subplot to plot area)
# for the whole layout tree. then we can compute the "padding borders" of this
# layout as the biggest padding of the children on the perimeter. then we need to
# recursively pass those borders back down the tree, one side at a time, but ONLY
# to those perimeter children.
# leftpad, toppad, rightpad, bottompad
function _update_min_padding!(layout::GridLayout)
@@ -217,10 +275,11 @@ function _update_min_padding!(layout::GridLayout)
end
function _update_position!(layout::GridLayout)
map(_update_position!, layout.grid)
function update_position!(layout::GridLayout)
map(update_position!, layout.grid)
end
# some lengths are fixed... we have to split up the free space among the list v
function recompute_lengths(v)
# dump(v)
tot = 0pct
@@ -242,11 +301,11 @@ function recompute_lengths(v)
end
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
function update_child_bboxes!(layout::GridLayout)
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
nr, nc = size(layout)
# create a matrix for each minimum padding direction
_update_min_padding!(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)
@@ -263,6 +322,12 @@ function update_child_bboxes!(layout::GridLayout)
pad_bottom = maximum(minpad_bottom, 2)
# @show pad_left pad_top pad_right pad_bottom
# make sure the perimeter match the parent
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
pad_top[1] = max(pad_top[1], minimum_perimeter[2])
pad_right[end] = max(pad_right[end], minimum_perimeter[3])
pad_bottom[end] = max(pad_bottom[end], minimum_perimeter[4])
# 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)
@@ -303,11 +368,36 @@ function update_child_bboxes!(layout::GridLayout)
child_height = pad_top[r] + plotarea_height + pad_bottom[r]
bbox!(child, BoundingBox(child_left, child_top, child_width, child_height))
# this is the minimum perimeter as decided by this child's parent, so that
# all children on this border have the same value
min_child_perimeter = [
c == 1 ? layout.minpad[1] : 0mm,
r == 1 ? layout.minpad[2] : 0mm,
c == nc ? layout.minpad[3] : 0mm,
r == nr ? layout.minpad[4] : 0mm
]
# recursively update the child's children
update_child_bboxes!(child)
update_child_bboxes!(child, min_child_perimeter)
end
end
# for each inset (floating) subplot, resolve the relative position
# to absolute canvas coordinates, relative to the parent's plotarea
function update_inset_bboxes!(plt::Plot)
for sp in plt.inset_subplots
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
# @show bbox(sp.parent) sp[:relative_bbox] p_area
plotarea!(sp, p_area)
bbox!(sp, bbox(
left(p_area) - leftpad(sp),
top(p_area) - toppad(sp),
width(p_area) + leftpad(sp) + rightpad(sp),
height(p_area) + toppad(sp) + bottompad(sp)
))
end
end
# ----------------------------------------------------------------------
@@ -376,40 +466,21 @@ 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
# # just a single subplot
# function build_layout(sp::Subplot, n::Integer)
# sp, Subplot[sp], SubplotMap(gensym() => sp)
# end
# n is the number of subplots... build a grid and initialize the inner subplots recursively
function build_layout(layout::GridLayout, n::Integer)
nr, nc = size(layout)
subplots = Subplot[]
@@ -435,6 +506,8 @@ function build_layout(layout::GridLayout, n::Integer)
append!(subplots, sps)
merge!(spmap, m)
i += length(sps)
elseif isa(l, Subplot)
error("Subplot exists. Cannot re-use existing layout. Please make a new one.")
end
i >= n && break # only add n subplots
end
@@ -512,44 +585,13 @@ 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)
@@ -562,17 +604,14 @@ 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))))
@@ -581,30 +620,16 @@ function create_grid_vcat(expr::Expr)
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
@@ -644,7 +669,9 @@ end
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...)
if length(axes) > 0
link_axes!(axes...)
end
end
# don't do anything for most layout types
@@ -664,6 +691,16 @@ function link_axes!(layout::GridLayout, link::Symbol)
link_axes!(layout.grid[r,:], :yaxis)
end
end
if link == :square
sps = filter(l -> isa(l, Subplot), layout.grid)
if !isempty(sps)
base_axis = sps[1][:xaxis]
for sp in sps
link_axes!(base_axis, sp[:xaxis])
link_axes!(base_axis, sp[:yaxis])
end
end
end
if link == :all
link_axes!(layout.grid, :xaxis)
link_axes!(layout.grid, :yaxis)
+57 -5
View File
@@ -119,11 +119,13 @@ const _mimeformats = Dict(
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg"
"image/svg+xml" => "svg",
"text/plain" => "txt",
)
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
)
# a backup for html... passes to svg or png depending on the html_output_format arg
@@ -138,6 +140,8 @@ function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
elseif output_type == :svg
# info("writing svg to html output")
writemime(io, MIME("image/svg+xml"), plt)
elseif output_type == :txt
writemime(io, MIME("text/plain"), plt)
else
error("only png or svg allowed. got: $output_type")
end
@@ -145,12 +149,48 @@ end
# for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats)
@eval function _writemime(io::IO, m, plt::Plot)
warn("_writemime is not defined for this backend. m=", string(m))
end
@eval function _display(plt::Plot)
warn("_display is not defined for this backend.")
end
@eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
prepare_output(plt)
_writemime(io, m, plt)
end
end
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
if is_installed("FileIO")
@eval begin
import FileIO
function _writemime(io::IO, ::MIME"image/png", plt::Plot)
fn = tempname()
# first save a pdf file
pdf(plt, fn)
# load that pdf into a FileIO Stream
s = FileIO.load(fn * ".pdf")
# save a png
pngfn = fn * ".png"
FileIO.save(pngfn, s)
# now write from the file
write(io, readall(open(pngfn)))
end
end
end
# function html_output_format(fmt)
# if fmt == "png"
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
@@ -188,6 +228,11 @@ function setup_ijulia()
global _ijulia_output
Dict{Compat.ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt))
end
# default text/plain passes to html... handles Interact issues
function Base.writemime(io::IO, m::MIME"text/plain", plt::Plot)
writemime(io, MIME("text/html"), plt)
end
end
set_ijulia_output("text/html")
end
@@ -203,10 +248,11 @@ function setup_atom()
# @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
# # connects the render function
# for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
# Atom.Media.media(Plot{T}, Atom.Media.Plot)
# end
Atom.Media.media(Plot, Atom.Media.Graphical)
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
# Atom.displaysize(::Plot) = (535, 379)
@@ -214,9 +260,15 @@ function setup_atom()
# this is like "display"... sends an html div with the plot to the PlotPane
function Atom.Media.render(pane::Atom.PlotPane, plt::Plot)
@show "here"
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
end
# # force text/plain to output to the PlotPane
# function Base.writemime(io::IO, ::MIME"text/plain", plt::Plot)
# # writemime(io::IO, MIME("text/html"), plt)
# Atom.Media.render(pane)
# 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))))
+399
View File
@@ -0,0 +1,399 @@
# ------------------------------------------------------------------
# preprocessing
function command_idx(kw_list::AVec{KW}, kw::KW)
Int(kw[:series_plotindex]) - Int(kw_list[1][:series_plotindex]) + 1
end
function _expand_seriestype_array(d::KW, args)
sts = get(d, :seriestype, :path)
if typeof(sts) <: AbstractArray
delete!(d, :seriestype)
RecipeData[begin
dc = copy(d)
dc[:seriestype] = sts[r,:]
RecipeData(dc, args)
end for r=1:size(sts,1)]
else
RecipeData[RecipeData(copy(d), args)]
end
end
function _preprocess_args(d::KW, args, still_to_process::Vector{RecipeData})
# the grouping mechanism is a recipe on a GroupBy object
# we simply add the GroupBy object to the front of the args list to allow
# the recipe to be applied
if haskey(d, :group)
args = (extractGroupArgs(d[:group], args...), args...)
end
# if we were passed a vector/matrix of seriestypes and there's more than one row,
# we want to duplicate the inputs, once for each seriestype row.
if !isempty(args)
append!(still_to_process, _expand_seriestype_array(d, args))
end
# remove subplot and axis args from d... they will be passed through in the kw_list
if !isempty(args)
for (k,v) in d
for defdict in (_subplot_defaults,
_axis_defaults,
_axis_defaults_byletter)
if haskey(defdict, k)
delete!(d, k)
end
end
end
end
args
end
# ------------------------------------------------------------------
# user recipes
function _process_userrecipes(plt::Plot, d::KW, args)
still_to_process = RecipeData[]
args = _preprocess_args(d, args, still_to_process)
# 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[]
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)
rd_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for recipedata in rd_list
# 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)
_process_userrecipe(plt, kw_list, recipedata)
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
# don't allow something else to handle it
d[:smooth] = false
kw_list
end
function _process_userrecipe(plt::Plot, kw_list::Vector{KW}, recipedata::RecipeData)
# when the arg tuple is empty, that means there's nothing left to recursively
# process... finish up and add to the kw_list
kw = recipedata.d
_preprocess_userrecipe(kw)
warnOnUnsupported_scales(plt.backend, kw)
# add the plot index
plt.n += 1
kw[:series_plotindex] = plt.n
push!(kw_list, kw)
_add_errorbar_kw(kw_list, kw)
_add_smooth_kw(kw_list, kw)
return
end
function _preprocess_userrecipe(kw::KW)
_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], kw[:y], kw[:z])
end
# map line_z if it's a Function
if isa(get(kw, :line_z, nothing), Function)
kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
end
# convert a ribbon into a fillrange
if get(kw, :ribbon, nothing) != nothing
make_fillrange_from_ribbon(kw)
end
return
end
function _add_errorbar_kw(kw_list::Vector{KW}, kw::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(kw, 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
end
function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
# handle smoothing by adding a new series
if get(kw, :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,
)))
end
end
# ------------------------------------------------------------------
# plot recipes
# Grab the first in line to be processed and pass it through apply_recipe
# to generate a list of RecipeData objects (data + attributes).
# If we applied a "plot recipe" without error, then add the returned datalist's KWs,
# otherwise we just add the original KW.
function _process_plotrecipe(plt::Plot, kw::KW, kw_list::Vector{KW}, still_to_process::Vector{KW})
if !isa(get(kw, :seriestype, nothing), Symbol)
# seriestype was never set, or it's not a Symbol, so it can't be a plot recipe
push!(kw_list, kw)
return
end
try
st = kw[:seriestype]
st = kw[:seriestype] = get(_typeAliases, st, st)
datalist = RecipesBase.apply_recipe(kw, Val{st}, plt)
for data in datalist
if data.d[:seriestype] == st
error("Plot recipe $st returned the same seriestype: $(data.d)")
end
push!(still_to_process, data.d)
end
catch err
if isa(err, MethodError)
push!(kw_list, kw)
else
rethrow()
end
end
return
end
# ------------------------------------------------------------------
# setup plot and subplot
function _plot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# merge in anything meant for the Plot
for kw in kw_list, (k,v) in kw
haskey(_plot_defaults, k) && (d[k] = pop!(kw, k))
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
# handle inset subplots
insets = plt[:inset_subplots]
if insets != nothing
if !(typeof(insets) <: AVec)
insets = [insets]
end
for inset in insets
parent, bb = is_2tuple(inset) ? inset : (nothing, inset)
P = typeof(parent)
if P <: Integer
parent = plt.subplots[parent]
elseif P == Symbol
parent = plt.spmap[parent]
else
parent = plt.layout
end
sp = Subplot(backend(), parent=parent)
sp.plt = plt
sp.attr[:relative_bbox] = bb
sp.attr[:subplot_index] = length(plt.subplots)
push!(plt.subplots, sp)
push!(plt.inset_subplots, sp)
end
end
end
function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
# we'll keep a map of subplot to an attribute override dict.
# Subplot/Axis attributes set by a user/series recipe apply only to the
# Subplot object which they belong to.
# TODO: allow matrices to still apply to all subplots
sp_attrs = Dict{Subplot,Any}()
for kw in kw_list
# get the Subplot object to which the series belongs.
sps = get(kw, :subplot, :auto)
sp = get_subplot(plt, cycle(sps == :auto ? plt.subplots : plt.subplots[sps], command_idx(kw_list,kw)))
kw[:subplot] = sp
# extract subplot/axis attributes from kw and add to sp_attr
attr = KW()
for (k,v) in kw
if haskey(_subplot_defaults, k) || haskey(_axis_defaults_byletter, k)
attr[k] = pop!(kw, k)
end
if haskey(_axis_defaults, k)
v = pop!(kw, k)
for letter in (:x,:y,:z)
attr[Symbol(letter,k)] = v
end
end
end
sp_attrs[sp] = attr
end
# override subplot/axis args. `sp_attrs` take precendence
for (idx,sp) in enumerate(plt.subplots)
attr = merge(d, get(sp_attrs, sp, KW()))
_update_subplot_args(plt, sp, attr, idx, false)
end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
end
# getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes
function _prepare_subplot{T}(plt::Plot{T}, d::KW)
st::Symbol = d[:seriestype]
sp::Subplot{T} = d[:subplot]
sp_idx = get_subplot_index(plt, sp)
_update_subplot_args(plt, sp, d, sp_idx, true)
st = _override_seriestype_check(d, st)
# 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
sp
end
# ------------------------------------------------------------------
# series types
function _override_seriestype_check(d::KW, st::Symbol)
# do we want to override the series type?
if !is3d(st)
z = d[:z]
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d)
d[:seriestype] = st
end
end
st
end
function _prepare_annotations(sp::Subplot, d::KW)
# strip out series annotations (those which are based on series x/y coords)
# and add them to the subplot attr
sp_anns = annotations(sp[:annotations])
anns = annotations(pop!(d, :series_annotations, []))
if length(anns) > 0
x, y = d[:x], d[: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)
end
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
# 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
end
function _add_the_series(plt, d)
warnOnUnsupported_args(plt.backend, d)
warnOnUnsupported(plt.backend, d)
series = Series(d)
push!(plt.series_list, series)
_series_added(plt, series)
end
# -------------------------------------------------------------------------------
# this method recursively applies series recipes when the seriestype is not supported
# natively by the backend
function _process_seriesrecipe(plt::Plot, d::KW)
# replace seriestype aliases
st = Symbol(d[:seriestype])
st = d[:seriestype] = get(_typeAliases, st, st)
# shapes shouldn't have fillrange set
if d[:seriestype] == :shape
d[:fillrange] = nothing
end
# if it's natively supported, finalize processing and pass along to the backend, otherwise recurse
if st in supported_types()
sp = _prepare_subplot(plt, d)
_prepare_annotations(sp, d)
_expand_subplot_extrema(sp, d, st)
_add_the_series(plt, d)
else
# get a sub list of series for this seriestype
datalist = RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z])
# assuming there was no error, recursively apply the series recipes
for data in datalist
if isa(data, RecipeData)
_process_seriesrecipe(plt, data.d)
else
warn("Unhandled recipe: $(data)")
break
end
end
end
nothing
end
+74 -326
View File
@@ -49,7 +49,7 @@ function plot(args...; kw...)
# create an empty Plot then process
plt = Plot()
# plt.user_attr = d
_plot!(plt, d, args...)
_plot!(plt, d, args)
end
# build a new plot from existing plots
@@ -94,6 +94,9 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
for (idx, sp) in enumerate(plt.subplots)
_initialize_subplot(plt, sp)
serieslist = series_list(sp)
if sp in sp.plt.inset_subplots
push!(plt.inset_subplots, sp)
end
sp.plt = plt
sp.attr[:subplot_index] = idx
for series in serieslist
@@ -102,6 +105,14 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
end
end
# first apply any args for the subplots
for (idx,sp) in enumerate(plt.subplots)
_update_subplot_args(plt, sp, d, idx, false)
end
# do we need to link any axes together?
link_axes!(plt.layout, plt[:link])
# finish up
current(plt)
if get(d, :show, default(:show))
@@ -128,261 +139,61 @@ function plot!(plt::Plot, args...; kw...)
d = KW(kw)
preprocessArgs!(d)
# merge!(plt.user_attr, d)
_plot!(plt, d, args...)
end
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)
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
# 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
_plot!(plt, d, args)
end
# -------------------------------------------------------------------------------
# this is the core plotting function. recursively apply recipes to build
# a list of series KW dicts.
# note: at entry, we only have those preprocessed args which were passed in... no default values yet
function _plot!(plt::Plot, d::KW, args...)
# d = plt.user_attr
d[:plot_object] = plt
function _plot!(plt::Plot, d::KW, args::Tuple)
# 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
# --------------------------------
# "USER RECIPES"
# --------------------------------
kw_list = _process_userrecipes(plt, d, args)
# 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.
# --------------------------------
# "PLOT RECIPES"
# --------------------------------
# "plot recipe", which acts like a series type, and is processed before
# the plot layout is created, which allows for setting layouts and other plot-wide attributes.
# we get inputs which have been fully processed by "user recipes" and "type recipes",
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.
still_to_process = kw_list
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
next_kw = shift!(still_to_process)
_process_plotrecipe(plt, next_kw, kw_list, still_to_process)
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])
# --------------------------------
# Plot/Subplot/Layout setup
# --------------------------------
_plot_setup(plt, d, kw_list)
_subplot_setup(plt, d, kw_list)
# !!! note: At this point, kw_list is fully decomposed into individual series... one KW per series. !!!
# !!! The next step is to recursively apply series recipes until the backend supports that series type !!!
# 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
# --------------------------------
# "SERIES RECIPES"
# --------------------------------
for kw in kw_list
sp::Subplot = kw[:subplot]
# idx = get_subplot_index(plt, sp)
# 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)
# # we update subplot args in case something like the color palatte is part of the recipe
# _update_subplot_args(plt, sp, kw, idx, true)
# set default values, select from attribute cycles, and generally set the final attributes
_add_defaults!(kw, plt, sp, command_idx)
_add_defaults!(kw, plt, sp, command_idx(kw_list,kw))
# 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,
@@ -390,38 +201,22 @@ function _plot!(plt::Plot, d::KW, args...)
# 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)
_process_seriesrecipe(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()
# do we want to force display?
if plt[:show]
gui(plt)
end
plt
end
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
# we're getting ready to display/output. prep for layout calcs, then update
# the plot object after
function prepare_output(plt::Plot)
@@ -429,8 +224,21 @@ function prepare_output(plt::Plot)
w, h = plt.attr[:size]
plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
# One pass down and back up the tree to compute the minimum padding
# of the children on the perimeter. This is an backend callback.
_update_min_padding!(plt.layout)
for sp in plt.inset_subplots
_update_min_padding!(sp)
end
# now another pass down, to update the bounding boxes
update_child_bboxes!(plt.layout)
# update those bounding boxes of inset subplots
update_inset_bboxes!(plt)
# the backend callback, to reposition subplots, etc
_update_plot_object(plt)
end
@@ -440,75 +248,15 @@ function prepared_object(plt::Plot)
end
# --------------------------------------------------------------------
# plot to a Subplot
# function get_indices(orig, labels)
# Int[findnext(labels, l, 1) for l in orig]
# end
# # 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
# --------------------------------------------------------------------
# --------------------------------------------------------------------
# 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(sp::Subplot, args...; kw...)
plt = sp.plt
plot(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
end
function plot!(sp::Subplot, args...; kw...)
plt = sp.plt
plot!(plt, args...; kw..., subplot = findfirst(plt.subplots, sp))
end
# --------------------------------------------------------------------
+468
View File
@@ -0,0 +1,468 @@
function _precompile_()
ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
precompile(Plots.py_add_series, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Function,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Plots.OHLC, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.LinSpace{Float64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, DataFrames.DataFrame,))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Int64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Function, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{ASCIIString, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Base.FloatRange{Float64},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._plot!, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Array{Float64, 1},))
precompile(Plots._plot!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Array{Float64, 2},))
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Int64,))
precompile(Plots._before_layout_calcs, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._add_defaults!, (Base.Dict{Symbol, Any}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Int64,))
precompile(Plots._apply_series_recipe, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.setup_ijulia, ())
precompile(Plots.call, (Type{Plots.Plot{Plots.UnicodePlotsBackend}}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.create_grid_vcat, (Expr,))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.update_child_bboxes!, (Plots.GridLayout, Array{Measures.Length{:mm, Float64}, 1},))
precompile(Plots.preprocessArgs!, (Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.Plot{Plots.PyPlotBackend}}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.fix_xy_lengths!, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots._update_min_padding!, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.warnOnUnsupported_args, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots.build_layout, (Plots.GridLayout, Int64,))
precompile(Plots.build_layout, (Plots.GridLayout, Int64, Array{Plots.Plot, 1},))
precompile(Plots.warnOnUnsupported, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
precompile(Plots.link_axes!, (Plots.GridLayout, Symbol,))
precompile(Plots.warnOnUnsupported, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots._update_plot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.font, (Int64,))
precompile(Plots.recompute_lengths, (Array{Measures.Measure, 1},))
precompile(Plots._update_plot_object, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.font, (Symbol,))
precompile(Plots.create_grid, (Expr,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Void, Int64,))
precompile(Plots.pickDefaultBackend, ())
precompile(Plots.default_should_widen, (Plots.Axis,))
precompile(Plots.setup_atom, ())
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Symbol, Int64,))
precompile(Plots.my_hist_2d, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1}, Int64,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, ASCIIString, Int64,))
precompile(Plots.create_grid_curly, (Expr,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Bool, Int64,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Int64, Int64,))
precompile(Plots.my_hist, (Array{Any, 1}, Array{Float64, 1}, Int64,))
precompile(Plots.getpctrange, (Int64,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1},))
precompile(Plots.default, (Symbol,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
precompile(Plots.pie_labels, (Plots.Subplot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Measures.Length{:mm, Float64}, Int64,))
precompile(Plots.py_path, (Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots._update_min_padding!, (Plots.GridLayout,))
precompile(Plots.warnOnUnsupported_scales, (Plots.UnicodePlotsBackend, Base.Dict{Symbol, Any},))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Plots.Font, Int64,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Tuple{Int64, Int64}, Symbol,))
precompile(Plots.slice_arg!, (Array{Any, 1}, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Symbol, Array{Any, 1}, Int64,))
precompile(Plots.default, (Symbol, Tuple{Int64, Int64},))
precompile(Plots.warnOnUnsupported_scales, (Plots.PyPlotBackend, Base.Dict{Symbol, Any},))
precompile(Plots.axis_limits, (Plots.Axis, Bool,))
precompile(Plots.default, (Symbol, Bool,))
precompile(Plots.getColorZ, (Plots.ColorGradient, Float64,))
precompile(Plots._update_plot_args, (Plots.Plot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.Surface}, Function, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
precompile(Plots.font, (Symbol,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, Base.StepRange{Int64, Int64}, Symbol,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.UnicodePlotsBackend,))
precompile(Plots.extractGroupArgs, (Array{ASCIIString, 1}, Array{Float64, 1},))
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.Subplot}, Plots.PyPlotBackend,))
precompile(Plots._update_subplot_args, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.extractGroupArgs, (Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots.bbox_to_pcts, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}}, Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}, Bool,))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.py_marker, (Plots.Shape,))
precompile(Plots.getindex, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.getindex, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.discrete_value!, (Plots.Axis, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots.prepare_output, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.update_inset_bboxes!, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.add_layout_pct!, (Base.Dict{Symbol, Any}, Expr, Int64, Int64,))
precompile(Plots.process_axis_arg!, (Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
precompile(Plots.call, (Type{Plots.Shape}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 2},))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout}, Plots.RootLayout,))
precompile(Plots.plot, (Array{Any, 1}, Function, Function,))
precompile(Plots.should_add_to_legend, (Plots.Series,))
precompile(Plots.plot, (Array{Any, 1}, DataFrames.DataFrame, Symbol,))
precompile(Plots.plot, (Array{Any, 1}, Array{Plots.OHLC, 1},))
precompile(Plots.convertToAnyVector, (Array{Float64, 2}, Base.Dict{Symbol, Any},))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Array{ASCIIString, 1}, Array{Float64, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Symbol, 1}, Int64,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Int64, 1},))
precompile(Plots.pie, (Array{Any, 1}, Array{ASCIIString, 1},))
precompile(Plots.aliasesAndAutopick, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any}, Array{Any, 1}, Int64,))
precompile(Plots.merge_with_base_supported, (Array{Symbol, 1},))
precompile(Plots.histogram2d, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.StepRange{Int64, Int64}, Array{Float64, 2},))
precompile(Plots.plot, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.font, ())
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Any, 1}, Base.FloatRange{Float64}, Base.FloatRange{Float64},))
precompile(Plots.plot, (Array{Any, 1}, Array{Function, 1}, Array{Float64, 1},))
precompile(Plots.scatter, (Array{Any, 1}, Base.LinSpace{Float64},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Base.LinSpace{Float64},))
precompile(Plots.plot!, (Array{Any, 1}, Base.LinSpace{Float64}, Array{Float64, 1},))
precompile(Plots.get_zvalues, (Int64,))
precompile(Plots.plot, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots.histogram, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.hline!, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.layout_args, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.heatmap, (Array{Any, 1}, Array{Union{UTF8String, ASCIIString}, 1},))
precompile(Plots._replace_linewidth, (Base.Dict{Symbol, Any},))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
precompile(Plots.py_markercolor, (Base.Dict{Symbol, Any},))
precompile(Plots.unzip, (Array{Tuple{Float64, Float64}, 1},))
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 2}, Symbol,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1},))
precompile(Plots.contour, (Array{Any, 1}, Base.FloatRange{Float64},))
precompile(Plots.scatter, (Array{Any, 1}, DataFrames.DataFrame,))
precompile(Plots.scatter!, (Array{Any, 1}, Base.LinSpace{Float64},))
precompile(Plots.scatter!, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.getxy, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
precompile(Plots.plot, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.get_xy, (Array{Plots.OHLC, 1}, Base.UnitRange{Int64},))
precompile(Plots.convertToAnyVector, (Array{Function, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Int64, Float64, Plots.PlotText,))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 1},))
precompile(Plots.get_color_palette, (Symbol, ColorTypes.RGB{Float64}, Int64,))
precompile(Plots.py_add_annotations, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Plots.PlotText,))
precompile(Plots.py_colormap, (Plots.ColorGradient, Float64,))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Stroke,))
precompile(Plots.call, (Type{Plots.ColorVector}, Array{Symbol, 1},))
precompile(Plots.py_colormap, (Plots.ColorGradient, Void,))
precompile(Plots.py_fillcolor, (Base.Dict{Symbol, Any},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Float64,))
precompile(Plots.plot!, (Array{Any, 1}, Array{Float64, 2},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.call, (Type{Plots.Plot},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1},))
precompile(Plots.plot!, (Array{Any, 1}, Array{Int64, 1},))
precompile(Plots.getExtension, (UTF8String,))
precompile(Plots.call, (Array{Any, 1}, Type{Plots.EmptyLayout},))
precompile(Plots.update!, (Array{Any, 1}, Plots.Axis,))
precompile(Plots.frame, (Plots.Animation, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.link_axes!, (Array{Plots.AbstractLayout, 1}, Symbol,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1},))
precompile(Plots.fakedata, (Int64,))
precompile(Plots.plot!, (Array{Any, 1}, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.py_compute_axis_minval, (Plots.Axis,))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.command_idx, (Array{Base.Dict{Symbol, Any}, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.getindex, (Plots.Axis, Symbol,))
precompile(Plots.__init__, ())
precompile(Plots.isvertical, (Base.Dict{Symbol, Any},))
precompile(Plots.getExtension, (ASCIIString,))
precompile(Plots.py_marker, (Symbol,))
precompile(Plots.py_init_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64},))
precompile(Plots.bucket_index, (Float64, Base.LinSpace{Float64},))
precompile(Plots.default, (Array{Any, 1},))
precompile(Plots.filter_data!, (Base.Dict{Symbol, Any}, Array{Int64, 1},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{Symbol, 1}, Base.LinSpace{Float64},))
precompile(Plots.slice_arg, (Array{Symbol, 2}, Int64,))
precompile(Plots.getindex, (Plots.Plot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.plot!, (Array{Any, 1},))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.FloatRange{Float64},))
precompile(Plots.getindex, (Plots.Plot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.handle_dfs, (DataFrames.DataFrame, Base.Dict{Symbol, Any}, ASCIIString, Symbol,))
precompile(Plots.filter_data, (Base.UnitRange{Int64}, Array{Int64, 1},))
precompile(Plots.call, (Type{Plots.ColorWrapper}, ColorTypes.RGBA{Float64},))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
precompile(Plots.processLineArg, (Base.Dict{Symbol, Any}, Array{Symbol, 2},))
precompile(Plots.color_or_nothing!, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.processMarkerArg, (Base.Dict{Symbol, Any}, Plots.Shape,))
precompile(Plots.py_fillcolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.transpose_z, (Base.Dict{Symbol, Any}, Array{Float64, 2}, Bool,))
precompile(Plots.py_linecolor, (Base.Dict{Symbol, Any},))
precompile(Plots.call, (Type{Plots.OHLC}, Float64, Float64, Float64, Float64,))
precompile(Plots.setxy!, (Plots.Plot{Plots.PyPlotBackend}, Tuple{Array{Float64, 1}, Array{Float64, 1}}, Int64,))
precompile(Plots.push!, (Plots.Segments, Float64, Float64, Float64, Float64,))
precompile(Plots.handle_group, (DataFrames.DataFrame, Base.Dict{Symbol, Any},))
precompile(Plots.lightness_from_background, (ColorTypes.RGB{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.LinSpace{Float64},))
precompile(Plots.py_bbox, (Array{Any, 1},))
precompile(Plots.py_markerstrokecolor, (Base.Dict{Symbol, Any},))
precompile(Plots.arrow, ())
precompile(Plots.convert, (Type{Array{Float64, 1}}, Base.StepRange{Int64, Int64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Float64, 1},))
precompile(Plots.convertLegendValue, (Symbol,))
precompile(Plots.slice_arg, (Array{Measures.Length{:mm, Float64}, 2}, Int64,))
precompile(Plots.calc_num_subplots, (Plots.GridLayout,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.slice_arg, (Array{Plots.ColorWrapper, 2}, Int64,))
precompile(Plots.slice_arg, (Array{ASCIIString, 2}, Int64,))
precompile(Plots.filter_data, (Array{Float64, 1}, Array{Int64, 1},))
precompile(Plots.py_linecolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.discrete_value!, (Plots.Axis, ASCIIString,))
precompile(Plots.allShapes, (ColorTypes.RGBA{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Array{Int64, 1},))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.LinSpace{Float64},))
precompile(Plots.discrete_value!, (Plots.Axis, Symbol,))
precompile(Plots.push!, (Plots.Segments, Float64, Int64, Int64, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.heatmap_edges, (Array{Float64, 1},))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.StepRange{Int64, Int64},))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Shape, Symbol,))
precompile(Plots.py_color, (Plots.ColorWrapper, Float64,))
precompile(Plots.call, (Type{Plots.GridLayout}, Int64, Int64,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, ColorTypes.RGBA{Float64}, Symbol,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Bool, Symbol,))
precompile(Plots.hvline_limits, (Plots.Axis,))
precompile(Plots.current, ())
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Float64, Symbol,))
precompile(Plots.compute_gridsize, (Int64, Int64, Int64,))
precompile(Plots.py_color, (ColorTypes.RGB{Float64}, Void,))
precompile(Plots.interpolate_rgb, (ColorTypes.RGBA{Float64}, ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Base.UnitRange{Int64},))
precompile(Plots.allShapes, (Float64,))
precompile(Plots.warn_on_deprecated_backend, (Symbol,))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Int64, 1},))
precompile(Plots.setindex!, (Plots.GridLayout, Plots.EmptyLayout, Int64, Int64,))
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Int64, Int64},))
precompile(Plots.allShapes, (Int64,))
precompile(Plots.py_markercolormap, (Base.Dict{Symbol, Any},))
precompile(Plots.interpolate_rgb, (ColorTypes.RGB{Float64}, ColorTypes.RGB{Float64}, Float64,))
precompile(Plots.get_ticks, (Plots.Axis,))
precompile(Plots.backend, ())
precompile(Plots.get_xy, (Plots.OHLC{Float64}, Int64, Float64,))
precompile(Plots.allShapes, (Plots.Stroke,))
precompile(Plots.replaceAliases!, (Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any},))
precompile(Plots._create_backend_figure, (Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, UTF8String,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Symbol,))
precompile(Plots.allShapes, (Plots.Shape,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Plots.Stroke, Symbol,))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Array{Float64, 1},))
precompile(Plots.plot, (Array{Float64, 1},))
precompile(Plots.rowsize, (Expr,))
precompile(Plots.get_axis, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.png, (Plots.Plot{Plots.PyPlotBackend}, ASCIIString,))
precompile(Plots.expand_extrema!, (Plots.Axis, Tuple{Float64, Float64},))
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Plots.Shape,))
precompile(Plots.processFillArg, (Base.Dict{Symbol, Any}, Bool,))
precompile(Plots.supported_types, (Plots.PyPlotBackend,))
precompile(Plots.get_axis, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.setindex!, (Plots.GridLayout, Plots.GridLayout, Int64, Int64,))
precompile(Plots.plot, ())
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.FloatRange{Float64},))
precompile(Plots._markershape_supported, (Plots.PyPlotBackend, Symbol,))
precompile(Plots.ok, (Float64, Float64, Int64,))
precompile(Plots.allShapes, (Symbol,))
precompile(Plots._initialize_backend, (Plots.PyPlotBackend,))
precompile(Plots.plot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Plot{Plots.PyPlotBackend},))
precompile(Plots.bar, (Array{Float64, 1},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Base.LinSpace{Float64},))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Int64, Symbol,))
precompile(Plots.nanappend!, (Array{Float64, 1}, Array{Float64, 1},))
precompile(Plots.autopick, (Array{ColorTypes.RGBA, 1}, Int64,))
precompile(Plots.compute_xyz, (Void, Array{Int64, 1}, Void,))
precompile(Plots._add_markershape, (Base.Dict{Symbol, Any},))
precompile(Plots._backend_instance, (Symbol,))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.update_child_bboxes!, (Plots.GridLayout,))
precompile(Plots._replace_markershape, (Symbol,))
precompile(Plots.has_black_border_for_default, (Symbol,))
precompile(Plots._filter_input_data!, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Base.UnitRange{Int64},))
precompile(Plots.text, (ASCIIString, Int64, Symbol,))
precompile(Plots.allShapes, (Array{Symbol, 2},))
precompile(Plots.py_color_fix, (Tuple{Float64, Float64, Float64, Float64}, Base.UnitRange{Int64},))
precompile(Plots.replaceAlias!, (Base.Dict{Symbol, Any}, Symbol, Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{ASCIIString, 1}, Array{Float64, 1}, Void,))
precompile(Plots.layout_args, (Int64,))
precompile(Plots.text, (ASCIIString, Symbol, Int64,))
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Base.FloatRange{Float64}, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.all3D, (Base.Dict{Symbol, Any},))
precompile(Plots.cycle, (Array{Plots.Subplot, 1}, Int64,))
precompile(Plots.compute_xyz, (Base.StepRange{Int64, Int64}, Array{Float64, 1}, Void,))
precompile(Plots.plotarea!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.like_surface, (Symbol,))
precompile(Plots.build_layout, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Array{Union{UTF8String, ASCIIString}, 1}, Array{Union{UTF8String, ASCIIString}, 1}, Plots.Surface{Array{Float64, 2}},))
precompile(Plots.py_linestyle, (Symbol, Symbol,))
precompile(Plots.plot!, (Array{Float64, 2},))
precompile(Plots.plot!, (Plots.Plot{Plots.PyPlotBackend}, Array{Float64, 2},))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGB{Float64}, 1}, Base.LinSpace{Float64},))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64}, Void,))
precompile(Plots.yaxis!, (ASCIIString, Symbol,))
precompile(Plots.compute_xyz, (Base.LinSpace{Float64}, Array{Float64, 1}, Void,))
precompile(Plots.isijulia, ())
precompile(Plots.addExtension, (UTF8String, ASCIIString,))
precompile(Plots.call, (Type{Plots.ColorGradient}, Array{ColorTypes.RGBA{Float64}, 1}, Array{Float64, 1},))
precompile(Plots.expand_extrema!, (Plots.Subplot{Plots.PyPlotBackend}, Float64, Float64, Float64, Float64,))
precompile(Plots.plotarea!, (Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.layout_args, (Base.Dict{Symbol, Any},))
precompile(Plots.compute_xyz, (Base.FloatRange{Float64}, Array{Float64, 1}, Void,))
precompile(Plots.addExtension, (ASCIIString, ASCIIString,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Symbol, Symbol,))
precompile(Plots._initialize_backend, (Plots.PlotlyBackend,))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Int64, Float64, Float64,))
precompile(Plots.bbox!, (Plots.Subplot{Plots.PyPlotBackend}, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.vline!, (Array{Int64, 1},))
precompile(Plots.supported_markers, (Plots.PyPlotBackend,))
precompile(Plots.bbox!, (Plots.GridLayout, Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.stroke, (Int64,))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Array{Float64, 1}, Void,))
precompile(Plots.right, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.extractGroupArgs, (Symbol, DataFrames.DataFrame, Symbol,))
precompile(Plots.generate_colorgradient, (ColorTypes.RGB{Float64},))
precompile(Plots.expand_extrema!, (Plots.Extrema, Bool,))
precompile(Plots.py_colormap, (Plots.ColorWrapper, Void,))
precompile(Plots.expand_extrema!, (Plots.Extrema, Float64,))
precompile(Plots.contour, (Base.FloatRange{Float64},))
precompile(Plots.bottom, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.text, (ASCIIString, Symbol,))
precompile(Plots.create_grid, (Symbol,))
precompile(Plots.expand_extrema!, (Plots.Axis, Bool,))
precompile(Plots.handleColors!, (Base.Dict{Symbol, Any}, Array{Symbol, 2}, Symbol,))
precompile(Plots.convertToAnyVector, (Void, Base.Dict{Symbol, Any},))
precompile(Plots.py_dpi_scale, (Plots.Plot{Plots.PyPlotBackend}, Int64,))
precompile(Plots.png, (ASCIIString,))
precompile(Plots.supported_scales, (Plots.PyPlotBackend,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Float64,))
precompile(Plots.extendSeriesData, (Array{Float64, 1}, Float64,))
precompile(Plots.compute_xyz, (Void, Array{Float64, 1}, Void,))
precompile(Plots.py_color, (Symbol,))
precompile(Plots.expand_extrema!, (Plots.Extrema, Int64,))
precompile(Plots.supported_styles, (Plots.PyPlotBackend,))
precompile(Plots._initialize_backend, (Plots.UnicodePlotsBackend,))
precompile(Plots._initialize_backend, (Plots.GRBackend,))
precompile(Plots.is3d, (Symbol,))
precompile(Plots.supported_types, (Plots.UnicodePlotsBackend,))
precompile(Plots.compute_xyz, (Array{Float64, 1}, Function, Void,))
precompile(Plots.py_color, (Symbol, Void,))
precompile(Plots.trueOrAllTrue, (Function, Array{Symbol, 2},))
precompile(Plots.typemin, (Measures.Length{:mm, Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Float64,))
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.leftpad, (Plots.GridLayout,))
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots.centers, (Base.LinSpace{Float64},))
precompile(Plots.expand_extrema!, (Plots.Axis, Int64,))
precompile(Plots.text, (ASCIIString,))
precompile(Plots.convertColor, (ColorTypes.RGB{Float64},))
precompile(Plots.py_color, (Plots.ColorWrapper, Void,))
precompile(Plots.py_color, (Plots.ColorWrapper,))
precompile(Plots.trueOrAllTrue, (Function, Int64,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64},))
precompile(Plots.extrema, (Plots.Axis,))
precompile(Plots.top, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.convertColor, (Symbol,))
precompile(Plots.size, (Plots.Surface{Array{Float64, 2}},))
precompile(Plots.isdark, (ColorTypes.RGB{Float64},))
precompile(Plots.rowsize, (Symbol,))
precompile(Plots.series_list, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.convertToAnyVector, (Array{Float64, 1}, Base.Dict{Symbol, Any},))
precompile(Plots.update!, (Plots.Axis,))
precompile(Plots.push!, (Plots.Plot{Plots.PyPlotBackend}, Float64, Array{Float64, 1},))
precompile(Plots.wraptuple, (Bool,))
precompile(Plots.call, (Type{Plots.Shape}, Array{Tuple{Float64, Float64}, 1},))
precompile(Plots.slice_arg, (Base.StepRange{Int64, Int64}, Int64,))
precompile(Plots.sticks_fillfrom, (Void, Int64,))
precompile(Plots.left, (Measures.BoundingBox{Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}, Tuple{Measures.Length{:mm, Float64}, Measures.Length{:mm, Float64}}},))
precompile(Plots.gr, ())
precompile(Plots.leftpad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.supported_markers, ())
precompile(Plots.colorscheme, (Symbol,))
precompile(Plots.convertColor, (ColorTypes.RGB{Float64}, Void,))
precompile(Plots.isscalar, (Int64,))
precompile(Plots.wraptuple, (Int64,))
precompile(Plots.call, (Type{Plots.Plot}, Plots.UnicodePlotsBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.supported_styles, ())
precompile(Plots.frame, (Plots.Animation,))
precompile(Plots.toppad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.link_axes!, (Plots.Subplot{Plots.UnicodePlotsBackend}, Symbol,))
precompile(Plots.convertLegendValue, (Bool,))
precompile(Plots.convertColor, (ColorTypes.RGBA{Float64}, Void,))
precompile(Plots.plotly, ())
precompile(Plots.ispositive, (Measures.Length{:mm, Float64},))
precompile(Plots.rightpad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.GroupBy}, Array{ASCIIString, 1}, Array{Array{Int64, 1}, 1},))
precompile(Plots.px2inch, (Int64,))
precompile(Plots.slice_arg, (Tuple{Int64, Int64}, Int64,))
precompile(Plots.call, (Type{Plots.UnicodePlotsBackend},))
precompile(Plots.trueOrAllTrue, (Function, Symbol,))
precompile(Plots.bottompad, (Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.annotate!, (Array{Tuple{Int64, Float64, Plots.PlotText}, 1},))
precompile(Plots.get_subplot_index, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.Plot}, Plots.PyPlotBackend, Int64, Base.Dict{Symbol, Any}, Base.Dict{Symbol, Any}, Array{Plots.Series, 1}, Void, Array{Plots.Subplot, 1}, Base.Dict{Any, Plots.Subplot}, Plots.EmptyLayout, Array{Plots.Subplot, 1}, Bool,))
precompile(Plots.title!, (ASCIIString,))
precompile(Plots.slice_arg, (Bool, Int64,))
precompile(Plots.wraptuple, (Float64,))
precompile(Plots.bottompad, (Plots.GridLayout,))
precompile(Plots.py_stepstyle, (Symbol,))
precompile(Plots.link_axes!, (Plots.Subplot{Plots.PyPlotBackend}, Symbol,))
precompile(Plots.call, (Type{Plots.GRBackend},))
precompile(Plots.unicodeplots, ())
precompile(Plots.rightpad, (Plots.GridLayout,))
precompile(Plots.call, (Type{Plots.PlotlyBackend},))
precompile(Plots.py_color, (ColorTypes.RGBA{Float64},))
precompile(Plots.toppad, (Plots.GridLayout,))
precompile(Plots.calc_edges, (Array{Float64, 1}, Int64,))
precompile(Plots.colorscheme, (ColorTypes.RGBA{Float64},))
precompile(Plots.slice_arg, (Int64, Int64,))
precompile(Plots.pyplot, ())
precompile(Plots._update_subplot_args, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend}, Base.Dict{Symbol, Any}, Int64,))
precompile(Plots._series_added, (Plots.Plot{Plots.PyPlotBackend}, Plots.Series,))
precompile(Plots.get_color_palette, (Array{ColorTypes.RGBA, 1}, ColorTypes.RGB{Float64}, Int64,))
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.slice_arg, (Void, Int64,))
precompile(Plots.cycle, (Int64, Int64,))
precompile(Plots._initialize_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.call, (Type{Plots.PyPlotBackend},))
precompile(Plots.update_child_bboxes!, (Plots.Subplot{Plots.PyPlotBackend}, Array{Measures.Length{:mm, Float64}, 1},))
precompile(Plots.filter_data, (Void, Array{Int64, 1},))
precompile(Plots.slice_arg, (Symbol, Int64,))
precompile(Plots.slice_arg, (ASCIIString, Int64,))
precompile(Plots.layout_args, (Plots.GridLayout,))
precompile(Plots.wraptuple, (Tuple{},))
precompile(Plots.calc_num_subplots, (Plots.EmptyLayout,))
precompile(Plots.wraptuple, (Tuple{Symbol, Float64, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{ASCIIString, Tuple{Int64, Int64}, Base.StepRange{Int64, Int64}, Symbol},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Float64, Array{Symbol, 2}},))
precompile(Plots.wraptuple, (Tuple{Int64, Array{Symbol, 2}},))
precompile(Plots.wraptuple, (Tuple{ASCIIString, Symbol},))
precompile(Plots._replace_markershape, (Array{Symbol, 2},))
precompile(Plots.wraptuple, (Tuple{Symbol, Int64},))
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol, Symbol},))
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{Float64, Array{Symbol, 2}, Int64},))
precompile(Plots.py_color, (ColorTypes.RGB{Float64},))
precompile(Plots.wraptuple, (Tuple{Int64, Float64, Symbol},))
precompile(Plots.tovec, (Array{Float64, 1},))
precompile(Plots.get_subplot, (Plots.Plot{Plots.PyPlotBackend}, Plots.Subplot{Plots.PyPlotBackend},))
precompile(Plots.eltype, (Plots.Surface{Array{Float64, 2}},))
precompile(Plots.nobigs, (Array{Float64, 1},))
precompile(Plots.get_subplot, (Plots.Plot{Plots.UnicodePlotsBackend}, Plots.Subplot{Plots.UnicodePlotsBackend},))
precompile(Plots.annotations, (Array{Any, 1},))
precompile(Plots.wraptuple, (Tuple{Int64, Symbol},))
precompile(Plots.colorscheme, (Plots.ColorWrapper,))
precompile(Plots.colorscheme, (Plots.ColorGradient,))
precompile(Plots.text, (Plots.PlotText,))
precompile(Plots._replace_markershape, (Plots.Shape,))
precompile(Plots.wraptuple, (Tuple{Array{Symbol, 2}, Int64, Float64, Plots.Stroke},))
precompile(Plots.wraptuple, (Tuple{Plots.Shape, Int64, ColorTypes.RGBA{Float64}},))
end
+412 -555
View File
File diff suppressed because it is too large Load Diff
+132 -95
View File
@@ -1,78 +1,106 @@
# 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]
# 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
# 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
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
# 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
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
# missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
# update color
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp, plotIndex)
# fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# 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
# numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
# update markerstrokecolor
c = d[:markerstrokecolor]
c = if c == :match
sp[:foreground_color_subplot]
# string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW)
if all3D(d)
Any[Surface(v)]
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
Any[v[:,i] for i in 1:size(v,2)]
end, nothing
end
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# function
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
# instead of process_inputs:
# 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!")
# --------------------------------------------------------------------
# we are going to build recipes to do the processing and splitting of the args
# ensure we dispatch to the slicer
immutable SliceIt end
@@ -117,7 +145,10 @@ immutable SliceIt end
end
# this is the default "type recipe"... just pass the object through
@recipe f{T}(::Type{T}, v::T) = v
@recipe f{T<:Any}(::Type{T}, v::T) = v
# this should catch unhandled "series recipes" and error with a nice message
@recipe f{V<:Val}(::Type{V}, x, y, z) = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
@@ -156,14 +187,23 @@ end
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
# if there's more than 3 inputs, it can't be passed directly to SliceIt
# so we'll apply_type_recipe to all of them
@recipe function f(v1, v2, v3, v4, vrest...)
did_replace = false
newargs = map(v -> begin
newv = _apply_type_recipe(d, v)
if newv !== v
did_replace = true
end
newv
end, (v1, v2, v3, v4, vrest...))
if !did_replace
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
end
newargs
end
# # --------------------------------------------------------------------
@@ -217,33 +257,30 @@ end
# # plotting arbitrary shapes/polygons
@recipe function f(shape::Shape)
seriestype := :shape
seriestype --> :shape
shape_coords(shape)
end
@recipe function f(shapes::AVec{Shape})
seriestype := :shape
seriestype --> :shape
shape_coords(shapes)
end
@recipe function f(shapes::AMat{Shape})
seriestype --> :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]))))
@series 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
# @recipe function f(f::FuncOrFuncs)
# plt = d[:plot_object]
# f, xmin(plt), xmax(plt)
# end
#
# # --------------------------------------------------------------------
@@ -268,22 +305,22 @@ end
# # 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
# 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
# st = get(d, :seriestype, :none)
# if size(x) == size(y) == size(z)
# if !is3d(st)
# seriestype := :path3d
# end
# end
SliceIt, x, y, z
end
@@ -323,7 +360,7 @@ end
@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)
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints = 200)
fx, fy, fz, linspace(umin, umax, numPoints)
end
-550
View File
@@ -1,550 +0,0 @@
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
# Special handling for: no args, xmin/xmax, parametric, dataframes
# Then once inputs have been converted, build the series args, map functions, etc.
# This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
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
+7 -6
View File
@@ -30,17 +30,18 @@ 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, idx::Integer) = Int(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
))
series.d[:primary] && series.d[:label] != "" &&
!(series.d[:seriestype] in (
:hexbin,:histogram2d,:hline,:vline,
:contour,:contourf,:contour3d,:surface,:wireframe,
:heatmap, :pie, :image
))
end
# ----------------------------------------------------------------------
+10 -7
View File
@@ -73,20 +73,23 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T}
subplots::Vector{Subplot}
spmap::SubplotMap # provide any label as a map to a subplot
layout::AbstractLayout
inset_subplots::Vector{Subplot} # list of inset subplots
init::Bool
end
function Plot()
Plot(backend(), 0, KW(), KW(), Series[], nothing,
Subplot[], SubplotMap(), EmptyLayout(), false)
Subplot[], SubplotMap(), EmptyLayout(),
Subplot[], 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)
# -----------------------------------------------------------------------
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
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)
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
# -----------------------------------------------------------------------
+144 -15
View File
@@ -131,20 +131,104 @@ function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
end
function imageHack(d::KW)
:heatmap in supportedTypes() || error("Neither :image or :heatmap are supported!")
:heatmap in supported_types() || error("Neither :image or :heatmap are supported!")
d[:seriestype] = :heatmap
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
end
# ---------------------------------------------------------------
type Segments
pts::Vector{Float64}
end
Segments() = Segments(zeros(0))
function Base.push!(segments::Segments, vs...)
push!(segments.pts, NaN)
for v in vs
push!(segments.pts, v)
end
segments
end
function Base.push!(segments::Segments, vs::AVec)
push!(segments.pts, NaN)
for v in vs
push!(segments.pts, v)
end
segments
end
# -----------------------------------------------------
# helper to manage NaN-separated segments
type SegmentsIterator
args::Tuple
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
SegmentsIterator(tup, n)
end
# helpers to figure out if there are NaN values in a list of array types
anynan(i::Int, args::Tuple) = any(a -> !isfinite(cycle(a,i)), args)
anynan(istart::Int, iend::Int, args::Tuple) = any(i -> anynan(i, args), istart:iend)
allnan(istart::Int, iend::Int, args::Tuple) = all(i -> anynan(i, args), istart:iend)
function Base.start(itr::SegmentsIterator)
nextidx = 1
if anynan(1, itr.args)
_, nextidx = next(itr, 1)
end
nextidx
end
Base.done(itr::SegmentsIterator, nextidx::Int) = nextidx > itr.n
function Base.next(itr::SegmentsIterator, nextidx::Int)
i = istart = iend = nextidx
# find the next NaN, and iend is the one before
while i <= itr.n + 1
if i > itr.n || anynan(i, itr.args)
# done... array end or found NaN
iend = i-1
break
end
i += 1
end
# find the next non-NaN, and set nextidx
while i <= itr.n
if !anynan(i, itr.args)
break
end
i += 1
end
istart:iend, i
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
Base.cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
Base.cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
Base.cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
Base.cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
Base.cycle(v, idx::Int) = v
Base.cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
Base.cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
Base.cycle(v, idx::AVec{Int}) = v
Base.cycle(grad::ColorGradient, idx::Int) = cycle(grad.colors, idx)
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
@@ -181,6 +265,7 @@ function _expand_limits(lims, x)
nothing
end
expand_data(v, n::Integer) = [cycle(v, i) for i=1:n]
# 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...)
@@ -199,20 +284,16 @@ function replaceType(vec, val)
push!(vec, val)
end
function replaceAlias!(d::KW, k::Symbol, aliases::KW)
function replaceAlias!(d::KW, k::Symbol, aliases::Dict{Symbol,Symbol})
if haskey(aliases, k)
d[aliases[k]] = pop!(d, k)
end
end
function replaceAliases!(d::KW, aliases::KW)
function replaceAliases!(d::KW, aliases::Dict{Symbol,Symbol})
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
@@ -232,6 +313,27 @@ function heatmap_edges(v::AVec)
end
function calc_r_extrema(x, y)
xmin, xmax = extrema(x)
ymin, ymax = extrema(y)
r = 0.5 * min(xmax - xmin, ymax - ymin)
extrema(r)
end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
phi, r = x, y
r = 0.5 * (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r))
x = zeros(n)
y = zeros(n)
for i in 1:n
x[i] = cycle(r,i) * cos(cycle(phi,i))
y[i] = cycle(r,i) * sin(cycle(phi,i))
end
x, y
end
function fakedata(sz...)
y = zeros(sz...)
for r in 2:size(y,1)
@@ -260,8 +362,11 @@ ismatrix(::Any) = false
isscalar(::Real) = true
isscalar(::Any) = false
is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2
isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.d)
# ticksType{T<:Real,S<:Real}(ticks::@compat(Tuple{T,S})) = :limits
@@ -285,6 +390,30 @@ 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))
function nansplit(v::AVec)
vs = Vector{eltype(v)}[]
while true
idx = findfirst(isnan, v)
if idx <= 0
# no nans
push!(vs, v)
break
elseif idx > 1
push!(vs, v[1:idx-1])
end
v = v[idx+1:end]
end
vs
end
function nanvcat(vs::AVec)
v_out = zeros(0)
for v in vs
nanappend!(v_out, v)
end
v_out
end
# 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)
@@ -297,7 +426,7 @@ 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)
function transpose_z(d, z, transpose_on_match::Bool = true)
if d[:match_dimensions] == transpose_on_match
z'
else
@@ -508,16 +637,16 @@ 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])
expand_extrema!(sp.attr[:xaxis], xyz[1])
expand_extrema!(sp.attr[:yaxis], xyz[2])
expand_extrema!(sp.attr[:zaxis], xyz[3])
_series_updated(plt, series)
end
# -------------------------------------------------------
# indexing notation
Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
# 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)
+2 -2
View File
@@ -1,12 +1,12 @@
julia 0.4
RecipesBase
Colors
PlotUtils
StatPlots
Reexport
Measures
FactCheck
Images
PyPlot
@osx QuartzImageIO
GR
DataFrames
+14 -9
View File
@@ -13,7 +13,9 @@ try
end
using Plots, FactCheck
using Plots
using StatPlots
using FactCheck
using Glob
default(size=(500,300))
@@ -22,7 +24,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.7.0"
const _current_plots_version = v"0.8.0"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
@@ -41,21 +43,24 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
fn = "ref$idx.png"
# firgure out version info
G = glob(relpath(refdir) * "/*")
G = glob(joinpath(relpath(refdir), "*"))
# @show refdir fn G
versions = map(fn -> VersionNumber(split(fn,"/")[end]), G)
slash = (@windows ? "\\" : "/")
versions = map(fn -> VersionNumber(split(fn, slash)[end]), G)
versions = reverse(sort(versions))
versions = filter(v -> v <= _current_plots_version, versions)
# @show refdir fn versions
reffn = nothing
newdir = joinpath(refdir, string(_current_plots_version))
newfn = joinpath(newdir, fn)
# figure out which reference file we should compare to, by finding the highest versioned file
reffn = nothing
for v in versions
try
tmpfn = joinpath(refdir, string(v), fn)
# @show "trying", tmpfn
f = open(tmpfn)
tmpfn = joinpath(refdir, string(v), fn)
if isfile(tmpfn)
reffn = tmpfn
break
end
end
+3 -3
View File
@@ -5,7 +5,7 @@ include("imgcomp.jl")
# don't actually show the plots
srand(1234)
default(show=false, reuse=true)
img_eps = 5e-2
img_eps = isinteractive() ? 1e-2 : 10e-2
# facts("Gadfly") do
# @fact gadfly() --> Plots.GadflyBackend()
@@ -23,14 +23,14 @@ facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
image_comparison_facts(:pyplot, skip=[30], eps=img_eps)
image_comparison_facts(:pyplot, skip=[], eps=img_eps)
end
facts("GR") do
@fact gr() --> Plots.GRBackend()
@fact backend() --> Plots.GRBackend()
@linux_only image_comparison_facts(:gr, skip=[30], eps=img_eps)
# @linux_only image_comparison_facts(:gr, skip=[], eps=img_eps)
end
facts("Plotly") do
+36
View File
@@ -0,0 +1,36 @@
import SnoopCompile
### Log the compiles
# This only needs to be run once (to generate "/tmp/plots_compiles.csv")
# SnoopCompile.@snoop "/tmp/plots_compiles.csv" begin
# include(Pkg.dir("Plots", "test","runtests.jl"))
# end
# ----------------------------------------------------------
### Parse the compiles and generate precompilation scripts
# This can be run repeatedly to tweak the scripts
# IMPORTANT: we must have the module(s) defined for the parcelation
# step, otherwise we will get no precompiles for the Plots module
using Plots
data = SnoopCompile.read("/tmp/plots_compiles.csv")
# The Plots tests are run inside a module PlotsTest, so all
# the precompiles get credited to PlotsTest. Credit them to Plots instead.
subst = Dict("PlotsTests"=>"Plots")
# Blacklist helps fix problems:
# - MIME uses type-parameters with symbols like :image/png, which is
# not parseable
blacklist = ["MIME"]
# Use these two lines if you want to create precompile functions for
# individual packages
pc, discards = SnoopCompile.parcel(data[end:-1:1,2], subst=subst, blacklist=blacklist)
SnoopCompile.write("/tmp/precompile", pc)
pdir = Pkg.dir("Plots")
run(`cp /tmp/precompile/precompile_Plots.jl $pdir/src/precompile.jl`)
+5 -6
View File
@@ -1,23 +1,22 @@
# 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/JuliaStats/KernelDensity.jl.git")
Pkg.clone("StatPlots")
# 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.checkout("RecipesBase")
Pkg.clone("VisualRegressionTests")
ENV["PYTHON"] = ""