diff --git a/.travis.yml b/.travis.yml
index 4663f986..275f1d99 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,8 +13,8 @@ script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
# - julia -e 'Pkg.clone("https://github.com/tbreloff/Images.jl.git"); Pkg.checkout("Images","tom_imgcompare");'
- - julia -e 'Pkg.clone("Images"); Pkg.build("Images")'
- - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
+ # - julia -e 'Pkg.clone("Images"); Pkg.build("Images")'
+ # - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
- julia -e 'Pkg.clone("https://github.com/tbreloff/VisualRegressionTests.jl.git");'
- julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
- julia -e 'Pkg.clone("Cairo"); Pkg.build("Cairo")'
diff --git a/README.md b/README.md
index 22740644..69f76c99 100644
--- a/README.md
+++ b/README.md
@@ -18,399 +18,4 @@ Plots is a plotting API and toolset. My goals with the package are:
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
-Check out the [summary graphs](img/supported/supported.md) for the features that each backend supports.
-
-Please add wishlist items, bugs, or any other comments/questions to the issues list.
-
-## Examples for each implemented backend:
-
-- [Gadfly.jl/Immerse.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/gadfly_examples.md)
-- [PyPlot.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/pyplot_examples.md)
-- [UnicodePlots.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/unicodeplots_examples.md)
-- [Qwt.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/qwt_examples.md)
-
-Also check out the many [IJulia notebooks](http://nbviewer.ipython.org/github/tbreloff/ExamplePlots.jl/tree/master/examples/) with many examples.
-
-## Installation
-
-First, add the package
-
-```julia
-Pkg.add("Plots")
-
-# if you want the latest features:
-Pkg.checkout("Plots")
-
-# or for the bleeding edge:
-Pkg.checkout("Plots", "dev")
-```
-
-then get any plotting packages you need (obviously, you should get at least one backend).
-
-```julia
-Pkg.add("Gadfly")
-Pkg.add("Immerse")
-Pkg.add("PyPlot")
-Pkg.add("UnicodePlots")
-Pkg.add("Qwt")
-Pkg.add("Bokeh")
-```
-
-## Use
-
-Load it in. The underlying plotting backends are not imported until `backend()` is called (which happens
-on your first call to `plot` or `subplot`). This means that you don't need any backends to be installed when you call `using Plots`.
-
-Plots will try to figure out a good default backend for you automatically based on what backends are installed.
-
-```julia
-using Plots
-```
-
-Do a plot in Gadfly (inspired by [this example](http://gadflyjl.org/geom_point.html)), then save a png:
-
-```julia
-gadfly() # switch to Gadfly as a backend
-dataframes() # turn on support for DataFrames inputs
-
-# load some data
-using RDatasets
-iris = dataset("datasets", "iris");
-
-# This will bring up a browser window with the plot. Add a semicolon at the end to skip display.
-scatter(iris, :SepalLength, :SepalWidth, group=:Species, m=([:+ :d :s], 12), smooth=0.99, bg=:black)
-
-# save a png (equivalent to png("gadfly1.png") and savefig("gadfly1.png"))
-png("gadfly1")
-```
-
-
-
-## API
-
-Call `backend(backend::Symbol)` or the shorthands (`gadfly()`, `qwt()`, `unicodeplots()`, etc) to set the current plotting backend.
-Subsequent commands are converted into the relevant plotting commands for that package:
-
-```julia
-gadfly()
-plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
-qwt()
-plot(1:10) # this effectively calls `Qwt.plot(1:10)`
-```
-
-Use `plot` to create a new plot object, and `plot!` to add to an existing one:
-
-```julia
-plot(args...; kw...) # creates a new plot window, and sets it to be the `current`
-plot!(args...; kw...) # adds to the `current`
-plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
-```
-
-Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity.
-There are many ways to pass in data to the plot functions... some examples:
-
-- Vector-like (subtypes of AbstractArray{T,1})
-- Matrix-like (subtypes of AbstractArray{T,2})
-- Vectors of Vectors
-- Functions
-- Vectors of Functions
-- DataFrames with column symbols (initialize with `dataframes()`)
-
-In general, you can pass in a `y` only, or an `x` and `y`, both of whatever type(s) you want, and Plots will slice up the data as needed.
-For matrices, data is split by columns. For functions, data is mapped. For DataFrames, a Symbol/Symbols in place of x/y will map to
-the relevant column(s).
-
-Here are some example usages... remember you can always use `plot!` to update an existing plot, and that, unless specified, you will update the `current()`.
-
-```julia
-plot() # empty plot object
-plot(4) # initialize with 4 empty series
-plot(rand(10)) # plot 1 series... x = 1:10
-plot(rand(10,5)) # plot 5 series... x = 1:10
-plot(rand(10), rand(10)) # plot 1 series
-plot(rand(10,5), rand(10)) # plot 5 series... y is the same for all
-plot(sin, rand(10)) # y = sin(x)
-plot(rand(10), sin) # same... y = sin(x)
-plot([sin,cos], 0:0.1:π) # plot 2 series, sin(x) and cos(x)
-plot([sin,cos], 0, π) # plot sin and cos on the range [0, π]
-plot(1:10, Any[rand(10), sin]) # plot 2 series, y = rand(10) for the first, y = sin(x) for the second... x = 1:10 for both
-plot(dataset("Ecdat", "Airline"), :Cost) # plot from a DataFrame (call `dataframes()` first to import DataFrames and initialize)
-```
-
-All plot methods accept a number of keyword arguments (see the tables below), which follow some rules:
-- Many arguments have aliases which are replaced during preprocessing. `c` is the same as `color`, `m` is the same as `marker`, etc. You can choose how verbose you'd like to be. (see the tables below)
-- There are some special arguments (`xaxis`, `yaxis`, `line`, `marker`, `fill` and the aliases `l`, `m`, `f`) which magically set many related things at once. (see the __Tip__ below)
-- If the argument is a "matrix-type", then each column will map to a series, cycling through columns if there are fewer columns than series. Anything else will apply the argument value to every series.
-- Many arguments accept many different types... for example the `color` (also `markercolor`, `fillcolor`, etc) argument will accept strings or symbols with a color name, or any `Colors.Colorant`, or a `ColorScheme`, or a symbol representing a `ColorGradient`, or an AbstractVector of colors/symbols/etc...
-
-You can update certain plot settings after plot creation (not supported on all backends):
-
-```julia
-plot!(title = "New Title", xlabel = "New xlabel", ylabel = "New ylabel")
-plot!(xlims = (0, 5.5), ylims = (-2.2, 6), xticks = 0:0.5:10, yticks = [0,1,5,10])
-
-# using shorthands:
-xaxis!("mylabel", :log10, :flip)
-```
-
-With `subplot`, create multiple plots at once, with flexible layout options:
-
-```julia
-y = rand(100,3)
-subplot(y; n = 3) # create an automatic grid, and let it figure out the shape
-subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows
-subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns
-subplot(y; layout = [1, 2]) # explicit layout. Lists the number of plots in each row
-```
-
-__Tip__: You can call `subplot!(args...; kw...)` to add to an existing subplot.
-
-__Tip__: Calling `subplot!` on a `Plot` object, or `plot!` on a `Subplot` object will throw an error.
-
-Shorthands:
-
-```julia
-scatter(args...; kw...) = plot(args...; kw..., linetype = :scatter)
-scatter!(args...; kw...) = plot!(args...; kw..., linetype = :scatter)
-bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
-bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
-histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
-histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
-heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
-heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
-sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
-sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
-hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
-hline!(args...; kw...) = plot!(args...; kw..., linetype = :hline)
-vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
-vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
-ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
-ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
-
-title!(s::AbstractString) = plot!(title = s)
-xlabel!(s::AbstractString) = plot!(xlabel = s)
-ylabel!(s::AbstractString) = plot!(ylabel = s)
-xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(xlims = lims)
-ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(ylims = lims)
-xticks!{T<:Real}(v::AVec{T}) = plot!(xticks = v)
-yticks!{T<:Real}(v::AVec{T}) = plot!(yticks = v)
-xflip!(flip::Bool = true) = plot!(xflip = flip)
-yflip!(flip::Bool = true) = plot!(yflip = flip)
-xaxis!(args...) = plot!(xaxis = args)
-yaxis!(args...) = plot!(yaxis = args)
-annotate!(anns) = plot!(annotation = anns)
-```
-
-### Keyword arguments:
-
-Keyword | Default | Type | Aliases
----- | ---- | ---- | ----
-`:annotation` | `nothing` | Series | `:ann`, `:annotate`, `:annotations`, `:anns`
-`:axis` | `left` | Series | `:axiss`
-`:background_color` | `RGB{U8}(1.0,1.0,1.0)` | Plot | `:background`, `:background_colour`, `:bg`, `:bg_color`, `:bgcolor`
-`:color_palette` | `auto` | Plot | `:palette`
-`:fill` | `nothing` | Series | `:area`, `:f`
-`:fillalpha` | `nothing` | Series | `:fa`, `:fillalphas`, `:fillopacity`
-`:fillcolor` | `match` | Series | `:fc`, `:fcolor`, `:fillcolors`, `:fillcolour`
-`:fillrange` | `nothing` | Series | `:fillranges`, `:fillrng`
-`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground`, `:foreground_colour`
-`:grid` | `true` | Plot |
-`:group` | `nothing` | Series | `:g`, `:groups`
-`:guidefont` | `Plots.Font("Helvetica",11,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
-`:label` | `AUTO` | Series | `:lab`, `:labels`
-`:layout` | `nothing` | Plot |
-`:legend` | `true` | Plot | `:leg`
-`:legendfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
-`:line` | `nothing` | Series | `:l`
-`:linealpha` | `nothing` | Series | `:la`, `:linealphas`, `:lineopacity`
-`:linecolor` | `auto` | Series | `:c`, `:color`, `:colour`, `:linecolors`
-`:linestyle` | `solid` | Series | `:linestyles`, `:ls`, `:s`, `:style`
-`:linetype` | `path` | Series | `:linetypes`, `:lt`, `:t`, `:type`
-`:linewidth` | `1` | Series | `:linewidths`, `:lw`, `:w`, `:width`
-`:link` | `false` | Plot |
-`:linkfunc` | `nothing` | Plot |
-`:linkx` | `false` | Plot | `:xlink`
-`:linky` | `false` | Plot | `:ylink`
-`:marker` | `nothing` | Series | `:m`, `:mark`
-`:markeralpha` | `nothing` | Series | `:alpha`, `:ma`, `:markeralphas`, `:markeropacity`, `:opacity`
-`:markercolor` | `match` | Series | `:markercolors`, `:markercolour`, `:mc`, `:mcolor`
-`:markershape` | `none` | Series | `:markershapes`, `:shape`
-`:markersize` | `6` | Series | `:markersizes`, `:ms`, `:msize`
-`:markerstrokealpha` | `nothing` | Series | `:markerstrokealphas`
-`:markerstrokecolor` | `match` | Series | `:markerstrokecolors`
-`:markerstrokestyle` | `solid` | Series | `:markerstrokestyles`
-`:markerstrokewidth` | `1` | Series | `:markerstrokewidths`
-`:n` | `-1` | Plot |
-`:nbins` | `30` | Series | `:nb`, `:nbin`, `:nbinss`
-`:nc` | `-1` | Plot |
-`:nlevels` | `15` | Series | `:nlevelss`
-`:nr` | `-1` | Plot |
-`:pos` | `(0,0)` | Plot |
-`:show` | `false` | Plot | `:display`, `:gui`
-`:size` | `(500,300)` | Plot | `:windowsize`, `:wsize`
-`:smooth` | `false` | Series | `:reg`, `:regression`, `:smooths`
-`:surface` | `nothing` | Series | `:surfaces`
-`:tickfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
-`:title` | `` | Plot |
-`:windowtitle` | `Plots.jl` | Plot | `:wtitle`
-`:xaxis` | `nothing` | Plot |
-`:xflip` | `false` | Plot |
-`:xlabel` | `` | Plot | `:xlab`
-`:xlims` | `auto` | Plot | `:xlim`, `:xlimit`, `:xlimits`
-`:xscale` | `identity` | Plot |
-`:xticks` | `auto` | Plot | `:xtick`
-`:yaxis` | `nothing` | Plot |
-`:yflip` | `false` | Plot |
-`:ylabel` | `` | Plot | `:ylab`
-`:ylims` | `auto` | Plot | `:ylim`, `:ylimit`, `:ylimits`
-`:yrightlabel` | `` | Plot | `:y2lab`, `:y2label`, `:ylab2`, `:ylabel2`, `:ylabelright`, `:ylabr`, `:yrlab`
-`:yscale` | `identity` | Plot |
-`:yticks` | `auto` | Plot | `:ytick`
-`:z` | `nothing` | Series | `:zs`
-
-
-### Plot types:
-
-Type | Desc | Aliases
----- | ---- | ----
-`:none` | No line | `:n`, `:no`
-`:line` | Lines with sorted x-axis | `:l`
-`:path` | Lines | `:p`
-`:steppre` | Step plot (vertical then horizontal) | `:stepinv`, `:stepinverted`, `:stepsinv`, `:stepsinverted`
-`:steppost` | Step plot (horizontal then vertical) | `:stair`, `:stairs`, `:step`, `:steps`
-`:sticks` | Vertical lines | `:stem`, `:stems`
-`:scatter` | Points, no lines | `:dots`
-`:heatmap` | Colored regions by density |
-`:hexbin` | Similar to heatmap |
-`:hist` | Histogram (doesn't use x) | `:histogram`
-`:bar` | Bar plot (centered on x values) |
-`:hline` | Horizontal line (doesn't use x) |
-`:vline` | Vertical line (doesn't use x) |
-`:ohlc` | Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC}) |
-`:contour` | Contour lines (uses z) |
-`:path3d` | 3D path (uses z) | `:line3d`
-`:scatter3d` | 3D scatter plot (uses z) |
-
-
-### Line styles:
-
-Type | Aliases
----- | ----
-`:auto` | `:a`
-`:solid` | `:s`
-`:dash` | `:d`
-`:dot` |
-`:dashdot` | `:dd`
-`:dashdotdot` | `:ddd`
-
-
-### Markers:
-
-Type | Aliases
----- | ----
-`:none` | `:n`, `:no`
-`:auto` | `:a`
-`:cross` | `:+`, `:plus`
-`:diamond` | `:d`
-`:dtriangle` | `:V`, `:downtri`, `:downtriangle`, `:dt`, `:dtri`, `:v`
-`:ellipse` | `:c`, `:circle`
-`:heptagon` | `:hep`
-`:hexagon` | `:h`, `:hex`
-`:octagon` | `:o`, `:oct`
-`:pentagon` | `:p`, `:pent`
-`:rect` | `:r`, `:sq`, `:square`
-`:star4` |
-`:star5` | `:s`, `:star`, `:star1`
-`:star6` |
-`:star7` |
-`:star8` | `:s2`, `:star2`
-`:utriangle` | `:^`, `:uptri`, `:uptriangle`, `:ut`, `:utri`
-`:xcross` | `:X`, `:x`
-
-
-__Tip__: With supported backends, you can pass a `Plots.Shape` object for the `marker`/`markershape` arguments. `Shape` takes a vector of 2-tuples in the constructor, defining the points of the polygon's shape in a unit-scaled coordinate space. To make a square, for example, you could do `Shape([(1,1),(1,-1),(-1,-1),(-1,1)])`
-
-__Tip__: You can see the default value for a given argument with `default(arg::Symbol)`, and set the default value with `default(arg::Symbol, value)` or `default(; kw...)`. For example set the default window size and whether we should show a legend with `default(size=(600,400), leg=false)`.
-
-__Tip__: There are some helper arguments you can set: `xaxis`, `yaxis`, `line`, `marker`, `fill`. These go through special preprocessing to extract values into individual arguments. The order doesn't matter, and if you pass a single value it's equivalent to wrapping it in a Tuple. Examples:
-
-```
-plot(y, xaxis = ("mylabel", :log, :flip, (-1,1))) # this sets the `xlabel`, `xscale`, `xflip`, and `xlims` arguments automatically
-plot(y, line = (:bar, :blue, :dot, 10)) # this sets the `linetype`, `color`, `linestyle`, and `linewidth` arguments automatically
-plot(y, marker = (:rect, :red, 10)) # this sets the `markershape`, `markercolor`, and `markersize` arguments automatically
-plot(y, fill = (:green, 10)) # this sets the `fillcolor` and `fillrange` arguments automatically
- # Note: `fillrange` can be:
- a number (fill to horizontal line)
- a vector of numbers (different for each data point)
- a tuple of vectors (fill a band)
-```
-
-__Tip__: When plotting multiple lines, you can set all series to use the same value, or pass in a matrix to cycle through values. Example:
-
-```julia
-plot(rand(100,4); color = [:red RGB(0,0,1)], # (Matrix) lines 1 and 3 are red, lines 2 and 4 are blue
- axis = :auto, # lines 1 and 3 are on the left axis, lines 2 and 4 are on the right
- markershape = [:rect, :star] # (Vector) ALL lines are passed the vector [:rect, :star1]
- width = 5) # all lines have a width of 5
-```
-
-__Tip__: Not all features are supported for each backend, but you can see what's supported by calling the functions: `supportedArgs()`, `supportedAxes()`, `supportedTypes()`, `supportedStyles()`, `supportedMarkers()`, `subplotSupported()`
-
-__Tip__: Call `gui()` to display the plot in a window. Interactivity depends on backend. Plotting at the REPL (without semicolon) implicitly calls `gui()`.
-
-### Animations
-
-Animations are created in 3 steps (see example #2):
-- Initialize an `Animation` object.
-- Save each frame of the animation with `frame(anim)`.
-- Convert the frames to an animated gif with `gif(anim, filename, fps=15)`
-
-
-## TODO features:
-
-- [x] Plot vectors/matrices/functions
-- [x] Plot DataFrames
-- [x] Histograms
-- [x] Grouping
-- [x] Annotations
-- [x] Scales
-- [x] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
-- [x] Custom markers
-- [x] Animations
-- [x] Subplots
-- [ ] Contours
-- [ ] Boxplots
-- [ ] 3D plotting
-- [ ] Scenes/Drawing
-- [ ] Graphs
-- [ ] Interactivity (GUIs)
-
-## TODO backends:
-
-- [x] Gadfly.jl
-- [x] Immerse.jl
-- [x] PyPlot.jl
-- [x] UnicodePlots.jl
-- [x] Qwt.jl
-- [x] Winston.jl (deprecated)
-- [ ] GLPlot.jl
-- [ ] Bokeh.jl
-- [ ] Vega.jl
-- [ ] Gaston.jl
-- [ ] Plotly.jl
-- [ ] GoogleCharts.jl
-- [ ] PLplot.jl
-- [ ] TextPlots.jl
-- [ ] ASCIIPlots.jl
-- [ ] Sparklines.jl
-- [ ] Hinton.jl
-- [ ] ImageTerm.jl
-- [ ] GraphViz.jl
-- [ ] TikzGraphs.jl
-- [ ] GraphLayout.jl
-
-## More information on backends (both supported and unsupported)
-
-See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
-
-
+View the [full documentation](http://plots.readthedocs.org).
diff --git a/REQUIRE b/REQUIRE
index 04b7f31e..126413bb 100644
--- a/REQUIRE
+++ b/REQUIRE
@@ -3,3 +3,5 @@ julia 0.4
Colors
Reexport
Compat
+Requires
+FixedSizeArrays
diff --git a/docs/example_generation.jl b/deprecated/docs/example_generation.jl
similarity index 100%
rename from docs/example_generation.jl
rename to deprecated/docs/example_generation.jl
diff --git a/docs/readme_template.md b/deprecated/docs/readme_template.md
similarity index 100%
rename from docs/readme_template.md
rename to deprecated/docs/readme_template.md
diff --git a/img/gadfly1.png b/deprecated/img/gadfly1.png
similarity index 100%
rename from img/gadfly1.png
rename to deprecated/img/gadfly1.png
diff --git a/img/supported/Plots.supportGraphArgs.png b/deprecated/img/supported/Plots.supportGraphArgs.png
similarity index 100%
rename from img/supported/Plots.supportGraphArgs.png
rename to deprecated/img/supported/Plots.supportGraphArgs.png
diff --git a/img/supported/Plots.supportGraphAxes.png b/deprecated/img/supported/Plots.supportGraphAxes.png
similarity index 100%
rename from img/supported/Plots.supportGraphAxes.png
rename to deprecated/img/supported/Plots.supportGraphAxes.png
diff --git a/img/supported/Plots.supportGraphMarkers.png b/deprecated/img/supported/Plots.supportGraphMarkers.png
similarity index 100%
rename from img/supported/Plots.supportGraphMarkers.png
rename to deprecated/img/supported/Plots.supportGraphMarkers.png
diff --git a/img/supported/Plots.supportGraphScales.png b/deprecated/img/supported/Plots.supportGraphScales.png
similarity index 100%
rename from img/supported/Plots.supportGraphScales.png
rename to deprecated/img/supported/Plots.supportGraphScales.png
diff --git a/img/supported/Plots.supportGraphStyles.png b/deprecated/img/supported/Plots.supportGraphStyles.png
similarity index 100%
rename from img/supported/Plots.supportGraphStyles.png
rename to deprecated/img/supported/Plots.supportGraphStyles.png
diff --git a/img/supported/Plots.supportGraphTypes.png b/deprecated/img/supported/Plots.supportGraphTypes.png
similarity index 100%
rename from img/supported/Plots.supportGraphTypes.png
rename to deprecated/img/supported/Plots.supportGraphTypes.png
diff --git a/img/supported/supported.md b/deprecated/img/supported/supported.md
similarity index 100%
rename from img/supported/supported.md
rename to deprecated/img/supported/supported.md
diff --git a/src/plotter.jl b/deprecated/plotter.jl
similarity index 84%
rename from src/plotter.jl
rename to deprecated/plotter.jl
index 3ca93d15..ee62107b 100644
--- a/src/plotter.jl
+++ b/deprecated/plotter.jl
@@ -8,6 +8,7 @@ immutable UnicodePlotsPackage <: PlottingPackage end
immutable WinstonPackage <: PlottingPackage end
immutable BokehPackage <: PlottingPackage end
immutable PlotlyPackage <: PlottingPackage end
+immutable GRPackage <: PlottingPackage end
immutable GLVisualizePackage <: PlottingPackage end
immutable NoPackage <: PlottingPackage end
@@ -21,18 +22,20 @@ export
unicodeplots,
bokeh,
plotly,
+ gr,
glvisualize
# winston
-gadfly() = backend(:gadfly)
-immerse() = backend(:immerse)
-pyplot() = backend(:pyplot)
-qwt() = backend(:qwt)
-unicodeplots() = backend(:unicodeplots)
-bokeh() = backend(:bokeh)
-plotly() = backend(:plotly)
-glvisualize() = backend(:glvisualize)
-# winston() = backend(:winston)
+gadfly(; kw...) = (default(; kw...); backend(:gadfly))
+immerse(; kw...) = (default(; kw...); backend(:immerse))
+pyplot(; kw...) = (default(; kw...); backend(:pyplot))
+qwt(; kw...) = (default(; kw...); backend(:qwt))
+unicodeplots(; kw...) = (default(; kw...); backend(:unicodeplots))
+bokeh(; kw...) = (default(; kw...); backend(:bokeh))
+plotly(; kw...) = (default(; kw...); backend(:plotly))
+gr(; kw...) = (default(; kw...); backend(:gr))
+glvisualize(; kw...) = (default(; kw...); backend(:glvisualize))
+# winston(; kw...) = (default(; kw...); backend(:winston))
backend_name(::GadflyPackage) = :gadfly
backend_name(::ImmersePackage) = :immerse
@@ -41,6 +44,7 @@ backend_name(::UnicodePlotsPackage) = :unicodeplots
backend_name(::QwtPackage) = :qwt
backend_name(::BokehPackage) = :bokeh
backend_name(::PlotlyPackage) = :plotly
+backend_name(::GRPackage) = :gr
backend_name(::GLVisualizePackage) = :glvisualize
backend_name(::NoPackage) = :none
@@ -56,6 +60,7 @@ include("backends/winston.jl")
include("backends/web.jl")
include("backends/bokeh.jl")
include("backends/plotly.jl")
+include("backends/gr.jl")
include("backends/glvisualize.jl")
@@ -77,12 +82,12 @@ subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, s
# ---------------------------------------------------------
-const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly]
-const INITIALIZED_BACKENDS = Set{Symbol}()
+const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly, :gr]
+const _initialized_backends = Set{Symbol}()
backends() = BACKENDS
-function backendInstance(sym::Symbol)
+function _backend_instance(sym::Symbol)
sym == :qwt && return QwtPackage()
sym == :gadfly && return GadflyPackage()
sym == :unicodeplots && return UnicodePlotsPackage()
@@ -91,6 +96,7 @@ function backendInstance(sym::Symbol)
sym == :winston && return WinstonPackage()
sym == :bokeh && return BokehPackage()
sym == :plotly && return PlotlyPackage()
+ sym == :gr && return GRPackage()
sym == :glvisualize && return GLVisualizePackage()
sym == :none && return NoPackage()
error("Unsupported backend $sym")
@@ -101,12 +107,12 @@ type CurrentBackend
sym::Symbol
pkg::PlottingPackage
end
-CurrentBackend(sym::Symbol) = CurrentBackend(sym, backendInstance(sym))
+CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
# ---------------------------------------------------------
function pickDefaultBackend()
- for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "UnicodePlots", "Bokeh", "GLVisualize")
+ for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
if Pkg.installed(pkgstr) != nothing
return backend(symbol(lowercase(pkgstr)))
end
@@ -128,7 +134,7 @@ function backend()
end
currentBackendSymbol = CURRENT_BACKEND.sym
- if !(currentBackendSymbol in INITIALIZED_BACKENDS)
+ if !(currentBackendSymbol in _initialized_backends)
# initialize
println("[Plots.jl] Initializing backend: ", CURRENT_BACKEND.sym)
@@ -235,13 +241,26 @@ function backend()
# end borrowing (thanks :)
###########################
+ try
+ include(joinpath(Pkg.dir("Plots"), "src", "backends", "plotly_blink.jl"))
+ catch err
+ warn("Error including PlotlyJS: $err\n Note: Will fall back to built-in display.")
+ end
+
end
catch err
warn("Couldn't setup Plotly")
rethrow(err)
end
- elseif currentBackendSymbol == :glvisualize
+ elseif currentBackendSymbol == :gr
+ try
+ @eval import GR
+ catch err
+ warn("Couldn't import GR. Install it with: Pkg.add(\"GR\").")
+ end
+
+ elseif currentBackendSymbol == :glvisualize
try
@eval import GLVisualize
@eval export GLVisualize
@@ -264,7 +283,7 @@ function backend()
else
error("Unknown backend $currentBackendSymbol. Choose from: $BACKENDS")
end
- push!(INITIALIZED_BACKENDS, currentBackendSymbol)
+ push!(_initialized_backends, currentBackendSymbol)
end
CURRENT_BACKEND.pkg
@@ -297,7 +316,9 @@ function backend(modname)
CURRENT_BACKEND.pkg = BokehPackage()
elseif modname == :plotly
CURRENT_BACKEND.pkg = PlotlyPackage()
-elseif modname == :glvisualize
+ elseif modname == :gr
+ CURRENT_BACKEND.pkg = GRPackage()
+ elseif modname == :glvisualize
CURRENT_BACKEND.pkg = GLVisualizePackage()
else
error("Unknown backend $modname. Choose from: $BACKENDS")
diff --git a/test/refimg/gadfly/ref1.png b/deprecated/test/refimg/gadfly/ref1.png
similarity index 100%
rename from test/refimg/gadfly/ref1.png
rename to deprecated/test/refimg/gadfly/ref1.png
diff --git a/test/refimg/gadfly/ref10.png b/deprecated/test/refimg/gadfly/ref10.png
similarity index 100%
rename from test/refimg/gadfly/ref10.png
rename to deprecated/test/refimg/gadfly/ref10.png
diff --git a/test/refimg/gadfly/ref11.png b/deprecated/test/refimg/gadfly/ref11.png
similarity index 100%
rename from test/refimg/gadfly/ref11.png
rename to deprecated/test/refimg/gadfly/ref11.png
diff --git a/test/refimg/gadfly/ref12.png b/deprecated/test/refimg/gadfly/ref12.png
similarity index 100%
rename from test/refimg/gadfly/ref12.png
rename to deprecated/test/refimg/gadfly/ref12.png
diff --git a/deprecated/test/refimg/gadfly/ref13.png b/deprecated/test/refimg/gadfly/ref13.png
new file mode 100644
index 00000000..e533d428
Binary files /dev/null and b/deprecated/test/refimg/gadfly/ref13.png differ
diff --git a/test/refimg/gadfly/ref14.png b/deprecated/test/refimg/gadfly/ref14.png
similarity index 100%
rename from test/refimg/gadfly/ref14.png
rename to deprecated/test/refimg/gadfly/ref14.png
diff --git a/deprecated/test/refimg/gadfly/ref15.png b/deprecated/test/refimg/gadfly/ref15.png
new file mode 100644
index 00000000..a7847442
Binary files /dev/null and b/deprecated/test/refimg/gadfly/ref15.png differ
diff --git a/test/refimg/gadfly/ref16.png b/deprecated/test/refimg/gadfly/ref16.png
similarity index 100%
rename from test/refimg/gadfly/ref16.png
rename to deprecated/test/refimg/gadfly/ref16.png
diff --git a/test/refimg/gadfly/ref17.png b/deprecated/test/refimg/gadfly/ref17.png
similarity index 100%
rename from test/refimg/gadfly/ref17.png
rename to deprecated/test/refimg/gadfly/ref17.png
diff --git a/test/refimg/gadfly/ref18.png b/deprecated/test/refimg/gadfly/ref18.png
similarity index 100%
rename from test/refimg/gadfly/ref18.png
rename to deprecated/test/refimg/gadfly/ref18.png
diff --git a/test/refimg/gadfly/ref2.png b/deprecated/test/refimg/gadfly/ref2.png
similarity index 100%
rename from test/refimg/gadfly/ref2.png
rename to deprecated/test/refimg/gadfly/ref2.png
diff --git a/test/refimg/gadfly/ref20.png b/deprecated/test/refimg/gadfly/ref20.png
similarity index 100%
rename from test/refimg/gadfly/ref20.png
rename to deprecated/test/refimg/gadfly/ref20.png
diff --git a/test/refimg/gadfly/ref21.png b/deprecated/test/refimg/gadfly/ref21.png
similarity index 100%
rename from test/refimg/gadfly/ref21.png
rename to deprecated/test/refimg/gadfly/ref21.png
diff --git a/test/refimg/gadfly/ref22.png b/deprecated/test/refimg/gadfly/ref22.png
similarity index 100%
rename from test/refimg/gadfly/ref22.png
rename to deprecated/test/refimg/gadfly/ref22.png
diff --git a/test/refimg/gadfly/ref3.png b/deprecated/test/refimg/gadfly/ref3.png
similarity index 100%
rename from test/refimg/gadfly/ref3.png
rename to deprecated/test/refimg/gadfly/ref3.png
diff --git a/test/refimg/gadfly/ref4.png b/deprecated/test/refimg/gadfly/ref4.png
similarity index 100%
rename from test/refimg/gadfly/ref4.png
rename to deprecated/test/refimg/gadfly/ref4.png
diff --git a/test/refimg/gadfly/ref5.png b/deprecated/test/refimg/gadfly/ref5.png
similarity index 100%
rename from test/refimg/gadfly/ref5.png
rename to deprecated/test/refimg/gadfly/ref5.png
diff --git a/test/refimg/gadfly/ref6.png b/deprecated/test/refimg/gadfly/ref6.png
similarity index 100%
rename from test/refimg/gadfly/ref6.png
rename to deprecated/test/refimg/gadfly/ref6.png
diff --git a/test/refimg/gadfly/ref7.png b/deprecated/test/refimg/gadfly/ref7.png
similarity index 100%
rename from test/refimg/gadfly/ref7.png
rename to deprecated/test/refimg/gadfly/ref7.png
diff --git a/test/refimg/gadfly/ref8.png b/deprecated/test/refimg/gadfly/ref8.png
similarity index 100%
rename from test/refimg/gadfly/ref8.png
rename to deprecated/test/refimg/gadfly/ref8.png
diff --git a/test/refimg/gadfly/ref9.png b/deprecated/test/refimg/gadfly/ref9.png
similarity index 100%
rename from test/refimg/gadfly/ref9.png
rename to deprecated/test/refimg/gadfly/ref9.png
diff --git a/test/refimg/pyplot/ref1.png b/deprecated/test/refimg/pyplot/ref1.png
similarity index 100%
rename from test/refimg/pyplot/ref1.png
rename to deprecated/test/refimg/pyplot/ref1.png
diff --git a/test/refimg/pyplot/ref10.png b/deprecated/test/refimg/pyplot/ref10.png
similarity index 100%
rename from test/refimg/pyplot/ref10.png
rename to deprecated/test/refimg/pyplot/ref10.png
diff --git a/deprecated/test/refimg/pyplot/ref11.png b/deprecated/test/refimg/pyplot/ref11.png
new file mode 100644
index 00000000..c7ca4373
Binary files /dev/null and b/deprecated/test/refimg/pyplot/ref11.png differ
diff --git a/test/refimg/pyplot/ref12.png b/deprecated/test/refimg/pyplot/ref12.png
similarity index 100%
rename from test/refimg/pyplot/ref12.png
rename to deprecated/test/refimg/pyplot/ref12.png
diff --git a/deprecated/test/refimg/pyplot/ref13.png b/deprecated/test/refimg/pyplot/ref13.png
new file mode 100644
index 00000000..bc7a7265
Binary files /dev/null and b/deprecated/test/refimg/pyplot/ref13.png differ
diff --git a/test/refimg/pyplot/ref14.png b/deprecated/test/refimg/pyplot/ref14.png
similarity index 100%
rename from test/refimg/pyplot/ref14.png
rename to deprecated/test/refimg/pyplot/ref14.png
diff --git a/test/refimg/pyplot/ref15.png b/deprecated/test/refimg/pyplot/ref15.png
similarity index 100%
rename from test/refimg/pyplot/ref15.png
rename to deprecated/test/refimg/pyplot/ref15.png
diff --git a/test/refimg/pyplot/ref16.png b/deprecated/test/refimg/pyplot/ref16.png
similarity index 100%
rename from test/refimg/pyplot/ref16.png
rename to deprecated/test/refimg/pyplot/ref16.png
diff --git a/test/refimg/pyplot/ref17.png b/deprecated/test/refimg/pyplot/ref17.png
similarity index 100%
rename from test/refimg/pyplot/ref17.png
rename to deprecated/test/refimg/pyplot/ref17.png
diff --git a/test/refimg/pyplot/ref18.png b/deprecated/test/refimg/pyplot/ref18.png
similarity index 100%
rename from test/refimg/pyplot/ref18.png
rename to deprecated/test/refimg/pyplot/ref18.png
diff --git a/test/refimg/pyplot/ref2.png b/deprecated/test/refimg/pyplot/ref2.png
similarity index 100%
rename from test/refimg/pyplot/ref2.png
rename to deprecated/test/refimg/pyplot/ref2.png
diff --git a/test/refimg/pyplot/ref20.png b/deprecated/test/refimg/pyplot/ref20.png
similarity index 100%
rename from test/refimg/pyplot/ref20.png
rename to deprecated/test/refimg/pyplot/ref20.png
diff --git a/test/refimg/pyplot/ref21.png b/deprecated/test/refimg/pyplot/ref21.png
similarity index 100%
rename from test/refimg/pyplot/ref21.png
rename to deprecated/test/refimg/pyplot/ref21.png
diff --git a/test/refimg/pyplot/ref22.png b/deprecated/test/refimg/pyplot/ref22.png
similarity index 100%
rename from test/refimg/pyplot/ref22.png
rename to deprecated/test/refimg/pyplot/ref22.png
diff --git a/test/refimg/pyplot/ref24.png b/deprecated/test/refimg/pyplot/ref24.png
similarity index 100%
rename from test/refimg/pyplot/ref24.png
rename to deprecated/test/refimg/pyplot/ref24.png
diff --git a/test/refimg/pyplot/ref3.png b/deprecated/test/refimg/pyplot/ref3.png
similarity index 100%
rename from test/refimg/pyplot/ref3.png
rename to deprecated/test/refimg/pyplot/ref3.png
diff --git a/test/refimg/pyplot/ref4.png b/deprecated/test/refimg/pyplot/ref4.png
similarity index 100%
rename from test/refimg/pyplot/ref4.png
rename to deprecated/test/refimg/pyplot/ref4.png
diff --git a/test/refimg/pyplot/ref5.png b/deprecated/test/refimg/pyplot/ref5.png
similarity index 100%
rename from test/refimg/pyplot/ref5.png
rename to deprecated/test/refimg/pyplot/ref5.png
diff --git a/test/refimg/pyplot/ref6.png b/deprecated/test/refimg/pyplot/ref6.png
similarity index 100%
rename from test/refimg/pyplot/ref6.png
rename to deprecated/test/refimg/pyplot/ref6.png
diff --git a/test/refimg/pyplot/ref7.png b/deprecated/test/refimg/pyplot/ref7.png
similarity index 100%
rename from test/refimg/pyplot/ref7.png
rename to deprecated/test/refimg/pyplot/ref7.png
diff --git a/test/refimg/pyplot/ref8.png b/deprecated/test/refimg/pyplot/ref8.png
similarity index 100%
rename from test/refimg/pyplot/ref8.png
rename to deprecated/test/refimg/pyplot/ref8.png
diff --git a/test/refimg/pyplot/ref9.png b/deprecated/test/refimg/pyplot/ref9.png
similarity index 100%
rename from test/refimg/pyplot/ref9.png
rename to deprecated/test/refimg/pyplot/ref9.png
diff --git a/test/test_plottypes.jl b/deprecated/test/test_plottypes.jl
similarity index 100%
rename from test/test_plottypes.jl
rename to deprecated/test/test_plottypes.jl
diff --git a/src/Plots.jl b/src/Plots.jl
index feca5ce9..352d8aae 100644
--- a/src/Plots.jl
+++ b/src/Plots.jl
@@ -6,6 +6,8 @@ module Plots
using Compat
using Reexport
@reexport using Colors
+using Requires
+using FixedSizeArrays
export
Plot,
@@ -18,8 +20,6 @@ export
plot,
plot!,
- # plot_display,
- # plot_display!,
subplot,
subplot!,
@@ -33,6 +33,8 @@ export
bar!,
histogram,
histogram!,
+ histogram2d,
+ histogram2d!,
density,
density!,
heatmap,
@@ -57,8 +59,11 @@ export
wireframe!,
path3d,
path3d!,
+ plot3d,
+ plot3d!,
scatter3d,
scatter3d!,
+ abline!,
title!,
xlabel!,
@@ -79,6 +84,7 @@ export
backend,
backends,
+ backend_name,
aliases,
dataframes,
@@ -112,17 +118,14 @@ export
Animation,
frame,
gif,
+ @animate,
+ @gif,
# recipes
PlotRecipe,
# EllipseRecipe,
- # spy,
- corrplot
-
-# ---------------------------------------------------------
-
-
-const IMG_DIR = Pkg.dir("Plots") * "/img/"
+ spy
+ # corrplot
# ---------------------------------------------------------
@@ -131,7 +134,7 @@ include("types.jl")
include("utils.jl")
include("colors.jl")
include("components.jl")
-include("plotter.jl")
+include("plotter2.jl")
include("args.jl")
include("plot.jl")
include("subplot.jl")
@@ -148,6 +151,8 @@ bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
+histogram2d(args...; kw...) = plot(args...; kw..., linetype = :hist2d)
+histogram2d!(args...; kw...) = plot!(args...; kw..., linetype = :hist2d)
density(args...; kw...) = plot(args...; kw..., linetype = :density)
density!(args...; kw...) = plot!(args...; kw..., linetype = :density)
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
@@ -172,6 +177,8 @@ wireframe(args...; kw...) = plot(args...; kw..., linetype = :wireframe)
wireframe!(args...; kw...) = plot!(args...; kw..., linetype = :wireframe)
path3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
path3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
+plot3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
+plot3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
scatter3d(args...; kw...) = plot(args...; kw..., linetype = :scatter3d)
scatter3d!(args...; kw...) = plot!(args...; kw..., linetype = :scatter3d)
@@ -220,38 +227,16 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
# ---------------------------------------------------------
-
-# try
-# import DataFrames
-# dataframes()
-# end
-
-# const CURRENT_BACKEND = pickDefaultBackend()
-
-# for be in backends()
-# try
-# backend(be)
-# backend()
-# catch err
-# @show err
-# end
-# end
-
const CURRENT_BACKEND = CurrentBackend(:none)
-# function __init__()
-# # global const CURRENT_BACKEND = pickDefaultBackend()
-# # global const CURRENT_BACKEND = CurrentBackend(:none)
+function __init__()
-# # global CURRENT_BACKEND
-# # println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
-
-# # # auto init dataframes if the import statement doesn't error out
-# # try
-# # @eval import DataFrames
-# # dataframes()
-# # end
-# end
+ # override IJulia inline display
+ if isijulia()
+ @eval import IJulia
+ IJulia.display_dict(plt::PlottingObject) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
+ end
+end
# ---------------------------------------------------------
diff --git a/src/animation.jl b/src/animation.jl
index b923cf38..a11e48db 100644
--- a/src/animation.jl
+++ b/src/animation.jl
@@ -1,19 +1,18 @@
-immutable Animation{P<:PlottingObject}
- plt::P
+immutable Animation
dir::ASCIIString
frames::Vector{ASCIIString}
end
-function Animation(plt::PlottingObject)
- Animation(plt, mktempdir(), ASCIIString[])
+function Animation()
+ tmpdir = convert(ASCIIString, mktempdir())
+ Animation(tmpdir, ASCIIString[])
end
-Animation() = Animation(current())
-function frame(anim::Animation)
+function frame{P<:PlottingObject}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i)
- png(anim.plt, joinpath(anim.dir, filename))
+ png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename)
end
@@ -29,11 +28,11 @@ function gif(anim::Animation, fn::@compat(AbstractString) = "tmp.gif"; fps::Inte
fn = abspath(fn)
try
-
+
# high quality
speed = round(Int, 100 / fps)
- run(`convert -delay $speed -loop 0 $(anim.dir)/*.png $fn`)
-
+ run(`convert -delay $speed -loop 0 $(anim.dir)/*.png -alpha off $fn`)
+
catch err
warn("Tried to create gif using convert (ImageMagick), but got error: $err\nWill try ffmpeg, but it's lower quality...)")
@@ -52,3 +51,86 @@ end
function Base.writemime(io::IO, ::MIME"text/html", agif::AnimatedGif)
write(io, "\" />")
end
+
+
+# -----------------------------------------------
+
+function _animate(forloop::Expr, args...; callgif = false)
+ if forloop.head != :for
+ error("@animate macro expects a for-block. got: $(forloop.head)")
+ end
+
+ # add the call to frame to the end of each iteration
+ animsym = gensym("anim")
+ countersym = gensym("counter")
+ block = forloop.args[2]
+
+ # create filter
+ n = length(args)
+ filterexpr = if n == 0
+ # no filter... every iteration gets a frame
+ true
+
+ elseif args[1] == :every
+ # filter every `freq` frames (starting with the first frame)
+ @assert n == 2
+ freq = args[2]
+ @assert isa(freq, Integer) && freq > 0
+ :(mod1($countersym, $freq) == 1)
+
+ elseif args[1] == :when
+ # filter on custom expression
+ @assert n == 2
+ args[2]
+
+ else
+ error("Unsupported animate filter: $args")
+ end
+
+ push!(block.args, :(if $filterexpr; frame($animsym); end))
+ push!(block.args, :($countersym += 1))
+
+ # add a final call to `gif(anim)`?
+ retval = callgif ? :(gif($animsym)) : animsym
+
+ # full expression:
+ esc(quote
+ $animsym = Animation() # init animation object
+ $countersym = 1 # init iteration counter
+ $forloop # for loop, saving a frame after each iteration
+ $retval # return the animation object, or the gif
+ end)
+end
+
+"""
+Builds an `Animation` using one frame per loop iteration, then create an animated GIF.
+
+Example:
+
+```
+ p = plot(1)
+ @gif for x=0:0.1:5
+ push!(p, 1, sin(x))
+ end
+```
+"""
+macro gif(forloop::Expr, args...)
+ _animate(forloop, args...; callgif = true)
+end
+
+"""
+Collect one frame per for-block iteration and return an `Animation` object.
+
+Example:
+
+```
+ p = plot(1)
+ anim = @animate for x=0:0.1:5
+ push!(p, 1, sin(x))
+ end
+ gif(anim)
+```
+"""
+macro animate(forloop::Expr, args...)
+ _animate(forloop, args...)
+end
diff --git a/src/args.jl b/src/args.jl
index 53337b87..41139354 100644
--- a/src/args.jl
+++ b/src/args.jl
@@ -2,15 +2,15 @@
const _allAxes = [:auto, :left, :right]
@compat const _axesAliases = Dict(
- :a => :auto,
- :l => :left,
+ :a => :auto,
+ :l => :left,
:r => :right
)
const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe]
const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
- :heatmap, :hexbin, :hist, :density, :bar, :hline, :vline, :ohlc,
+ :heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc,
:contour, :pie
], _3dTypes)
@compat const _typeAliases = Dict(
@@ -39,7 +39,6 @@ const _allTypes = vcat([
ishistlike(lt::Symbol) = lt in (:hist, :density)
islinelike(lt::Symbol) = lt in (:line, :path, :steppre, :steppost)
-isheatmaplike(lt::Symbol) = lt in (:heatmap, :hexbin)
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
@@ -129,7 +128,7 @@ _seriesDefaults[:markerstrokecolor] = :match
_seriesDefaults[:markerstrokealpha] = nothing
# _seriesDefaults[:ribbon] = nothing
# _seriesDefaults[:ribboncolor] = :match
-_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
+_seriesDefaults[:nbins] = 30 # number of bins for hists
_seriesDefaults[:smooth] = false # regression line?
_seriesDefaults[:group] = nothing # groupby vector
# _seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
@@ -138,7 +137,8 @@ _seriesDefaults[:y] = nothing
_seriesDefaults[:z] = nothing # depth for contour, surface, etc
_seriesDefaults[:zcolor] = nothing # value for color scale
# _seriesDefaults[:surface] = nothing
-_seriesDefaults[:nlevels] = 15
+# _seriesDefaults[:nlevels] = 15
+_seriesDefaults[:levels] = 15
_seriesDefaults[:orientation] = :vertical
@@ -149,7 +149,8 @@ _plotDefaults[:title] = ""
_plotDefaults[:xlabel] = ""
_plotDefaults[:ylabel] = ""
_plotDefaults[:yrightlabel] = ""
-_plotDefaults[:legend] = true
+_plotDefaults[:legend] = :best
+_plotDefaults[:colorbar] = :legend
_plotDefaults[:background_color] = colorant"white"
_plotDefaults[:foreground_color] = :auto
_plotDefaults[:xlims] = :auto
@@ -177,14 +178,14 @@ _plotDefaults[:tickfont] = font(8)
_plotDefaults[:guidefont] = font(11)
_plotDefaults[:legendfont] = font(8)
_plotDefaults[:grid] = true
-_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
-
+_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
+_plotDefaults[:overwrite_figure] = false
# TODO: x/y scales
const _allArgs = sort(collect(union(keys(_seriesDefaults), keys(_plotDefaults))))
-supportedArgs(::PlottingPackage) = _allArgs
+supportedArgs(::PlottingPackage) = error("supportedArgs not defined") #_allArgs
supportedArgs() = supportedArgs(backend())
@@ -230,6 +231,7 @@ end
:type => :linetype,
:lt => :linetype,
:t => :linetype,
+ :seriestype => :linetype,
:style => :linestyle,
:s => :linestyle,
:ls => :linestyle,
@@ -271,6 +273,9 @@ end
:ylabel2 => :yrightlabel,
:y2label => :yrightlabel,
:leg => :legend,
+ :key => :legend,
+ :cbar => :colorbar,
+ :cb => :colorbar,
:bg => :background_color,
:bgcolor => :background_color,
:bg_color => :background_color,
@@ -283,6 +288,9 @@ end
:foreground_colour => :foreground_color,
:regression => :smooth,
:reg => :smooth,
+ :nlevels => :levels,
+ :nlev => :levels,
+ :levs => :levels,
:xlim => :xlims,
:xlimit => :xlims,
:xlimits => :xlims,
@@ -299,6 +307,14 @@ end
:palette => :color_palette,
:xlink => :linkx,
:ylink => :linky,
+ :nrow => :nr,
+ :nrows => :nr,
+ :ncol => :nc,
+ :ncols => :nc,
+ :clf => :overwrite_figure,
+ :clearfig => :overwrite_figure,
+ :overwrite => :overwrite_figure,
+ :reuse => :overwrite_figure,
)
# add all pluralized forms to the _keyAliases dict
@@ -348,12 +364,6 @@ end
# -----------------------------------------------------------------------------
-wraptuple(x::@compat(Tuple)) = x
-wraptuple(x) = (x,)
-
-trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
-trueOrAllTrue(f::Function, x) = f(x)
-
function handleColors!(d::Dict, arg, csym::Symbol)
try
if arg == :auto
@@ -405,11 +415,13 @@ end
function processLineArg(d::Dict, arg)
# linetype
- if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
+ # if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
+ if allLineTypes(arg)
d[:linetype] = arg
-
+
# linestyle
- elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
+ # elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
+ elseif allStyles(arg)
d[:linestyle] = arg
elseif typeof(arg) <: Stroke
@@ -424,11 +436,13 @@ function processLineArg(d::Dict, arg)
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
# linealpha
- elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
+ # elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
+ elseif allAlphas(arg)
d[:linealpha] = arg
# linewidth
- elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
+ # elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
+ elseif allReals(arg)
d[:linewidth] = arg
# color
@@ -442,13 +456,16 @@ end
function processMarkerArg(d::Dict, arg)
# markershape
- if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
+ # if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
+ # d[:markershape] = arg
+
+ # elseif trueOrAllTrue(a -> isa(a, Shape), arg)
+ if allShapes(arg)
d[:markershape] = arg
- elseif trueOrAllTrue(a -> isa(a, Shape), arg)
- d[:markershape] = arg
-
+
# stroke style
- elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
+ # elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
+ elseif allStyles(arg)
d[:markerstrokestyle] = arg
elseif typeof(arg) <: Stroke
@@ -463,17 +480,19 @@ function processMarkerArg(d::Dict, arg)
arg.alpha == nothing || (d[:markeralpha] = arg.alpha)
# linealpha
- elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
+ # elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
+ elseif allAlphas(arg)
d[:markeralpha] = arg
# markersize
- elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
+ # elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
+ elseif allReals(arg)
d[:markersize] = arg
# markercolor
elseif !handleColors!(d, arg, :markercolor)
warn("Skipped marker arg $arg.")
-
+
end
end
@@ -485,15 +504,31 @@ function processFillArg(d::Dict, arg)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
+ # fillrange function
+ # elseif trueOrAllTrue(a -> isa(a, Function), arg)
+ elseif allFunctions(arg)
+ d[:fillrange] = arg
+
+ # fillalpha
+ # elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
+ elseif allAlphas(arg)
+ d[:fillalpha] = arg
+
elseif !handleColors!(d, arg, :fillcolor)
+
d[:fillrange] = arg
end
end
+_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
+_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
+_replace_markershape(shape) = shape
+
+
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
function preprocessArgs!(d::Dict)
replaceAliases!(d, _keyAliases)
-
+
# handle axis args
for axisletter in ("x", "y")
asym = symbol(axisletter * "axis")
@@ -501,6 +536,12 @@ function preprocessArgs!(d::Dict)
processAxisArg(d, axisletter, arg)
end
delete!(d, asym)
+
+ # turn :labels into :ticks_and_labels
+ tsym = symbol(axisletter * "ticks")
+ if haskey(d, tsym) && ticksType(d[tsym]) == :labels
+ d[tsym] = (1:length(d[tsym]), d[tsym])
+ end
end
# handle line args
@@ -516,7 +557,12 @@ function preprocessArgs!(d::Dict)
anymarker = true
end
delete!(d, :marker)
- if anymarker && !haskey(d, :markershape)
+ # if anymarker && !haskey(d, :markershape)
+ # d[:markershape] = :ellipse
+ # end
+ if haskey(d, :markershape)
+ d[:markershape] = _replace_markershape(d[:markershape])
+ elseif anymarker
d[:markershape] = :ellipse
end
@@ -528,6 +574,14 @@ function preprocessArgs!(d::Dict)
# convert into strokes and brushes
+ # legends
+ if haskey(d, :legend)
+ d[:legend] = convertLegendValue(d[:legend])
+ end
+ if haskey(d, :colorbar)
+ d[:colorbar] = convertLegendValue(d[:colorbar])
+ end
+
# handle subplot links
if haskey(d, :link)
l = d[:link]
@@ -588,9 +642,12 @@ function warnOnUnsupportedArgs(pkg::PlottingPackage, d::Dict)
end
end
+_markershape_supported(pkg::PlottingPackage, shape::Symbol) = shape in supportedMarkers(pkg)
+_markershape_supported(pkg::PlottingPackage, shape::Shape) = Shape in supportedMarkers(pkg)
+_markershape_supported(pkg::PlottingPackage, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
- (d[:axis] in supportedAxes(pkg)
+ (d[:axis] in supportedAxes(pkg)
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
(d[:linetype] == :none
|| d[:linetype] in supportedTypes(pkg)
@@ -598,8 +655,9 @@ function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
(d[:linestyle] in supportedStyles(pkg)
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
(d[:markershape] == :none
- || d[:markershape] in supportedMarkers(pkg)
- || (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
+ || _markershape_supported(pkg, d[:markershape])
+ # || d[:markershape] in supportedMarkers(pkg)
+ # || (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
end
@@ -635,6 +693,19 @@ function setDictValue(d_in::Dict, d_out::Dict, k::Symbol, idx::Int, defaults::Di
end
end
+function convertLegendValue(val::Symbol)
+ if val in (:both, :all, :yes)
+ :best
+ elseif val in (:no, :none)
+ :none
+ elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend)
+ val
+ else
+ error("Invalid symbol for legend: $val")
+ end
+end
+convertLegendValue(val::Bool) = val ? :best : :none
+
# -----------------------------------------------------------------------------
# build the argument dictionary for the plot
@@ -655,6 +726,13 @@ function getPlotArgs(pkg::PlottingPackage, kw, idx::Int; set_defaults = true)
end
end
+ # handle legend/colorbar
+ d[:legend] = convertLegendValue(d[:legend])
+ d[:colorbar] = convertLegendValue(d[:colorbar])
+ if d[:colorbar] == :legend
+ d[:colorbar] = d[:legend]
+ end
+
# convert color
handlePlotColors(pkg, d)
@@ -683,7 +761,7 @@ function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::I
d[k] = kwdict[k]
end
end
-
+
if haskey(_typeAliases, d[:linetype])
d[:linetype] = _typeAliases[d[:linetype]]
end
@@ -710,8 +788,6 @@ function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::I
c = (c == :match ? d[:linecolor] : getSeriesRGBColor(c, plotargs, plotIndex))
d[:fillcolor] = c
- # TODO: rebuild
-
# set label
label = d[:label]
label = (label == "AUTO" ? "y$globalIndex" : label)
diff --git a/src/backends/bokeh.jl b/src/backends/bokeh.jl
index c6b678df..09fa303d 100644
--- a/src/backends/bokeh.jl
+++ b/src/backends/bokeh.jl
@@ -1,6 +1,15 @@
# https://github.com/bokeh/Bokeh.jl
+
+function _initialize_backend(::BokehPackage; kw...)
+ @eval begin
+ warn("Bokeh is no longer supported... many features will likely be broken.")
+ import Bokeh
+ export Bokeh
+ end
+end
+
# make255(x) = round(Int, 255 * x)
# function bokehcolor(c::Colorant)
diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl
index 441c1b7e..963af95d 100644
--- a/src/backends/gadfly.jl
+++ b/src/backends/gadfly.jl
@@ -1,6 +1,15 @@
# https://github.com/dcjones/Gadfly.jl
+
+function _initialize_backend(::GadflyPackage; kw...)
+ @eval begin
+ import Gadfly, Compose
+ export Gadfly, Compose
+ include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
+ end
+end
+
# ---------------------------------------------------------------------------
# immutable MissingVec <: AbstractVector{Float64} end
@@ -27,7 +36,7 @@ function getLineGeom(d::Dict)
xbins, ybins = maketuple(d[:nbins])
if lt == :hexbin
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
- elseif lt == :heatmap
+ elseif lt == :hist2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif lt == :hist
Gadfly.Geom.histogram(bincount = xbins)
@@ -44,7 +53,7 @@ function getLineGeom(d::Dict)
elseif lt == :vline
Gadfly.Geom.vline
elseif lt == :contour
- Gadfly.Geom.contour(levels = d[:nlevels])
+ Gadfly.Geom.contour(levels = d[:levels])
else
nothing
end
@@ -159,11 +168,16 @@ end
# ---------------------------------------------------------------------------
+# extract the underlying ShapeGeometry object(s)
+getMarkerGeom(shape::Shape) = gadflyshape(shape)
+getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
+getMarkerGeom(shapes::AVec) = map(getMarkerGeom, shapes)
+getMarkerGeom(d::Dict) = getMarkerGeom(d[:markershape])
-function getMarkerGeom(d::Dict)
- shape = d[:markershape]
- gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
-end
+# function getMarkerGeom(d::Dict)
+# shape = d[:markershape]
+# gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
+# end
function getGadflyMarkerTheme(d::Dict, plotargs::Dict)
@@ -192,6 +206,7 @@ function getGadflyMarkerTheme(d::Dict, plotargs::Dict)
end
function addGadflyContColorScale(plt::Plot{GadflyPackage}, c)
+ plt.plotargs[:colorbar] == :none && return
if !isa(c, ColorGradient)
c = colorscheme(:bluesreds)
end
@@ -224,7 +239,7 @@ end
function addToGadflyLegend(plt::Plot, d::Dict)
# add the legend?
- if plt.plotargs[:legend]
+ if plt.plotargs[:legend] != :none && d[:label] != ""
gplt = getGadflyContext(plt)
# add the legend if needed
@@ -288,7 +303,7 @@ function addGadflySeries!(plt::Plot, d::Dict)
lt = d[:linetype]
if lt == :ohlc
error("Haven't re-implemented after refactoring")
- elseif lt in (:heatmap, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction))
+ elseif lt in (:hist2d, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction))
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:linecolor], p))))
elseif lt == :scatter && d[:markershape] == :none
d[:markershape] = :ellipse
@@ -299,7 +314,7 @@ function addGadflySeries!(plt::Plot, d::Dict)
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...))
end
- lt in (:hist, :heatmap, :hexbin, :contour) || addToGadflyLegend(plt, d)
+ lt in (:hist2d, :hexbin, :contour) || addToGadflyLegend(plt, d)
# now save the layers that apply to this series
d[:gadflylayers] = layers
@@ -359,7 +374,7 @@ function addGadflyTicksGuide(gplt, ticks, isx::Bool)
gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
labelmap = Dict(zip(ticks...))
labelfunc = val -> labelmap[val]
- push!(gplt.scales, gfunc(levels = ticks[1], labels = labelfunc))
+ push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
else
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
@@ -482,9 +497,13 @@ function updateGadflyPlotTheme(plt::Plot, d::Dict)
# # TODO: should this be part of the main `plot` command in plot.jl???
# d = merge!(plt.plotargs, d)
- # hide the legend?
- if !get(d, :legend, true)
- kwargs[:key_position] = :none
+ # # hide the legend?
+ # if !get(d, :legend, true)
+ # kwargs[:key_position] = :none
+ # end
+ leg = d[d[:legend] == :none ? :colorbar : :legend]
+ if leg != :best
+ kwargs[:key_position] = leg == :inside ? :right : leg
end
if !get(d, :grid, true)
@@ -656,7 +675,7 @@ setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt,
# -------------------------------------------------------------------------
-function dowritemime{P<:GadflyOrImmerse}(io::IO, func, plt::PlottingObject{P})
+function dowritemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, func, plt::PlottingObject{P})
gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
@@ -667,10 +686,11 @@ getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
+getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
-for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript")
- @eval function Base.writemime{P<:GadflyOrImmerse}(io::IO, ::$mime, plt::PlottingObject{P})
+for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
+ @eval function Base.writemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, ::$mime, plt::PlottingObject{P})
func = getGadflyWriteFunc($mime())
dowritemime(io, func, plt)
end
diff --git a/src/backends/gadfly_shapes.jl b/src/backends/gadfly_shapes.jl
index 73ccd4ec..25672598 100644
--- a/src/backends/gadfly_shapes.jl
+++ b/src/backends/gadfly_shapes.jl
@@ -66,7 +66,7 @@ function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aes
end
function gadflyshape(sv::Shape)
- ShapeGeometry([(x,-y) for (x,y) in sv.vertices])
+ ShapeGeometry(sv.vertices)
end
diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl
index 591172a0..82d60fcf 100644
--- a/src/backends/glvisualize.jl
+++ b/src/backends/glvisualize.jl
@@ -2,6 +2,13 @@
# [WEBSITE]
+function _initialize_backend(::GLVisualizePackage; kw...)
+ @eval begin
+ import GLVisualize
+ export GLVisualize
+ end
+end
+
# ---------------------------------------------------------------------------
immutable GLScreenWrapper
@@ -12,6 +19,8 @@ function _create_plot(pkg::GLVisualizePackage; kw...)
d = Dict(kw)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
+
+ # TODO: this should be moved to the display method?
w=GLVisualize.glscreen()
@async GLVisualize.renderloop(w)
Plot(GLScreenWrapper(w), pkg, 0, d, Dict[])
@@ -22,6 +31,7 @@ function _add_series(::GLVisualizePackage, plt::Plot; kw...)
d = Dict(kw)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
+ # TODO: this should be moved to the display method?
x,y,z=map(Float32,d[:x]), map(Float32,d[:y]), map(Float32,d[:z].surf)
GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface),plt.o.window)
plt
@@ -50,13 +60,16 @@ end
# accessors for x/y data
function Base.getindex(plt::Plot{GLVisualizePackage}, i::Int)
- series = plt.o.lines[i]
- series.x, series.y
+ # TODO:
+ # series = plt.o.lines[i]
+ # series.x, series.y
+ nothing, nothing
end
function Base.setindex!(plt::Plot{GLVisualizePackage}, xy::Tuple, i::Integer)
- series = plt.o.lines[i]
- series.x, series.y = xy
+ # TODO:
+ # series = plt.o.lines[i]
+ # series.x, series.y = xy
plt
end
@@ -82,6 +95,10 @@ end
function Base.display(::PlotsDisplay, plt::Plot{GLVisualizePackage})
# TODO: display/show the plot
+
+ # NOTE: I think maybe this should be empty? We can start with the assumption that creating
+ # and adding to a plot will automatically open a window and draw to it, then the display
+ # wouldn't actually need to do anything
end
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizePackage})
diff --git a/src/backends/gr.jl b/src/backends/gr.jl
new file mode 100644
index 00000000..5f43a8c0
--- /dev/null
+++ b/src/backends/gr.jl
@@ -0,0 +1,790 @@
+
+# https://github.com/jheinen/GR.jl
+
+function _initialize_backend(::GRPackage; kw...)
+ @eval begin
+ import GR
+ export GR
+ end
+end
+
+const gr_linetype = Dict(
+ :auto => 1, :solid => 1, :dash => 2, :dot => 3, :dashdot => 4,
+ :dashdotdot => -1 )
+
+const gr_markertype = Dict(
+ :auto => 1, :none => -1, :ellipse => -1, :rect => -7, :diamond => -13,
+ :utriangle => -3, :dtriangle => -5, :pentagon => -21, :hexagon => -22,
+ :heptagon => -23, :octagon => -24, :cross => 2, :xcross => 5,
+ :star4 => -25, :star5 => -26, :star6 => -27, :star7 => -28, :star8 => -29,
+ :vline => -30, :hline => -31 )
+
+const gr_halign = Dict(:left => 1, :hcenter => 2, :right => 3)
+const gr_valign = Dict(:top => 1, :vcenter => 3, :bottom => 5)
+
+const gr_font_family = Dict(
+ "times" => 1, "helvetica" => 5, "courier" => 9, "bookman" => 14,
+ "newcenturyschlbk" => 18, "avantgarde" => 22, "palatino" => 26)
+
+function gr_getcolorind(v)
+ c = getColor(v)
+ return convert(Int, GR.inqcolorfromrgb(c.r, c.g, c.b))
+end
+
+function gr_getaxisind(p)
+ axis = get(p, :axis, :none)
+ if axis in [:none, :left]
+ return 1
+ else
+ return 2
+ end
+end
+
+function gr_setmarkershape(p)
+ if haskey(p, :markershape)
+ shape = p[:markershape]
+ if isa(shape, Shape)
+ p[:vertices] = shape.vertices
+ else
+ GR.setmarkertype(gr_markertype[shape])
+ p[:vertices] = :none
+ end
+ end
+end
+
+function gr_polymarker(p, x, y)
+ if p[:vertices] != :none
+ vertices= p[:vertices]
+ dx = Float64[el[1] for el in vertices] * 0.01
+ dy = Float64[el[2] for el in vertices] * 0.01
+ GR.selntran(0)
+ GR.setfillcolorind(gr_getcolorind(p[:markercolor]))
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ for i = 1:length(x)
+ xn, yn = GR.wctondc(x[i], y[i])
+ GR.fillarea(xn + dx, yn + dy)
+ end
+ GR.selntran(1)
+ else
+ GR.polymarker(x, y)
+ end
+end
+
+function gr_polyline(x, y)
+ if NaN in x || NaN in y
+ i = 1
+ j = 1
+ n = length(x)
+ while i < n
+ while j < n && x[j] != Nan && y[j] != NaN
+ j += 1
+ end
+ if i < j
+ GR.polyline(x[i:j], y[i:j])
+ end
+ i = j + 1
+ end
+ else
+ GR.polyline(x, y)
+ end
+end
+
+function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
+ subplot=[0, 1, 0, 1])
+ d = plt.plotargs
+
+ clear && GR.clearws()
+
+ mwidth, mheight, width, height = GR.inqdspsize()
+ w, h = d[:size]
+ viewport = zeros(4)
+ if w > h
+ ratio = float(h) / w
+ msize = mwidth * w / width
+ GR.setwsviewport(0, msize, 0, msize * ratio)
+ GR.setwswindow(0, 1, 0, ratio)
+ viewport[1] = subplot[1] + 0.125 * (subplot[2] - subplot[1])
+ viewport[2] = subplot[1] + 0.95 * (subplot[2] - subplot[1])
+ viewport[3] = ratio * (subplot[3] + 0.125 * (subplot[4] - subplot[3]))
+ viewport[4] = ratio * (subplot[3] + 0.95 * (subplot[4] - subplot[3]))
+ else
+ ratio = float(w) / h
+ msize = mheight * h / height
+ GR.setwsviewport(0, msize * ratio, 0, msize)
+ GR.setwswindow(0, ratio, 0, 1)
+ viewport[1] = ratio * (subplot[1] + 0.125 * (subplot[2] - subplot[1]))
+ viewport[2] = ratio * (subplot[1] + 0.95 * (subplot[2] - subplot[1]))
+ viewport[3] = subplot[3] + 0.125 * (subplot[4] - subplot[3])
+ viewport[4] = subplot[3] + 0.95 * (subplot[4] - subplot[3])
+ end
+
+ if haskey(d, :background_color)
+ GR.savestate()
+ GR.selntran(0)
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ GR.setfillcolorind(gr_getcolorind(d[:background_color]))
+ if w > h
+ GR.fillrect(subplot[1], subplot[2], ratio*subplot[3], ratio*subplot[4])
+ else
+ GR.fillrect(ratio*subplot[1], ratio*subplot[2], subplot[3], subplot[4])
+ end
+ GR.selntran(1)
+ GR.restorestate()
+ c = getColor(d[:background_color])
+ if 0.21 * c.r + 0.72 * c.g + 0.07 * c.b < 0.9
+ fg = convert(Int, GR.inqcolorfromrgb(1-c.r, 1-c.g, 1-c.b))
+ else
+ fg = 1
+ end
+ else
+ fg = 1
+ end
+
+ extrema = zeros(2, 4)
+ num_axes = 1
+ cmap = false
+ axes_2d = true
+ grid_flag = get(d, :grid, true)
+
+ for axis = 1:2
+ xmin = ymin = typemax(Float64)
+ xmax = ymax = typemin(Float64)
+ for p in plt.seriesargs
+ if axis == gr_getaxisind(p)
+ if axis == 2
+ num_axes = 2
+ end
+ if p[:linetype] == :bar
+ x, y = 1:length(p[:y]), p[:y]
+ elseif p[:linetype] == :ohlc
+ x, y = 1:size(p[:y], 1), p[:y]
+ elseif p[:linetype] in [:hist, :density]
+ x, y = Base.hist(p[:y])
+ elseif p[:linetype] in [:hist2d, :hexbin]
+ E = zeros(length(p[:x]),2)
+ E[:,1] = p[:x]
+ E[:,2] = p[:y]
+ if isa(p[:nbins], Tuple)
+ xbins, ybins = p[:nbins]
+ else
+ xbins = ybins = p[:nbins]
+ end
+ cmap = true
+ x, y, H = Base.hist2d(E, xbins, ybins)
+ elseif p[:linetype] == :pie
+ axes_2d = false
+ xmin, xmax, ymin, ymax = 0, 1, 0, 1
+ x, y = p[:x], p[:y]
+ else
+ if p[:linetype] in [:contour, :surface]
+ cmap = true
+ end
+ if p[:linetype] in [:surface, :wireframe, :path3d, :scatter3d]
+ axes_2d = false
+ end
+ x, y = p[:x], p[:y]
+ end
+ if p[:linetype] != :pie
+ xmin = min(minimum(x), xmin)
+ xmax = max(maximum(x), xmax)
+ if p[:linetype] == :ohlc
+ for val in y
+ ymin = min(val.open, val.high, val.low, val.close, ymin)
+ ymax = max(val.open, val.high, val.low, val.close, ymax)
+ end
+ else
+ ymin = min(minimum(y), ymin)
+ ymax = max(maximum(y), ymax)
+ end
+ end
+ end
+ end
+ if d[:xlims] != :auto
+ xmin, xmax = d[:xlims]
+ end
+ if d[:ylims] != :auto
+ ymin, ymax = d[:ylims]
+ end
+ if xmax <= xmin
+ xmax = xmin + 1
+ end
+ if ymax <= ymin
+ ymax = ymin + 1
+ end
+ extrema[axis,:] = [xmin, xmax, ymin, ymax]
+ end
+
+ if num_axes == 2 || !axes_2d
+ viewport[2] -= 0.0525
+ end
+ if cmap
+ viewport[2] -= 0.1
+ end
+ GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
+
+ scale = 0
+ d[:xscale] == :log10 && (scale |= GR.OPTION_X_LOG)
+ d[:yscale] == :log10 && (scale |= GR.OPTION_Y_LOG)
+ get(d, :xflip, false) && (scale |= GR.OPTION_FLIP_X)
+ get(d, :yflip, false) && (scale |= GR.OPTION_FLIP_Y)
+
+ for axis = 1:num_axes
+ xmin, xmax, ymin, ymax = extrema[axis,:]
+ if scale & GR.OPTION_X_LOG == 0
+ xmin, xmax = GR.adjustlimits(xmin, xmax)
+ majorx = 5
+ xtick = GR.tick(xmin, xmax) / majorx
+ else
+ xtick = majorx = 1
+ end
+ if scale & GR.OPTION_Y_LOG == 0
+ ymin, ymax = GR.adjustlimits(ymin, ymax)
+ majory = 5
+ ytick = GR.tick(ymin, ymax) / majory
+ else
+ ytick = majory = 1
+ end
+ if scale & GR.OPTION_FLIP_X == 0
+ xorg = (xmin, xmax)
+ else
+ xorg = (xmax, xmin)
+ end
+ if scale & GR.OPTION_FLIP_Y == 0
+ yorg = (ymin, ymax)
+ else
+ yorg = (ymax, ymin)
+ end
+
+ GR.setwindow(xmin, xmax, ymin, ymax)
+ GR.setscale(scale)
+
+ diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ charheight = max(0.018 * diag, 0.01)
+ GR.setcharheight(charheight)
+ GR.settextcolorind(fg)
+
+ if axes_2d
+ GR.setlinewidth(1)
+ GR.setlinecolorind(fg)
+ ticksize = 0.0075 * diag
+ if grid_flag && fg == 1
+ GR.grid(xtick, ytick, 0, 0, majorx, majory)
+ end
+ if num_axes == 1
+ GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
+ GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, -majory, -ticksize)
+ elseif axis == 1
+ GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
+ else
+ GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, majory, -ticksize)
+ end
+ end
+ end
+
+ if get(d, :title, "") != ""
+ GR.savestate()
+ GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
+ GR.settextcolorind(fg)
+ GR.text(0.5 * (viewport[1] + viewport[2]), min(ratio, 1), d[:title])
+ GR.restorestate()
+ end
+ if get(d, :xlabel, "") != ""
+ GR.savestate()
+ GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
+ GR.settextcolorind(fg)
+ GR.text(0.5 * (viewport[1] + viewport[2]), 0, d[:xlabel])
+ GR.restorestate()
+ end
+ if get(d, :ylabel, "") != ""
+ GR.savestate()
+ GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
+ GR.setcharup(-1, 0)
+ GR.settextcolorind(fg)
+ GR.text(0, 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
+ GR.restorestate()
+ end
+ if get(d, :yrightlabel, "") != ""
+ GR.savestate()
+ GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
+ GR.setcharup(1, 0)
+ GR.settextcolorind(fg)
+ GR.text(1, 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
+ GR.restorestate()
+ end
+
+ legend = false
+
+ for p in plt.seriesargs
+ GR.savestate()
+ xmin, xmax, ymin, ymax = extrema[gr_getaxisind(p),:]
+ GR.setwindow(xmin, xmax, ymin, ymax)
+ if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks, :hline, :vline, :ohlc]
+ haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
+ haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
+ haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
+ end
+ if p[:linetype] == :path
+ if haskey(p, :fillcolor)
+ GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ end
+ if length(p[:x]) > 1
+ if p[:fillrange] != nothing
+ GR.fillarea([p[:x][1]; p[:x]; p[:x][length(p[:x])]], [p[:fillrange]; p[:y]; p[:fillrange]])
+ end
+ GR.polyline(p[:x], p[:y])
+ end
+ legend = true
+ end
+ if p[:linetype] == :line
+ if length(p[:x]) > 1
+ gr_polyline(p[:x], p[:y])
+ end
+ legend = true
+ elseif p[:linetype] in [:steppre, :steppost]
+ n = length(p[:x])
+ x = zeros(2*n + 1)
+ y = zeros(2*n + 1)
+ x[1], y[1] = p[:x][1], p[:y][1]
+ j = 2
+ for i = 2:n
+ if p[:linetype] == :steppre
+ x[j], x[j+1] = p[:x][i-1], p[:x][i]
+ y[j], y[j+1] = p[:y][i], p[:y][i]
+ else
+ x[j], x[j+1] = p[:x][i], p[:x][i]
+ y[j], y[j+1] = p[:y][i-1], p[:y][i]
+ end
+ j += 2
+ end
+ if n > 1
+ GR.polyline(x, y)
+ end
+ legend = true
+ elseif p[:linetype] == :sticks
+ x, y = p[:x], p[:y]
+ for i = 1:length(y)
+ GR.polyline([x[i], x[i]], [ymin, y[i]])
+ end
+ legend = true
+ elseif p[:linetype] == :scatter || (p[:markershape] != :none && axes_2d)
+ haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
+ gr_setmarkershape(p)
+ if haskey(d, :markersize)
+ if typeof(d[:markersize]) <: Number
+ GR.setmarkersize(d[:markersize] / 4.0)
+ if length(p[:x]) > 0
+ gr_polymarker(p, p[:x], p[:y])
+ end
+ else
+ c = p[:markercolor]
+ GR.setcolormap(-GR.COLORMAP_GLOWING)
+ for i = 1:length(p[:x])
+ if isa(c, ColorGradient) && p[:zcolor] != nothing
+ ci = round(Int, 1000 + p[:zcolor][i] * 255)
+ GR.setmarkercolorind(ci)
+ end
+ GR.setmarkersize(d[:markersize][i] / 4.0)
+ gr_polymarker(p, [p[:x][i]], [p[:y][i]])
+ end
+ end
+ else
+ if length(p[:x]) > 0
+ gr_polymarker(p, p[:x], p[:y])
+ end
+ end
+ legend = true
+ elseif p[:linetype] == :bar
+ y = p[:y]
+ for i = 1:length(y)
+ GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
+ GR.setfillcolorind(1)
+ GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
+ GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
+ end
+ elseif p[:linetype] in [:hist, :density]
+ h = Base.hist(p[:y])
+ x, y = float(collect(h[1])), float(h[2])
+ for i = 2:length(y)
+ GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ GR.fillrect(x[i-1], x[i], ymin, y[i])
+ GR.setfillcolorind(1)
+ GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
+ GR.fillrect(x[i-1], x[i], ymin, y[i])
+ end
+ elseif p[:linetype] in [:hline, :vline]
+ for xy in p[:y]
+ if p[:linetype] == :hline
+ GR.polyline([xmin, xmax], [xy, xy])
+ else
+ GR.polyline([xy, xy], [ymin, ymax])
+ end
+ end
+ elseif p[:linetype] in [:hist2d, :hexbin]
+ E = zeros(length(p[:x]),2)
+ E[:,1] = p[:x]
+ E[:,2] = p[:y]
+ if isa(p[:nbins], Tuple)
+ xbins, ybins = p[:nbins]
+ else
+ xbins = ybins = p[:nbins]
+ end
+ x, y, H = Base.hist2d(E, xbins, ybins)
+ counts = round(Int32, 1000 + 255 * H / maximum(H))
+ n, m = size(counts)
+ GR.setcolormap(GR.COLORMAP_COOLWARM)
+ GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts)
+ GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
+ viewport[3], viewport[4])
+ GR.setspace(0, maximum(counts), 0, 90)
+ diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ charheight = max(0.016 * diag, 0.01)
+ GR.setcharheight(charheight)
+ GR.colormap()
+ elseif p[:linetype] == :contour
+ x, y, z = p[:x], p[:y], p[:z].surf
+ zmin, zmax = minimum(z), maximum(z)
+ if typeof(p[:levels]) <: Array
+ h = p[:levels]
+ else
+ h = linspace(zmin, zmax, p[:levels])
+ end
+ GR.setspace(zmin, zmax, 0, 90)
+ GR.setcolormap(GR.COLORMAP_COOLWARM)
+ GR.contour(x, y, h, reshape(z, length(x) * length(y)), 1000)
+ GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
+ viewport[3], viewport[4])
+ l = round(Int32, 1000 + (h - minimum(h)) / (maximum(h) - minimum(h)) * 255)
+ GR.setwindow(xmin, xmax, zmin, zmax)
+ GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
+ ztick = 0.5 * GR.tick(zmin, zmax)
+ diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ charheight = max(0.016 * diag, 0.01)
+ GR.setcharheight(charheight)
+ GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005)
+ elseif p[:linetype] in [:surface, :wireframe]
+ x, y, z = p[:x], p[:y], p[:z].surf
+ zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
+ GR.setspace(zmin, zmax, 40, 70)
+ xtick = GR.tick(xmin, xmax) / 2
+ ytick = GR.tick(ymin, ymax) / 2
+ ztick = GR.tick(zmin, zmax) / 2
+ diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ charheight = max(0.018 * diag, 0.01)
+ ticksize = 0.01 * (viewport[2] - viewport[1])
+ GR.setlinewidth(1)
+ if grid_flag
+ GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
+ GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
+ end
+ z = reshape(z, length(x) * length(y))
+ if p[:linetype] == :surface
+ GR.setcolormap(GR.COLORMAP_COOLWARM)
+ GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
+ else
+ GR.setfillcolorind(0)
+ GR.surface(x, y, z, GR.OPTION_FILLED_MESH)
+ end
+ GR.setlinewidth(1)
+ GR.setcharheight(charheight)
+ GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
+ GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
+ if cmap
+ GR.setviewport(viewport[2] + 0.07, viewport[2] + 0.1,
+ viewport[3], viewport[4])
+ GR.colormap()
+ end
+ elseif p[:linetype] in [:path3d, :scatter3d]
+ x, y, z = p[:x], p[:y], p[:z]
+ zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
+ GR.setspace(zmin, zmax, 40, 70)
+ xtick = GR.tick(xmin, xmax) / 2
+ ytick = GR.tick(ymin, ymax) / 2
+ ztick = GR.tick(zmin, zmax) / 2
+ diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ charheight = max(0.018 * diag, 0.01)
+ ticksize = 0.01 * (viewport[2] - viewport[1])
+ GR.setlinewidth(1)
+ if grid_flag && p[:linetype] == :path3d
+ GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
+ GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
+ end
+ if p[:linetype] == :scatter3d
+ haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
+ gr_setmarkershape(p)
+ for i = 1:length(z)
+ px, py = GR.wc3towc(x[i], y[i], z[i])
+ gr_polymarker(p, [px], [py])
+ end
+ else
+ haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
+ if length(x) > 0
+ GR.polyline3d(x, y, z)
+ end
+ end
+ GR.setlinewidth(1)
+ GR.setcharheight(charheight)
+ GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
+ GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
+ elseif p[:linetype] == :ohlc
+ y = p[:y]
+ n = size(y, 1)
+ ticksize = 0.5 * (xmax - xmin) / n
+ for i in 1:n
+ GR.polyline([i-ticksize, i], [y[i].open, y[i].open])
+ GR.polyline([i, i], [y[i].low, y[i].high])
+ GR.polyline([i, i+ticksize], [y[i].close, y[i].close])
+ end
+ elseif p[:linetype] == :pie
+ GR.selntran(0)
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ xmin, xmax, ymin, ymax = viewport
+ ymax -= 0.05 * (xmax - xmin)
+ xcenter = 0.5 * (xmin + xmax)
+ ycenter = 0.5 * (ymin + ymax)
+ if xmax - xmin > ymax - ymin
+ r = 0.5 * (ymax - ymin)
+ xmin, xmax = xcenter - r, xcenter + r
+ else
+ r = 0.5 * (xmax - xmin)
+ ymin, ymax = ycenter - r, ycenter + r
+ end
+ labels, slices = p[:x], p[:y]
+ numslices = length(slices)
+ total = sum(slices)
+ a1 = 0
+ x = zeros(3)
+ y = zeros(3)
+ for i in 1:numslices
+ a2 = round(Int, a1 + (slices[i] / total) * 360.0)
+ GR.setfillcolorind(980 + (i-1) % 20)
+ GR.fillarc(xmin, xmax, ymin, ymax, a1, a2)
+ alpha = 0.5 * (a1 + a2)
+ cosf = r * cos(alpha * pi / 180)
+ sinf = r * sin(alpha * pi / 180)
+ x[1] = xcenter + cosf
+ y[1] = ycenter + sinf
+ x[2] = x[1] + 0.1 * cosf
+ y[2] = y[1] + 0.1 * sinf
+ y[3] = y[2]
+ if 90 <= alpha < 270
+ x[3] = x[2] - 0.05
+ GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF)
+ GR.text(x[3] - 0.01, y[3], string(labels[i]))
+ else
+ x[3] = x[2] + 0.05
+ GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
+ GR.text(x[3] + 0.01, y[3], string(labels[i]))
+ end
+ GR.polyline(x, y)
+ a1 = a2
+ end
+ GR.selntran(1)
+ end
+ GR.restorestate()
+ end
+
+ if d[:legend] != :none && legend
+ GR.savestate()
+ GR.selntran(0)
+ GR.setscale(0)
+ w = 0
+ i = 0
+ for p in plt.seriesargs
+ if typeof(p[:label]) <: Array
+ i += 1
+ lab = p[:label][i]
+ else
+ lab = p[:label]
+ end
+ tbx, tby = GR.inqtext(0, 0, lab)
+ w = max(w, tbx[3])
+ end
+ px = viewport[2] - 0.05 - w
+ py = viewport[4] - 0.06
+ dy = 0.03 * sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
+ GR.setfillintstyle(GR.INTSTYLE_SOLID)
+ GR.setfillcolorind(0)
+ GR.fillrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
+ GR.setlinetype(1)
+ GR.setlinewidth(1)
+ GR.drawrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
+ haskey(d, :linewidth) && GR.setlinewidth(d[:linewidth])
+ i = 0
+ for p in plt.seriesargs
+ if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
+ haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
+ haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
+ GR.polyline([px - 0.07, px - 0.01], [py, py])
+ end
+ if p[:linetype] == :scatter || p[:markershape] != :none
+ haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
+ gr_setmarkershape(p)
+ if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
+ gr_polymarker(p, [px - 0.06, px - 0.02], [py, py])
+ else
+ gr_polymarker(p, [px - 0.06, px - 0.04, px - 0.02], [py, py, py])
+ end
+ end
+ if typeof(p[:label]) <: Array
+ i += 1
+ lab = p[:label][i]
+ else
+ lab = p[:label]
+ end
+ GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
+ GR.settextcolorind(1)
+ GR.text(px, py, lab)
+ py -= dy
+ end
+ GR.selntran(1)
+ GR.restorestate()
+ end
+
+ if haskey(d, :anns)
+ GR.savestate()
+ for ann in d[:anns]
+ x, y, val = ann
+ x, y = GR.wctondc(x, y)
+ alpha = val.font.rotation
+ family = lowercase(val.font.family)
+ GR.setcharheight(0.7 * val.font.pointsize / d[:size][2])
+ GR.setcharup(sin(val.font.rotation), cos(val.font.rotation))
+ if haskey(gr_font_family, family)
+ GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
+ end
+ GR.settextcolorind(gr_getcolorind(val.font.color))
+ GR.settextalign(gr_halign[val.font.halign], gr_valign[val.font.valign])
+ GR.text(x, y, val.str)
+ end
+ GR.restorestate()
+ end
+
+ update && GR.updatews()
+end
+
+function gr_display(subplt::Subplot{GRPackage})
+ clear = true
+ update = false
+ l = enumerate(subplt.layout)
+ nr = nrows(subplt.layout)
+ for (i, (r, c)) in l
+ nc = ncols(subplt.layout, r)
+ if i == length(l)
+ update = true
+ end
+ subplot = [(c-1)/nc, c/nc, 1-r/nr, 1-(r-1)/nr]
+ gr_display(subplt.plts[i], clear, update, subplot)
+ clear = false
+ end
+end
+
+function _create_plot(pkg::GRPackage; kw...)
+ d = Dict(kw)
+ Plot(nothing, pkg, 0, d, Dict[])
+end
+
+function _add_series(::GRPackage, plt::Plot; kw...)
+ d = Dict(kw)
+ push!(plt.seriesargs, d)
+ plt
+end
+
+function _add_annotations{X,Y,V}(plt::Plot{GRPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
+ if haskey(plt.plotargs, :anns)
+ append!(plt.plotargs[:anns], anns)
+ else
+ plt.plotargs[:anns] = anns
+ end
+end
+
+# ----------------------------------------------------------------
+
+function _before_update_plot(plt::Plot{GRPackage})
+end
+
+function _update_plot(plt::Plot{GRPackage}, d::Dict)
+ for k in (:title, :xlabel, :ylabel)
+ haskey(d, k) && (plt.plotargs[k] = d[k])
+ end
+end
+
+function _update_plot_pos_size(plt::PlottingObject{GRPackage}, d::Dict)
+end
+
+# ----------------------------------------------------------------
+
+function Base.getindex(plt::Plot{GRPackage}, i::Int)
+ d = plt.seriesargs[i]
+ d[:x], d[:y]
+end
+
+function Base.setindex!(plt::Plot{GRPackage}, xy::Tuple, i::Integer)
+ d = plt.seriesargs[i]
+ d[:x], d[:y] = xy
+ plt
+end
+
+# ----------------------------------------------------------------
+
+function _create_subplot(subplt::Subplot{GRPackage}, isbefore::Bool)
+ true
+end
+
+function _expand_limits(lims, plt::Plot{GRPackage}, isx::Bool)
+ # TODO: call expand limits for each plot data
+end
+
+function _remove_axis(plt::Plot{GRPackage}, isx::Bool)
+ # TODO: if plot is inner subplot, might need to remove ticks or axis labels
+end
+
+# ----------------------------------------------------------------
+
+function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{GRPackage})
+ GR.emergencyclosegks()
+ ENV["GKS_WSTYPE"] = "png"
+ gr_display(plt)
+ GR.emergencyclosegks()
+ write(io, readall("gks.png"))
+end
+
+function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::PlottingObject{GRPackage})
+ GR.emergencyclosegks()
+ ENV["GKS_WSTYPE"] = "svg"
+ gr_display(plt)
+ GR.emergencyclosegks()
+ write(io, readall("gks.svg"))
+end
+
+function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{GRPackage})
+ writemime(io, MIME("image/svg+xml"), plt)
+end
+
+function Base.writemime(io::IO, m::MIME"application/pdf", plt::PlottingObject{GRPackage})
+ GR.emergencyclosegks()
+ ENV["GKS_WSTYPE"] = "pdf"
+ gr_display(plt)
+ GR.emergencyclosegks()
+ write(io, readall("gks.pdf"))
+end
+
+function Base.writemime(io::IO, m::MIME"application/postscript", plt::PlottingObject{GRPackage})
+ GR.emergencyclosegks()
+ ENV["GKS_WSTYPE"] = "ps"
+ gr_display(plt)
+ GR.emergencyclosegks()
+ write(io, readall("gks.ps"))
+end
+
+function Base.display(::PlotsDisplay, plt::Plot{GRPackage})
+ gr_display(plt)
+end
+
+function Base.display(::PlotsDisplay, plt::Subplot{GRPackage})
+ gr_display(plt)
+ true
+end
diff --git a/src/backends/immerse.jl b/src/backends/immerse.jl
index ee199f8e..3eb6cfba 100644
--- a/src/backends/immerse.jl
+++ b/src/backends/immerse.jl
@@ -1,6 +1,13 @@
# https://github.com/JuliaGraphics/Immerse.jl
+function _initialize_backend(::ImmersePackage; kw...)
+ @eval begin
+ import Immerse, Gadfly, Compose, Gtk
+ export Immerse, Gadfly, Compose, Gtk
+ include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
+ end
+end
function createImmerseFigure(d::Dict)
w,h = d[:size]
diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl
new file mode 100644
index 00000000..f76cb33b
--- /dev/null
+++ b/src/backends/pgfplots.jl
@@ -0,0 +1,107 @@
+
+# https://github.com/sisl/PGFPlots.jl
+
+function _initialize_backend(::PGFPlotsPackage; kw...)
+ @eval begin
+ import PGFPlots
+ export PGFPlots
+ # TODO: other initialization that needs to be eval-ed
+ end
+ # TODO: other initialization
+end
+
+# ---------------------------------------------------------------------------
+
+function _create_plot(pkg::PGFPlotsPackage; kw...)
+ d = Dict{Symbol,Any}(kw)
+ # TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
+ # TODO: initialize the plot... title, xlabel, bgcolor, etc
+ Plot(nothing, pkg, 0, d, Dict[])
+end
+
+
+function _add_series(::PGFPlotsPackage, plt::Plot; kw...)
+ d = Dict{Symbol,Any}(kw)
+ # TODO: add one series to the underlying package
+ push!(plt.seriesargs, d)
+ plt
+end
+
+function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
+ # set or add to the annotation_list
+ if haskey(plt.plotargs, :annotation_list)
+ append!(plt.plotargs[:annotation_list], anns)
+ else
+ plt.plotargs[:annotation_list] = anns
+ end
+end
+
+# ----------------------------------------------------------------
+
+function _before_update_plot(plt::Plot{PGFPlotsPackage})
+end
+
+# TODO: override this to update plot items (title, xlabel, etc) after creation
+function _update_plot(plt::Plot{PGFPlotsPackage}, d::Dict)
+end
+
+function _update_plot_pos_size(plt::PlottingObject{PGFPlotsPackage}, d::Dict)
+end
+
+# ----------------------------------------------------------------
+
+# accessors for x/y data
+
+function Base.getindex(plt::Plot{PGFPlotsPackage}, i::Int)
+ d = plt.seriesargs[i]
+ d[:x], d[:y]
+end
+
+function Base.setindex!(plt::Plot{PGFPlotsPackage}, xy::Tuple, i::Integer)
+ d = plt.seriesargs[i]
+ d[:x], d[:y] = xy
+ plt
+end
+
+# ----------------------------------------------------------------
+
+function _create_subplot(subplt::Subplot{PGFPlotsPackage}, isbefore::Bool)
+ # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
+ true
+end
+
+function _expand_limits(lims, plt::Plot{PGFPlotsPackage}, isx::Bool)
+ # TODO: call expand limits for each plot data
+end
+
+function _remove_axis(plt::Plot{PGFPlotsPackage}, isx::Bool)
+ # TODO: if plot is inner subplot, might need to remove ticks or axis labels
+end
+
+# ----------------------------------------------------------------
+
+
+# ----------------------------------------------------------------
+
+################# This is the important method to implement!!! #################
+function _make_pgf_plot(plt::Plot{PGFPlotsPackage})
+ # TODO: convert plt.plotargs and plt.seriesargs into PGFPlots calls
+ # TODO: return the PGFPlots object
+end
+
+function Base.writemime(io::IO, mime::MIME"image/png", plt::PlottingObject{PGFPlotsPackage})
+ plt.o = _make_pgf_plot(plt)
+ writemime(io, mime, plt.o)
+end
+
+# function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PGFPlotsPackage})
+# end
+
+function Base.display(::PlotsDisplay, plt::PlottingObject{PGFPlotsPackage})
+ plt.o = _make_pgf_plot(plt)
+ display(plt.o)
+end
+
+# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsPackage})
+# # TODO: display/show the subplot
+# end
diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl
index a417d3fb..bf8614bc 100644
--- a/src/backends/plotly.jl
+++ b/src/backends/plotly.jl
@@ -1,10 +1,40 @@
# https://plot.ly/javascript/getting-started
+function _initialize_backend(::PlotlyPackage; kw...)
+ @eval begin
+ import JSON
+ JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
+
+ ############################
+ # borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
+ _js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
+
+ # if we're in IJulia call setupnotebook to load js and css
+ if isijulia()
+ # the first script is some hack I needed to do in order for the notebook
+ # to not complain about Plotly being undefined
+ display("text/html", """
+
+
+ """)
+ # display("text/html", "
Plotly javascript loaded.
") + end + # end borrowing (thanks :) + ########################### + + end + # TODO: other initialization +end + # --------------------------------------------------------------------------- function _create_plot(pkg::PlotlyPackage; kw...) - d = Dict(kw) + d = Dict{Symbol,Any}(kw) # TODO: create the window/canvas/context that is the plot within the backend (call it `o`) # TODO: initialize the plot... title, xlabel, bgcolor, etc Plot(nothing, pkg, 0, d, Dict[]) @@ -12,7 +42,7 @@ end function _add_series(::PlotlyPackage, plt::Plot; kw...) - d = Dict(kw) + d = Dict{Symbol,Any}(kw) # TODO: add one series to the underlying package push!(plt.seriesargs, d) plt @@ -83,7 +113,7 @@ end # _plotDefaults[:yflip] = false function plotlyfont(font::Font, color = font.color) - Dict( + Dict{Symbol,Any}( :family => font.family, :size => round(Int, font.pointsize*1.4), :color => webcolor(color), @@ -91,7 +121,7 @@ function plotlyfont(font::Font, color = font.color) end function get_annotation_dict(x, y, val::Union{AbstractString,Symbol}) - Dict( + Dict{Symbol,Any}( :text => val, :xref => "x", :x => x, @@ -102,7 +132,7 @@ function get_annotation_dict(x, y, val::Union{AbstractString,Symbol}) end function get_annotation_dict(x, y, ptxt::PlotText) - merge(get_annotation_dict(x, y, ptxt.str), Dict( + merge(get_annotation_dict(x, y, ptxt.str), Dict{Symbol,Any}( :font => plotlyfont(ptxt.font), :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, @@ -127,7 +157,7 @@ scalesym(isx::Bool) = symbol((isx ? "x" : "y") * "scale") labelsym(isx::Bool) = symbol((isx ? "x" : "y") * "label") function plotlyaxis(d::Dict, isx::Bool) - ax = Dict( + ax = Dict{Symbol,Any}( :title => d[labelsym(isx)], :showgrid => d[:grid], :zeroline => false, @@ -176,9 +206,10 @@ function plotlyaxis(d::Dict, isx::Bool) ax end -function get_plot_json(plt::Plot{PlotlyPackage}) - d = plt.plotargs - d_out = Dict() +# function get_plot_json(plt::Plot{PlotlyPackage}) +# d = plt.plotargs +function plotly_layout(d::Dict) + d_out = Dict{Symbol,Any}() bgcolor = webcolor(d[:background_color]) fgcolor = webcolor(d[:foreground_color]) @@ -186,96 +217,18 @@ function get_plot_json(plt::Plot{PlotlyPackage}) # set the fields for the plot d_out[:title] = d[:title] d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor) - d_out[:margin] = Dict(:l=>35, :b=>30, :r=>8, :t=>20) + d_out[:margin] = Dict{Symbol,Any}(:l=>35, :b=>30, :r=>8, :t=>20) d_out[:plot_bgcolor] = bgcolor d_out[:paper_bgcolor] = bgcolor - + # TODO: x/y axis tick values/labels d_out[:xaxis] = plotlyaxis(d, true) d_out[:yaxis] = plotlyaxis(d, false) - # # x-axis - # d_out[:xaxis] = Dict( - # :title => d[:xlabel], - # :showgrid => d[:grid], - # :zeroline => false, - # ) - # merge!(d_out[:xaxis], if use_axis_field(d[:xticks]) - # ax = Dict( - # :titlefont => plotlyfont(d[:guidefont]), - # :type => plotlyscale(d[:xscale]), - # :tickfont => plotlyfont(d[:tickfont]), - # :tickcolor => fgcolor, - # :linecolor => fgcolor, - # ) - - # # xlims - # lims = d[:xlims] - # if lims != :auto && limsType(lims) == :limits - # ax[:range] = lims - # end - - # # xflip - # if d[:xflip] - # ax[:autorange] = "reversed" - # end - - # # xticks - # ticks = d[:xticks] - # if ticks != :auto - # ttype = ticksType(ticks) - # if ttype == :ticks - # ax[:tickmode] = "array" - # ax[:tickvals] = ticks - # elseif ttype == :ticks_and_labels - # ax[:tickmode] = "array" - # ax[:tickvals], ax[:ticktext] = ticks - # end - # end - - # ax - # else - # Dict( - # :showticklabels => false, - # :showgrid => false, - # ) - # end) - - - # # y-axis - # d_out[:yaxis] = Dict( - # :title => d[:ylabel], - # :showgrid => d[:grid], - # :zeroline => false, - # ) - # merge!(d_out[:yaxis], if use_axis_field(d[:yticks]) - # Dict( - # :titlefont => plotlyfont(d[:guidefont]), - # :type => plotlyscale(d[:yscale]), - # :tickfont => plotlyfont(d[:tickfont]), - # :tickcolor => fgcolor, - # :linecolor => fgcolor, - # ) - # else - # Dict( - # :showticklabels => false, - # :showgrid => false, - # ) - # end) - - # lims = d[:ylims] - # if lims != :auto && limsType(lims) == :limits - # d_out[:yaxis][:range] = lims - # end - - # if d[:yflip] - # d_out[:yaxis][:autorange] = "reversed" - # end - # legend - d_out[:showlegend] = d[:legend] - if d[:legend] - d_out[:legend] = Dict( + d_out[:showlegend] = d[:legend] != :none + if d[:legend] != :none + d_out[:legend] = Dict{Symbol,Any}( :bgcolor => bgcolor, :bordercolor => fgcolor, :font => plotlyfont(d[:legendfont]), @@ -288,17 +241,20 @@ function get_plot_json(plt::Plot{PlotlyPackage}) d_out[:annotations] = [get_annotation_dict(ann...) for ann in anns] end - # finally build and return the json - JSON.json(d_out) + d_out +end + +function get_plot_json(plt::Plot{PlotlyPackage}) + JSON.json(plotly_layout(plt.plotargs)) end -function plotly_colorscale(grad::ColorGradient) - [[grad.values[i], webcolor(grad.colors[i])] for i in 1:length(grad.colors)] +function plotly_colorscale(grad::ColorGradient, alpha = nothing) + [[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)] end -plotly_colorscale(c) = plotly_colorscale(ColorGradient(:bluesreds)) +plotly_colorscale(c, alpha = nothing) = plotly_colorscale(ColorGradient(:bluesreds), alpha) -const _plotly_markers = Dict( +const _plotly_markers = Dict{Symbol,Any}( :rect => "square", :xcross => "x", :utriangle => "triangle-up", @@ -309,8 +265,8 @@ const _plotly_markers = Dict( ) # get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict) -function get_series_json(d::Dict; plot_index = nothing) - d_out = Dict() +function plotly_series(d::Dict; plot_index = nothing) + d_out = Dict{Symbol,Any}() x, y = collect(d[:x]), collect(d[:y]) d_out[:name] = d[:label] @@ -340,7 +296,7 @@ function get_series_json(d::Dict; plot_index = nothing) d_out[:type] = "bar" d_out[:x], d_out[:y] = x, y - elseif lt == :heatmap + elseif lt == :hist2d d_out[:type] = "histogram2d" d_out[:x], d_out[:y] = x, y if isa(d[:nbins], Tuple) @@ -360,16 +316,26 @@ function get_series_json(d::Dict; plot_index = nothing) d_out[:histnorm] = "probability density" end - elseif lt in (:contour, :surface, :wireframe) - d_out[:type] = lt == :wireframe ? :surface : string(lt) + elseif lt == :heatmap + d_out[:type] = "heatmap" d_out[:x], d_out[:y] = x, y d_out[:z] = d[:z].surf - # d_out[:showscale] = d[:legend] - if lt == :contour - d_out[:ncontours] = d[:nlevels] - d_out[:contours] = Dict(:coloring => d[:fillrange] != nothing ? "fill" : "lines") - end - d_out[:colorscale] = plotly_colorscale(d[lt == :contour ? :linecolor : :fillcolor]) + d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + + elseif lt == :contour + d_out[:type] = "contour" + d_out[:x], d_out[:y] = x, y + d_out[:z] = d[:z].surf + # d_out[:showscale] = d[:colorbar] != :none + d_out[:ncontours] = d[:levels] + d_out[:contours] = Dict{Symbol,Any}(:coloring => d[:fillrange] != nothing ? "fill" : "lines") + d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha]) + + elseif lt in (:surface, :wireframe) + d_out[:type] = "surface" + d_out[:x], d_out[:y] = x, y + d_out[:z] = d[:z].surf + d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) elseif lt == :pie d_out[:type] = "pie" @@ -389,30 +355,37 @@ function get_series_json(d::Dict; plot_index = nothing) else warn("Plotly: linetype $lt isn't supported.") - return Dict() + return Dict{Symbol,Any}() end # add "marker" if hasmarker - d_out[:marker] = Dict( + d_out[:marker] = Dict{Symbol,Any}( :symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])), :opacity => d[:markeralpha], :size => 2 * d[:markersize], :color => webcolor(d[:markercolor], d[:markeralpha]), - :line => Dict( + :line => Dict{Symbol,Any}( :color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]), :width => d[:markerstrokewidth], ), ) + + # gotta hack this (for now?) since plotly can't handle rgba values inside the gradient if d[:zcolor] != nothing - d_out[:marker][:color] = d[:zcolor] - d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor]) + # d_out[:marker][:color] = d[:zcolor] + # 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[:zcolor]) + d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:zcolor]] end + end # add "line" if hasline - d_out[:line] = Dict( + d_out[:line] = Dict{Symbol,Any}( :color => webcolor(d[:linecolor], d[:linealpha]), :width => d[:linewidth], :shape => if lt == :steppre @@ -438,14 +411,14 @@ end # get a list of dictionaries, each representing the series params function get_series_json(plt::Plot{PlotlyPackage}) - JSON.json(map(get_series_json, plt.seriesargs)) + JSON.json(map(plotly_series, plt.seriesargs)) end function get_series_json(subplt::Subplot{PlotlyPackage}) ds = Dict[] for (i,plt) in enumerate(subplt.plts) for d in plt.seriesargs - push!(ds, get_series_json(d, plot_index = i)) + push!(ds, plotly_series(d, plot_index = i)) end end JSON.json(ds) @@ -479,10 +452,10 @@ function html_body(subplt::Subplot{PlotlyPackage}) html = ["