Compare commits
203 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd4dd13270 | |||
| ded9f332f6 | |||
| d09ca46141 | |||
| b28cd7f8bd | |||
| a4054aa500 | |||
| 3332bfcee1 | |||
| cc798a0c0a | |||
| fe2030b7e3 | |||
| ed1cce86ef | |||
| 9a544b0ff3 | |||
| 82f7b29836 | |||
| 076acfb242 | |||
| ed336bc0ff | |||
| 5699446d69 | |||
| a43d32949e | |||
| 02a1e648bc | |||
| 9d3e0651e2 | |||
| cdff5a9039 | |||
| ba0b5500ca | |||
| 1439a7e289 | |||
| 9761ede5c4 | |||
| e342805752 | |||
| d08672aa71 | |||
| a3d4e05b0e | |||
| 51eeed3d50 | |||
| 51c45456c3 | |||
| 074ba63bf5 | |||
| f3d552d8a0 | |||
| c5fb4a9228 | |||
| 55d7e910e4 | |||
| ea29af8d3d | |||
| 88b9d71bd7 | |||
| 165c84c246 | |||
| 347820867d | |||
| 26d0dfbf3d | |||
| 6aa4849266 | |||
| 335b3802b8 | |||
| 73bd3fa60c | |||
| 6b61c5900c | |||
| 9da4083096 | |||
| 86fe244d95 | |||
| 732f2846de | |||
| 4f238caf5c | |||
| c9388e9f56 | |||
| 2a9fa9539f | |||
| b8d136588c | |||
| 92c9e82dee | |||
| 0fdb48bda3 | |||
| e8d4fd7aac | |||
| 6a4a78a26a | |||
| 6c6769ca98 | |||
| 3e49af9093 | |||
| 5f8ecfa3fa | |||
| aca03d2609 | |||
| 5db9493d2b | |||
| ac3c041d6d | |||
| a319c0c94a | |||
| f74d619748 | |||
| eef1981f20 | |||
| ade9d86696 | |||
| 935c1cfeab | |||
| 5706770a11 | |||
| 2643417c0b | |||
| d388036601 | |||
| 96df75cc05 | |||
| c62d8d6753 | |||
| 1562c96d4c | |||
| 94c87d436f | |||
| b9c8ffb5cf | |||
| a37a23bcfc | |||
| 863ad22b48 | |||
| bce865ff9f | |||
| 1963fe208e | |||
| 5c4526725b | |||
| 3f42e9c5bd | |||
| b1c9d0a0af | |||
| adcbfb4b9e | |||
| b3ebccab36 | |||
| d5797054fb | |||
| aab0ec22b9 | |||
| f7babcc1d2 | |||
| d077307721 | |||
| 72e8e10bd6 | |||
| 5ea9e8a0d7 | |||
| 87b050fad2 | |||
| 0c8cd74e28 | |||
| 445d970784 | |||
| 125a1eb9fc | |||
| a2a578d04d | |||
| 11e5c0aa9d | |||
| 14b856b0cf | |||
| 2e8dd73822 | |||
| da9fdb356c | |||
| 054a99ca38 | |||
| baf33609af | |||
| b4eb0b6b41 | |||
| 3e9a47a683 | |||
| d71c3ecd86 | |||
| e5a864a760 | |||
| 81b59f9bc9 | |||
| 2c2a36ce34 | |||
| cb0020c629 | |||
| 003d39c8cd | |||
| ca866183f1 | |||
| b6e627369b | |||
| da96cfc158 | |||
| 0abbd53e07 | |||
| 6fc0f858c7 | |||
| b3613b68cd | |||
| 2b6619b3c4 | |||
| a33161aa9c | |||
| 5c3c5b999f | |||
| 7acca18313 | |||
| 7b71d9a448 | |||
| 64ffa3e70f | |||
| fd88972380 | |||
| dd7b09552a | |||
| 0b23aa9e7e | |||
| 0caa31bd6b | |||
| cafac135a0 | |||
| 6ac312bd49 | |||
| 489877d6bf | |||
| b0b2e695e1 | |||
| c3808c0c5b | |||
| c09545de64 | |||
| 7566b0159c | |||
| ed7cc9b89e | |||
| 55501e68fb | |||
| eabe670ae8 | |||
| 9fffef6f53 | |||
| 368429b757 | |||
| 49f774eb0d | |||
| 0487d7a058 | |||
| 5943e77563 | |||
| b10f0fb945 | |||
| c299891fb0 | |||
| fe0f22dfc0 | |||
| 002603c388 | |||
| 30ef8456c3 | |||
| bee1ce401a | |||
| e18c4a370a | |||
| 2a60a929f1 | |||
| 939295ab04 | |||
| f6a0ef6a61 | |||
| b3bce314e9 | |||
| e28b85d8b6 | |||
| a0af2fc997 | |||
| 7f7f5c6f12 | |||
| d21fbfc9be | |||
| 366dc1cca9 | |||
| e9e3913bb7 | |||
| 5491f6eff7 | |||
| 32e36ba324 | |||
| 9d4c456461 | |||
| cdc7920dff | |||
| cdb4901d91 | |||
| c7f3520ea8 | |||
| f0e728c316 | |||
| 4b1f127eaf | |||
| 1db2d8d8d8 | |||
| 87bb45d01b | |||
| 6beadcece8 | |||
| fc6f0f3a86 | |||
| ef7370f56d | |||
| 52ba7cdbff | |||
| b0c9dd44e9 | |||
| 92ec093ed9 | |||
| 6d2a1aafd2 | |||
| f3a7734584 | |||
| 9cf92f37f5 | |||
| 34831d42a4 | |||
| 607d5d7841 | |||
| 75adfd2e9d | |||
| e92b5b2d35 | |||
| a8c40a5493 | |||
| be5c3fb55c | |||
| e6e4a63022 | |||
| 1cdc8928ba | |||
| ad111a0163 | |||
| 7091a4899c | |||
| 3bd9e70fa9 | |||
| 54bd2c620e | |||
| 121640b1b3 | |||
| 55e388513c | |||
| b153dcbd63 | |||
| 242cbe5ecb | |||
| f1cca13796 | |||
| 918ba72107 | |||
| e596f27666 | |||
| a40d0000c5 | |||
| fb82da74a1 | |||
| b0991a0624 | |||
| 6236acea02 | |||
| 391c7e8570 | |||
| 58041cc64e | |||
| 8c7d3a6e92 | |||
| ae1982369c | |||
| 5f85ac01f7 | |||
| cca263fb2b | |||
| 809ed02b85 | |||
| 9eab1083ab | |||
| 60523bef80 | |||
| 46b959ff3c |
@@ -11,10 +11,13 @@ notifications:
|
||||
# uncomment the following lines to override the default test script
|
||||
script:
|
||||
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
|
||||
- julia -e 'Pkg.clone("https://github.com/tbreloff/Images.jl.git"); Pkg.checkout("Images","tom_imgcompare");'
|
||||
- julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
|
||||
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
|
||||
# - julia -e 'Pkg.clone("https://github.com/tbreloff/Images.jl.git"); Pkg.checkout("Images","tom_imgcompare");'
|
||||
# - julia -e 'Pkg.clone("Images"); Pkg.build("Images")'
|
||||
# - julia -e 'Pkg.clone("ImageMagick"); Pkg.build("ImageMagick")'
|
||||
- julia -e 'Pkg.clone("https://github.com/tbreloff/VisualRegressionTests.jl.git");'
|
||||
- julia -e 'Pkg.clone("https://github.com/tbreloff/ExamplePlots.jl.git");'
|
||||
- julia -e 'Pkg.clone("Cairo"); Pkg.build("Cairo")'
|
||||
- julia -e 'ENV["PYTHON"] = ""; Pkg.clone("PyPlot"); Pkg.build("PyPlot")'
|
||||
- julia -e 'Pkg.clone(pwd()); Pkg.build("Plots")'
|
||||
- julia -e 'Pkg.test("Plots"; coverage=false)'
|
||||
# - julia -e 'cd(Pkg.dir("Plots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
|
||||
|
||||
@@ -18,389 +18,4 @@ Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
|
||||
|
||||
Check out the [summary graphs](https://github.com/tbreloff/ExamplePlots.jl/tree/master/img/supported/supported.md) for the features that each backend supports.
|
||||
|
||||
Please add wishlist items, bugs, or any other comments/questions to the issues list.
|
||||
|
||||
## Examples for each implemented backend:
|
||||
|
||||
- [Gadfly.jl/Immerse.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/gadfly_examples.md)
|
||||
- [PyPlot.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/pyplot_examples.md)
|
||||
- [UnicodePlots.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/unicodeplots_examples.md)
|
||||
- [Qwt.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/qwt_examples.md)
|
||||
|
||||
Also check out the many [IJulia notebooks](http://nbviewer.ipython.org/github/tbreloff/ExamplePlots.jl/tree/master/examples/) with many examples.
|
||||
|
||||
## Installation
|
||||
|
||||
First, add the package
|
||||
|
||||
```julia
|
||||
Pkg.add("Plots")
|
||||
|
||||
# if you want the latest features:
|
||||
Pkg.checkout("Plots")
|
||||
|
||||
# or for the bleeding edge:
|
||||
Pkg.checkout("Plots", "dev")
|
||||
```
|
||||
|
||||
then get any plotting packages you need (obviously, you should get at least one backend).
|
||||
|
||||
```julia
|
||||
Pkg.add("Gadfly")
|
||||
Pkg.add("Immerse")
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git")
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
Load it in. The underlying plotting backends are not imported until `backend()` is called (which happens
|
||||
on your first call to `plot` or `subplot`). This means that you don't need any backends to be installed when you call `using Plots`.
|
||||
|
||||
Plots will try to figure out a good default backend for you automatically based on what backends are installed.
|
||||
|
||||
```julia
|
||||
using Plots
|
||||
```
|
||||
|
||||
Do a plot in Gadfly (inspired by [this example](http://gadflyjl.org/geom_point.html)), then save a png:
|
||||
|
||||
```julia
|
||||
gadfly() # switch to Gadfly as a backend
|
||||
dataframes() # turn on support for DataFrames inputs
|
||||
|
||||
# load some data
|
||||
using RDatasets
|
||||
iris = dataset("datasets", "iris");
|
||||
|
||||
# This will bring up a browser window with the plot. Add a semicolon at the end to skip display.
|
||||
scatter(iris, :SepalLength, :SepalWidth, group=:Species, m=([:+ :d :s], 12), smooth=0.99, bg=:black)
|
||||
|
||||
# save a png (equivalent to png("gadfly1.png") and savefig("gadfly1.png"))
|
||||
png("gadfly1")
|
||||
```
|
||||
|
||||

|
||||
|
||||
## API
|
||||
|
||||
Call `backend(backend::Symbol)` or the shorthands (`gadfly()`, `qwt()`, `unicodeplots()`, etc) to set the current plotting backend.
|
||||
Subsequent commands are converted into the relevant plotting commands for that package:
|
||||
|
||||
```julia
|
||||
gadfly()
|
||||
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
|
||||
qwt()
|
||||
plot(1:10) # this effectively calls `Qwt.plot(1:10)`
|
||||
```
|
||||
|
||||
Use `plot` to create a new plot object, and `plot!` to add to an existing one:
|
||||
|
||||
```julia
|
||||
plot(args...; kw...) # creates a new plot window, and sets it to be the `current`
|
||||
plot!(args...; kw...) # adds to the `current`
|
||||
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
|
||||
```
|
||||
|
||||
Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity.
|
||||
There are many ways to pass in data to the plot functions... some examples:
|
||||
|
||||
- Vector-like (subtypes of AbstractArray{T,1})
|
||||
- Matrix-like (subtypes of AbstractArray{T,2})
|
||||
- Vectors of Vectors
|
||||
- Functions
|
||||
- Vectors of Functions
|
||||
- DataFrames with column symbols (initialize with `dataframes()`)
|
||||
|
||||
In general, you can pass in a `y` only, or an `x` and `y`, both of whatever type(s) you want, and Plots will slice up the data as needed.
|
||||
For matrices, data is split by columns. For functions, data is mapped. For DataFrames, a Symbol/Symbols in place of x/y will map to
|
||||
the relevant column(s).
|
||||
|
||||
Here are some example usages... remember you can always use `plot!` to update an existing plot, and that, unless specified, you will update the `current()`.
|
||||
|
||||
```julia
|
||||
plot() # empty plot object
|
||||
plot(4) # initialize with 4 empty series
|
||||
plot(rand(10)) # plot 1 series... x = 1:10
|
||||
plot(rand(10,5)) # plot 5 series... x = 1:10
|
||||
plot(rand(10), rand(10)) # plot 1 series
|
||||
plot(rand(10,5), rand(10)) # plot 5 series... y is the same for all
|
||||
plot(sin, rand(10)) # y = sin(x)
|
||||
plot(rand(10), sin) # same... y = sin(x)
|
||||
plot([sin,cos], 0:0.1:π) # plot 2 series, sin(x) and cos(x)
|
||||
plot([sin,cos], 0, π) # plot sin and cos on the range [0, π]
|
||||
plot(1:10, Any[rand(10), sin]) # plot 2 series, y = rand(10) for the first, y = sin(x) for the second... x = 1:10 for both
|
||||
plot(dataset("Ecdat", "Airline"), :Cost) # plot from a DataFrame (call `dataframes()` first to import DataFrames and initialize)
|
||||
```
|
||||
|
||||
All plot methods accept a number of keyword arguments (see the tables below), which follow some rules:
|
||||
- Many arguments have aliases which are replaced during preprocessing. `c` is the same as `color`, `m` is the same as `marker`, etc. You can choose how verbose you'd like to be. (see the tables below)
|
||||
- There are some special arguments (`xaxis`, `yaxis`, `line`, `marker`, `fill` and the aliases `l`, `m`, `f`) which magically set many related things at once. (see the __Tip__ below)
|
||||
- If the argument is a "matrix-type", then each column will map to a series, cycling through columns if there are fewer columns than series. Anything else will apply the argument value to every series.
|
||||
- Many arguments accept many different types... for example the `color` (also `markercolor`, `fillcolor`, etc) argument will accept strings or symbols with a color name, or any `Colors.Colorant`, or a `ColorScheme`, or a symbol representing a `ColorGradient`, or an AbstractVector of colors/symbols/etc...
|
||||
|
||||
You can update certain plot settings after plot creation (not supported on all backends):
|
||||
|
||||
```julia
|
||||
plot!(title = "New Title", xlabel = "New xlabel", ylabel = "New ylabel")
|
||||
plot!(xlims = (0, 5.5), ylims = (-2.2, 6), xticks = 0:0.5:10, yticks = [0,1,5,10])
|
||||
|
||||
# using shorthands:
|
||||
xaxis!("mylabel", :log10, :flip)
|
||||
```
|
||||
|
||||
With `subplot`, create multiple plots at once, with flexible layout options:
|
||||
|
||||
```julia
|
||||
y = rand(100,3)
|
||||
subplot(y; n = 3) # create an automatic grid, and let it figure out the shape
|
||||
subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows
|
||||
subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns
|
||||
subplot(y; layout = [1, 2]) # explicit layout. Lists the number of plots in each row
|
||||
```
|
||||
|
||||
__Tip__: You can call `subplot!(args...; kw...)` to add to an existing subplot.
|
||||
|
||||
__Tip__: Calling `subplot!` on a `Plot` object, or `plot!` on a `Subplot` object will throw an error.
|
||||
|
||||
Shorthands:
|
||||
|
||||
```julia
|
||||
scatter(args...; kw...) = plot(args...; kw..., linetype = :scatter)
|
||||
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :scatter)
|
||||
bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
|
||||
sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
|
||||
hline!(args...; kw...) = plot!(args...; kw..., linetype = :hline)
|
||||
vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
|
||||
vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
|
||||
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
|
||||
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
|
||||
|
||||
title!(s::AbstractString) = plot!(title = s)
|
||||
xlabel!(s::AbstractString) = plot!(xlabel = s)
|
||||
ylabel!(s::AbstractString) = plot!(ylabel = s)
|
||||
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(xlims = lims)
|
||||
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(ylims = lims)
|
||||
xticks!{T<:Real}(v::AVec{T}) = plot!(xticks = v)
|
||||
yticks!{T<:Real}(v::AVec{T}) = plot!(yticks = v)
|
||||
xflip!(flip::Bool = true) = plot!(xflip = flip)
|
||||
yflip!(flip::Bool = true) = plot!(yflip = flip)
|
||||
xaxis!(args...) = plot!(xaxis = args)
|
||||
yaxis!(args...) = plot!(yaxis = args)
|
||||
annotate!(anns) = plot!(annotation = anns)
|
||||
```
|
||||
|
||||
### Keyword arguments:
|
||||
|
||||
Keyword | Default | Type | Aliases
|
||||
---- | ---- | ---- | ----
|
||||
`:annotation` | `nothing` | Series | `:ann`, `:annotate`, `:annotations`, `:anns`
|
||||
`:axis` | `left` | Series | `:axiss`
|
||||
`:background_color` | `RGB{U8}(1.0,1.0,1.0)` | Plot | `:background`, `:bg`, `:bg_color`, `:bgcolor`
|
||||
`:color` | `auto` | Series | `:c`, `:colors`
|
||||
`:color_palette` | `auto` | Plot | `:palette`
|
||||
`:fill` | `nothing` | Series | `:area`, `:f`
|
||||
`:fillcolor` | `match` | Series | `:fc`, `:fcolor`, `:fillcolors`
|
||||
`:fillopacity` | `nothing` | Series | `:fillopacitys`, `:fo`
|
||||
`:fillrange` | `nothing` | Series | `:fillranges`, `:fillrng`
|
||||
`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground`
|
||||
`:grid` | `true` | Plot |
|
||||
`:group` | `nothing` | Series | `:g`, `:groups`
|
||||
`:guidefont` | `Plots.Font("Helvetica",11,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
|
||||
`:label` | `AUTO` | Series | `:lab`, `:labels`
|
||||
`:layout` | `nothing` | Plot |
|
||||
`:legend` | `true` | Plot | `:leg`
|
||||
`:legendfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
|
||||
`:line` | `nothing` | Series | `:l`
|
||||
`:lineopacity` | `nothing` | Series | `:lineopacitys`, `:lo`
|
||||
`:linestyle` | `solid` | Series | `:linestyles`, `:ls`, `:s`, `:style`
|
||||
`:linetype` | `path` | Series | `:linetypes`, `:lt`, `:t`, `:type`
|
||||
`:linewidth` | `1` | Series | `:linewidths`, `:lw`, `:w`, `:width`
|
||||
`:link` | `false` | Plot |
|
||||
`:linkfunc` | `nothing` | Plot |
|
||||
`:linkx` | `false` | Plot | `:xlink`
|
||||
`:linky` | `false` | Plot | `:ylink`
|
||||
`:marker` | `nothing` | Series | `:m`, `:mark`
|
||||
`:markercolor` | `match` | Series | `:markercolors`, `:mc`, `:mcolor`
|
||||
`:markeropacity` | `nothing` | Series | `:alpha`, `:markeropacitys`, `:mo`, `:opacity`
|
||||
`:markershape` | `none` | Series | `:markershapes`, `:shape`
|
||||
`:markersize` | `6` | Series | `:markersizes`, `:ms`, `:msize`
|
||||
`:n` | `-1` | Plot |
|
||||
`:nbins` | `100` | Series | `:nb`, `:nbin`, `:nbinss`
|
||||
`:nc` | `-1` | Plot |
|
||||
`:nr` | `-1` | Plot |
|
||||
`:pos` | `(0,0)` | Plot |
|
||||
`:show` | `false` | Plot | `:display`, `:gui`
|
||||
`:size` | `(500,300)` | Plot | `:windowsize`, `:wsize`
|
||||
`:smooth` | `false` | Series | `:reg`, `:regression`, `:smooths`
|
||||
`:tickfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
|
||||
`:title` | `` | Plot |
|
||||
`:windowtitle` | `Plots.jl` | Plot | `:wtitle`
|
||||
`:xaxis` | `nothing` | Plot |
|
||||
`:xflip` | `false` | Plot |
|
||||
`:xlabel` | `` | Plot | `:xlab`
|
||||
`:xlims` | `auto` | Plot | `:xlim`, `:xlimit`, `:xlimits`
|
||||
`:xscale` | `identity` | Plot |
|
||||
`:xticks` | `auto` | Plot | `:xtick`
|
||||
`:yaxis` | `nothing` | Plot |
|
||||
`:yflip` | `false` | Plot |
|
||||
`:ylabel` | `` | Plot | `:ylab`
|
||||
`:ylims` | `auto` | Plot | `:ylim`, `:ylimit`, `:ylimits`
|
||||
`:yrightlabel` | `` | Plot | `:y2lab`, `:y2label`, `:ylab2`, `:ylabel2`, `:ylabelright`, `:ylabr`, `:yrlab`
|
||||
`:yscale` | `identity` | Plot |
|
||||
`:yticks` | `auto` | Plot | `:ytick`
|
||||
`:z` | `nothing` | Series | `:zs`
|
||||
|
||||
|
||||
### Plot types:
|
||||
|
||||
Type | Desc | Aliases
|
||||
---- | ---- | ----
|
||||
`:none` | No line | `:n`, `:no`
|
||||
`:line` | Lines with sorted x-axis | `:l`
|
||||
`:path` | Lines | `:p`
|
||||
`:steppre` | Step plot (vertical then horizontal) | `:stepinv`, `:stepinverted`, `:stepsinv`, `:stepsinverted`
|
||||
`:steppost` | Step plot (horizontal then vertical) | `:stair`, `:stairs`, `:step`, `:steps`
|
||||
`:sticks` | Vertical lines | `:stem`, `:stems`
|
||||
`:scatter` | Points, no lines | `:dots`
|
||||
`:heatmap` | Colored regions by density |
|
||||
`:hexbin` | Similar to heatmap |
|
||||
`:hist` | Histogram (doesn't use x) | `:histogram`
|
||||
`:bar` | Bar plot (centered on x values) |
|
||||
`:hline` | Horizontal line (doesn't use x) |
|
||||
`:vline` | Vertical line (doesn't use x) |
|
||||
`:ohlc` | Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC}) |
|
||||
|
||||
|
||||
### Line styles:
|
||||
|
||||
Type | Aliases
|
||||
---- | ----
|
||||
`:auto` | `:a`
|
||||
`:solid` | `:s`
|
||||
`:dash` | `:d`
|
||||
`:dot` |
|
||||
`:dashdot` | `:dd`
|
||||
`:dashdotdot` | `:ddd`
|
||||
|
||||
|
||||
### Markers:
|
||||
|
||||
Type | Aliases
|
||||
---- | ----
|
||||
`:none` | `:n`, `:no`
|
||||
`:auto` | `:a`
|
||||
`:cross` | `:+`, `:plus`
|
||||
`:diamond` | `:d`
|
||||
`:dtriangle` | `:V`, `:downtri`, `:downtriangle`, `:dt`, `:dtri`, `:v`
|
||||
`:ellipse` | `:c`, `:circle`
|
||||
`:heptagon` | `:hep`
|
||||
`:hexagon` | `:h`, `:hex`
|
||||
`:octagon` | `:o`, `:oct`
|
||||
`:pentagon` | `:p`, `:pent`
|
||||
`:rect` | `:r`, `:sq`, `:square`
|
||||
`:star4` |
|
||||
`:star5` | `:s`, `:star`, `:star1`
|
||||
`:star6` |
|
||||
`:star7` |
|
||||
`:star8` | `:s2`, `:star2`
|
||||
`:utriangle` | `:^`, `:uptri`, `:uptriangle`, `:ut`, `:utri`
|
||||
`:xcross` | `:X`, `:x`
|
||||
|
||||
|
||||
__Tip__: With supported backends, you can pass a `Plots.Shape` object for the `marker`/`markershape` arguments. `Shape` takes a vector of 2-tuples in the constructor, defining the points of the polygon's shape in a unit-scaled coordinate space. To make a square, for example, you could do `Shape([(1,1),(1,-1),(-1,-1),(-1,1)])`
|
||||
|
||||
__Tip__: You can see the default value for a given argument with `default(arg::Symbol)`, and set the default value with `default(arg::Symbol, value)` or `default(; kw...)`. For example set the default window size and whether we should show a legend with `default(size=(600,400), leg=false)`.
|
||||
|
||||
__Tip__: There are some helper arguments you can set: `xaxis`, `yaxis`, `line`, `marker`, `fill`. These go through special preprocessing to extract values into individual arguments. The order doesn't matter, and if you pass a single value it's equivalent to wrapping it in a Tuple. Examples:
|
||||
|
||||
```
|
||||
plot(y, xaxis = ("mylabel", :log, :flip, (-1,1))) # this sets the `xlabel`, `xscale`, `xflip`, and `xlims` arguments automatically
|
||||
plot(y, line = (:bar, :blue, :dot, 10)) # this sets the `linetype`, `color`, `linestyle`, and `linewidth` arguments automatically
|
||||
plot(y, marker = (:rect, :red, 10)) # this sets the `markershape`, `markercolor`, and `markersize` arguments automatically
|
||||
plot(y, fill = (:green, 10)) # this sets the `fillcolor` and `fillrange` arguments automatically
|
||||
# Note: `fillrange` can be:
|
||||
a number (fill to horizontal line)
|
||||
a vector of numbers (different for each data point)
|
||||
a tuple of vectors (fill a band)
|
||||
```
|
||||
|
||||
__Tip__: When plotting multiple lines, you can set all series to use the same value, or pass in a matrix to cycle through values. Example:
|
||||
|
||||
```julia
|
||||
plot(rand(100,4); color = [:red RGB(0,0,1)], # (Matrix) lines 1 and 3 are red, lines 2 and 4 are blue
|
||||
axis = :auto, # lines 1 and 3 are on the left axis, lines 2 and 4 are on the right
|
||||
markershape = [:rect, :star] # (Vector) ALL lines are passed the vector [:rect, :star1]
|
||||
width = 5) # all lines have a width of 5
|
||||
```
|
||||
|
||||
__Tip__: Not all features are supported for each backend, but you can see what's supported by calling the functions: `supportedArgs()`, `supportedAxes()`, `supportedTypes()`, `supportedStyles()`, `supportedMarkers()`, `subplotSupported()`
|
||||
|
||||
__Tip__: Call `gui()` to display the plot in a window. Interactivity depends on backend. Plotting at the REPL (without semicolon) implicitly calls `gui()`.
|
||||
|
||||
### Animations
|
||||
|
||||
Animations are created in 3 steps (see example #2):
|
||||
- Initialize an `Animation` object.
|
||||
- Save each frame of the animation with `frame(anim)`.
|
||||
- Convert the frames to an animated gif with `gif(anim, filename, fps=15)`
|
||||
|
||||
|
||||
## TODO features:
|
||||
|
||||
- [x] Plot vectors/matrices/functions
|
||||
- [x] Plot DataFrames
|
||||
- [x] Histograms
|
||||
- [x] Grouping
|
||||
- [x] Annotations
|
||||
- [x] Scales
|
||||
- [x] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
|
||||
- [x] Custom markers
|
||||
- [x] Animations
|
||||
- [x] Subplots
|
||||
- [ ] Contours
|
||||
- [ ] Boxplots
|
||||
- [ ] 3D plotting
|
||||
- [ ] Scenes/Drawing
|
||||
- [ ] Graphs
|
||||
- [ ] Interactivity (GUIs)
|
||||
|
||||
## TODO backends:
|
||||
|
||||
- [x] Gadfly.jl
|
||||
- [x] Immerse.jl
|
||||
- [x] PyPlot.jl
|
||||
- [x] UnicodePlots.jl
|
||||
- [x] Qwt.jl
|
||||
- [x] Winston.jl (deprecated)
|
||||
- [ ] GLPlot.jl
|
||||
- [ ] Bokeh.jl
|
||||
- [ ] Vega.jl
|
||||
- [ ] Gaston.jl
|
||||
- [ ] Plotly.jl
|
||||
- [ ] GoogleCharts.jl
|
||||
- [ ] PLplot.jl
|
||||
- [ ] TextPlots.jl
|
||||
- [ ] ASCIIPlots.jl
|
||||
- [ ] Sparklines.jl
|
||||
- [ ] Hinton.jl
|
||||
- [ ] ImageTerm.jl
|
||||
- [ ] GraphViz.jl
|
||||
- [ ] TikzGraphs.jl
|
||||
- [ ] GraphLayout.jl
|
||||
|
||||
## More information on backends (both supported and unsupported)
|
||||
|
||||
See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
|
||||
|
||||
|
||||
View the [full documentation](http://plots.readthedocs.org).
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
julia 0.3
|
||||
julia 0.4
|
||||
|
||||
Colors
|
||||
Reexport
|
||||
Compat
|
||||
Requires
|
||||
FixedSizeArrays
|
||||
|
||||
@@ -31,7 +31,7 @@ const examples = PlotExample[
|
||||
[
|
||||
:(p = plot([sin,cos], zeros(0), leg=false)),
|
||||
:(anim = Animation()),
|
||||
:(for x in linspace(0, 10π, 200)
|
||||
:(for x in linspace(0, 10π, 100)
|
||||
push!(p, x, Float64[sin(x), cos(x)])
|
||||
frame(anim)
|
||||
end)
|
||||
@@ -46,24 +46,28 @@ const examples = PlotExample[
|
||||
[
|
||||
:(y = rand(100)),
|
||||
:(plot(0:10:100,rand(11,4),lab="lines",w=3, palette=:grays, fill=(0.5,:auto))),
|
||||
:(scatter!(y, z=abs(y-.5), m=(10,:heat), lab="grad"))
|
||||
:(scatter!(y, zcolor=abs(y-.5), m=(:heat,0.8,stroke(1,:green)), ms=10*abs(y-0.5)+4, lab="grad"))
|
||||
]),
|
||||
PlotExample("Global",
|
||||
"Change the guides/background/limits/ticks. Convenience args `xaxis` and `yaxis` allow you to pass a tuple or value which will be mapped to the relevant args automatically. The `xaxis` below will be replaced with `xlabel` and `xlims` args automatically during the preprocessing step. You can also use shorthand functions: `title!`, `xaxis!`, `yaxis!`, `xlabel!`, `ylabel!`, `xlims!`, `ylims!`, `xticks!`, `yticks!`",
|
||||
[
|
||||
:(plot(rand(20,3), xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2), leg=false)),
|
||||
:(y = rand(20,3)),
|
||||
:(plot(y, xaxis=("XLABEL",(-5,30),0:2:20,:flip), background_color = RGB(0.2,0.2,0.2), leg=false)),
|
||||
:(hline!(mean(y,1)+rand(1,3), line=(4,:dash,0.6,[:lightgreen :green :darkgreen]))),
|
||||
:(vline!([5,10])),
|
||||
:(title!("TITLE")),
|
||||
:(yaxis!("YLABEL", :log10))
|
||||
]),
|
||||
PlotExample("Two-axis",
|
||||
"Use the `axis` arguments.\n\nNote: Currently only supported with Qwt and PyPlot",
|
||||
[
|
||||
:(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT"))
|
||||
:(plot(Vector[randn(100), randn(100)*100], axis = [:l :r], ylabel="LEFT", yrightlabel="RIGHT", xlabel="X", title="TITLE"))
|
||||
]),
|
||||
PlotExample("Arguments",
|
||||
"Plot multiple series with different numbers of points. Mix arguments that apply to all series (marker/markersize) with arguments unique to each series (colors). Special arguments `line`, `marker`, and `fill` will automatically figure out what arguments to set (for example, we are setting the `linestyle`, `linewidth`, and `color` arguments with `line`.) Note that we pass a matrix of colors, and this applies the colors to each series.",
|
||||
[
|
||||
:(plot(Vector[rand(10), rand(20)], marker=(:ellipse,8), line=(:dot,3,[:black :orange])))
|
||||
:(ys = Vector[rand(10), rand(20)]),
|
||||
:(plot(ys, line=(:dot,4,[:black :orange]), marker=([:hex :d],12,0.8,stroke(3,:gray))))
|
||||
]),
|
||||
PlotExample("Build plot in pieces",
|
||||
"Start with a base plot...",
|
||||
@@ -78,7 +82,7 @@ const examples = PlotExample[
|
||||
PlotExample("Heatmaps",
|
||||
"",
|
||||
[
|
||||
:(heatmap(randn(10000),randn(10000), nbins=100))
|
||||
:(heatmap(randn(10000),randn(10000), nbins=20))
|
||||
]),
|
||||
PlotExample("Line types",
|
||||
"",
|
||||
@@ -112,7 +116,7 @@ const examples = PlotExample[
|
||||
PlotExample("Histogram",
|
||||
"",
|
||||
[
|
||||
:(histogram(randn(1000), nbins=50))
|
||||
:(histogram(randn(1000), nbins=20))
|
||||
]),
|
||||
PlotExample("Subplots",
|
||||
"""
|
||||
@@ -163,8 +167,37 @@ const examples = PlotExample[
|
||||
m=(Shape(verts),30,RGBA(0,0,0,0.2)),
|
||||
bg=:pink, fg=:darkblue,
|
||||
xlim = (0,1), ylim=(0,1), leg=false))
|
||||
]),
|
||||
|
||||
PlotExample("Contours",
|
||||
"",
|
||||
[
|
||||
:(x = 1:0.3:20),
|
||||
:(y = x),
|
||||
:(f(x,y) = sin(x)+cos(y)),
|
||||
:(contour(x, y, f, fill=true))
|
||||
]),
|
||||
|
||||
PlotExample("Pie",
|
||||
"",
|
||||
[
|
||||
:(x = ["Nerds", "Hackers", "Scientists"]),
|
||||
:(y = [0.4, 0.35, 0.25]),
|
||||
:(pie(x, y, title="The Julia Community", l=0.5))
|
||||
]),
|
||||
|
||||
PlotExample("3D",
|
||||
"",
|
||||
[
|
||||
:(n = 100),
|
||||
:(ts = linspace(0,8π,n)),
|
||||
:(x = ts .* map(cos,ts)),
|
||||
:(y = 0.1ts .* map(sin,ts)),
|
||||
:(z = 1:n),
|
||||
:(plot(x, y, z, zcolor=reverse(z), m=(10,0.8,:blues,stroke(0)), leg=false, w=5)),
|
||||
:(plot!(zeros(n),zeros(n),1:n, w=10))
|
||||
])
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -301,20 +334,23 @@ end
|
||||
|
||||
|
||||
@compat const _ltdesc = Dict(
|
||||
:none => "No line",
|
||||
:line => "Lines with sorted x-axis",
|
||||
:path => "Lines",
|
||||
:steppre => "Step plot (vertical then horizontal)",
|
||||
:steppost => "Step plot (horizontal then vertical)",
|
||||
:sticks => "Vertical lines",
|
||||
:scatter => "Points, no lines",
|
||||
:heatmap => "Colored regions by density",
|
||||
:hexbin => "Similar to heatmap",
|
||||
:hist => "Histogram (doesn't use x)",
|
||||
:bar => "Bar plot (centered on x values)",
|
||||
:hline => "Horizontal line (doesn't use x)",
|
||||
:vline => "Vertical line (doesn't use x)",
|
||||
:ohlc => "Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC})",
|
||||
:none => "No line",
|
||||
:line => "Lines with sorted x-axis",
|
||||
:path => "Lines",
|
||||
:steppre => "Step plot (vertical then horizontal)",
|
||||
:steppost => "Step plot (horizontal then vertical)",
|
||||
:sticks => "Vertical lines",
|
||||
:scatter => "Points, no lines",
|
||||
:heatmap => "Colored regions by density",
|
||||
:hexbin => "Similar to heatmap",
|
||||
:hist => "Histogram (doesn't use x)",
|
||||
:bar => "Bar plot (centered on x values)",
|
||||
:hline => "Horizontal line (doesn't use x)",
|
||||
:vline => "Vertical line (doesn't use x)",
|
||||
:ohlc => "Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC})",
|
||||
:contour => "Contour lines (uses z)",
|
||||
:path3d => "3D path (uses z)",
|
||||
:scatter3d => "3D scatter plot (uses z)",
|
||||
)
|
||||
|
||||
function buildReadme()
|
||||
@@ -18,7 +18,7 @@ Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
|
||||
|
||||
Check out the [summary graphs](https://github.com/tbreloff/ExamplePlots.jl/tree/master/img/supported/supported.md) for the features that each backend supports.
|
||||
Check out the [summary graphs](img/supported/supported.md) for the features that each backend supports.
|
||||
|
||||
Please add wishlist items, bugs, or any other comments/questions to the issues list.
|
||||
|
||||
@@ -52,7 +52,8 @@ Pkg.add("Gadfly")
|
||||
Pkg.add("Immerse")
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.clone("https://github.com/tbreloff/Qwt.jl.git")
|
||||
Pkg.add("Qwt")
|
||||
Pkg.add("Bokeh")
|
||||
```
|
||||
|
||||
## Use
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -1,11 +1,16 @@
|
||||
|
||||
|
||||
immutable GadflyPackage <: PlottingPackage end
|
||||
immutable ImmersePackage <: PlottingPackage end
|
||||
immutable PyPlotPackage <: PlottingPackage end
|
||||
immutable QwtPackage <: PlottingPackage end
|
||||
immutable GadflyPackage <: PlottingPackage end
|
||||
immutable ImmersePackage <: PlottingPackage end
|
||||
immutable PyPlotPackage <: PlottingPackage end
|
||||
immutable QwtPackage <: PlottingPackage end
|
||||
immutable UnicodePlotsPackage <: PlottingPackage end
|
||||
immutable WinstonPackage <: PlottingPackage end
|
||||
immutable WinstonPackage <: PlottingPackage end
|
||||
immutable BokehPackage <: PlottingPackage end
|
||||
immutable PlotlyPackage <: PlottingPackage end
|
||||
immutable GRPackage <: PlottingPackage end
|
||||
immutable GLVisualizePackage <: PlottingPackage end
|
||||
immutable NoPackage <: PlottingPackage end
|
||||
|
||||
typealias GadflyOrImmerse @compat(Union{GadflyPackage, ImmersePackage})
|
||||
|
||||
@@ -14,21 +19,34 @@ export
|
||||
immerse,
|
||||
pyplot,
|
||||
qwt,
|
||||
unicodeplots
|
||||
unicodeplots,
|
||||
bokeh,
|
||||
plotly,
|
||||
gr,
|
||||
glvisualize
|
||||
# winston
|
||||
|
||||
gadfly() = backend(:gadfly)
|
||||
immerse() = backend(:immerse)
|
||||
pyplot() = backend(:pyplot)
|
||||
qwt() = backend(:qwt)
|
||||
unicodeplots() = backend(:unicodeplots)
|
||||
# winston() = backend(:winston)
|
||||
gadfly(; kw...) = (default(; kw...); backend(:gadfly))
|
||||
immerse(; kw...) = (default(; kw...); backend(:immerse))
|
||||
pyplot(; kw...) = (default(; kw...); backend(:pyplot))
|
||||
qwt(; kw...) = (default(; kw...); backend(:qwt))
|
||||
unicodeplots(; kw...) = (default(; kw...); backend(:unicodeplots))
|
||||
bokeh(; kw...) = (default(; kw...); backend(:bokeh))
|
||||
plotly(; kw...) = (default(; kw...); backend(:plotly))
|
||||
gr(; kw...) = (default(; kw...); backend(:gr))
|
||||
glvisualize(; kw...) = (default(; kw...); backend(:glvisualize))
|
||||
# winston(; kw...) = (default(; kw...); backend(:winston))
|
||||
|
||||
backend_name(::GadflyPackage) = :gadfly
|
||||
backend_name(::ImmersePackage) = :immerse
|
||||
backend_name(::PyPlotPackage) = :pyplot
|
||||
backend_name(::UnicodePlotsPackage) = :unicodeplots
|
||||
backend_name(::QwtPackage) = :qwt
|
||||
backend_name(::BokehPackage) = :bokeh
|
||||
backend_name(::PlotlyPackage) = :plotly
|
||||
backend_name(::GRPackage) = :gr
|
||||
backend_name(::GLVisualizePackage) = :glvisualize
|
||||
backend_name(::NoPackage) = :none
|
||||
|
||||
include("backends/supported.jl")
|
||||
|
||||
@@ -39,16 +57,23 @@ include("backends/pyplot.jl")
|
||||
include("backends/immerse.jl")
|
||||
include("backends/winston.jl")
|
||||
|
||||
include("backends/web.jl")
|
||||
include("backends/bokeh.jl")
|
||||
include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
|
||||
include("backends/glvisualize.jl")
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
|
||||
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
|
||||
updatePlotItems(pkg::PlottingPackage, plt::Plot, d::Dict) = error("updatePlotItems($pkg, plt, d) is not implemented")
|
||||
_update_plot(pkg::PlottingPackage, plt::Plot, d::Dict) = error("_update_plot($pkg, plt, d) is not implemented")
|
||||
# Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented")
|
||||
|
||||
updatePositionAndSize{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing #error("updatePositionAndSize(plt,d) is not implemented for $P")
|
||||
_update_plot_pos_size{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing #error("_update_plot_pos_size(plt,d) is not implemented for $P")
|
||||
|
||||
subplot(pkg::PlottingPackage; kw...) = error("subplot($pkg; kw...) is not implemented")
|
||||
subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
|
||||
@@ -57,66 +82,43 @@ subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, s
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse]
|
||||
const INITIALIZED_BACKENDS = Set{Symbol}()
|
||||
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly, :gr]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
backends() = BACKENDS
|
||||
|
||||
|
||||
function backendInstance(sym::Symbol)
|
||||
function _backend_instance(sym::Symbol)
|
||||
sym == :qwt && return QwtPackage()
|
||||
sym == :gadfly && return GadflyPackage()
|
||||
sym == :unicodeplots && return UnicodePlotsPackage()
|
||||
sym == :pyplot && return PyPlotPackage()
|
||||
sym == :immerse && return ImmersePackage()
|
||||
sym == :winston && return WinstonPackage()
|
||||
sym == :bokeh && return BokehPackage()
|
||||
sym == :plotly && return PlotlyPackage()
|
||||
sym == :gr && return GRPackage()
|
||||
sym == :glvisualize && return GLVisualizePackage()
|
||||
sym == :none && return NoPackage()
|
||||
error("Unsupported backend $sym")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
type CurrentBackend
|
||||
sym::Symbol
|
||||
pkg::PlottingPackage
|
||||
end
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, backendInstance(sym))
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
try
|
||||
if Pkg.installed("Immerse") != nothing
|
||||
return CurrentBackend(:immerse)
|
||||
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
|
||||
if Pkg.installed(pkgstr) != nothing
|
||||
return backend(symbol(lowercase(pkgstr)))
|
||||
end
|
||||
end
|
||||
try
|
||||
if Pkg.installed("Qwt") != nothing
|
||||
return CurrentBackend(:qwt)
|
||||
end
|
||||
end
|
||||
try
|
||||
if Pkg.installed("PyPlot") != nothing
|
||||
return CurrentBackend(:pyplot)
|
||||
end
|
||||
end
|
||||
try
|
||||
if Pkg.installed("Gadfly") != nothing
|
||||
return CurrentBackend(:gadfly)
|
||||
end
|
||||
end
|
||||
try
|
||||
if Pkg.installed("UnicodePlots") != nothing
|
||||
return CurrentBackend(:unicodeplots)
|
||||
end
|
||||
end
|
||||
try
|
||||
if Pkg.installed("Winston") != nothing
|
||||
return CurrentBackend(:winston)
|
||||
end
|
||||
end
|
||||
warn("You don't have any of the supported backends installed! Chose from ", backends())
|
||||
return CurrentBackend(:gadfly)
|
||||
backend(:plotly)
|
||||
end
|
||||
# const CURRENT_BACKEND = pickDefaultBackend()
|
||||
# println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
@@ -125,10 +127,14 @@ end
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
# error()
|
||||
|
||||
global CURRENT_BACKEND
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
currentBackendSymbol = CURRENT_BACKEND.sym
|
||||
if !(currentBackendSymbol in INITIALIZED_BACKENDS)
|
||||
if !(currentBackendSymbol in _initialized_backends)
|
||||
|
||||
# initialize
|
||||
println("[Plots.jl] Initializing backend: ", CURRENT_BACKEND.sym)
|
||||
@@ -143,8 +149,8 @@ function backend()
|
||||
|
||||
elseif currentBackendSymbol == :gadfly
|
||||
try
|
||||
@eval import Gadfly, Compose, DataFrames
|
||||
@eval export Gadfly, Compose, DataFrames
|
||||
@eval import Gadfly, Compose
|
||||
@eval export Gadfly, Compose
|
||||
@eval include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
catch err
|
||||
warn("Couldn't import Gadfly. Install it with: Pkg.add(\"Gadfly\").")
|
||||
@@ -166,10 +172,11 @@ function backend()
|
||||
@eval export PyPlot
|
||||
@eval const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
@eval const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
|
||||
@eval const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
|
||||
# @eval const pycolorbar = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colorbar"))
|
||||
if !isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
PyPlot.ioff() # stops wierd behavior of displaying incomplete graphs in IJulia
|
||||
|
||||
|
||||
# # TODO: how the hell can I use PyQt4??
|
||||
# "pyqt4"=>:qt_pyqt4
|
||||
# PyPlot.backend[1] = "pyqt4"
|
||||
@@ -198,6 +205,70 @@ function backend()
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :bokeh
|
||||
try
|
||||
@eval import Bokeh
|
||||
@eval export Bokeh
|
||||
catch err
|
||||
warn("Couldn't import Bokeh. Install it with: Pkg.add(\"Bokeh\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :plotly
|
||||
try
|
||||
@eval begin
|
||||
import JSON
|
||||
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
|
||||
|
||||
############################
|
||||
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
|
||||
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
# the first script is some hack I needed to do in order for the notebook
|
||||
# to not complain about Plotly being undefined
|
||||
display("text/html", """
|
||||
<script type="text/javascript">
|
||||
require=requirejs=define=undefined;
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(open(readall, _js_path, "r"))
|
||||
</script>
|
||||
""")
|
||||
# display("text/html", "<p>Plotly javascript loaded.</p>")
|
||||
end
|
||||
# end borrowing (thanks :)
|
||||
###########################
|
||||
|
||||
try
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "plotly_blink.jl"))
|
||||
catch err
|
||||
warn("Error including PlotlyJS: $err\n Note: Will fall back to built-in display.")
|
||||
end
|
||||
|
||||
end
|
||||
catch err
|
||||
warn("Couldn't setup Plotly")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :gr
|
||||
try
|
||||
@eval import GR
|
||||
catch err
|
||||
warn("Couldn't import GR. Install it with: Pkg.add(\"GR\").")
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :glvisualize
|
||||
try
|
||||
@eval import GLVisualize
|
||||
@eval export GLVisualize
|
||||
catch err
|
||||
warn("Couldn't setup GLVisualize")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :winston
|
||||
warn("Winston support is deprecated and broken. Try another backend: $BACKENDS")
|
||||
try
|
||||
@@ -212,7 +283,7 @@ function backend()
|
||||
else
|
||||
error("Unknown backend $currentBackendSymbol. Choose from: $BACKENDS")
|
||||
end
|
||||
push!(INITIALIZED_BACKENDS, currentBackendSymbol)
|
||||
push!(_initialized_backends, currentBackendSymbol)
|
||||
|
||||
end
|
||||
CURRENT_BACKEND.pkg
|
||||
@@ -222,13 +293,12 @@ end
|
||||
Set the plot backend. Choose from: :qwt, :gadfly, :unicodeplots, :immerse, :pyplot
|
||||
"""
|
||||
function backend(pkg::PlottingPackage)
|
||||
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
end
|
||||
|
||||
function backend(modname)
|
||||
|
||||
|
||||
# set the PlottingPackage
|
||||
if modname == :qwt
|
||||
CURRENT_BACKEND.pkg = QwtPackage()
|
||||
@@ -242,6 +312,14 @@ function backend(modname)
|
||||
CURRENT_BACKEND.pkg = ImmersePackage()
|
||||
elseif modname == :winston
|
||||
CURRENT_BACKEND.pkg = WinstonPackage()
|
||||
elseif modname == :bokeh
|
||||
CURRENT_BACKEND.pkg = BokehPackage()
|
||||
elseif modname == :plotly
|
||||
CURRENT_BACKEND.pkg = PlotlyPackage()
|
||||
elseif modname == :gr
|
||||
CURRENT_BACKEND.pkg = GRPackage()
|
||||
elseif modname == :glvisualize
|
||||
CURRENT_BACKEND.pkg = GLVisualizePackage()
|
||||
else
|
||||
error("Unknown backend $modname. Choose from: $BACKENDS")
|
||||
end
|
||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 24 KiB |
@@ -1,24 +1,31 @@
|
||||
|
||||
if VERSION >= v"0.4-"
|
||||
__precompile__()
|
||||
end
|
||||
__precompile__()
|
||||
|
||||
module Plots
|
||||
|
||||
using Compat
|
||||
using Reexport
|
||||
@reexport using Colors
|
||||
using Requires
|
||||
using FixedSizeArrays
|
||||
|
||||
export
|
||||
Plot,
|
||||
Subplot,
|
||||
SubplotLayout,
|
||||
GridLayout,
|
||||
FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
# plot_display,
|
||||
# plot_display!,
|
||||
subplot,
|
||||
subplot!,
|
||||
|
||||
current,
|
||||
default,
|
||||
with,
|
||||
|
||||
scatter,
|
||||
scatter!,
|
||||
@@ -26,8 +33,12 @@ export
|
||||
bar!,
|
||||
histogram,
|
||||
histogram!,
|
||||
density,
|
||||
density!,
|
||||
heatmap,
|
||||
heatmap!,
|
||||
hexbin,
|
||||
hexbin!,
|
||||
sticks,
|
||||
sticks!,
|
||||
hline,
|
||||
@@ -36,6 +47,21 @@ export
|
||||
vline!,
|
||||
ohlc,
|
||||
ohlc!,
|
||||
pie,
|
||||
pie!,
|
||||
contour,
|
||||
contour!,
|
||||
surface,
|
||||
surface!,
|
||||
wireframe,
|
||||
wireframe!,
|
||||
path3d,
|
||||
path3d!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
scatter3d,
|
||||
scatter3d!,
|
||||
abline!,
|
||||
|
||||
title!,
|
||||
xlabel!,
|
||||
@@ -56,12 +82,16 @@ export
|
||||
|
||||
backend,
|
||||
backends,
|
||||
backend_name,
|
||||
aliases,
|
||||
dataframes,
|
||||
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
|
||||
colorscheme,
|
||||
@@ -86,25 +116,23 @@ export
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
@animate,
|
||||
@gif,
|
||||
|
||||
# recipes
|
||||
PlotRecipe,
|
||||
EllipseRecipe,
|
||||
spy,
|
||||
# EllipseRecipe,
|
||||
# spy,
|
||||
corrplot
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
const IMG_DIR = Pkg.dir("Plots") * "/img/"
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
include("types.jl")
|
||||
include("utils.jl")
|
||||
include("colors.jl")
|
||||
include("plotter.jl")
|
||||
include("components.jl")
|
||||
include("plotter2.jl")
|
||||
include("args.jl")
|
||||
include("plot.jl")
|
||||
include("subplot.jl")
|
||||
@@ -121,8 +149,12 @@ bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
density(args...; kw...) = plot(args...; kw..., linetype = :density)
|
||||
density!(args...; kw...) = plot!(args...; kw..., linetype = :density)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
|
||||
hexbin(args...; kw...) = plot(args...; kw..., linetype = :hexbin)
|
||||
hexbin!(args...; kw...) = plot!(args...; kw..., linetype = :hexbin)
|
||||
sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
|
||||
@@ -131,6 +163,20 @@ vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
|
||||
vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
|
||||
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
|
||||
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
|
||||
pie(args...; kw...) = plot(args...; kw..., linetype = :pie)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., linetype = :pie)
|
||||
contour(args...; kw...) = plot(args...; kw..., linetype = :contour)
|
||||
contour!(args...; kw...) = plot!(args...; kw..., linetype = :contour)
|
||||
surface(args...; kw...) = plot(args...; kw..., linetype = :surface)
|
||||
surface!(args...; kw...) = plot!(args...; kw..., linetype = :surface)
|
||||
wireframe(args...; kw...) = plot(args...; kw..., linetype = :wireframe)
|
||||
wireframe!(args...; kw...) = plot!(args...; kw..., linetype = :wireframe)
|
||||
path3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
|
||||
path3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
|
||||
plot3d(args...; kw...) = plot(args...; kw..., linetype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., linetype = :path3d)
|
||||
scatter3d(args...; kw...) = plot(args...; kw..., linetype = :scatter3d)
|
||||
scatter3d!(args...; kw...) = plot!(args...; kw..., linetype = :scatter3d)
|
||||
|
||||
|
||||
title!(s::@compat(AbstractString); kw...) = plot!(; title = s, kw...)
|
||||
@@ -177,34 +223,15 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
try
|
||||
import DataFrames
|
||||
dataframes()
|
||||
end
|
||||
|
||||
# const CURRENT_BACKEND = pickDefaultBackend()
|
||||
|
||||
# for be in backends()
|
||||
# try
|
||||
# backend(be)
|
||||
# backend()
|
||||
# catch err
|
||||
# @show err
|
||||
# end
|
||||
# end
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
function __init__()
|
||||
global const CURRENT_BACKEND = pickDefaultBackend()
|
||||
# global CURRENT_BACKEND
|
||||
# println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
|
||||
|
||||
# # auto init dataframes if the import statement doesn't error out
|
||||
# try
|
||||
# @eval import DataFrames
|
||||
# dataframes()
|
||||
# end
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
@eval import IJulia
|
||||
IJulia.display_dict(plt::PlottingObject) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
|
||||
immutable Animation{P<:PlottingObject}
|
||||
plt::P
|
||||
immutable Animation
|
||||
dir::ASCIIString
|
||||
frames::Vector{ASCIIString}
|
||||
end
|
||||
|
||||
function Animation(plt::PlottingObject)
|
||||
Animation(plt, mktempdir(), ASCIIString[])
|
||||
function Animation()
|
||||
tmpdir = convert(ASCIIString, mktempdir())
|
||||
Animation(tmpdir, ASCIIString[])
|
||||
end
|
||||
Animation() = Animation(current())
|
||||
|
||||
function frame(anim::Animation)
|
||||
function frame{P<:PlottingObject}(anim::Animation, plt::P=current())
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(anim.plt, joinpath(anim.dir, filename))
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
push!(anim.frames, filename)
|
||||
end
|
||||
|
||||
@@ -29,11 +28,11 @@ function gif(anim::Animation, fn::@compat(AbstractString) = "tmp.gif"; fps::Inte
|
||||
fn = abspath(fn)
|
||||
|
||||
try
|
||||
|
||||
|
||||
# high quality
|
||||
speed = round(Int, 100 / fps)
|
||||
run(`convert -delay $speed -loop 0 $(anim.dir)/*.png $fn`)
|
||||
|
||||
run(`convert -delay $speed -loop 0 $(anim.dir)/*.png -alpha off $fn`)
|
||||
|
||||
catch err
|
||||
warn("Tried to create gif using convert (ImageMagick), but got error: $err\nWill try ffmpeg, but it's lower quality...)")
|
||||
|
||||
@@ -52,3 +51,86 @@ end
|
||||
function Base.writemime(io::IO, ::MIME"text/html", agif::AnimatedGif)
|
||||
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />")
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------
|
||||
|
||||
function _animate(forloop::Expr, args...; callgif = false)
|
||||
if forloop.head != :for
|
||||
error("@animate macro expects a for-block. got: $(forloop.head)")
|
||||
end
|
||||
|
||||
# add the call to frame to the end of each iteration
|
||||
animsym = gensym("anim")
|
||||
countersym = gensym("counter")
|
||||
block = forloop.args[2]
|
||||
|
||||
# create filter
|
||||
n = length(args)
|
||||
filterexpr = if n == 0
|
||||
# no filter... every iteration gets a frame
|
||||
true
|
||||
|
||||
elseif args[1] == :every
|
||||
# filter every `freq` frames (starting with the first frame)
|
||||
@assert n == 2
|
||||
freq = args[2]
|
||||
@assert isa(freq, Integer) && freq > 0
|
||||
:(mod1($countersym, $freq) == 1)
|
||||
|
||||
elseif args[1] == :when
|
||||
# filter on custom expression
|
||||
@assert n == 2
|
||||
args[2]
|
||||
|
||||
else
|
||||
error("Unsupported animate filter: $args")
|
||||
end
|
||||
|
||||
push!(block.args, :(if $filterexpr; frame($animsym); end))
|
||||
push!(block.args, :($countersym += 1))
|
||||
|
||||
# add a final call to `gif(anim)`?
|
||||
retval = callgif ? :(gif($animsym)) : animsym
|
||||
|
||||
# full expression:
|
||||
esc(quote
|
||||
$animsym = Animation() # init animation object
|
||||
$countersym = 1 # init iteration counter
|
||||
$forloop # for loop, saving a frame after each iteration
|
||||
$retval # return the animation object, or the gif
|
||||
end)
|
||||
end
|
||||
|
||||
"""
|
||||
Builds an `Animation` using one frame per loop iteration, then create an animated GIF.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
@gif for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
```
|
||||
"""
|
||||
macro gif(forloop::Expr, args...)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
end
|
||||
|
||||
"""
|
||||
Collect one frame per for-block iteration and return an `Animation` object.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
gif(anim)
|
||||
```
|
||||
"""
|
||||
macro animate(forloop::Expr, args...)
|
||||
_animate(forloop, args...)
|
||||
end
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
|
||||
const _allAxes = [:auto, :left, :right]
|
||||
@compat const _axesAliases = Dict(
|
||||
:a => :auto,
|
||||
:l => :left,
|
||||
:a => :auto,
|
||||
:l => :left,
|
||||
:r => :right
|
||||
)
|
||||
|
||||
const _allTypes = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||
:heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc, :contour]
|
||||
const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe]
|
||||
const _allTypes = vcat([
|
||||
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||
:heatmap, :hexbin, :hist, :density, :bar, :hline, :vline, :ohlc,
|
||||
:contour, :pie
|
||||
], _3dTypes)
|
||||
@compat const _typeAliases = Dict(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
@@ -26,9 +30,18 @@ const _allTypes = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||
:stems => :sticks,
|
||||
:dots => :scatter,
|
||||
:histogram => :hist,
|
||||
:contours => :contours,
|
||||
:pdf => :density,
|
||||
:contours => :contour,
|
||||
:line3d => :path3d,
|
||||
:surf => :surface,
|
||||
:wire => :wireframe,
|
||||
)
|
||||
|
||||
ishistlike(lt::Symbol) = lt in (:hist, :density)
|
||||
islinelike(lt::Symbol) = lt in (:line, :path, :steppre, :steppost)
|
||||
isheatmaplike(lt::Symbol) = lt in (:heatmap, :hexbin)
|
||||
|
||||
|
||||
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
@compat const _styleAliases = Dict(
|
||||
:a => :auto,
|
||||
@@ -78,61 +91,56 @@ const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
|
||||
:hep => :heptagon,
|
||||
:o => :octagon,
|
||||
:oct => :octagon,
|
||||
:spike => :vline,
|
||||
)
|
||||
|
||||
const _allScales = [:identity, :log, :log2, :log10, :asinh, :sqrt]
|
||||
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
@compat const _scaleAliases = Dict(
|
||||
:none => :identity,
|
||||
:ln => :log,
|
||||
:log => :log10,
|
||||
)
|
||||
|
||||
supportedAxes(::PlottingPackage) = _allAxes
|
||||
supportedTypes(::PlottingPackage) = _allTypes
|
||||
supportedStyles(::PlottingPackage) = _allStyles
|
||||
supportedMarkers(::PlottingPackage) = _allMarkers
|
||||
supportedScales(::PlottingPackage) = _allScales
|
||||
subplotSupported(::PlottingPackage) = true
|
||||
|
||||
supportedAxes() = supportedAxes(backend())
|
||||
supportedTypes() = supportedTypes(backend())
|
||||
supportedStyles() = supportedStyles(backend())
|
||||
supportedMarkers() = supportedMarkers(backend())
|
||||
supportedScales() = supportedScales(backend())
|
||||
subplotSupported() = subplotSupported(backend())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
const _seriesDefaults = Dict{Symbol, Any}()
|
||||
|
||||
# series-specific
|
||||
_seriesDefaults[:axis] = :left
|
||||
_seriesDefaults[:color] = :auto
|
||||
_seriesDefaults[:label] = "AUTO"
|
||||
_seriesDefaults[:linetype] = :path
|
||||
_seriesDefaults[:linestyle] = :solid
|
||||
_seriesDefaults[:linewidth] = 1
|
||||
_seriesDefaults[:lineopacity] = nothing
|
||||
_seriesDefaults[:markershape] = :none
|
||||
_seriesDefaults[:markercolor] = :match
|
||||
_seriesDefaults[:markeropacity] = nothing
|
||||
_seriesDefaults[:markersize] = 6
|
||||
_seriesDefaults[:fillrange] = nothing # ribbons, areas, etc
|
||||
_seriesDefaults[:fillcolor] = :match
|
||||
_seriesDefaults[:fillopacity] = nothing
|
||||
# _seriesDefaults[:ribbon] = nothing
|
||||
# _seriesDefaults[:ribboncolor] = :match
|
||||
_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
|
||||
# _seriesDefaults[:heatmap_c] = (0.15, 0.5) # TODO: this should be replaced with a ColorGradient
|
||||
# _seriesDefaults[:fill] = nothing # fills in the area
|
||||
_seriesDefaults[:smooth] = false # regression line?
|
||||
_seriesDefaults[:group] = nothing # groupby vector
|
||||
_seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
|
||||
_seriesDefaults[:z] = nothing # depth for contour, color scale, etc
|
||||
# _seriesDefaults[:args] = [] # additional args to pass to the backend
|
||||
# _seriesDefaults[:kwargs] = [] # additional keyword args to pass to the backend
|
||||
# # note: can be Vector{Dict} or Vector{Tuple}
|
||||
_seriesDefaults[:surface] = nothing
|
||||
_seriesDefaults[:nlevels] = 15
|
||||
_seriesDefaults[:axis] = :left
|
||||
_seriesDefaults[:label] = "AUTO"
|
||||
_seriesDefaults[:linetype] = :path
|
||||
_seriesDefaults[:linestyle] = :solid
|
||||
_seriesDefaults[:linewidth] = 1
|
||||
_seriesDefaults[:linecolor] = :auto
|
||||
_seriesDefaults[:linealpha] = nothing
|
||||
# _seriesDefaults[:linestroke] = Stroke(1, :auto, nothing, :solid) # linewidth, linecolor, linealpha, linestyle
|
||||
# _seriesDefaults[:fillbrush] = Brush(nothing, :match, nothing) # fillrange, fillcolor, fillalpha
|
||||
_seriesDefaults[:fillrange] = nothing # ribbons, areas, etc
|
||||
_seriesDefaults[:fillcolor] = :match
|
||||
_seriesDefaults[:fillalpha] = nothing
|
||||
_seriesDefaults[:markershape] = :none
|
||||
# _seriesDefaults[:markerstroke] = Stroke(1, :match_foreground, nothing, :solid)
|
||||
# _seriesDefaults[:markerbrush] = Brush(6, :match, nothing)
|
||||
_seriesDefaults[:markercolor] = :match
|
||||
_seriesDefaults[:markeralpha] = nothing
|
||||
_seriesDefaults[:markersize] = 6
|
||||
_seriesDefaults[:markerstrokestyle] = :solid
|
||||
_seriesDefaults[:markerstrokewidth] = 1
|
||||
_seriesDefaults[:markerstrokecolor] = :match
|
||||
_seriesDefaults[:markerstrokealpha] = nothing
|
||||
# _seriesDefaults[:ribbon] = nothing
|
||||
# _seriesDefaults[:ribboncolor] = :match
|
||||
_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
|
||||
_seriesDefaults[:smooth] = false # regression line?
|
||||
_seriesDefaults[:group] = nothing # groupby vector
|
||||
# _seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
|
||||
_seriesDefaults[:x] = nothing
|
||||
_seriesDefaults[:y] = nothing
|
||||
_seriesDefaults[:z] = nothing # depth for contour, surface, etc
|
||||
_seriesDefaults[:zcolor] = nothing # value for color scale
|
||||
# _seriesDefaults[:surface] = nothing
|
||||
# _seriesDefaults[:nlevels] = 15
|
||||
_seriesDefaults[:levels] = 15
|
||||
_seriesDefaults[:orientation] = :vertical
|
||||
|
||||
|
||||
const _plotDefaults = Dict{Symbol, Any}()
|
||||
@@ -142,7 +150,8 @@ _plotDefaults[:title] = ""
|
||||
_plotDefaults[:xlabel] = ""
|
||||
_plotDefaults[:ylabel] = ""
|
||||
_plotDefaults[:yrightlabel] = ""
|
||||
_plotDefaults[:legend] = true
|
||||
_plotDefaults[:legend] = :best
|
||||
_plotDefaults[:colorbar] = :legend
|
||||
_plotDefaults[:background_color] = colorant"white"
|
||||
_plotDefaults[:foreground_color] = :auto
|
||||
_plotDefaults[:xlims] = :auto
|
||||
@@ -170,22 +179,17 @@ _plotDefaults[:tickfont] = font(8)
|
||||
_plotDefaults[:guidefont] = font(11)
|
||||
_plotDefaults[:legendfont] = font(8)
|
||||
_plotDefaults[:grid] = true
|
||||
|
||||
_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
|
||||
_plotDefaults[:overwrite_figure] = false
|
||||
|
||||
|
||||
# TODO: x/y scales
|
||||
|
||||
const _allArgs = sort(collect(union(keys(_seriesDefaults), keys(_plotDefaults))))
|
||||
supportedArgs(::PlottingPackage) = _allArgs
|
||||
supportedArgs(::PlottingPackage) = error("supportedArgs not defined") #_allArgs
|
||||
supportedArgs() = supportedArgs(backend())
|
||||
|
||||
|
||||
@compat const _argNotes = Dict(
|
||||
:color => "Series color. To have different marker and/or fill colors, optionally set the markercolor and fillcolor args.",
|
||||
:z => "Determines the depth. For color gradients, we expect 0 ≤ z ≤ 1.",
|
||||
# :heatmap_c => "For Qwt heatmaps only... will be deprecated eventually.",
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -215,79 +219,103 @@ end
|
||||
# Alternate args
|
||||
|
||||
@compat const _keyAliases = Dict(
|
||||
:c => :color,
|
||||
:lab => :label,
|
||||
:l => :line,
|
||||
:w => :linewidth,
|
||||
:width => :linewidth,
|
||||
:lw => :linewidth,
|
||||
:lo => :lineopacity,
|
||||
:type => :linetype,
|
||||
:lt => :linetype,
|
||||
:t => :linetype,
|
||||
:style => :linestyle,
|
||||
:s => :linestyle,
|
||||
:ls => :linestyle,
|
||||
:m => :marker,
|
||||
:mark => :marker,
|
||||
:shape => :markershape,
|
||||
:mc => :markercolor,
|
||||
:mcolor => :markercolor,
|
||||
:ms => :markersize,
|
||||
:msize => :markersize,
|
||||
:mo => :markeropacity,
|
||||
:opacity => :markeropacity,
|
||||
:alpha => :markeropacity,
|
||||
:f => :fill,
|
||||
:area => :fill,
|
||||
:fillrng => :fillrange,
|
||||
:fc => :fillcolor,
|
||||
:fcolor => :fillcolor,
|
||||
:fo => :fillopacity,
|
||||
:g => :group,
|
||||
:nb => :nbins,
|
||||
:nbin => :nbins,
|
||||
:rib => :ribbon,
|
||||
:ann => :annotation,
|
||||
:anns => :annotation,
|
||||
:annotate => :annotation,
|
||||
:annotations => :annotation,
|
||||
:xlab => :xlabel,
|
||||
:ylab => :ylabel,
|
||||
:yrlab => :yrightlabel,
|
||||
:ylabr => :yrightlabel,
|
||||
:y2lab => :yrightlabel,
|
||||
:ylab2 => :yrightlabel,
|
||||
:ylabelright => :yrightlabel,
|
||||
:ylabel2 => :yrightlabel,
|
||||
:y2label => :yrightlabel,
|
||||
:leg => :legend,
|
||||
:bg => :background_color,
|
||||
:bgcolor => :background_color,
|
||||
:bg_color => :background_color,
|
||||
:background => :background_color,
|
||||
:fg => :foreground_color,
|
||||
:fgcolor => :foreground_color,
|
||||
:fg_color => :foreground_color,
|
||||
:foreground => :foreground_color,
|
||||
:regression => :smooth,
|
||||
:reg => :smooth,
|
||||
:xlim => :xlims,
|
||||
:xlimit => :xlims,
|
||||
:xlimits => :xlims,
|
||||
:ylim => :ylims,
|
||||
:ylimit => :ylims,
|
||||
:ylimits => :ylims,
|
||||
:xtick => :xticks,
|
||||
:ytick => :yticks,
|
||||
:windowsize => :size,
|
||||
:wsize => :size,
|
||||
:wtitle => :windowtitle,
|
||||
:gui => :show,
|
||||
:display => :show,
|
||||
:palette => :color_palette,
|
||||
:xlink => :linkx,
|
||||
:ylink => :linky,
|
||||
:c => :linecolor,
|
||||
:color => :linecolor,
|
||||
:colour => :linecolor,
|
||||
:lab => :label,
|
||||
:l => :line,
|
||||
:w => :linewidth,
|
||||
:width => :linewidth,
|
||||
:lw => :linewidth,
|
||||
:la => :linealpha,
|
||||
:lineopacity => :linealpha,
|
||||
:type => :linetype,
|
||||
:lt => :linetype,
|
||||
:t => :linetype,
|
||||
:seriestype => :linetype,
|
||||
:style => :linestyle,
|
||||
:s => :linestyle,
|
||||
:ls => :linestyle,
|
||||
:m => :marker,
|
||||
:mark => :marker,
|
||||
:shape => :markershape,
|
||||
:mc => :markercolor,
|
||||
:mcolor => :markercolor,
|
||||
:markercolour => :markercolor,
|
||||
:ms => :markersize,
|
||||
:msize => :markersize,
|
||||
:ma => :markeralpha,
|
||||
:alpha => :markeralpha,
|
||||
:opacity => :markeralpha,
|
||||
:markeropacity => :markeralpha,
|
||||
:f => :fill,
|
||||
:area => :fill,
|
||||
:fillrng => :fillrange,
|
||||
:fc => :fillcolor,
|
||||
:fcolor => :fillcolor,
|
||||
:fillcolour => :fillcolor,
|
||||
:fa => :fillalpha,
|
||||
:fillopacity => :fillalpha,
|
||||
:g => :group,
|
||||
:nb => :nbins,
|
||||
:nbin => :nbins,
|
||||
:rib => :ribbon,
|
||||
:ann => :annotation,
|
||||
:anns => :annotation,
|
||||
:annotate => :annotation,
|
||||
:annotations => :annotation,
|
||||
:xlab => :xlabel,
|
||||
:ylab => :ylabel,
|
||||
:yrlab => :yrightlabel,
|
||||
:ylabr => :yrightlabel,
|
||||
:y2lab => :yrightlabel,
|
||||
:ylab2 => :yrightlabel,
|
||||
:ylabelright => :yrightlabel,
|
||||
:ylabel2 => :yrightlabel,
|
||||
:y2label => :yrightlabel,
|
||||
:leg => :legend,
|
||||
:key => :legend,
|
||||
:cbar => :colorbar,
|
||||
:cb => :colorbar,
|
||||
:bg => :background_color,
|
||||
:bgcolor => :background_color,
|
||||
:bg_color => :background_color,
|
||||
:background => :background_color,
|
||||
:background_colour => :background_color,
|
||||
:fg => :foreground_color,
|
||||
:fgcolor => :foreground_color,
|
||||
:fg_color => :foreground_color,
|
||||
:foreground => :foreground_color,
|
||||
:foreground_colour => :foreground_color,
|
||||
:regression => :smooth,
|
||||
:reg => :smooth,
|
||||
:nlevels => :levels,
|
||||
:nlev => :levels,
|
||||
:levs => :levels,
|
||||
:xlim => :xlims,
|
||||
:xlimit => :xlims,
|
||||
:xlimits => :xlims,
|
||||
:ylim => :ylims,
|
||||
:ylimit => :ylims,
|
||||
:ylimits => :ylims,
|
||||
:xtick => :xticks,
|
||||
:ytick => :yticks,
|
||||
:windowsize => :size,
|
||||
:wsize => :size,
|
||||
:wtitle => :windowtitle,
|
||||
:gui => :show,
|
||||
:display => :show,
|
||||
:palette => :color_palette,
|
||||
:xlink => :linkx,
|
||||
:ylink => :linky,
|
||||
:nrow => :nr,
|
||||
:nrows => :nr,
|
||||
:ncol => :nc,
|
||||
:ncols => :nc,
|
||||
:clf => :overwrite_figure,
|
||||
:clearfig => :overwrite_figure,
|
||||
:overwrite => :overwrite_figure,
|
||||
:reuse => :overwrite_figure,
|
||||
)
|
||||
|
||||
# add all pluralized forms to the _keyAliases dict
|
||||
@@ -337,12 +365,6 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
wraptuple(x::@compat(Tuple)) = x
|
||||
wraptuple(x) = (x,)
|
||||
|
||||
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
|
||||
trueOrAllTrue(f::Function, x) = f(x)
|
||||
|
||||
function handleColors!(d::Dict, arg, csym::Symbol)
|
||||
try
|
||||
if arg == :auto
|
||||
@@ -394,23 +416,38 @@ end
|
||||
function processLineArg(d::Dict, arg)
|
||||
|
||||
# linetype
|
||||
if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
# if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
if allLineTypes(arg)
|
||||
d[:linetype] = arg
|
||||
|
||||
|
||||
# linestyle
|
||||
elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
# elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
elseif allStyles(arg)
|
||||
d[:linestyle] = arg
|
||||
|
||||
elseif typeof(arg) <: Stroke
|
||||
arg.width == nothing || (d[:linewidth] = arg.width)
|
||||
arg.color == nothing || (d[:linecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:linealpha] = arg.alpha)
|
||||
arg.style == nothing || (d[:linestyle] = arg.style)
|
||||
|
||||
elseif typeof(arg) <: Brush
|
||||
arg.size == nothing || (d[:fillrange] = arg.size)
|
||||
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
|
||||
|
||||
# linealpha
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
|
||||
elseif allAlphas(arg)
|
||||
d[:linealpha] = arg
|
||||
|
||||
# linewidth
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
elseif allReals(arg)
|
||||
d[:linewidth] = arg
|
||||
|
||||
# lineopacity
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Real && a >= 0 && a <= 1, arg)
|
||||
d[:lineopacity] = arg
|
||||
|
||||
# color
|
||||
elseif !handleColors!(d, arg, :color)
|
||||
elseif !handleColors!(d, arg, :linecolor)
|
||||
warn("Skipped line arg $arg.")
|
||||
|
||||
end
|
||||
@@ -420,37 +457,79 @@ end
|
||||
function processMarkerArg(d::Dict, arg)
|
||||
|
||||
# markershape
|
||||
if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
|
||||
d[:markershape] = arg
|
||||
elseif trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
# if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
|
||||
# d[:markershape] = arg
|
||||
|
||||
# elseif trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
if allShapes(arg)
|
||||
d[:markershape] = arg
|
||||
|
||||
# stroke style
|
||||
# elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
elseif allStyles(arg)
|
||||
d[:markerstrokestyle] = arg
|
||||
|
||||
elseif typeof(arg) <: Stroke
|
||||
arg.width == nothing || (d[:markerstrokewidth] = arg.width)
|
||||
arg.color == nothing || (d[:markerstrokecolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:markerstrokealpha] = arg.alpha)
|
||||
arg.style == nothing || (d[:markerstrokestyle] = arg.style)
|
||||
|
||||
elseif typeof(arg) <: Brush
|
||||
arg.size == nothing || (d[:markersize] = arg.size)
|
||||
arg.color == nothing || (d[:markercolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:markeralpha] = arg.alpha)
|
||||
|
||||
# linealpha
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
|
||||
elseif allAlphas(arg)
|
||||
d[:markeralpha] = arg
|
||||
|
||||
# markersize
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
elseif allReals(arg)
|
||||
d[:markersize] = arg
|
||||
|
||||
# lineopacity
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Real && a >= 0 && a <= 1, arg)
|
||||
d[:markeropacity] = arg
|
||||
|
||||
# markercolor
|
||||
elseif !handleColors!(d, arg, :markercolor)
|
||||
warn("Skipped marker arg $arg.")
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function processFillArg(d::Dict, arg)
|
||||
if !handleColors!(d, arg, :fillcolor)
|
||||
|
||||
if typeof(arg) <: Brush
|
||||
arg.size == nothing || (d[:fillrange] = arg.size)
|
||||
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
|
||||
|
||||
# fillrange function
|
||||
# elseif trueOrAllTrue(a -> isa(a, Function), arg)
|
||||
elseif allFunctions(arg)
|
||||
d[:fillrange] = arg
|
||||
|
||||
# fillalpha
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
|
||||
elseif allAlphas(arg)
|
||||
d[:fillalpha] = arg
|
||||
|
||||
elseif !handleColors!(d, arg, :fillcolor)
|
||||
|
||||
d[:fillrange] = arg
|
||||
end
|
||||
end
|
||||
|
||||
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
|
||||
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
|
||||
_replace_markershape(shape) = shape
|
||||
|
||||
|
||||
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
|
||||
function preprocessArgs!(d::Dict)
|
||||
replaceAliases!(d, _keyAliases)
|
||||
|
||||
|
||||
# handle axis args
|
||||
for axisletter in ("x", "y")
|
||||
asym = symbol(axisletter * "axis")
|
||||
@@ -458,6 +537,12 @@ function preprocessArgs!(d::Dict)
|
||||
processAxisArg(d, axisletter, arg)
|
||||
end
|
||||
delete!(d, asym)
|
||||
|
||||
# turn :labels into :ticks_and_labels
|
||||
tsym = symbol(axisletter * "ticks")
|
||||
if haskey(d, tsym) && ticksType(d[tsym]) == :labels
|
||||
d[tsym] = (1:length(d[tsym]), d[tsym])
|
||||
end
|
||||
end
|
||||
|
||||
# handle line args
|
||||
@@ -473,7 +558,12 @@ function preprocessArgs!(d::Dict)
|
||||
anymarker = true
|
||||
end
|
||||
delete!(d, :marker)
|
||||
if anymarker && !haskey(d, :markershape)
|
||||
# if anymarker && !haskey(d, :markershape)
|
||||
# d[:markershape] = :ellipse
|
||||
# end
|
||||
if haskey(d, :markershape)
|
||||
d[:markershape] = _replace_markershape(d[:markershape])
|
||||
elseif anymarker
|
||||
d[:markershape] = :ellipse
|
||||
end
|
||||
|
||||
@@ -483,6 +573,16 @@ function preprocessArgs!(d::Dict)
|
||||
end
|
||||
delete!(d, :fill)
|
||||
|
||||
# convert into strokes and brushes
|
||||
|
||||
# legends
|
||||
if haskey(d, :legend)
|
||||
d[:legend] = convertLegendValue(d[:legend])
|
||||
end
|
||||
if haskey(d, :colorbar)
|
||||
d[:colorbar] = convertLegendValue(d[:colorbar])
|
||||
end
|
||||
|
||||
# handle subplot links
|
||||
if haskey(d, :link)
|
||||
l = d[:link]
|
||||
@@ -543,9 +643,12 @@ function warnOnUnsupportedArgs(pkg::PlottingPackage, d::Dict)
|
||||
end
|
||||
end
|
||||
|
||||
_markershape_supported(pkg::PlottingPackage, shape::Symbol) = shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::PlottingPackage, shape::Shape) = Shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::PlottingPackage, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
|
||||
function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
|
||||
(d[:axis] in supportedAxes(pkg)
|
||||
(d[:axis] in supportedAxes(pkg)
|
||||
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
|
||||
(d[:linetype] == :none
|
||||
|| d[:linetype] in supportedTypes(pkg)
|
||||
@@ -553,8 +656,9 @@ function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
|
||||
(d[:linestyle] in supportedStyles(pkg)
|
||||
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
|
||||
(d[:markershape] == :none
|
||||
|| d[:markershape] in supportedMarkers(pkg)
|
||||
|| (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
|
||||
|| _markershape_supported(pkg, d[:markershape])
|
||||
# || d[:markershape] in supportedMarkers(pkg)
|
||||
# || (Shape in supportedMarkers(pkg) && typeof(d[:markershape]) <: Shape)
|
||||
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
|
||||
end
|
||||
|
||||
@@ -590,6 +694,19 @@ function setDictValue(d_in::Dict, d_out::Dict, k::Symbol, idx::Int, defaults::Di
|
||||
end
|
||||
end
|
||||
|
||||
function convertLegendValue(val::Symbol)
|
||||
if val in (:both, :all, :yes)
|
||||
:best
|
||||
elseif val in (:no, :none)
|
||||
:none
|
||||
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend)
|
||||
val
|
||||
else
|
||||
error("Invalid symbol for legend: $val")
|
||||
end
|
||||
end
|
||||
convertLegendValue(val::Bool) = val ? :best : :none
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# build the argument dictionary for the plot
|
||||
@@ -610,6 +727,13 @@ function getPlotArgs(pkg::PlottingPackage, kw, idx::Int; set_defaults = true)
|
||||
end
|
||||
end
|
||||
|
||||
# handle legend/colorbar
|
||||
d[:legend] = convertLegendValue(d[:legend])
|
||||
d[:colorbar] = convertLegendValue(d[:colorbar])
|
||||
if d[:colorbar] == :legend
|
||||
d[:colorbar] = d[:legend]
|
||||
end
|
||||
|
||||
# convert color
|
||||
handlePlotColors(pkg, d)
|
||||
|
||||
@@ -623,7 +747,7 @@ end
|
||||
|
||||
|
||||
# build the argument dictionary for a series
|
||||
function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in initargs, not plt
|
||||
function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt
|
||||
kwdict = Dict(kw)
|
||||
d = Dict()
|
||||
|
||||
@@ -638,7 +762,7 @@ function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::I
|
||||
d[k] = kwdict[k]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if haskey(_typeAliases, d[:linetype])
|
||||
d[:linetype] = _typeAliases[d[:linetype]]
|
||||
end
|
||||
@@ -648,17 +772,22 @@ function getSeriesArgs(pkg::PlottingPackage, initargs::Dict, kw, commandIndex::I
|
||||
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
|
||||
|
||||
# update color
|
||||
d[:color] = getSeriesRGBColor(d[:color], initargs, plotIndex)
|
||||
d[:linecolor] = getSeriesRGBColor(d[:linecolor], plotargs, plotIndex)
|
||||
|
||||
# update markercolor
|
||||
mc = d[:markercolor]
|
||||
mc = (mc == :match ? d[:color] : getSeriesRGBColor(mc, initargs, plotIndex))
|
||||
d[:markercolor] = mc
|
||||
c = d[:markercolor]
|
||||
c = (c == :match ? d[:linecolor] : getSeriesRGBColor(c, plotargs, plotIndex))
|
||||
d[:markercolor] = c
|
||||
|
||||
# update markerstrokecolor
|
||||
c = d[:markerstrokecolor]
|
||||
c = (c == :match ? plotargs[:foreground_color] : getSeriesRGBColor(c, plotargs, plotIndex))
|
||||
d[:markerstrokecolor] = c
|
||||
|
||||
# update fillcolor
|
||||
mc = d[:fillcolor]
|
||||
mc = (mc == :match ? d[:color] : getSeriesRGBColor(mc, initargs, plotIndex))
|
||||
d[:fillcolor] = mc
|
||||
c = d[:fillcolor]
|
||||
c = (c == :match ? d[:linecolor] : getSeriesRGBColor(c, plotargs, plotIndex))
|
||||
d[:fillcolor] = c
|
||||
|
||||
# set label
|
||||
label = d[:label]
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
function _initialize_backend(::BokehPackage; kw...)
|
||||
@eval begin
|
||||
warn("Bokeh is no longer supported... many features will likely be broken.")
|
||||
import Bokeh
|
||||
export Bokeh
|
||||
end
|
||||
end
|
||||
|
||||
# make255(x) = round(Int, 255 * x)
|
||||
|
||||
# function bokehcolor(c::Colorant)
|
||||
# @sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
|
||||
# end
|
||||
# bokehcolor(cs::ColorScheme) = bokehcolor(getColor(cs))
|
||||
|
||||
|
||||
const _glyphtypes = Dict(
|
||||
:ellipse => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
:dtriangle => :InvertedTriangle,
|
||||
# :pentagon =>
|
||||
# :hexagon =>
|
||||
# :heptagon =>
|
||||
# :octagon =>
|
||||
:cross => :Cross,
|
||||
:xcross => :X,
|
||||
:star5 => :Asterisk,
|
||||
)
|
||||
|
||||
|
||||
function bokeh_glyph_type(d::Dict)
|
||||
lt = d[:linetype]
|
||||
mt = d[:markershape]
|
||||
if lt == :scatter && mt == :none
|
||||
mt = :ellipse
|
||||
end
|
||||
|
||||
# if we have a marker, use that
|
||||
if lt == :scatter || mt != :none
|
||||
return _glyphtypes[mt]
|
||||
end
|
||||
|
||||
# otherwise return a line
|
||||
return :Line
|
||||
end
|
||||
|
||||
function get_stroke_vector(linestyle::Symbol)
|
||||
dash = 12
|
||||
dot = 3
|
||||
gap = 2
|
||||
linestyle == :solid && return Int[]
|
||||
linestyle == :dash && return Int[dash, gap]
|
||||
linestyle == :dot && return Int[dot, gap]
|
||||
linestyle == :dashdot && return Int[dash, gap, dot, gap]
|
||||
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
|
||||
error("unsupported linestyle: ", linestyle)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::BokehPackage; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
# dumpdict(d, "plot", true)
|
||||
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
|
||||
datacolumns = Bokeh.BokehDataSet[]
|
||||
tools = Bokeh.tools()
|
||||
filename = tempname() * ".html"
|
||||
title = d[:title]
|
||||
w, h = d[:size]
|
||||
xaxis_type = d[:xscale] == :log10 ? :log : :auto
|
||||
yaxis_type = d[:yscale] == :log10 ? :log : :auto
|
||||
# legend = d[:legend] ? xxxx : nothing
|
||||
legend = nothing
|
||||
extra_args = Dict() # TODO: we'll put extra settings (xlim, etc) here
|
||||
bplt = Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
|
||||
|
||||
Plot(bplt, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::BokehPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
# dumpdict(d, "plot!", true)
|
||||
|
||||
bdata = Dict{Symbol, Vector}(:x => collect(d[:x]), :y => collect(d[:y]))
|
||||
|
||||
glyph = Bokeh.Bokehjs.Glyph(
|
||||
glyphtype = bokeh_glyph_type(d),
|
||||
linecolor = webcolor(d[:linecolor]), # shape's stroke or line color
|
||||
linewidth = d[:linewidth], # shape's stroke width or line width
|
||||
fillcolor = webcolor(d[:markercolor]),
|
||||
size = ceil(Int, d[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
||||
dash = get_stroke_vector(d[:linestyle])
|
||||
)
|
||||
|
||||
legend = nothing # TODO
|
||||
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
|
||||
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{BokehPackage}, d::Dict)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{BokehPackage}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{BokehPackage}, i::Int)
|
||||
series = plt.o.datacolumns[i].data
|
||||
series[:x], series[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{BokehPackage}, xy::Tuple, i::Integer)
|
||||
series = plt.o.datacolumns[i].data
|
||||
series[:x], series[:y] = xy
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{BokehPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{BokehPackage}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
|
||||
end
|
||||
|
||||
|
||||
function _expand_limits(lims, plt::Plot{BokehPackage}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{BokehPackage}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{BokehPackage})
|
||||
# TODO: write a png to io
|
||||
warn("mime png not implemented")
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{BokehPackage})
|
||||
Bokeh.showplot(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{BokehPackage})
|
||||
# TODO: display/show the subplot
|
||||
end
|
||||
@@ -1,14 +1,27 @@
|
||||
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
function _initialize_backend(::GadflyPackage; kw...)
|
||||
@eval begin
|
||||
import Gadfly, Compose
|
||||
export Gadfly, Compose
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# immutable MissingVec <: AbstractVector{Float64} end
|
||||
# Base.size(v::MissingVec) = (1,)
|
||||
# Base.getindex(v::MissingVec, i::Integer) = 0.0
|
||||
|
||||
function createGadflyPlotObject(d::Dict)
|
||||
gplt = Gadfly.Plot()
|
||||
gplt.mapping = Dict()
|
||||
gplt.data_source = DataFrames.DataFrame()
|
||||
gplt.layers = gplt.layers[1:0]
|
||||
gplt.data_source = Gadfly.DataFrames.DataFrame()
|
||||
# gplt.layers = gplt.layers[1:0]
|
||||
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
|
||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]),
|
||||
Gadfly.Guide.ylabel(d[:ylabel]),
|
||||
Gadfly.Guide.title(d[:title])]
|
||||
@@ -36,42 +49,61 @@ function getLineGeom(d::Dict)
|
||||
elseif lt == :steppre
|
||||
Gadfly.Geom.step(direction = :vh)
|
||||
elseif lt == :hline
|
||||
Gadfly.Geom.hline(color = getColor(d[:color]), size = d[:linewidth] * Gadfly.px)
|
||||
Gadfly.Geom.hline
|
||||
elseif lt == :vline
|
||||
Gadfly.Geom.vline(color = getColor(d[:color]), size = d[:linewidth] * Gadfly.px)
|
||||
Gadfly.Geom.vline
|
||||
elseif lt == :contour
|
||||
Gadfly.Geom.contour(levels = d[:nlevels])
|
||||
Gadfly.Geom.contour(levels = d[:levels])
|
||||
else
|
||||
nothing
|
||||
end
|
||||
end
|
||||
|
||||
function get_extra_theme_args(d::Dict, k::Symbol)
|
||||
# gracefully handles old Gadfly versions
|
||||
extra_theme_args = Dict()
|
||||
try
|
||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k])
|
||||
catch err
|
||||
if string(err) == "UndefVarError(:get_stroke_vector)"
|
||||
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
|
||||
else
|
||||
rethrow()
|
||||
end
|
||||
end
|
||||
extra_theme_args
|
||||
end
|
||||
|
||||
function getGadflyLineTheme(d::Dict)
|
||||
|
||||
lc = getColor(d[:color])
|
||||
α = d[:lineopacity]
|
||||
if α != nothing
|
||||
lc = RGBA(lc, α)
|
||||
end
|
||||
lc = convertColor(getColor(d[:linecolor]), d[:linealpha])
|
||||
# lc = getColor(d[:linecolor])
|
||||
# α = d[:linealpha]
|
||||
# if α != nothing
|
||||
# lc = RGBA(lc, α)
|
||||
# end
|
||||
|
||||
fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha])
|
||||
# fc = getColor(d[:fillcolor])
|
||||
# α = d[:fillalpha]
|
||||
# if α != nothing
|
||||
# fc = RGBA(fc, α)
|
||||
# end
|
||||
|
||||
fc = getColor(d[:fillcolor])
|
||||
α = d[:fillopacity]
|
||||
if α != nothing
|
||||
fc = RGBA(fc, α)
|
||||
end
|
||||
|
||||
Gadfly.Theme(;
|
||||
default_color = lc,
|
||||
line_width = (d[:linetype] == :sticks ? 1 : d[:linewidth]) * Gadfly.px,
|
||||
line_style = Gadfly.get_stroke_vector(d[:linestyle]),
|
||||
# line_style = Gadfly.get_stroke_vector(d[:linestyle]),
|
||||
lowlight_color = x->RGB(fc), # fill/ribbon
|
||||
lowlight_opacity = alpha(fc), # fill/ribbon
|
||||
bar_highlight = RGB(lc), # bars
|
||||
get_extra_theme_args(d, :linestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
# add a line as a new layer
|
||||
function addGadflyLine!(plt::Plot, d::Dict, geoms...)
|
||||
function addGadflyLine!(plt::Plot, numlayers::Int, d::Dict, geoms...)
|
||||
gplt = getGadflyContext(plt)
|
||||
gfargs = vcat(geoms...,
|
||||
getGadflyLineTheme(d))
|
||||
@@ -87,68 +119,118 @@ function addGadflyLine!(plt::Plot, d::Dict, geoms...)
|
||||
push!(gfargs, Gadfly.Geom.ribbon)
|
||||
end
|
||||
|
||||
# h/vlines
|
||||
if lt == :hline
|
||||
kwargs[:yintercept] = d[:y]
|
||||
elseif lt == :vline
|
||||
kwargs[:xintercept] = d[:y]
|
||||
elseif lt == :sticks
|
||||
w = 0.01 * mean(diff(d[:x]))
|
||||
kwargs[:xmin] = d[:x] - w
|
||||
kwargs[:xmax] = d[:x] + w
|
||||
elseif lt == :contour
|
||||
d[:y] = reverse(d[:y])
|
||||
kwargs[:z] = d[:surface]
|
||||
if lt in (:hline, :vline)
|
||||
kwargs[lt == :hline ? :yintercept : :xintercept] = d[:y]
|
||||
|
||||
else
|
||||
if lt == :sticks
|
||||
w = 0.01 * mean(diff(d[:x]))
|
||||
kwargs[:xmin] = d[:x] - w
|
||||
kwargs[:xmax] = d[:x] + w
|
||||
elseif lt == :contour
|
||||
# d[:y] = reverse(d[:y])
|
||||
kwargs[:z] = d[:z].surf
|
||||
addGadflyContColorScale(plt, d[:linecolor])
|
||||
end
|
||||
|
||||
kwargs[:x] = d[lt == :hist ? :y : :x]
|
||||
kwargs[:y] = d[:y]
|
||||
|
||||
end
|
||||
|
||||
# # h/vlines
|
||||
# if lt == :hline
|
||||
# kwargs[:yintercept] = d[:y]
|
||||
# elseif lt == :vline
|
||||
# kwargs[:xintercept] = d[:y]
|
||||
# elseif lt == :sticks
|
||||
# w = 0.01 * mean(diff(d[:x]))
|
||||
# kwargs[:xmin] = d[:x] - w
|
||||
# kwargs[:xmax] = d[:x] + w
|
||||
# elseif lt == :contour
|
||||
# d[:y] = reverse(d[:y])
|
||||
# kwargs[:z] = d[:surface]
|
||||
# end
|
||||
|
||||
# if lt == :hist
|
||||
# kwargs[:x] = kwargs[:y] = d[:y]
|
||||
# elseif lt != :hline && lt != :vline
|
||||
# kwargs[:x] = d[:x]
|
||||
# kwargs[:y] = d[:y]
|
||||
# end
|
||||
|
||||
# add the layer
|
||||
x = d[d[:linetype] == :hist ? :y : :x]
|
||||
Gadfly.layer(gfargs...; x = x, y = d[:y], kwargs...)
|
||||
# # add the layer
|
||||
# x = d[d[:linetype] == :hist ? :y : :x]
|
||||
# Gadfly.layer(gfargs...; x = x, y = d[:y], order=numlayers, kwargs...)
|
||||
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# extract the underlying ShapeGeometry object(s)
|
||||
getMarkerGeom(shape::Shape) = gadflyshape(shape)
|
||||
getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
|
||||
getMarkerGeom(shapes::AVec) = map(getMarkerGeom, shapes)
|
||||
getMarkerGeom(d::Dict) = getMarkerGeom(d[:markershape])
|
||||
|
||||
function getMarkerGeom(d::Dict)
|
||||
shape = d[:markershape]
|
||||
gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
|
||||
end
|
||||
# function getMarkerGeom(d::Dict)
|
||||
# shape = d[:markershape]
|
||||
# gadflyshape(isa(shape, Shape) ? shape : _shapes[shape])
|
||||
# end
|
||||
|
||||
|
||||
function getGadflyMarkerTheme(d::Dict, initargs::Dict)
|
||||
function getGadflyMarkerTheme(d::Dict, plotargs::Dict)
|
||||
c = getColor(d[:markercolor])
|
||||
α = d[:markeropacity]
|
||||
α = d[:markeralpha]
|
||||
if α != nothing
|
||||
c = RGBA(RGB(c), α)
|
||||
end
|
||||
|
||||
fg = getColor(initargs[:foreground_color])
|
||||
Gadfly.Theme(
|
||||
ms = d[:markersize]
|
||||
ms = if typeof(ms) <: AVec
|
||||
warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
||||
mean(ms) * Gadfly.px
|
||||
else
|
||||
ms * Gadfly.px
|
||||
end
|
||||
|
||||
# fg = getColor(plotargs[:foreground_color])
|
||||
Gadfly.Theme(;
|
||||
default_color = c,
|
||||
default_point_size = d[:markersize] * Gadfly.px,
|
||||
discrete_highlight_color = c -> RGB(fg),
|
||||
highlight_width = d[:linewidth] * Gadfly.px,
|
||||
default_point_size = ms,
|
||||
discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])),
|
||||
highlight_width = d[:markerstrokewidth] * Gadfly.px,
|
||||
# get_extra_theme_args(d, :markerstrokestyle)...
|
||||
)
|
||||
end
|
||||
|
||||
function addGadflyMarker!(plt::Plot, d::Dict, initargs::Dict, geoms...)
|
||||
function addGadflyContColorScale(plt::Plot{GadflyPackage}, c)
|
||||
plt.plotargs[:colorbar] == :none && return
|
||||
if !isa(c, ColorGradient)
|
||||
c = colorscheme(:bluesreds)
|
||||
end
|
||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
|
||||
end
|
||||
|
||||
function addGadflyMarker!(plt::Plot, numlayers::Int, d::Dict, plotargs::Dict, geoms...)
|
||||
gfargs = vcat(geoms...,
|
||||
getGadflyMarkerTheme(d, initargs),
|
||||
getGadflyMarkerTheme(d, plotargs),
|
||||
getMarkerGeom(d))
|
||||
kwargs = Dict()
|
||||
|
||||
# handle continuous color scales for the markers
|
||||
z = d[:z]
|
||||
if z != nothing && typeof(z) <: AVec
|
||||
kwargs[:color] = z
|
||||
if !isa(d[:markercolor], ColorGradient)
|
||||
d[:markercolor] = colorscheme(:bluesreds)
|
||||
end
|
||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:markercolor], p))))
|
||||
zcolor = d[:zcolor]
|
||||
if zcolor != nothing && typeof(zcolor) <: AVec
|
||||
kwargs[:color] = zcolor
|
||||
addGadflyContColorScale(plt, d[:markercolor])
|
||||
# if !isa(d[:markercolor], ColorGradient)
|
||||
# d[:markercolor] = colorscheme(:bluesreds)
|
||||
# end
|
||||
# push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:markercolor], p))))
|
||||
end
|
||||
|
||||
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], kwargs...)
|
||||
Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...)
|
||||
end
|
||||
|
||||
|
||||
@@ -157,7 +239,7 @@ end
|
||||
function addToGadflyLegend(plt::Plot, d::Dict)
|
||||
|
||||
# add the legend?
|
||||
if plt.initargs[:legend]
|
||||
if plt.plotargs[:legend] != :none && d[:label] != ""
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add the legend if needed
|
||||
@@ -172,7 +254,7 @@ function addToGadflyLegend(plt::Plot, d::Dict)
|
||||
# since gadfly will call unique(colors), but doesn't also merge the rows that match
|
||||
# Should ensure from this side that colors which are the same are merged together
|
||||
|
||||
c = getColor(d[d[:markershape] == :none ? :color : :markercolor])
|
||||
c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor])
|
||||
foundit = false
|
||||
|
||||
# extend the label if we found this color
|
||||
@@ -202,6 +284,7 @@ getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=
|
||||
function addGadflySeries!(plt::Plot, d::Dict)
|
||||
|
||||
layers = Gadfly.Layer[]
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add a regression line?
|
||||
# TODO: make more flexible
|
||||
@@ -210,7 +293,7 @@ function addGadflySeries!(plt::Plot, d::Dict)
|
||||
# lines
|
||||
geom = getLineGeom(d)
|
||||
if geom != nothing
|
||||
prepend!(layers, addGadflyLine!(plt, d, geom, smooth...))
|
||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...))
|
||||
|
||||
# don't add a regression for markers too
|
||||
smooth = Any[]
|
||||
@@ -220,20 +303,22 @@ function addGadflySeries!(plt::Plot, d::Dict)
|
||||
lt = d[:linetype]
|
||||
if lt == :ohlc
|
||||
error("Haven't re-implemented after refactoring")
|
||||
elseif lt in (:heatmap, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:linecolor], p))))
|
||||
elseif lt == :scatter && d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
end
|
||||
|
||||
# markers
|
||||
if d[:markershape] != :none
|
||||
prepend!(layers, addGadflyMarker!(plt, d, plt.initargs, smooth...))
|
||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...))
|
||||
end
|
||||
|
||||
lt in (:hist, :heatmap, :hexbin, :contour) || addToGadflyLegend(plt, d)
|
||||
lt in (:heatmap, :hexbin, :contour) || addToGadflyLegend(plt, d)
|
||||
|
||||
# now save the layers that apply to this series
|
||||
d[:gadflylayers] = layers
|
||||
prepend!(getGadflyContext(plt).layers, layers)
|
||||
prepend!(gplt.layers, layers)
|
||||
end
|
||||
|
||||
|
||||
@@ -245,7 +330,7 @@ end
|
||||
# z = d[:z]
|
||||
|
||||
# # handle line segments of different colors
|
||||
# cscheme = d[:color]
|
||||
# cscheme = d[:linecolor]
|
||||
# if isa(cscheme, ColorVector)
|
||||
# # create a color scale, and set the color group to the index of the color
|
||||
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
|
||||
@@ -257,7 +342,7 @@ end
|
||||
# cs = collect(repmat(csindices', 2, 1))[1:end-1]
|
||||
# grp = collect(repmat((1:length(d[:y]))', 2, 1))[1:end-1]
|
||||
# d[:x], d[:y] = map(createSegments, (d[:x], d[:y]))
|
||||
# colorgroup = [(:color, cs), (:group, grp)]
|
||||
# colorgroup = [(:linecolor, cs), (:group, grp)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -289,7 +374,7 @@ function addGadflyTicksGuide(gplt, ticks, isx::Bool)
|
||||
gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
|
||||
labelmap = Dict(zip(ticks...))
|
||||
labelfunc = val -> labelmap[val]
|
||||
push!(gplt.scales, gfunc(levels = ticks[1], labels = labelfunc))
|
||||
push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
|
||||
|
||||
else
|
||||
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
|
||||
@@ -305,7 +390,7 @@ function getGadflyScaleFunction(d::Dict, isx::Bool)
|
||||
hasScaleKey = haskey(d, scalekey)
|
||||
if hasScaleKey
|
||||
scale = d[scalekey]
|
||||
scale == :log && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey
|
||||
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey
|
||||
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey
|
||||
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey
|
||||
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey
|
||||
@@ -323,14 +408,19 @@ function addGadflyLimitsScale(gplt, d::Dict, isx::Bool)
|
||||
# do we want to add min/max limits for the axis?
|
||||
limsym = isx ? :xlims : :ylims
|
||||
limargs = Any[]
|
||||
lims = get(d, limsym, :auto)
|
||||
lims == :auto && return
|
||||
|
||||
if limsType(lims) == :limits
|
||||
push!(limargs, (:minvalue, min(lims...)))
|
||||
push!(limargs, (:maxvalue, max(lims...)))
|
||||
# map :auto to nothing, otherwise add to limargs
|
||||
lims = get(d, limsym, :auto)
|
||||
# lims == :auto && return
|
||||
if lims == :auto
|
||||
lims = nothing
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
if limsType(lims) == :limits
|
||||
push!(limargs, (:minvalue, min(lims...)))
|
||||
push!(limargs, (:maxvalue, max(lims...)))
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
end
|
||||
end
|
||||
|
||||
# replace any current scales with this one
|
||||
@@ -385,13 +475,13 @@ function updateGadflyGuides(plt::Plot, d::Dict)
|
||||
|
||||
ticks = get(d, :xticks, :auto)
|
||||
if ticks == :none
|
||||
handleLinkInner(plt, true)
|
||||
_remove_axis(plt, true)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, true)
|
||||
end
|
||||
ticks = get(d, :yticks, :auto)
|
||||
if ticks == :none
|
||||
handleLinkInner(plt, false)
|
||||
_remove_axis(plt, false)
|
||||
else
|
||||
addGadflyTicksGuide(gplt, ticks, false)
|
||||
end
|
||||
@@ -403,13 +493,17 @@ end
|
||||
function updateGadflyPlotTheme(plt::Plot, d::Dict)
|
||||
kwargs = Dict()
|
||||
|
||||
# # get the full initargs, overriding any new settings
|
||||
# # get the full plotargs, overriding any new settings
|
||||
# # TODO: should this be part of the main `plot` command in plot.jl???
|
||||
# d = merge!(plt.initargs, d)
|
||||
# d = merge!(plt.plotargs, d)
|
||||
|
||||
# hide the legend?
|
||||
if !get(d, :legend, true)
|
||||
kwargs[:key_position] = :none
|
||||
# # hide the legend?
|
||||
# if !get(d, :legend, true)
|
||||
# kwargs[:key_position] = :none
|
||||
# end
|
||||
leg = d[d[:legend] == :none ? :colorbar : :legend]
|
||||
if leg != :best
|
||||
kwargs[:key_position] = leg == :inside ? :right : leg
|
||||
end
|
||||
|
||||
if !get(d, :grid, true)
|
||||
@@ -463,7 +557,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
|
||||
))
|
||||
end
|
||||
|
||||
function addAnnotations{X,Y,V}(plt::Plot{GadflyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GadflyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
@@ -473,7 +567,7 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
function plot(pkg::GadflyPackage; kw...)
|
||||
function _create_plot(pkg::GadflyPackage; kw...)
|
||||
d = Dict(kw)
|
||||
gplt = createGadflyPlotObject(d)
|
||||
Plot(gplt, pkg, 0, d, Dict[])
|
||||
@@ -481,7 +575,14 @@ end
|
||||
|
||||
|
||||
# plot one data series
|
||||
function plot!(::GadflyPackage, plt::Plot; kw...)
|
||||
function _add_series(::GadflyPackage, plt::Plot; kw...)
|
||||
|
||||
# first clear out the temporary layer
|
||||
gplt = getGadflyContext(plt)
|
||||
if gplt.layers[1].geom.tag == :remove
|
||||
gplt.layers = gplt.layers[2:end]
|
||||
end
|
||||
|
||||
d = Dict(kw)
|
||||
addGadflySeries!(plt, d)
|
||||
push!(plt.seriesargs, d)
|
||||
@@ -490,7 +591,7 @@ end
|
||||
|
||||
|
||||
|
||||
function updatePlotItems(plt::Plot{GadflyPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{GadflyPackage}, d::Dict)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
@@ -522,22 +623,22 @@ end
|
||||
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
function buildSubplotObject!(subplt::Subplot{GadflyPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{GadflyPackage}, isbefore::Bool)
|
||||
isbefore && return false # wait until after plotting to create the subplots
|
||||
subplt.o = nothing
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
function handleLinkInner(plt::Plot{GadflyPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{GadflyPackage}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function expandLimits!(lims, plt::Plot{GadflyPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{GadflyPackage}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
expandLimits!(lims, l.mapping[isx ? :x : :y])
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -569,12 +670,12 @@ function buildGadflySubplotContext(subplt::Subplot)
|
||||
end
|
||||
|
||||
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
|
||||
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.initargs[:size]...)
|
||||
setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getinitargs(subplt, 1)[:size]...)
|
||||
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.plotargs[:size]...)
|
||||
setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, 1)[:size]...)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
function dowritemime{P<:GadflyOrImmerse}(io::IO, func, plt::PlottingObject{P})
|
||||
function dowritemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, func, plt::PlottingObject{P})
|
||||
gplt = getGadflyContext(plt)
|
||||
setGadflyDisplaySize(plt)
|
||||
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
|
||||
@@ -585,10 +686,11 @@ getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
|
||||
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
|
||||
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
|
||||
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
|
||||
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
|
||||
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
|
||||
|
||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript")
|
||||
@eval function Base.writemime{P<:GadflyOrImmerse}(io::IO, ::$mime, plt::PlottingObject{P})
|
||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
|
||||
@eval function Base.writemime{P<:Union{GadflyPackage,ImmersePackage}}(io::IO, ::$mime, plt::PlottingObject{P})
|
||||
func = getGadflyWriteFunc($mime())
|
||||
dowritemime(io, func, plt)
|
||||
end
|
||||
@@ -597,14 +699,14 @@ end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GadflyPackage})
|
||||
setGadflyDisplaySize(plt.initargs[:size]...)
|
||||
setGadflyDisplaySize(plt.plotargs[:size]...)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{GadflyPackage})
|
||||
setGadflyDisplaySize(getinitargs(subplt,1)[:size]...)
|
||||
setGadflyDisplaySize(getplotargs(subplt,1)[:size]...)
|
||||
ctx = buildGadflySubplotContext(subplt)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
function _initialize_backend(::GLVisualizePackage; kw...)
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
immutable GLScreenWrapper
|
||||
window
|
||||
render
|
||||
end
|
||||
|
||||
function _create_plot(pkg::GLVisualizePackage; kw...)
|
||||
d = Dict(kw)
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
|
||||
# TODO: this should be moved to the display method?
|
||||
w,r=GLVisualize.glscreen()
|
||||
@async r()
|
||||
o = GLScreenWrapper(w,r)
|
||||
|
||||
Plot(o, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::GLVisualizePackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
# TODO: add one series to the underlying package
|
||||
push!(plt.seriesargs, d)
|
||||
|
||||
# TODO: this should be moved to the display method?
|
||||
x, y, z = map(Float32, d[:x]), map(Float32, d[:y]), map(Float32, d[:z].surf)
|
||||
viz = GLVisualize.visualize(x*ones(y)', ones(x)*y', z, :surface)
|
||||
GLVisualize.view(viz)
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GLVisualizePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{GLVisualizePackage})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{GLVisualizePackage}, d::Dict)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{GLVisualizePackage}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{GLVisualizePackage}, i::Int)
|
||||
# TODO:
|
||||
# series = plt.o.lines[i]
|
||||
# series.x, series.y
|
||||
nothing, nothing
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{GLVisualizePackage}, xy::Tuple, i::Integer)
|
||||
# TODO:
|
||||
# series = plt.o.lines[i]
|
||||
# series.x, series.y = xy
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{GLVisualizePackage})
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{GLVisualizePackage}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{GLVisualizePackage}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{GLVisualizePackage})
|
||||
# TODO: write a png to io
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GLVisualizePackage})
|
||||
# TODO: display/show the plot
|
||||
|
||||
# NOTE: I think maybe this should be empty? We can start with the assumption that creating
|
||||
# and adding to a plot will automatically open a window and draw to it, then the display
|
||||
# wouldn't actually need to do anything
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizePackage})
|
||||
# TODO: display/show the subplot
|
||||
end
|
||||
@@ -0,0 +1,790 @@
|
||||
|
||||
# https://github.com/jheinen/GR.jl
|
||||
|
||||
function _initialize_backend(::GRPackage; kw...)
|
||||
@eval begin
|
||||
import GR
|
||||
export GR
|
||||
end
|
||||
end
|
||||
|
||||
const gr_linetype = Dict(
|
||||
:auto => 1, :solid => 1, :dash => 2, :dot => 3, :dashdot => 4,
|
||||
:dashdotdot => -1 )
|
||||
|
||||
const gr_markertype = Dict(
|
||||
:auto => 1, :none => -1, :ellipse => -1, :rect => -7, :diamond => -13,
|
||||
:utriangle => -3, :dtriangle => -5, :pentagon => -21, :hexagon => -22,
|
||||
:heptagon => -23, :octagon => -24, :cross => 2, :xcross => 5,
|
||||
:star4 => -25, :star5 => -26, :star6 => -27, :star7 => -28, :star8 => -29,
|
||||
:vline => -30, :hline => -31 )
|
||||
|
||||
const gr_halign = Dict(:left => 1, :hcenter => 2, :right => 3)
|
||||
const gr_valign = Dict(:top => 1, :vcenter => 3, :bottom => 5)
|
||||
|
||||
const gr_font_family = Dict(
|
||||
"times" => 1, "helvetica" => 5, "courier" => 9, "bookman" => 14,
|
||||
"newcenturyschlbk" => 18, "avantgarde" => 22, "palatino" => 26)
|
||||
|
||||
function gr_getcolorind(v)
|
||||
c = getColor(v)
|
||||
return convert(Int, GR.inqcolorfromrgb(c.r, c.g, c.b))
|
||||
end
|
||||
|
||||
function gr_getaxisind(p)
|
||||
axis = get(p, :axis, :none)
|
||||
if axis in [:none, :left]
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end
|
||||
|
||||
function gr_setmarkershape(p)
|
||||
if haskey(p, :markershape)
|
||||
shape = p[:markershape]
|
||||
if isa(shape, Shape)
|
||||
p[:vertices] = shape.vertices
|
||||
else
|
||||
GR.setmarkertype(gr_markertype[shape])
|
||||
p[:vertices] = :none
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function gr_polymarker(p, x, y)
|
||||
if p[:vertices] != :none
|
||||
vertices= p[:vertices]
|
||||
dx = Float64[el[1] for el in vertices] * 0.01
|
||||
dy = Float64[el[2] for el in vertices] * 0.01
|
||||
GR.selntran(0)
|
||||
GR.setfillcolorind(gr_getcolorind(p[:markercolor]))
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
for i = 1:length(x)
|
||||
xn, yn = GR.wctondc(x[i], y[i])
|
||||
GR.fillarea(xn + dx, yn + dy)
|
||||
end
|
||||
GR.selntran(1)
|
||||
else
|
||||
GR.polymarker(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
function gr_polyline(x, y)
|
||||
if NaN in x || NaN in y
|
||||
i = 1
|
||||
j = 1
|
||||
n = length(x)
|
||||
while i < n
|
||||
while j < n && x[j] != Nan && y[j] != NaN
|
||||
j += 1
|
||||
end
|
||||
if i < j
|
||||
GR.polyline(x[i:j], y[i:j])
|
||||
end
|
||||
i = j + 1
|
||||
end
|
||||
else
|
||||
GR.polyline(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
subplot=[0, 1, 0, 1])
|
||||
d = plt.plotargs
|
||||
|
||||
clear && GR.clearws()
|
||||
|
||||
mwidth, mheight, width, height = GR.inqdspsize()
|
||||
w, h = d[:size]
|
||||
viewport = zeros(4)
|
||||
if w > h
|
||||
ratio = float(h) / w
|
||||
msize = mwidth * w / width
|
||||
GR.setwsviewport(0, msize, 0, msize * ratio)
|
||||
GR.setwswindow(0, 1, 0, ratio)
|
||||
viewport[1] = subplot[1] + 0.125 * (subplot[2] - subplot[1])
|
||||
viewport[2] = subplot[1] + 0.95 * (subplot[2] - subplot[1])
|
||||
viewport[3] = ratio * (subplot[3] + 0.125 * (subplot[4] - subplot[3]))
|
||||
viewport[4] = ratio * (subplot[3] + 0.95 * (subplot[4] - subplot[3]))
|
||||
else
|
||||
ratio = float(w) / h
|
||||
msize = mheight * h / height
|
||||
GR.setwsviewport(0, msize * ratio, 0, msize)
|
||||
GR.setwswindow(0, ratio, 0, 1)
|
||||
viewport[1] = ratio * (subplot[1] + 0.125 * (subplot[2] - subplot[1]))
|
||||
viewport[2] = ratio * (subplot[1] + 0.95 * (subplot[2] - subplot[1]))
|
||||
viewport[3] = subplot[3] + 0.125 * (subplot[4] - subplot[3])
|
||||
viewport[4] = subplot[3] + 0.95 * (subplot[4] - subplot[3])
|
||||
end
|
||||
|
||||
if haskey(d, :background_color)
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
GR.setfillcolorind(gr_getcolorind(d[:background_color]))
|
||||
if w > h
|
||||
GR.fillrect(subplot[1], subplot[2], ratio*subplot[3], ratio*subplot[4])
|
||||
else
|
||||
GR.fillrect(ratio*subplot[1], ratio*subplot[2], subplot[3], subplot[4])
|
||||
end
|
||||
GR.selntran(1)
|
||||
GR.restorestate()
|
||||
c = getColor(d[:background_color])
|
||||
if 0.21 * c.r + 0.72 * c.g + 0.07 * c.b < 0.9
|
||||
fg = convert(Int, GR.inqcolorfromrgb(1-c.r, 1-c.g, 1-c.b))
|
||||
else
|
||||
fg = 1
|
||||
end
|
||||
else
|
||||
fg = 1
|
||||
end
|
||||
|
||||
extrema = zeros(2, 4)
|
||||
num_axes = 1
|
||||
cmap = false
|
||||
axes_2d = true
|
||||
grid_flag = get(d, :grid, true)
|
||||
|
||||
for axis = 1:2
|
||||
xmin = ymin = typemax(Float64)
|
||||
xmax = ymax = typemin(Float64)
|
||||
for p in plt.seriesargs
|
||||
if axis == gr_getaxisind(p)
|
||||
if axis == 2
|
||||
num_axes = 2
|
||||
end
|
||||
if p[:linetype] == :bar
|
||||
x, y = 1:length(p[:y]), p[:y]
|
||||
elseif p[:linetype] == :ohlc
|
||||
x, y = 1:size(p[:y], 1), p[:y]
|
||||
elseif p[:linetype] in [:hist, :density]
|
||||
x, y = Base.hist(p[:y])
|
||||
elseif p[:linetype] in [:heatmap, :hexbin]
|
||||
E = zeros(length(p[:x]),2)
|
||||
E[:,1] = p[:x]
|
||||
E[:,2] = p[:y]
|
||||
if isa(p[:nbins], Tuple)
|
||||
xbins, ybins = p[:nbins]
|
||||
else
|
||||
xbins = ybins = p[:nbins]
|
||||
end
|
||||
cmap = true
|
||||
x, y, H = Base.hist2d(E, xbins, ybins)
|
||||
elseif p[:linetype] == :pie
|
||||
axes_2d = false
|
||||
xmin, xmax, ymin, ymax = 0, 1, 0, 1
|
||||
x, y = p[:x], p[:y]
|
||||
else
|
||||
if p[:linetype] in [:contour, :surface]
|
||||
cmap = true
|
||||
end
|
||||
if p[:linetype] in [:surface, :wireframe, :path3d, :scatter3d]
|
||||
axes_2d = false
|
||||
end
|
||||
x, y = p[:x], p[:y]
|
||||
end
|
||||
if p[:linetype] != :pie
|
||||
xmin = min(minimum(x), xmin)
|
||||
xmax = max(maximum(x), xmax)
|
||||
if p[:linetype] == :ohlc
|
||||
for val in y
|
||||
ymin = min(val.open, val.high, val.low, val.close, ymin)
|
||||
ymax = max(val.open, val.high, val.low, val.close, ymax)
|
||||
end
|
||||
else
|
||||
ymin = min(minimum(y), ymin)
|
||||
ymax = max(maximum(y), ymax)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if d[:xlims] != :auto
|
||||
xmin, xmax = d[:xlims]
|
||||
end
|
||||
if d[:ylims] != :auto
|
||||
ymin, ymax = d[:ylims]
|
||||
end
|
||||
if xmax <= xmin
|
||||
xmax = xmin + 1
|
||||
end
|
||||
if ymax <= ymin
|
||||
ymax = ymin + 1
|
||||
end
|
||||
extrema[axis,:] = [xmin, xmax, ymin, ymax]
|
||||
end
|
||||
|
||||
if num_axes == 2 || !axes_2d
|
||||
viewport[2] -= 0.0525
|
||||
end
|
||||
if cmap
|
||||
viewport[2] -= 0.1
|
||||
end
|
||||
GR.setviewport(viewport[1], viewport[2], viewport[3], viewport[4])
|
||||
|
||||
scale = 0
|
||||
d[:xscale] == :log10 && (scale |= GR.OPTION_X_LOG)
|
||||
d[:yscale] == :log10 && (scale |= GR.OPTION_Y_LOG)
|
||||
get(d, :xflip, false) && (scale |= GR.OPTION_FLIP_X)
|
||||
get(d, :yflip, false) && (scale |= GR.OPTION_FLIP_Y)
|
||||
|
||||
for axis = 1:num_axes
|
||||
xmin, xmax, ymin, ymax = extrema[axis,:]
|
||||
if scale & GR.OPTION_X_LOG == 0
|
||||
xmin, xmax = GR.adjustlimits(xmin, xmax)
|
||||
majorx = 5
|
||||
xtick = GR.tick(xmin, xmax) / majorx
|
||||
else
|
||||
xtick = majorx = 1
|
||||
end
|
||||
if scale & GR.OPTION_Y_LOG == 0
|
||||
ymin, ymax = GR.adjustlimits(ymin, ymax)
|
||||
majory = 5
|
||||
ytick = GR.tick(ymin, ymax) / majory
|
||||
else
|
||||
ytick = majory = 1
|
||||
end
|
||||
if scale & GR.OPTION_FLIP_X == 0
|
||||
xorg = (xmin, xmax)
|
||||
else
|
||||
xorg = (xmax, xmin)
|
||||
end
|
||||
if scale & GR.OPTION_FLIP_Y == 0
|
||||
yorg = (ymin, ymax)
|
||||
else
|
||||
yorg = (ymax, ymin)
|
||||
end
|
||||
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
GR.setscale(scale)
|
||||
|
||||
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
charheight = max(0.018 * diag, 0.01)
|
||||
GR.setcharheight(charheight)
|
||||
GR.settextcolorind(fg)
|
||||
|
||||
if axes_2d
|
||||
GR.setlinewidth(1)
|
||||
GR.setlinecolorind(fg)
|
||||
ticksize = 0.0075 * diag
|
||||
if grid_flag && fg == 1
|
||||
GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
end
|
||||
if num_axes == 1
|
||||
GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
|
||||
GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, -majory, -ticksize)
|
||||
elseif axis == 1
|
||||
GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize)
|
||||
else
|
||||
GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, majory, -ticksize)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if get(d, :title, "") != ""
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), min(ratio, 1), d[:title])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :xlabel, "") != ""
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), 0, d[:xlabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :ylabel, "") != ""
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.setcharup(-1, 0)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0, 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :yrightlabel, "") != ""
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.setcharup(1, 0)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(1, 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
legend = false
|
||||
|
||||
for p in plt.seriesargs
|
||||
GR.savestate()
|
||||
xmin, xmax, ymin, ymax = extrema[gr_getaxisind(p),:]
|
||||
GR.setwindow(xmin, xmax, ymin, ymax)
|
||||
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks, :hline, :vline, :ohlc]
|
||||
haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
|
||||
haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
|
||||
haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
|
||||
end
|
||||
if p[:linetype] == :path
|
||||
if haskey(p, :fillcolor)
|
||||
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
end
|
||||
if length(p[:x]) > 1
|
||||
if p[:fillrange] != nothing
|
||||
GR.fillarea([p[:x][1]; p[:x]; p[:x][length(p[:x])]], [p[:fillrange]; p[:y]; p[:fillrange]])
|
||||
end
|
||||
GR.polyline(p[:x], p[:y])
|
||||
end
|
||||
legend = true
|
||||
end
|
||||
if p[:linetype] == :line
|
||||
if length(p[:x]) > 1
|
||||
gr_polyline(p[:x], p[:y])
|
||||
end
|
||||
legend = true
|
||||
elseif p[:linetype] in [:steppre, :steppost]
|
||||
n = length(p[:x])
|
||||
x = zeros(2*n + 1)
|
||||
y = zeros(2*n + 1)
|
||||
x[1], y[1] = p[:x][1], p[:y][1]
|
||||
j = 2
|
||||
for i = 2:n
|
||||
if p[:linetype] == :steppre
|
||||
x[j], x[j+1] = p[:x][i-1], p[:x][i]
|
||||
y[j], y[j+1] = p[:y][i], p[:y][i]
|
||||
else
|
||||
x[j], x[j+1] = p[:x][i], p[:x][i]
|
||||
y[j], y[j+1] = p[:y][i-1], p[:y][i]
|
||||
end
|
||||
j += 2
|
||||
end
|
||||
if n > 1
|
||||
GR.polyline(x, y)
|
||||
end
|
||||
legend = true
|
||||
elseif p[:linetype] == :sticks
|
||||
x, y = p[:x], p[:y]
|
||||
for i = 1:length(y)
|
||||
GR.polyline([x[i], x[i]], [ymin, y[i]])
|
||||
end
|
||||
legend = true
|
||||
elseif p[:linetype] == :scatter || (p[:markershape] != :none && axes_2d)
|
||||
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
|
||||
gr_setmarkershape(p)
|
||||
if haskey(d, :markersize)
|
||||
if typeof(d[:markersize]) <: Number
|
||||
GR.setmarkersize(d[:markersize] / 4.0)
|
||||
if length(p[:x]) > 0
|
||||
gr_polymarker(p, p[:x], p[:y])
|
||||
end
|
||||
else
|
||||
c = p[:markercolor]
|
||||
GR.setcolormap(-GR.COLORMAP_GLOWING)
|
||||
for i = 1:length(p[:x])
|
||||
if isa(c, ColorGradient) && p[:zcolor] != nothing
|
||||
ci = round(Int, 1000 + p[:zcolor][i] * 255)
|
||||
GR.setmarkercolorind(ci)
|
||||
end
|
||||
GR.setmarkersize(d[:markersize][i] / 4.0)
|
||||
gr_polymarker(p, [p[:x][i]], [p[:y][i]])
|
||||
end
|
||||
end
|
||||
else
|
||||
if length(p[:x]) > 0
|
||||
gr_polymarker(p, p[:x], p[:y])
|
||||
end
|
||||
end
|
||||
legend = true
|
||||
elseif p[:linetype] == :bar
|
||||
y = p[:y]
|
||||
for i = 1:length(y)
|
||||
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
|
||||
GR.setfillcolorind(1)
|
||||
GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
|
||||
GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i])
|
||||
end
|
||||
elseif p[:linetype] in [:hist, :density]
|
||||
h = Base.hist(p[:y])
|
||||
x, y = float(collect(h[1])), float(h[2])
|
||||
for i = 2:length(y)
|
||||
GR.setfillcolorind(gr_getcolorind(p[:fillcolor]))
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
GR.fillrect(x[i-1], x[i], ymin, y[i])
|
||||
GR.setfillcolorind(1)
|
||||
GR.setfillintstyle(GR.INTSTYLE_HOLLOW)
|
||||
GR.fillrect(x[i-1], x[i], ymin, y[i])
|
||||
end
|
||||
elseif p[:linetype] in [:hline, :vline]
|
||||
for xy in p[:y]
|
||||
if p[:linetype] == :hline
|
||||
GR.polyline([xmin, xmax], [xy, xy])
|
||||
else
|
||||
GR.polyline([xy, xy], [ymin, ymax])
|
||||
end
|
||||
end
|
||||
elseif p[:linetype] in [:heatmap, :hexbin]
|
||||
E = zeros(length(p[:x]),2)
|
||||
E[:,1] = p[:x]
|
||||
E[:,2] = p[:y]
|
||||
if isa(p[:nbins], Tuple)
|
||||
xbins, ybins = p[:nbins]
|
||||
else
|
||||
xbins = ybins = p[:nbins]
|
||||
end
|
||||
x, y, H = Base.hist2d(E, xbins, ybins)
|
||||
counts = round(Int32, 1000 + 255 * H / maximum(H))
|
||||
n, m = size(counts)
|
||||
GR.setcolormap(GR.COLORMAP_COOLWARM)
|
||||
GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts)
|
||||
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
|
||||
viewport[3], viewport[4])
|
||||
GR.setspace(0, maximum(counts), 0, 90)
|
||||
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
charheight = max(0.016 * diag, 0.01)
|
||||
GR.setcharheight(charheight)
|
||||
GR.colormap()
|
||||
elseif p[:linetype] == :contour
|
||||
x, y, z = p[:x], p[:y], p[:z].surf
|
||||
zmin, zmax = minimum(z), maximum(z)
|
||||
if typeof(p[:levels]) <: Array
|
||||
h = p[:levels]
|
||||
else
|
||||
h = linspace(zmin, zmax, p[:levels])
|
||||
end
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
GR.setcolormap(GR.COLORMAP_COOLWARM)
|
||||
GR.contour(x, y, h, reshape(z, length(x) * length(y)), 1000)
|
||||
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
|
||||
viewport[3], viewport[4])
|
||||
l = round(Int32, 1000 + (h - minimum(h)) / (maximum(h) - minimum(h)) * 255)
|
||||
GR.setwindow(xmin, xmax, zmin, zmax)
|
||||
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
|
||||
ztick = 0.5 * GR.tick(zmin, zmax)
|
||||
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
charheight = max(0.016 * diag, 0.01)
|
||||
GR.setcharheight(charheight)
|
||||
GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005)
|
||||
elseif p[:linetype] in [:surface, :wireframe]
|
||||
x, y, z = p[:x], p[:y], p[:z].surf
|
||||
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
|
||||
GR.setspace(zmin, zmax, 40, 70)
|
||||
xtick = GR.tick(xmin, xmax) / 2
|
||||
ytick = GR.tick(ymin, ymax) / 2
|
||||
ztick = GR.tick(zmin, zmax) / 2
|
||||
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
charheight = max(0.018 * diag, 0.01)
|
||||
ticksize = 0.01 * (viewport[2] - viewport[1])
|
||||
GR.setlinewidth(1)
|
||||
if grid_flag
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
|
||||
end
|
||||
z = reshape(z, length(x) * length(y))
|
||||
if p[:linetype] == :surface
|
||||
GR.setcolormap(GR.COLORMAP_COOLWARM)
|
||||
GR.gr3.surface(x, y, z, GR.OPTION_COLORED_MESH)
|
||||
else
|
||||
GR.setfillcolorind(0)
|
||||
GR.surface(x, y, z, GR.OPTION_FILLED_MESH)
|
||||
end
|
||||
GR.setlinewidth(1)
|
||||
GR.setcharheight(charheight)
|
||||
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
|
||||
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
|
||||
if cmap
|
||||
GR.setviewport(viewport[2] + 0.07, viewport[2] + 0.1,
|
||||
viewport[3], viewport[4])
|
||||
GR.colormap()
|
||||
end
|
||||
elseif p[:linetype] in [:path3d, :scatter3d]
|
||||
x, y, z = p[:x], p[:y], p[:z]
|
||||
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
|
||||
GR.setspace(zmin, zmax, 40, 70)
|
||||
xtick = GR.tick(xmin, xmax) / 2
|
||||
ytick = GR.tick(ymin, ymax) / 2
|
||||
ztick = GR.tick(zmin, zmax) / 2
|
||||
diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
charheight = max(0.018 * diag, 0.01)
|
||||
ticksize = 0.01 * (viewport[2] - viewport[1])
|
||||
GR.setlinewidth(1)
|
||||
if grid_flag && p[:linetype] == :path3d
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
|
||||
end
|
||||
if p[:linetype] == :scatter3d
|
||||
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
|
||||
gr_setmarkershape(p)
|
||||
for i = 1:length(z)
|
||||
px, py = GR.wc3towc(x[i], y[i], z[i])
|
||||
gr_polymarker(p, [px], [py])
|
||||
end
|
||||
else
|
||||
haskey(p, :linewidth) && GR.setlinewidth(p[:linewidth])
|
||||
if length(x) > 0
|
||||
GR.polyline3d(x, y, z)
|
||||
end
|
||||
end
|
||||
GR.setlinewidth(1)
|
||||
GR.setcharheight(charheight)
|
||||
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
|
||||
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
|
||||
elseif p[:linetype] == :ohlc
|
||||
y = p[:y]
|
||||
n = size(y, 1)
|
||||
ticksize = 0.5 * (xmax - xmin) / n
|
||||
for i in 1:n
|
||||
GR.polyline([i-ticksize, i], [y[i].open, y[i].open])
|
||||
GR.polyline([i, i], [y[i].low, y[i].high])
|
||||
GR.polyline([i, i+ticksize], [y[i].close, y[i].close])
|
||||
end
|
||||
elseif p[:linetype] == :pie
|
||||
GR.selntran(0)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
xmin, xmax, ymin, ymax = viewport
|
||||
ymax -= 0.05 * (xmax - xmin)
|
||||
xcenter = 0.5 * (xmin + xmax)
|
||||
ycenter = 0.5 * (ymin + ymax)
|
||||
if xmax - xmin > ymax - ymin
|
||||
r = 0.5 * (ymax - ymin)
|
||||
xmin, xmax = xcenter - r, xcenter + r
|
||||
else
|
||||
r = 0.5 * (xmax - xmin)
|
||||
ymin, ymax = ycenter - r, ycenter + r
|
||||
end
|
||||
labels, slices = p[:x], p[:y]
|
||||
numslices = length(slices)
|
||||
total = sum(slices)
|
||||
a1 = 0
|
||||
x = zeros(3)
|
||||
y = zeros(3)
|
||||
for i in 1:numslices
|
||||
a2 = round(Int, a1 + (slices[i] / total) * 360.0)
|
||||
GR.setfillcolorind(980 + (i-1) % 20)
|
||||
GR.fillarc(xmin, xmax, ymin, ymax, a1, a2)
|
||||
alpha = 0.5 * (a1 + a2)
|
||||
cosf = r * cos(alpha * pi / 180)
|
||||
sinf = r * sin(alpha * pi / 180)
|
||||
x[1] = xcenter + cosf
|
||||
y[1] = ycenter + sinf
|
||||
x[2] = x[1] + 0.1 * cosf
|
||||
y[2] = y[1] + 0.1 * sinf
|
||||
y[3] = y[2]
|
||||
if 90 <= alpha < 270
|
||||
x[3] = x[2] - 0.05
|
||||
GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF)
|
||||
GR.text(x[3] - 0.01, y[3], string(labels[i]))
|
||||
else
|
||||
x[3] = x[2] + 0.05
|
||||
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
|
||||
GR.text(x[3] + 0.01, y[3], string(labels[i]))
|
||||
end
|
||||
GR.polyline(x, y)
|
||||
a1 = a2
|
||||
end
|
||||
GR.selntran(1)
|
||||
end
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
if d[:legend] != :none && legend
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setscale(0)
|
||||
w = 0
|
||||
i = 0
|
||||
for p in plt.seriesargs
|
||||
if typeof(p[:label]) <: Array
|
||||
i += 1
|
||||
lab = p[:label][i]
|
||||
else
|
||||
lab = p[:label]
|
||||
end
|
||||
tbx, tby = GR.inqtext(0, 0, lab)
|
||||
w = max(w, tbx[3])
|
||||
end
|
||||
px = viewport[2] - 0.05 - w
|
||||
py = viewport[4] - 0.06
|
||||
dy = 0.03 * sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
GR.setfillcolorind(0)
|
||||
GR.fillrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
|
||||
GR.setlinetype(1)
|
||||
GR.setlinewidth(1)
|
||||
GR.drawrect(px - 0.08, px + w + 0.02, py + dy, py - dy * length(plt.seriesargs))
|
||||
haskey(d, :linewidth) && GR.setlinewidth(d[:linewidth])
|
||||
i = 0
|
||||
for p in plt.seriesargs
|
||||
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
|
||||
haskey(p, :linecolor) && GR.setlinecolorind(gr_getcolorind(p[:linecolor]))
|
||||
haskey(p, :linestyle) && GR.setlinetype(gr_linetype[p[:linestyle]])
|
||||
GR.polyline([px - 0.07, px - 0.01], [py, py])
|
||||
end
|
||||
if p[:linetype] == :scatter || p[:markershape] != :none
|
||||
haskey(p, :markercolor) && GR.setmarkercolorind(gr_getcolorind(p[:markercolor]))
|
||||
gr_setmarkershape(p)
|
||||
if p[:linetype] in [:path, :line, :steppre, :steppost, :sticks]
|
||||
gr_polymarker(p, [px - 0.06, px - 0.02], [py, py])
|
||||
else
|
||||
gr_polymarker(p, [px - 0.06, px - 0.04, px - 0.02], [py, py, py])
|
||||
end
|
||||
end
|
||||
if typeof(p[:label]) <: Array
|
||||
i += 1
|
||||
lab = p[:label][i]
|
||||
else
|
||||
lab = p[:label]
|
||||
end
|
||||
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
|
||||
GR.settextcolorind(1)
|
||||
GR.text(px, py, lab)
|
||||
py -= dy
|
||||
end
|
||||
GR.selntran(1)
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
if haskey(d, :anns)
|
||||
GR.savestate()
|
||||
for ann in d[:anns]
|
||||
x, y, val = ann
|
||||
x, y = GR.wctondc(x, y)
|
||||
alpha = val.font.rotation
|
||||
family = lowercase(val.font.family)
|
||||
GR.setcharheight(0.7 * val.font.pointsize / d[:size][2])
|
||||
GR.setcharup(sin(val.font.rotation), cos(val.font.rotation))
|
||||
if haskey(gr_font_family, family)
|
||||
GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING)
|
||||
end
|
||||
GR.settextcolorind(gr_getcolorind(val.font.color))
|
||||
GR.settextalign(gr_halign[val.font.halign], gr_valign[val.font.valign])
|
||||
GR.text(x, y, val.str)
|
||||
end
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
update && GR.updatews()
|
||||
end
|
||||
|
||||
function gr_display(subplt::Subplot{GRPackage})
|
||||
clear = true
|
||||
update = false
|
||||
l = enumerate(subplt.layout)
|
||||
nr = nrows(subplt.layout)
|
||||
for (i, (r, c)) in l
|
||||
nc = ncols(subplt.layout, r)
|
||||
if i == length(l)
|
||||
update = true
|
||||
end
|
||||
subplot = [(c-1)/nc, c/nc, 1-r/nr, 1-(r-1)/nr]
|
||||
gr_display(subplt.plts[i], clear, update, subplot)
|
||||
clear = false
|
||||
end
|
||||
end
|
||||
|
||||
function _create_plot(pkg::GRPackage; kw...)
|
||||
d = Dict(kw)
|
||||
Plot(nothing, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
function _add_series(::GRPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GRPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
if haskey(plt.plotargs, :anns)
|
||||
append!(plt.plotargs[:anns], anns)
|
||||
else
|
||||
plt.plotargs[:anns] = anns
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{GRPackage})
|
||||
end
|
||||
|
||||
function _update_plot(plt::Plot{GRPackage}, d::Dict)
|
||||
for k in (:title, :xlabel, :ylabel)
|
||||
haskey(d, k) && (plt.plotargs[k] = d[k])
|
||||
end
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{GRPackage}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.getindex(plt::Plot{GRPackage}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{GRPackage}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{GRPackage}, isbefore::Bool)
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{GRPackage}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{GRPackage}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{GRPackage})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "png"
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
write(io, readall("gks.png"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::PlottingObject{GRPackage})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "svg"
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
write(io, readall("gks.svg"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{GRPackage})
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"application/pdf", plt::PlottingObject{GRPackage})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "pdf"
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
write(io, readall("gks.pdf"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"application/postscript", plt::PlottingObject{GRPackage})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "ps"
|
||||
gr_display(plt)
|
||||
GR.emergencyclosegks()
|
||||
write(io, readall("gks.ps"))
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GRPackage})
|
||||
gr_display(plt)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GRPackage})
|
||||
gr_display(plt)
|
||||
true
|
||||
end
|
||||
@@ -1,19 +1,13 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
# immutable ImmersePackage <: PlottingPackage end
|
||||
|
||||
# export immerse
|
||||
# immerse() = backend(:immerse)
|
||||
|
||||
|
||||
# supportedArgs(::ImmersePackage) = supportedArgs(GadflyPackage())
|
||||
# supportedAxes(::ImmersePackage) = supportedAxes(GadflyPackage())
|
||||
# supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
|
||||
# supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
|
||||
# supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
|
||||
# supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
|
||||
|
||||
function _initialize_backend(::ImmersePackage; kw...)
|
||||
@eval begin
|
||||
import Immerse, Gadfly, Compose, Gtk
|
||||
export Immerse, Gadfly, Compose, Gtk
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
end
|
||||
end
|
||||
|
||||
function createImmerseFigure(d::Dict)
|
||||
w,h = d[:size]
|
||||
@@ -21,9 +15,11 @@ function createImmerseFigure(d::Dict)
|
||||
Immerse.Figure(figidx)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
function plot(pkg::ImmersePackage; kw...)
|
||||
function _create_plot(pkg::ImmersePackage; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
# create the underlying Gadfly.Plot object
|
||||
@@ -35,7 +31,7 @@ end
|
||||
|
||||
|
||||
# plot one data series
|
||||
function plot!(::ImmersePackage, plt::Plot; kw...)
|
||||
function _add_series(::ImmersePackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
addGadflySeries!(plt, d)
|
||||
push!(plt.seriesargs, d)
|
||||
@@ -43,7 +39,7 @@ function plot!(::ImmersePackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
|
||||
function updatePlotItems(plt::Plot{ImmersePackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{ImmersePackage}, d::Dict)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
@@ -52,7 +48,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function addAnnotations{X,Y,V}(plt::Plot{ImmersePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{ImmersePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
@@ -78,14 +74,14 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function buildSubplotObject!(subplt::Subplot{ImmersePackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{ImmersePackage}, isbefore::Bool)
|
||||
return false
|
||||
# isbefore && return false
|
||||
end
|
||||
|
||||
function showSubplotObject(subplt::Subplot{ImmersePackage})
|
||||
# create the Gtk window with vertical box vsep
|
||||
d = getinitargs(subplt,1)
|
||||
d = getplotargs(subplt,1)
|
||||
w,h = d[:size]
|
||||
vsep = Gtk.GtkBoxLeaf(:v)
|
||||
win = Gtk.GtkWindowLeaf(vsep, d[:windowtitle], w, h)
|
||||
@@ -125,15 +121,15 @@ function showSubplotObject(subplt::Subplot{ImmersePackage})
|
||||
end
|
||||
|
||||
|
||||
function handleLinkInner(plt::Plot{ImmersePackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{ImmersePackage}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function expandLimits!(lims, plt::Plot{ImmersePackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{ImmersePackage}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
expandLimits!(lims, l.mapping[isx ? :x : :y])
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -148,7 +144,7 @@ function Base.display(::PlotsDisplay, plt::Plot{ImmersePackage})
|
||||
|
||||
fig, gplt = plt.o
|
||||
if fig == nothing
|
||||
fig = createImmerseFigure(plt.initargs)
|
||||
fig = createImmerseFigure(plt.plotargs)
|
||||
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
|
||||
plt.o = (fig, gplt)
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,474 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
function _initialize_backend(::PlotlyPackage; kw...)
|
||||
@eval begin
|
||||
import JSON
|
||||
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
|
||||
|
||||
############################
|
||||
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
|
||||
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
# the first script is some hack I needed to do in order for the notebook
|
||||
# to not complain about Plotly being undefined
|
||||
display("text/html", """
|
||||
<script type="text/javascript">
|
||||
require=requirejs=define=undefined;
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(open(readall, _js_path, "r"))
|
||||
</script>
|
||||
""")
|
||||
# display("text/html", "<p>Plotly javascript loaded.</p>")
|
||||
end
|
||||
# end borrowing (thanks :)
|
||||
###########################
|
||||
|
||||
end
|
||||
# TODO: other initialization
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PlotlyPackage; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
Plot(nothing, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyPackage, plt::Plot; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
# TODO: add one series to the underlying package
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PlotlyPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
# set or add to the annotation_list
|
||||
if haskey(plt.plotargs, :annotation_list)
|
||||
append!(plt.plotargs[:annotation_list], anns)
|
||||
else
|
||||
plt.plotargs[:annotation_list] = anns
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{PlotlyPackage})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PlotlyPackage}, d::Dict)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{PlotlyPackage}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{PlotlyPackage}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PlotlyPackage}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{PlotlyPackage}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{PlotlyPackage}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{PlotlyPackage}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO:
|
||||
# _plotDefaults[:yrightlabel] = ""
|
||||
# _plotDefaults[:xlims] = :auto
|
||||
# _plotDefaults[:ylims] = :auto
|
||||
# _plotDefaults[:xticks] = :auto
|
||||
# _plotDefaults[:yticks] = :auto
|
||||
# _plotDefaults[:xscale] = :identity
|
||||
# _plotDefaults[:yscale] = :identity
|
||||
# _plotDefaults[:xflip] = false
|
||||
# _plotDefaults[:yflip] = false
|
||||
|
||||
function plotlyfont(font::Font, color = font.color)
|
||||
Dict{Symbol,Any}(
|
||||
:family => font.family,
|
||||
:size => round(Int, font.pointsize*1.4),
|
||||
:color => webcolor(color),
|
||||
)
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, val::Union{AbstractString,Symbol})
|
||||
Dict{Symbol,Any}(
|
||||
:text => val,
|
||||
:xref => "x",
|
||||
:x => x,
|
||||
:yref => "y",
|
||||
:y => y,
|
||||
:showarrow => false,
|
||||
)
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, ptxt::PlotText)
|
||||
merge(get_annotation_dict(x, y, ptxt.str), Dict{Symbol,Any}(
|
||||
:font => plotlyfont(ptxt.font),
|
||||
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
|
||||
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
|
||||
:rotation => ptxt.font.rotation,
|
||||
))
|
||||
end
|
||||
|
||||
function plotlyscale(scale::Symbol)
|
||||
if scale == :log10
|
||||
"log"
|
||||
else
|
||||
"-"
|
||||
end
|
||||
end
|
||||
|
||||
use_axis_field(ticks) = !(ticks in (nothing, :none))
|
||||
|
||||
tickssym(isx::Bool) = symbol((isx ? "x" : "y") * "ticks")
|
||||
limssym(isx::Bool) = symbol((isx ? "x" : "y") * "lims")
|
||||
flipsym(isx::Bool) = symbol((isx ? "x" : "y") * "flip")
|
||||
scalesym(isx::Bool) = symbol((isx ? "x" : "y") * "scale")
|
||||
labelsym(isx::Bool) = symbol((isx ? "x" : "y") * "label")
|
||||
|
||||
function plotlyaxis(d::Dict, isx::Bool)
|
||||
ax = Dict{Symbol,Any}(
|
||||
:title => d[labelsym(isx)],
|
||||
:showgrid => d[:grid],
|
||||
:zeroline => false,
|
||||
)
|
||||
|
||||
fgcolor = webcolor(d[:foreground_color])
|
||||
tsym = tickssym(isx)
|
||||
|
||||
if use_axis_field(d[tsym])
|
||||
ax[:titlefont] = plotlyfont(d[:guidefont], fgcolor)
|
||||
ax[:type] = plotlyscale(d[scalesym(isx)])
|
||||
ax[:tickfont] = plotlyfont(d[:tickfont], fgcolor)
|
||||
ax[:tickcolor] = fgcolor
|
||||
ax[:linecolor] = fgcolor
|
||||
|
||||
# xlims
|
||||
lims = d[limssym(isx)]
|
||||
if lims != :auto && limsType(lims) == :limits
|
||||
ax[:range] = lims
|
||||
end
|
||||
|
||||
# xflip
|
||||
if d[flipsym(isx)]
|
||||
ax[:autorange] = "reversed"
|
||||
end
|
||||
|
||||
# xticks
|
||||
ticks = d[tsym]
|
||||
if ticks != :auto
|
||||
ttype = ticksType(ticks)
|
||||
if ttype == :ticks
|
||||
ax[:tickmode] = "array"
|
||||
ax[:tickvals] = ticks
|
||||
elseif ttype == :ticks_and_labels
|
||||
ax[:tickmode] = "array"
|
||||
ax[:tickvals], ax[:ticktext] = ticks
|
||||
end
|
||||
end
|
||||
|
||||
ax
|
||||
else
|
||||
ax[:showticklabels] = false
|
||||
ax[:showgrid] = false
|
||||
end
|
||||
|
||||
ax
|
||||
end
|
||||
|
||||
# function get_plot_json(plt::Plot{PlotlyPackage})
|
||||
# d = plt.plotargs
|
||||
function plotly_layout(d::Dict)
|
||||
d_out = Dict{Symbol,Any}()
|
||||
|
||||
bgcolor = webcolor(d[:background_color])
|
||||
fgcolor = webcolor(d[:foreground_color])
|
||||
|
||||
# set the fields for the plot
|
||||
d_out[:title] = d[:title]
|
||||
d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor)
|
||||
d_out[:margin] = Dict{Symbol,Any}(:l=>35, :b=>30, :r=>8, :t=>20)
|
||||
d_out[:plot_bgcolor] = bgcolor
|
||||
d_out[:paper_bgcolor] = bgcolor
|
||||
|
||||
# TODO: x/y axis tick values/labels
|
||||
d_out[:xaxis] = plotlyaxis(d, true)
|
||||
d_out[:yaxis] = plotlyaxis(d, false)
|
||||
|
||||
# legend
|
||||
d_out[:showlegend] = d[:legend] != :none
|
||||
if d[:legend] != :none
|
||||
d_out[:legend] = Dict{Symbol,Any}(
|
||||
:bgcolor => bgcolor,
|
||||
:bordercolor => fgcolor,
|
||||
:font => plotlyfont(d[:legendfont]),
|
||||
)
|
||||
end
|
||||
|
||||
# annotations
|
||||
anns = get(d, :annotation_list, [])
|
||||
if !isempty(anns)
|
||||
d_out[:annotations] = [get_annotation_dict(ann...) for ann in anns]
|
||||
end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
function get_plot_json(plt::Plot{PlotlyPackage})
|
||||
JSON.json(plotly_layout(plt.plotargs))
|
||||
end
|
||||
|
||||
|
||||
function plotly_colorscale(grad::ColorGradient)
|
||||
[[grad.values[i], webcolor(grad.colors[i])] for i in 1:length(grad.colors)]
|
||||
end
|
||||
plotly_colorscale(c) = plotly_colorscale(ColorGradient(:bluesreds))
|
||||
|
||||
const _plotly_markers = Dict{Symbol,Any}(
|
||||
:rect => "square",
|
||||
:xcross => "x",
|
||||
:utriangle => "triangle-up",
|
||||
:dtriangle => "triangle-down",
|
||||
:star5 => "star-triangle-up",
|
||||
:vline => "line-ns",
|
||||
:hline => "line-ew",
|
||||
)
|
||||
|
||||
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
|
||||
function plotly_series(d::Dict; plot_index = nothing)
|
||||
d_out = Dict{Symbol,Any}()
|
||||
|
||||
x, y = collect(d[:x]), collect(d[:y])
|
||||
d_out[:name] = d[:label]
|
||||
|
||||
lt = d[:linetype]
|
||||
isscatter = lt in (:scatter, :scatter3d)
|
||||
hasmarker = isscatter || d[:markershape] != :none
|
||||
hasline = !isscatter
|
||||
|
||||
# set the "type"
|
||||
if lt in (:line, :path, :scatter, :steppre, :steppost)
|
||||
d_out[:type] = "scatter"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
if d[:fillrange] == true || d[:fillrange] == 0
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha])
|
||||
elseif !(d[:fillrange] in (false, nothing))
|
||||
warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(d[:fillrange])")
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif lt == :bar
|
||||
d_out[:type] = "bar"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif lt == :heatmap
|
||||
d_out[:type] = "histogram2d"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
if isa(d[:nbins], Tuple)
|
||||
xbins, ybins = d[:nbins]
|
||||
else
|
||||
xbins = ybins = d[:nbins]
|
||||
end
|
||||
d_out[:nbinsx] = xbins
|
||||
d_out[:nbinsy] = ybins
|
||||
|
||||
elseif lt in (:hist, :density)
|
||||
d_out[:type] = "histogram"
|
||||
isvert = d[:orientation] in (:vertical, :v, :vert)
|
||||
d_out[isvert ? :x : :y] = y
|
||||
d_out[isvert ? :nbinsx : :nbinsy] = d[:nbins]
|
||||
if lt == :density
|
||||
d_out[:histnorm] = "probability density"
|
||||
end
|
||||
|
||||
elseif lt in (:contour, :surface, :wireframe)
|
||||
d_out[:type] = lt == :wireframe ? :surface : string(lt)
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:z] = d[:z].surf
|
||||
# d_out[:showscale] = d[:legend]
|
||||
if lt == :contour
|
||||
d_out[:ncontours] = d[:levels]
|
||||
d_out[:contours] = Dict{Symbol,Any}(:coloring => d[:fillrange] != nothing ? "fill" : "lines")
|
||||
end
|
||||
d_out[:colorscale] = plotly_colorscale(d[lt == :contour ? :linecolor : :fillcolor])
|
||||
|
||||
elseif lt == :pie
|
||||
d_out[:type] = "pie"
|
||||
d_out[:labels] = x
|
||||
d_out[:values] = y
|
||||
d_out[:hoverinfo] = "label+percent+name"
|
||||
|
||||
elseif lt in (:path3d, :scatter3d)
|
||||
d_out[:type] = "scatter3d"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
hasline ? "lines" : "none"
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:z] = collect(d[:z])
|
||||
|
||||
else
|
||||
warn("Plotly: linetype $lt isn't supported.")
|
||||
return Dict{Symbol,Any}()
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
d_out[:marker] = Dict{Symbol,Any}(
|
||||
:symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])),
|
||||
:opacity => d[:markeralpha],
|
||||
:size => 2 * d[:markersize],
|
||||
:color => webcolor(d[:markercolor], d[:markeralpha]),
|
||||
:line => Dict{Symbol,Any}(
|
||||
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
|
||||
:width => d[:markerstrokewidth],
|
||||
),
|
||||
)
|
||||
if d[:zcolor] != nothing
|
||||
d_out[:marker][:color] = d[:zcolor]
|
||||
d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor])
|
||||
end
|
||||
end
|
||||
|
||||
# add "line"
|
||||
if hasline
|
||||
d_out[:line] = Dict{Symbol,Any}(
|
||||
:color => webcolor(d[:linecolor], d[:linealpha]),
|
||||
:width => d[:linewidth],
|
||||
:shape => if lt == :steppre
|
||||
"vh"
|
||||
elseif lt == :steppost
|
||||
"hv"
|
||||
else
|
||||
"linear"
|
||||
end,
|
||||
:dash => string(d[:linestyle]),
|
||||
# :dash => "solid",
|
||||
)
|
||||
end
|
||||
|
||||
# # for subplots, we need to add the xaxis/yaxis fields
|
||||
# if plot_index != nothing
|
||||
# d_out[:xaxis] = "x$(plot_index)"
|
||||
# d_out[:yaxis] = "y$(plot_index)"
|
||||
# end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
# get a list of dictionaries, each representing the series params
|
||||
function get_series_json(plt::Plot{PlotlyPackage})
|
||||
JSON.json(map(plotly_series, plt.seriesargs))
|
||||
end
|
||||
|
||||
function get_series_json(subplt::Subplot{PlotlyPackage})
|
||||
ds = Dict[]
|
||||
for (i,plt) in enumerate(subplt.plts)
|
||||
for d in plt.seriesargs
|
||||
push!(ds, plotly_series(d, plot_index = i))
|
||||
end
|
||||
end
|
||||
JSON.json(ds)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function html_head(plt::PlottingObject{PlotlyPackage})
|
||||
"<script src=\"$(Pkg.dir("Plots","deps","plotly-latest.min.js"))\"></script>"
|
||||
end
|
||||
|
||||
function html_body(plt::Plot{PlotlyPackage}, style = nothing)
|
||||
if style == nothing
|
||||
w, h = plt.plotargs[:size]
|
||||
style = "width:$(w)px;height:$(h)px;"
|
||||
end
|
||||
uuid = Base.Random.uuid4()
|
||||
"""
|
||||
<div id=\"$(uuid)\" style=\"$(style)\"></div>
|
||||
<script>
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(get_series_json(plt)), $(get_plot_json(plt)));
|
||||
</script>
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
|
||||
function html_body(subplt::Subplot{PlotlyPackage})
|
||||
w, h = subplt.plts[1].plotargs[:size]
|
||||
html = ["<div style=\"width:$(w)px;height:$(h)px;\">"]
|
||||
nr = nrows(subplt.layout)
|
||||
ph = h / nr
|
||||
|
||||
for r in 1:nr
|
||||
push!(html, "<div style=\"clear:both;\">")
|
||||
|
||||
nc = ncols(subplt.layout, r)
|
||||
pw = w / nc
|
||||
|
||||
for c in 1:nc
|
||||
plt = subplt[r,c]
|
||||
push!(html, html_body(plt, "float:left; width:$(pw)px; height:$(ph)px;"))
|
||||
end
|
||||
|
||||
push!(html, "</div>")
|
||||
end
|
||||
push!(html, "</div>")
|
||||
|
||||
join(html)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{PlotlyPackage})
|
||||
warn("todo: png")
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PlotlyPackage})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::PlottingObject{PlotlyPackage})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{PlotlyPackage})
|
||||
# # TODO: display/show the subplot
|
||||
# end
|
||||
@@ -0,0 +1,128 @@
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
function _initialize_backend(::PlotlyJSPackage; kw...)
|
||||
@eval begin
|
||||
import PlotlyJS
|
||||
export PlotlyJS
|
||||
end
|
||||
|
||||
for (mime, fmt) in PlotlyJS._mimeformats
|
||||
@eval Base.writemime(io::IO, m::MIME{symbol($mime)}, p::Plot{PlotlyJSPackage}) = writemime(io, m, p.o)
|
||||
end
|
||||
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
IJulia.display_dict(plt::PlottingObject{PlotlyJSPackage}) = IJulia.display_dict(plt.o)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PlotlyJSPackage; kw...)
|
||||
d = Dict(kw)
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
# o = PlotlyJS.Plot(PlotlyJS.GenericTrace[], PlotlyJS.Layout(),
|
||||
# Base.Random.uuid4(), PlotlyJS.ElectronDisplay())
|
||||
# T = isijulia() ? PlotlyJS.JupyterPlot : PlotlyJS.ElectronPlot
|
||||
# o = T(PlotlyJS.Plot())
|
||||
o = PlotlyJS.plot()
|
||||
|
||||
Plot(o, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyJSPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
syncplot = plt.o
|
||||
|
||||
# dumpdict(d, "addseries", true)
|
||||
|
||||
# add to the data array
|
||||
pdict = plotly_series(d)
|
||||
typ = pop!(pdict, :type)
|
||||
gt = PlotlyJS.GenericTrace(typ; pdict...)
|
||||
PlotlyJS.addtraces!(syncplot, gt)
|
||||
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PlotlyJSPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
# set or add to the annotation_list
|
||||
if !haskey(plt.plotargs, :annotation_list)
|
||||
plt.plotargs[:annotation_list] = Any[]
|
||||
end
|
||||
append!(plt.plotargs[:annotation_list], anns)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{PlotlyJSPackage})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PlotlyJSPackage}, d::Dict)
|
||||
pdict = plotly_layout(d)
|
||||
# dumpdict(pdict, "pdict updateplot", true)
|
||||
syncplot = plt.o
|
||||
w,h = d[:size]
|
||||
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{PlotlyJSPackage}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{PlotlyJSPackage}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PlotlyJSPackage}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
# TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
|
||||
# PlotlyJS.restyle!(plt.o, i, plotly_series(d))
|
||||
PlotlyJS.restyle!(plt.o, i, Dict(:x=>(d[:x],), :y=>(d[:y],)))
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{PlotlyJSPackage}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{PlotlyJSPackage}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{PlotlyJSPackage}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{PlotlyJSPackage})
|
||||
Base.writemime(io, m, plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSPackage})
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSPackage})
|
||||
error()
|
||||
end
|
||||
|
||||
@@ -1,10 +1,37 @@
|
||||
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
function _initialize_backend(::PyPlotPackage)
|
||||
@eval begin
|
||||
import PyPlot
|
||||
export PyPlot
|
||||
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
const pypath = PyPlot.pywrap(PyPlot.pyimport("matplotlib.path"))
|
||||
const mplot3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d"))
|
||||
# const pycolorbar = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colorbar"))
|
||||
end
|
||||
|
||||
if !isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
PyPlot.ioff() # stops wierd behavior of displaying incomplete graphs in IJulia
|
||||
|
||||
# # TODO: how the hell can I use PyQt4??
|
||||
# "pyqt4"=>:qt_pyqt4
|
||||
# PyPlot.backend[1] = "pyqt4"
|
||||
# PyPlot.gui[1] = :qt_pyqt4
|
||||
# PyPlot.switch_backend("Qt4Agg")
|
||||
|
||||
# only turn on the gui if we want it
|
||||
if PyPlot.gui != :none
|
||||
PyPlot.pygui(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# convert colorant to 4-tuple RGBA
|
||||
getPyPlotColor(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
|
||||
getPyPlotColor(cvec::ColorVector, α=nothing) = map(getPyPlotColor, convertColor(cvec, α).v)
|
||||
getPyPlotColor(scheme::ColorScheme, α=nothing) = getPyPlotColor(convertColor(getColor(scheme), α))
|
||||
getPyPlotColor(c, α=nothing) = getPyPlotColor(convertColor(c, α))
|
||||
# getPyPlotColor(c, alpha) = getPyPlotColor(colorscheme(c, alpha))
|
||||
@@ -12,12 +39,14 @@ getPyPlotColor(c, α=nothing) = getPyPlotColor(convertColor(c, α))
|
||||
function getPyPlotColorMap(c::ColorGradient, α=nothing)
|
||||
# c = ColorGradient(c.colors, c.values, alpha=α)
|
||||
# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", map(getPyPlotColor, getColorVector(c)))
|
||||
pyvals = [(c.values[i], getPyPlotColor(c.colors[i], α)) for i in 1:length(c.colors)]
|
||||
# pyvals = [(c.values[i], getPyPlotColor(c.colors[i], α)) for i in 1:length(c.colors)]
|
||||
pyvals = [(v, getPyPlotColor(getColorZ(c, v), α)) for v in c.values]
|
||||
# @show c α pyvals
|
||||
pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
|
||||
end
|
||||
|
||||
# anything else just gets a redsblue gradient
|
||||
getPyPlotColorMap(c, α=nothing) = getPyPlotColorMap(ColorGradient(:redsblues), α)
|
||||
# anything else just gets a bluesred gradient
|
||||
getPyPlotColorMap(c, α=nothing) = getPyPlotColorMap(ColorGradient(:bluesreds), α)
|
||||
|
||||
# get the style (solid, dashed, etc)
|
||||
function getPyPlotLineStyle(linetype::Symbol, linestyle::Symbol)
|
||||
@@ -62,8 +91,14 @@ function getPyPlotMarker(marker::Symbol)
|
||||
return "o"
|
||||
end
|
||||
|
||||
# getPyPlotMarker(markers::AVec) = map(getPyPlotMarker, markers)
|
||||
function getPyPlotMarker(markers::AVec)
|
||||
warn("Vectors of markers are currently unsupported in PyPlot: $markers")
|
||||
getPyPlotMarker(markers[1])
|
||||
end
|
||||
|
||||
# pass through
|
||||
function getPyPlotMarker(marker::@compat(AbstractString))
|
||||
function getPyPlotMarker(marker::AbstractString)
|
||||
@assert length(marker) == 1
|
||||
marker
|
||||
end
|
||||
@@ -75,46 +110,73 @@ function getPyPlotStepStyle(linetype::Symbol)
|
||||
end
|
||||
|
||||
|
||||
immutable PyPlotFigWrapper
|
||||
fig
|
||||
end
|
||||
# immutable PyPlotFigWrapper
|
||||
# fig
|
||||
# kwargs # for add_subplot
|
||||
# end
|
||||
|
||||
immutable PyPlotAxisWrapper
|
||||
type PyPlotAxisWrapper
|
||||
ax
|
||||
rightax
|
||||
fig
|
||||
kwargs # for add_subplot
|
||||
end
|
||||
|
||||
getfig(wrap::@compat(Union{PyPlotAxisWrapper,PyPlotFigWrapper})) = wrap.fig
|
||||
# getfig(wrap::@compat(Union{PyPlotAxisWrapper,PyPlotFigWrapper})) = wrap.fig
|
||||
getfig(wrap::PyPlotAxisWrapper) = wrap.fig
|
||||
|
||||
|
||||
|
||||
# get a reference to the correct axis
|
||||
function getLeftAxis(wrap::PyPlotFigWrapper)
|
||||
axes = wrap.fig.o[:axes]
|
||||
if isempty(axes)
|
||||
return wrap.fig.o[:add_subplot](111)
|
||||
function getLeftAxis(wrap::PyPlotAxisWrapper)
|
||||
if wrap.ax == nothing
|
||||
axes = wrap.fig.o[:axes]
|
||||
if isempty(axes)
|
||||
return wrap.fig.o[:add_subplot](111; wrap.kwargs...)
|
||||
end
|
||||
axes[1]
|
||||
else
|
||||
wrap.ax
|
||||
end
|
||||
axes[1]
|
||||
end
|
||||
getLeftAxis(wrap::PyPlotAxisWrapper) = wrap.ax
|
||||
# getLeftAxis(wrap::PyPlotAxisWrapper) = wrap.ax
|
||||
# getRightAxis(x) = getLeftAxis(x)[:twinx]()
|
||||
|
||||
function getRightAxis(wrap::PyPlotAxisWrapper)
|
||||
if wrap.rightax == nothing
|
||||
wrap.rightax = getLeftAxis(wrap)[:twinx]()
|
||||
end
|
||||
wrap.rightax
|
||||
end
|
||||
|
||||
getLeftAxis(plt::Plot{PyPlotPackage}) = getLeftAxis(plt.o)
|
||||
getRightAxis(x) = getLeftAxis(x)[:twinx]()
|
||||
getRightAxis(plt::Plot{PyPlotPackage}) = getRightAxis(plt.o)
|
||||
getAxis(plt::Plot{PyPlotPackage}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt)
|
||||
|
||||
# left axis is PyPlot.<func>, right axis is "f.axes[0].twinx().<func>"
|
||||
function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol)
|
||||
|
||||
# # need to access mplot3d functions differently
|
||||
# if linetype == :surface
|
||||
# return mplot3d.pymember("Axes3D")[:plot_surface]
|
||||
# end
|
||||
|
||||
# in the 2-axis case we need to get: <rightaxis>[:<func>]
|
||||
ax = getAxis(plt, axis)
|
||||
ax[:set_ylabel](plt.initargs[:yrightlabel])
|
||||
# ax[:set_ylabel](plt.plotargs[:yrightlabel])
|
||||
fmap = @compat Dict(
|
||||
:hist => :hist,
|
||||
:sticks => :bar,
|
||||
:bar => :bar,
|
||||
:heatmap => :hexbin,
|
||||
:hexbin => :hexbin,
|
||||
:scatter => :scatter,
|
||||
:contour => :contour,
|
||||
:hist => :hist,
|
||||
:density => :hist,
|
||||
:sticks => :bar,
|
||||
:bar => :bar,
|
||||
:heatmap => :hexbin,
|
||||
:hexbin => :hexbin,
|
||||
:scatter => :scatter,
|
||||
:contour => :contour,
|
||||
:scatter3d => :scatter,
|
||||
:surface => :plot_surface,
|
||||
:wireframe => :plot_wireframe,
|
||||
# :surface => pycolors.pymember("LinearSegmentedColormap")[:from_list]
|
||||
)
|
||||
return ax[get(fmap, linetype, :plot)]
|
||||
end
|
||||
@@ -138,7 +200,7 @@ function handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Bool)
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
ax[:plot](xs, ys,
|
||||
# linestyle = getPyPlotLineStyle(:path, :dashdot),
|
||||
color = getPyPlotColor(d[:color]),
|
||||
color = getPyPlotColor(d[:linecolor]),
|
||||
linewidth = 2
|
||||
)
|
||||
end
|
||||
@@ -146,21 +208,56 @@ end
|
||||
handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Real) = handleSmooth(plt, ax, d, true)
|
||||
|
||||
|
||||
nop() = nothing
|
||||
|
||||
|
||||
makePyPlotCurrent(wrap::PyPlotFigWrapper) = PyPlot.figure(wrap.fig.o[:number])
|
||||
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = nothing #PyPlot.sca(wrap.ax.o)
|
||||
makePyPlotCurrent(plt::Plot{PyPlotPackage}) = makePyPlotCurrent(plt.o)
|
||||
# makePyPlotCurrent(wrap::PyPlotFigWrapper) = PyPlot.figure(wrap.fig.o[:number])
|
||||
# makePyPlotCurrent(wrap::PyPlotAxisWrapper) = nothing #PyPlot.sca(wrap.ax.o)
|
||||
makePyPlotCurrent(wrap::PyPlotAxisWrapper) = wrap.ax == nothing ? PyPlot.figure(wrap.fig.o[:number]) : nothing
|
||||
makePyPlotCurrent(plt::Plot{PyPlotPackage}) = plt.o == nothing ? nothing : makePyPlotCurrent(plt.o)
|
||||
|
||||
|
||||
function preparePlotUpdate(plt::Plot{PyPlotPackage})
|
||||
function _before_add_series(plt::Plot{PyPlotPackage})
|
||||
makePyPlotCurrent(plt)
|
||||
end
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
function pyplot_figure(plotargs::Dict)
|
||||
w,h = map(px2inch, plotargs[:size])
|
||||
bgcolor = getPyPlotColor(plotargs[:background_color])
|
||||
|
||||
# reuse the current figure?
|
||||
fig = if plotargs[:overwrite_figure]
|
||||
PyPlot.gcf()
|
||||
else
|
||||
PyPlot.figure()
|
||||
end
|
||||
|
||||
# update the specs
|
||||
# fig[:set_size_inches](w,h, (isijulia() ? [] : [true])...)
|
||||
fig[:set_size_inches](w, h, forward = true)
|
||||
fig[:set_facecolor](bgcolor)
|
||||
fig[:set_dpi](DPI)
|
||||
fig[:set_tight_layout](true)
|
||||
|
||||
# clear the figure
|
||||
PyPlot.clf()
|
||||
|
||||
# resize the window
|
||||
PyPlot.plt[:get_current_fig_manager]()[:resize](plotargs[:size]...)
|
||||
fig
|
||||
end
|
||||
|
||||
function pyplot_3d_setup!(wrap, d)
|
||||
# 3D?
|
||||
# if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper)
|
||||
if trueOrAllTrue(lt -> lt in _3dTypes, get(d, :linetype, :none))
|
||||
push!(wrap.kwargs, (:projection, "3d"))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# TODO:
|
||||
# fillto # might have to use barHack/histogramHack??
|
||||
# reg # true or false, add a regression line for each line
|
||||
@@ -169,7 +266,7 @@ end
|
||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
# show # true or false, show the plot (in case you don't want the window to pop up right away)
|
||||
|
||||
function plot(pkg::PyPlotPackage; kw...)
|
||||
function _create_plot(pkg::PyPlotPackage; kw...)
|
||||
# create the figure
|
||||
d = Dict(kw)
|
||||
|
||||
@@ -177,9 +274,13 @@ function plot(pkg::PyPlotPackage; kw...)
|
||||
if haskey(d, :subplot)
|
||||
wrap = nothing
|
||||
else
|
||||
w,h = map(px2inch, d[:size])
|
||||
bgcolor = getPyPlotColor(d[:background_color])
|
||||
wrap = PyPlotFigWrapper(PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96))
|
||||
wrap = PyPlotAxisWrapper(nothing, nothing, pyplot_figure(d), [])
|
||||
# wrap = PyPlotAxisWrapper(nothing, nothing, PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true), [])
|
||||
|
||||
# if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper)
|
||||
# push!(wrap.kwargs, (:projection, "3d"))
|
||||
# end
|
||||
pyplot_3d_setup!(wrap, d)
|
||||
end
|
||||
|
||||
plt = Plot(wrap, pkg, 0, d, Dict[])
|
||||
@@ -187,22 +288,36 @@ function plot(pkg::PyPlotPackage; kw...)
|
||||
end
|
||||
|
||||
|
||||
function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
ax = getAxis(plt, d[:axis])
|
||||
# 3D plots have a different underlying Axes object in PyPlot
|
||||
lt = d[:linetype]
|
||||
if lt in _3dTypes && isempty(plt.o.kwargs)
|
||||
push!(plt.o.kwargs, (:projection, "3d"))
|
||||
end
|
||||
|
||||
# handle mismatched x/y sizes, as PyPlot doesn't like that
|
||||
x, y = d[:x], d[:y]
|
||||
nx, ny = map(length, (x,y))
|
||||
if nx < ny
|
||||
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
end
|
||||
|
||||
ax = getAxis(plt, d[:axis])
|
||||
if !(lt in supportedTypes(pkg))
|
||||
error("linetype $(lt) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))")
|
||||
end
|
||||
|
||||
color = getPyPlotColor(d[:color], d[:lineopacity])
|
||||
color = getPyPlotColor(d[:linecolor], d[:linealpha])
|
||||
|
||||
|
||||
if lt == :sticks
|
||||
d,_ = sticksHack(;d...)
|
||||
|
||||
elseif lt == :scatter
|
||||
|
||||
elseif lt in (:scatter, :scatter3d)
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
end
|
||||
@@ -212,82 +327,140 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
linecolor = color
|
||||
linestyle = getPyPlotLineStyle(lt, d[:linestyle])
|
||||
for yi in d[:y]
|
||||
func = ax[lt == :hline ? :axhline : axvline]
|
||||
func = ax[lt == :hline ? :axhline : :axvline]
|
||||
func(yi, linewidth=d[:linewidth], color=linecolor, linestyle=linestyle)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
lt = d[:linetype]
|
||||
# lt = d[:linetype]
|
||||
extra_kwargs = Dict()
|
||||
|
||||
plotfunc = getPyPlotFunction(plt, d[:axis], lt)
|
||||
|
||||
# we have different args depending on plot type
|
||||
if lt in (:hist, :sticks, :bar)
|
||||
if lt in (:hist, :density, :sticks, :bar)
|
||||
|
||||
# NOTE: this is unsupported because it does the wrong thing... it shifts the whole axis
|
||||
# extra_kwargs[:bottom] = d[:fill]
|
||||
|
||||
if lt == :hist
|
||||
if ishistlike(lt)
|
||||
extra_kwargs[:bins] = d[:nbins]
|
||||
extra_kwargs[:normed] = lt == :density
|
||||
else
|
||||
extra_kwargs[:linewidth] = (lt == :sticks ? 0.1 : 0.9)
|
||||
end
|
||||
|
||||
elseif lt in (:heatmap, :hexbin)
|
||||
extra_kwargs[:gridsize] = d[:nbins]
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:color])
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor])
|
||||
|
||||
elseif lt == :contour
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:color])
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor])
|
||||
extra_kwargs[:linewidths] = d[:linewidth]
|
||||
extra_kwargs[:linestyles] = getPyPlotLineStyle(lt, d[:linestyle])
|
||||
# TODO: will need to call contourf to fill in the contours
|
||||
|
||||
elseif lt in (:surface, :wireframe)
|
||||
if lt == :surface
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
|
||||
end
|
||||
extra_kwargs[:rstride] = 1
|
||||
extra_kwargs[:cstride] = 1
|
||||
extra_kwargs[:linewidth] = d[:linewidth]
|
||||
extra_kwargs[:edgecolor] = getPyPlotColor(d[:linecolor], d[:linealpha])
|
||||
|
||||
else
|
||||
|
||||
extra_kwargs[:linestyle] = getPyPlotLineStyle(lt, d[:linestyle])
|
||||
extra_kwargs[:marker] = getPyPlotMarker(d[:markershape])
|
||||
|
||||
if lt == :scatter
|
||||
extra_kwargs[:s] = d[:markersize]^2
|
||||
if lt in (:scatter, :scatter3d)
|
||||
extra_kwargs[:s] = d[:markersize].^2
|
||||
c = d[:markercolor]
|
||||
if isa(c, ColorGradient) && d[:z] != nothing
|
||||
extra_kwargs[:c] = convert(Vector{Float64}, d[:z])
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeropacity])
|
||||
if d[:zcolor] != nothing
|
||||
if !isa(c, ColorGradient)
|
||||
c = colorscheme(:bluesreds)
|
||||
end
|
||||
extra_kwargs[:c] = convert(Vector{Float64}, d[:zcolor])
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeralpha])
|
||||
else
|
||||
extra_kwargs[:c] = getPyPlotColor(c, d[:markeropacity])
|
||||
# extra_kwargs[:c] = getPyPlotColor(c, d[:markeralpha])
|
||||
ppc = getPyPlotColor(c, d[:markeralpha])
|
||||
|
||||
# total hack due to PyPlot bug (see issue #145).
|
||||
# hack: duplicate the color vector when the total rgba fields is the same as the series length
|
||||
if (typeof(ppc) <: AbstractArray && length(ppc)*4 == length(x)) ||
|
||||
(typeof(ppc) <: Tuple && length(x) == 4)
|
||||
ppc = vcat(ppc, ppc)
|
||||
end
|
||||
extra_kwargs[:c] = ppc
|
||||
|
||||
end
|
||||
# if d[:markeralpha] != nothing
|
||||
# extra_kwargs[:alpha] = d[:markeralpha]
|
||||
# end
|
||||
extra_kwargs[:edgecolors] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
|
||||
extra_kwargs[:linewidths] = d[:markerstrokewidth]
|
||||
else
|
||||
extra_kwargs[:markersize] = d[:markersize]
|
||||
extra_kwargs[:markerfacecolor] = getPyPlotColor(d[:markercolor], d[:markeropacity])
|
||||
extra_kwargs[:markeredgecolor] = getPyPlotColor(plt.initargs[:foreground_color])
|
||||
extra_kwargs[:markeredgewidth] = d[:linewidth]
|
||||
extra_kwargs[:markerfacecolor] = getPyPlotColor(d[:markercolor], d[:markeralpha])
|
||||
extra_kwargs[:markeredgecolor] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
|
||||
extra_kwargs[:markeredgewidth] = d[:markerstrokewidth]
|
||||
extra_kwargs[:drawstyle] = getPyPlotStepStyle(lt)
|
||||
end
|
||||
end
|
||||
|
||||
# if d[:markeralpha] != nothing
|
||||
# extra_kwargs[:alpha] = d[:markeralpha]
|
||||
# elseif d[:linealpha] != nothing
|
||||
# extra_kwargs[:alpha] = d[:linealpha]
|
||||
# end
|
||||
|
||||
# set these for all types
|
||||
if lt != :contour
|
||||
extra_kwargs[:color] = color
|
||||
extra_kwargs[:linewidth] = d[:linewidth]
|
||||
if !(lt in (:contour,:surface,:wireframe))
|
||||
if !(lt in (:scatter, :scatter3d))
|
||||
extra_kwargs[:color] = color
|
||||
extra_kwargs[:linewidth] = d[:linewidth]
|
||||
end
|
||||
extra_kwargs[:label] = d[:label]
|
||||
extra_kwargs[:zorder] = plt.n
|
||||
end
|
||||
|
||||
# do the plot
|
||||
d[:serieshandle] = if lt == :hist
|
||||
d[:serieshandle] = if ishistlike(lt)
|
||||
plotfunc(d[:y]; extra_kwargs...)[1]
|
||||
|
||||
elseif lt == :contour
|
||||
# NOTE: x/y are backwards in pyplot, so we switch the x and y args (also y is reversed),
|
||||
# and take the transpose of the surface matrix
|
||||
x, y = d[:y], d[:x]
|
||||
surf = d[:surface]'
|
||||
handle = plotfunc(x, y, surf, d[:nlevels]; extra_kwargs...)
|
||||
x, y = d[:x], d[:y]
|
||||
surf = d[:z].surf'
|
||||
levels = d[:levels]
|
||||
if isscalar(levels)
|
||||
extra_args = (levels)
|
||||
elseif isvector(levels)
|
||||
extra_args = ()
|
||||
extra_kwargs[:levels] = levels
|
||||
else
|
||||
error("Only numbers and vectors are supported with levels keyword")
|
||||
end
|
||||
handle = plotfunc(x, y, surf, extra_args...; extra_kwargs...)
|
||||
if d[:fillrange] != nothing
|
||||
handle = ax[:contourf](x, y, surf, d[:nlevels]; cmap = getPyPlotColorMap(d[:fillcolor], d[:fillopacity]))
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
|
||||
delete!(extra_kwargs, :linewidths)
|
||||
handle = ax[:contourf](x, y, surf, extra_args...; extra_kwargs...)
|
||||
end
|
||||
handle
|
||||
|
||||
elseif lt in (:surface,:wireframe)
|
||||
x, y, z = d[:x], d[:y], Array(d[:z])
|
||||
if !ismatrix(x) || !ismatrix(y)
|
||||
x = repmat(x', length(y), 1)
|
||||
y = repmat(y, 1, length(d[:x]))
|
||||
z = z'
|
||||
end
|
||||
plotfunc(x, y, z; extra_kwargs...)
|
||||
elseif lt in _3dTypes
|
||||
plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...)
|
||||
elseif lt in (:scatter, :heatmap, :hexbin)
|
||||
plotfunc(d[:x], d[:y]; extra_kwargs...)
|
||||
else
|
||||
@@ -297,20 +470,22 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
handleSmooth(plt, ax, d, d[:smooth])
|
||||
|
||||
# add the colorbar legend
|
||||
if plt.initargs[:legend] && haskey(extra_kwargs, :cmap)
|
||||
PyPlot.colorbar(d[:serieshandle])
|
||||
if plt.plotargs[:colorbar] != :none && haskey(extra_kwargs, :cmap)
|
||||
PyPlot.colorbar(d[:serieshandle], ax=ax)
|
||||
end
|
||||
|
||||
# @show extra_kwargs
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[:set_axis_bgcolor](getPyPlotColor(plt.initargs[:background_color]))
|
||||
ax[:set_axis_bgcolor](getPyPlotColor(plt.plotargs[:background_color]))
|
||||
|
||||
fillrange = d[:fillrange]
|
||||
if fillrange != nothing && lt != :contour
|
||||
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillopacity])
|
||||
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillalpha])
|
||||
if typeof(fillrange) <: @compat(Union{Real, AVec})
|
||||
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor)
|
||||
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor, zorder = plt.n)
|
||||
else
|
||||
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor)
|
||||
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor, zorder = plt.n)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -329,34 +504,57 @@ function Base.getindex(plt::Plot{PyPlotPackage}, i::Integer)
|
||||
xy = series[:get_offsets]()
|
||||
return vec(xy[:,1]), vec(xy[:,2])
|
||||
end
|
||||
# series[:relim]()
|
||||
# mapping = getGadflyMappings(plt, i)[1]
|
||||
# mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PyPlotPackage}, xy::Tuple, i::Integer)
|
||||
series = plt.seriesargs[i][:serieshandle]
|
||||
function minmaxseries(ds, vec, axis)
|
||||
lo, hi = Inf, -Inf
|
||||
for d in ds
|
||||
d[:axis] == axis || continue
|
||||
v = d[vec]
|
||||
if length(v) > 0
|
||||
vlo, vhi = extrema(v)
|
||||
lo = min(lo, vlo)
|
||||
hi = max(hi, vhi)
|
||||
end
|
||||
end
|
||||
if lo == hi
|
||||
hi = if lo == 0
|
||||
1e-6
|
||||
else
|
||||
hi + min(abs(1e-2hi), 1e-6)
|
||||
end
|
||||
end
|
||||
lo, hi
|
||||
end
|
||||
|
||||
# TODO: this needs to handle one-sided fixed limits
|
||||
function set_lims!(plt::Plot{PyPlotPackage}, axis::Symbol)
|
||||
ax = getAxis(plt, axis)
|
||||
if plt.plotargs[:xlims] == :auto
|
||||
ax[:set_xlim](minmaxseries(plt.seriesargs, :x, axis)...)
|
||||
end
|
||||
if plt.plotargs[:ylims] == :auto
|
||||
ax[:set_ylim](minmaxseries(plt.seriesargs, :y, axis)...)
|
||||
end
|
||||
end
|
||||
|
||||
function Base.setindex!{X,Y}(plt::Plot{PyPlotPackage}, xy::Tuple{X,Y}, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
series = d[:serieshandle]
|
||||
x, y = xy
|
||||
d[:x], d[:y] = x, y
|
||||
try
|
||||
series[:set_data](xy...)
|
||||
series[:set_data](x, y)
|
||||
catch
|
||||
series[:set_offsets](hcat(xy...))
|
||||
series[:set_offsets](hcat(x, y))
|
||||
end
|
||||
|
||||
ax = series[:axes]
|
||||
if plt.initargs[:xlims] == :auto
|
||||
xmin, xmax = ax[:get_xlim]()
|
||||
ax[:set_xlim](min(xmin, minimum(xy[1])), max(xmax, maximum(xy[1])))
|
||||
end
|
||||
if plt.initargs[:ylims] == :auto
|
||||
ymin, ymax = ax[:get_ylim]()
|
||||
ax[:set_ylim](min(ymin, minimum(xy[2])), max(ymax, maximum(xy[2])))
|
||||
end
|
||||
set_lims!(plt, d[:axis])
|
||||
plt
|
||||
end
|
||||
|
||||
# getLeftAxis(plt)[:relim]()
|
||||
# getRightAxis(plt)[:relim]()
|
||||
# for mapping in getGadflyMappings(plt, i)
|
||||
# mapping[:x], mapping[:y] = xy
|
||||
# end
|
||||
function Base.setindex!{X,Y,Z}(plt::Plot{PyPlotPackage}, xyz::Tuple{X,Y,Z}, i::Integer)
|
||||
warn("setindex not implemented for xyz")
|
||||
plt
|
||||
end
|
||||
|
||||
@@ -366,7 +564,13 @@ function addPyPlotLims(ax, lims, isx::Bool)
|
||||
lims == :auto && return
|
||||
ltype = limsType(lims)
|
||||
if ltype == :limits
|
||||
ax[isx ? :set_xlim : :set_ylim](lims...)
|
||||
if isx
|
||||
isfinite(lims[1]) && ax[:set_xlim](left = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_xlim](right = lims[2])
|
||||
else
|
||||
isfinite(lims[1]) && ax[:set_ylim](bottom = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_ylim](top = lims[2])
|
||||
end
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
end
|
||||
@@ -382,7 +586,8 @@ function addPyPlotTicks(ax, ticks, isx::Bool)
|
||||
if ttype == :ticks
|
||||
ax[isx ? :set_xticks : :set_yticks](ticks)
|
||||
elseif ttype == :ticks_and_labels
|
||||
ax[isx ? :set_xticks : :set_yticks](ticks...)
|
||||
ax[isx ? :set_xticks : :set_yticks](ticks[1])
|
||||
ax[isx ? :set_xticklabels : :set_yticklabels](ticks[2])
|
||||
else
|
||||
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
|
||||
end
|
||||
@@ -390,7 +595,7 @@ end
|
||||
|
||||
usingRightAxis(plt::Plot{PyPlotPackage}) = any(args -> args[:axis] in (:right,:auto), plt.seriesargs)
|
||||
|
||||
function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
figorax = plt.o
|
||||
ax = getLeftAxis(figorax)
|
||||
# PyPlot.sca(ax)
|
||||
@@ -403,7 +608,7 @@ function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
ax[:set_ylabel](d[:ylabel])
|
||||
end
|
||||
if usingRightAxis(plt) && get(d, :yrightlabel, "") != ""
|
||||
rightax = getRightAxis(figorax)
|
||||
rightax = getRightAxis(figorax)
|
||||
rightax[:set_ylabel](d[:yrightlabel])
|
||||
end
|
||||
|
||||
@@ -432,22 +637,22 @@ function updatePlotItems(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
# font sizes
|
||||
for ax in axes
|
||||
# haskey(d, :yrightlabel) || continue
|
||||
|
||||
|
||||
|
||||
# guides
|
||||
sz = get(d, :guidefont, plt.initargs[:guidefont]).pointsize
|
||||
sz = get(d, :guidefont, plt.plotargs[:guidefont]).pointsize
|
||||
ax[:title][:set_fontsize](sz)
|
||||
ax[:xaxis][:label][:set_fontsize](sz)
|
||||
ax[:yaxis][:label][:set_fontsize](sz)
|
||||
|
||||
# ticks
|
||||
sz = get(d, :tickfont, plt.initargs[:tickfont]).pointsize
|
||||
sz = get(d, :tickfont, plt.plotargs[:tickfont]).pointsize
|
||||
for sym in (:get_xticklabels, :get_yticklabels)
|
||||
for lab in ax[sym]()
|
||||
lab[:set_fontsize](sz)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# grid
|
||||
if get(d, :grid, false)
|
||||
ax[:xaxis][:grid](true)
|
||||
@@ -461,7 +666,7 @@ end
|
||||
function applyPyPlotScale(ax, scaleType::Symbol, isx::Bool)
|
||||
func = ax[isx ? :set_xscale : :set_yscale]
|
||||
scaleType == :identity && return func("linear")
|
||||
scaleType == :log && return func("log", basex = e, basey = e)
|
||||
scaleType == :ln && return func("log", basex = e, basey = e)
|
||||
scaleType == :log2 && return func("log", basex = 2, basey = 2)
|
||||
scaleType == :log10 && return func("log", basex = 10, basey = 10)
|
||||
warn("Unhandled scaleType: ", scaleType)
|
||||
@@ -488,7 +693,7 @@ function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::PlotT
|
||||
)
|
||||
end
|
||||
|
||||
function addAnnotations{X,Y,V}(plt::Plot{PyPlotPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PyPlotPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createPyPlotAnnotationObject(plt, ann...)
|
||||
end
|
||||
@@ -497,12 +702,14 @@ end
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# NOTE: pyplot needs to build before
|
||||
function buildSubplotObject!(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
|
||||
l = subplt.layout
|
||||
|
||||
w,h = map(px2inch, getinitargs(subplt,1)[:size])
|
||||
bgcolor = getPyPlotColor(getinitargs(subplt,1)[:background_color])
|
||||
fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96)
|
||||
# w,h = map(px2inch, getplotargs(subplt,1)[:size])
|
||||
# bgcolor = getPyPlotColor(getplotargs(subplt,1)[:background_color])
|
||||
# fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true)
|
||||
plotargs = getplotargs(subplt, 1)
|
||||
fig = pyplot_figure(plotargs)
|
||||
|
||||
nr = nrows(l)
|
||||
for (i,(r,c)) in enumerate(l)
|
||||
@@ -512,10 +719,13 @@ function buildSubplotObject!(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
|
||||
fakeidx = (r-1) * nc + c
|
||||
ax = fig[:add_subplot](nr, nc, fakeidx)
|
||||
|
||||
subplt.plts[i].o = PyPlotAxisWrapper(ax, fig)
|
||||
subplt.plts[i].o = PyPlotAxisWrapper(ax, nothing, fig, [])
|
||||
pyplot_3d_setup!(subplt.plts[i].o, plotargs)
|
||||
end
|
||||
|
||||
subplt.o = PyPlotFigWrapper(fig)
|
||||
# subplt.o = PyPlotFigWrapper(fig, [])
|
||||
subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, [])
|
||||
pyplot_3d_setup!(subplt.o, plotargs)
|
||||
true
|
||||
end
|
||||
|
||||
@@ -528,26 +738,26 @@ function subplot(plts::AVec{Plot{PyPlotPackage}}, layout::SubplotLayout, d::Dict
|
||||
n = sum([plt.n for plt in plts])
|
||||
|
||||
pkg = PyPlotPackage()
|
||||
newplts = Plot{PyPlotPackage}[plot(pkg; subplot=true, plt.initargs...) for plt in plts]
|
||||
newplts = Plot{PyPlotPackage}[_create_plot(pkg; subplot=true, plt.plotargs...) for plt in plts]
|
||||
|
||||
subplt = Subplot(nothing, newplts, PyPlotPackage(), p, n, layout, d, true, false, false, (r,c) -> (nothing,nothing))
|
||||
|
||||
preprocessSubplot(subplt, d)
|
||||
buildSubplotObject!(subplt, true)
|
||||
_preprocess_subplot(subplt, d)
|
||||
_create_subplot(subplt, true)
|
||||
|
||||
for (i,plt) in enumerate(plts)
|
||||
for seriesargs in plt.seriesargs
|
||||
_plot_from_subplot!(newplts[i]; seriesargs...)
|
||||
_add_series_subplot(newplts[i]; seriesargs...)
|
||||
end
|
||||
end
|
||||
|
||||
postprocessSubplot(subplt, d)
|
||||
_postprocess_subplot(subplt, d)
|
||||
|
||||
subplt
|
||||
end
|
||||
|
||||
|
||||
function handleLinkInner(plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
if isx
|
||||
plot!(plt, xticks=zeros(0), xlabel="")
|
||||
else
|
||||
@@ -555,25 +765,35 @@ function handleLinkInner(plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
end
|
||||
end
|
||||
|
||||
function expandLimits!(lims, plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]()
|
||||
expandLimits!(lims, pltlims)
|
||||
_expand_limits(lims, pltlims)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
const _pyplot_legend_pos = Dict(
|
||||
:right => "right",
|
||||
:left => "center left",
|
||||
:top => "upper center",
|
||||
:bottom => "lower center"
|
||||
)
|
||||
|
||||
# function addPyPlotLegend(plt::Plot)
|
||||
function addPyPlotLegend(plt::Plot, ax)
|
||||
if plt.initargs[:legend]
|
||||
leg = plt.plotargs[:legend]
|
||||
if leg != :none
|
||||
# gotta do this to ensure both axes are included
|
||||
args = filter(x -> !(x[:linetype] in (:hist,:hexbin,:heatmap,:hline,:vline,:contour)), plt.seriesargs)
|
||||
args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:heatmap,:hline,:vline,:contour, :surface, :wireframe, :path3d, :scatter3d)), plt.seriesargs)
|
||||
args = filter(x -> x[:label] != "", args)
|
||||
if length(args) > 0
|
||||
ax[:legend]([d[:serieshandle] for d in args],
|
||||
leg = ax[:legend]([d[:serieshandle] for d in args],
|
||||
[d[:label] for d in args],
|
||||
loc="best",
|
||||
fontsize = plt.initargs[:legendfont].pointsize
|
||||
loc = get(_pyplot_legend_pos, leg, "best"),
|
||||
fontsize = plt.plotargs[:legendfont].pointsize
|
||||
# framealpha = 0.6
|
||||
)
|
||||
leg[:set_zorder](1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -581,7 +801,7 @@ end
|
||||
function finalizePlot(plt::Plot{PyPlotPackage})
|
||||
ax = getLeftAxis(plt)
|
||||
addPyPlotLegend(plt, ax)
|
||||
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
|
||||
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
|
||||
PyPlot.draw()
|
||||
end
|
||||
|
||||
@@ -590,8 +810,9 @@ function finalizePlot(subplt::Subplot{PyPlotPackage})
|
||||
for (i,plt) in enumerate(subplt.plts)
|
||||
ax = getLeftAxis(plt)
|
||||
addPyPlotLegend(plt, ax)
|
||||
updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color]))
|
||||
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
|
||||
end
|
||||
# fig[:tight_layout]()
|
||||
PyPlot.draw()
|
||||
end
|
||||
|
||||
@@ -648,7 +869,7 @@ const _pyplot_mimeformats = @compat Dict(
|
||||
"application/pdf" => "pdf",
|
||||
"image/png" => "png",
|
||||
"application/postscript" => "ps",
|
||||
# "image/svg+xml" => "svg"
|
||||
"image/svg+xml" => "svg"
|
||||
)
|
||||
|
||||
|
||||
@@ -658,14 +879,16 @@ for (mime, fmt) in _pyplot_mimeformats
|
||||
fig = getfig(plt.o)
|
||||
fig.o["canvas"][:print_figure](io,
|
||||
format=$fmt,
|
||||
bbox_inches="tight",
|
||||
# bbox_inches = "tight",
|
||||
# figsize = map(px2inch, plt.plotargs[:size]),
|
||||
facecolor = fig.o["get_facecolor"](),
|
||||
edgecolor = "none"
|
||||
# edgecolor = fig.o["get_edgecolor"]()
|
||||
edgecolor = "none",
|
||||
dpi = DPI
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotPackage})
|
||||
# finalizePlot(subplt)
|
||||
# writemime(io, m, getfig(subplt.o))
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
function _initialize_backend(::QwtPackage; kw...)
|
||||
@eval begin
|
||||
warn("Qwt is no longer supported... many features will likely be broken.")
|
||||
import Qwt
|
||||
export Qwt
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
@@ -70,7 +77,7 @@ function adjustQwtKeywords(plt::Plot{QwtPackage}, iscreating::Bool; kw...)
|
||||
d
|
||||
end
|
||||
|
||||
function plot(pkg::QwtPackage; kw...)
|
||||
function _create_plot(pkg::QwtPackage; kw...)
|
||||
d = Dict(kw)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot")
|
||||
@@ -79,7 +86,7 @@ function plot(pkg::QwtPackage; kw...)
|
||||
plt
|
||||
end
|
||||
|
||||
function plot!(::QwtPackage, plt::Plot; kw...)
|
||||
function _add_series(::QwtPackage, plt::Plot; kw...)
|
||||
d = adjustQwtKeywords(plt, false; kw...)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot!")
|
||||
@@ -131,7 +138,7 @@ function updateLimsAndTicks(plt::Plot{QwtPackage}, d::Dict, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
function updatePlotItems(plt::Plot{QwtPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{QwtPackage}, d::Dict)
|
||||
haskey(d, :title) && Qwt.title(plt.o, d[:title])
|
||||
haskey(d, :xlabel) && Qwt.xlabel(plt.o, d[:xlabel])
|
||||
haskey(d, :ylabel) && Qwt.ylabel(plt.o, d[:ylabel])
|
||||
@@ -139,7 +146,7 @@ function updatePlotItems(plt::Plot{QwtPackage}, d::Dict)
|
||||
updateLimsAndTicks(plt, d, false)
|
||||
end
|
||||
|
||||
function updatePositionAndSize(plt::PlottingObject{QwtPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::PlottingObject{QwtPackage}, d::Dict)
|
||||
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
|
||||
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
|
||||
end
|
||||
@@ -154,7 +161,7 @@ function addLineMarker(plt::Plot{QwtPackage}, d::Dict)
|
||||
ishorizontal = (d[:linetype] == :hline)
|
||||
marker[:setLineStyle](ishorizontal ? 1 : 2)
|
||||
marker[ishorizontal ? :setYValue : :setXValue](yi)
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(d[:color]))
|
||||
qcolor = Qwt.convertRGBToQColor(getColor(d[:linecolor]))
|
||||
linestyle = plt.o.widget[:getLineStyle](string(d[:linestyle]))
|
||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, d[:linewidth], linestyle))
|
||||
marker[:attach](plt.o.widget)
|
||||
@@ -182,7 +189,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function addAnnotations{X,Y,V}(plt::Plot{QwtPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{QwtPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createQwtAnnotation(plt, ann...)
|
||||
end
|
||||
@@ -211,7 +218,7 @@ end
|
||||
# -------------------------------
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{QwtPackage}, isbefore::Bool)
|
||||
isbefore && return false
|
||||
i = 0
|
||||
rows = Any[]
|
||||
@@ -228,23 +235,19 @@ function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool)
|
||||
# i += rowcnt
|
||||
# end
|
||||
subplt.o = Qwt.vsplitter(rows...)
|
||||
# Qwt.resizewidget(subplt.o, getinitargs(subplt,1)[:size]...)
|
||||
# Qwt.resizewidget(subplt.o, getplotargs(subplt,1)[:size]...)
|
||||
# Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
|
||||
true
|
||||
end
|
||||
|
||||
function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool)
|
||||
warn("handleLinkInner isn't implemented for qwt")
|
||||
end
|
||||
|
||||
function expandLimits!(lims, plt::Plot{QwtPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{QwtPackage}, isx::Bool)
|
||||
for series in plt.o.lines
|
||||
expandLimits!(lims, isx ? series.x : series.y)
|
||||
_expand_limits(lims, isx ? series.x : series.y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{QwtPackage}, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
@@ -274,10 +277,6 @@ function Base.display(::PlotsDisplay, subplt::Subplot{QwtPackage})
|
||||
for plt in subplt.plts
|
||||
Qwt.refresh(plt.o)
|
||||
end
|
||||
# iargs = getinitargs(subplt,1)
|
||||
# # iargs = subplt.initargs
|
||||
# Qwt.resizewidget(subplt.o, iargs[:size]...)
|
||||
# Qwt.movewidget(subplt.o, iargs[:pos]...)
|
||||
Qwt.showwidget(subplt.o)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,26 +1,51 @@
|
||||
|
||||
supportedAxes(::PlottingPackage) = [:left]
|
||||
supportedTypes(::PlottingPackage) = []
|
||||
supportedStyles(::PlottingPackage) = [:solid]
|
||||
supportedMarkers(::PlottingPackage) = [:none]
|
||||
supportedScales(::PlottingPackage) = [:identity]
|
||||
subplotSupported(::PlottingPackage) = false
|
||||
stringsSupported(::PlottingPackage) = false
|
||||
|
||||
supportedAxes() = supportedAxes(backend())
|
||||
supportedTypes() = supportedTypes(backend())
|
||||
supportedStyles() = supportedStyles(backend())
|
||||
supportedMarkers() = supportedMarkers(backend())
|
||||
supportedScales() = supportedScales(backend())
|
||||
subplotSupported() = subplotSupported(backend())
|
||||
stringsSupported() = stringsSupported(backend())
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
supportedArgs(::GadflyPackage) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:fillopacity,
|
||||
:fillalpha,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:colorbar,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:lineopacity,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeropacity,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokealpha,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -45,18 +70,22 @@ supportedArgs(::GadflyPackage) = [
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:zcolor,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
:surface,
|
||||
:nlevels,
|
||||
# :surface,
|
||||
:levels,
|
||||
]
|
||||
supportedAxes(::GadflyPackage) = [:auto, :left]
|
||||
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :heatmap, :hexbin, :hist, :bar,
|
||||
:hline, :vline, :contour]
|
||||
supportedStyles(::GadflyPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GadflyPackage) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GadflyPackage) = [:identity, :log, :log2, :log10, :asinh, :sqrt]
|
||||
supportedScales(::GadflyPackage) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GadflyPackage) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -68,6 +97,7 @@ supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
|
||||
supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
|
||||
supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
|
||||
supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
|
||||
subplotSupported(::ImmersePackage) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -77,7 +107,7 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:annotation,
|
||||
:axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -86,12 +116,17 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:colorbar,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokealpha,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -117,22 +152,26 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:zcolor, # only supported for scatter/scatter3d
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
:surface,
|
||||
:nlevels,
|
||||
:fillopacity,
|
||||
:lineopacity,
|
||||
:markeropacity,
|
||||
# :surface,
|
||||
:levels,
|
||||
:fillalpha,
|
||||
:linealpha,
|
||||
:markeralpha,
|
||||
:overwrite_figure,
|
||||
]
|
||||
supportedAxes(::PyPlotPackage) = _allAxes
|
||||
supportedTypes(::PyPlotPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedTypes(::PyPlotPackage) = [:none, :line, :path, :steppre, :steppost, #:sticks,
|
||||
:scatter, :heatmap, :hexbin, :hist, :density, :bar,
|
||||
:hline, :vline, :contour, :path3d, :scatter3d, :surface, :wireframe]
|
||||
supportedStyles(::PyPlotPackage) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
# supportedMarkers(::PyPlotPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :hexagon]
|
||||
supportedMarkers(::PyPlotPackage) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::PyPlotPackage) = [:identity, :log, :log2, :log10]
|
||||
supportedScales(::PyPlotPackage) = [:identity, :ln, :log2, :log10]
|
||||
subplotSupported(::PyPlotPackage) = true
|
||||
|
||||
|
||||
@@ -140,12 +179,86 @@ subplotSupported(::PyPlotPackage) = true
|
||||
|
||||
|
||||
|
||||
supportedArgs(::GRPackage) = [
|
||||
:annotation,
|
||||
:axis,
|
||||
:background_color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:colorbar,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
:nr,
|
||||
# :pos,
|
||||
:smooth,
|
||||
# :ribbon,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:windowtitle,
|
||||
:x,
|
||||
:xlabel,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:ylabel,
|
||||
:ylims,
|
||||
:yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:zcolor, # only supported for scatter/scatter3d
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
# :surface,
|
||||
:nlevels,
|
||||
:fillalpha,
|
||||
:linealpha,
|
||||
:markeralpha,
|
||||
]
|
||||
supportedAxes(::GRPackage) = _allAxes
|
||||
supportedTypes(::GRPackage) = [:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :heatmap, :hexbin, :hist, :density, :bar,
|
||||
:hline, :vline, :contour, :path3d, :scatter3d, :surface,
|
||||
:wireframe, :ohlc, :pie]
|
||||
supportedStyles(::GRPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GRPackage) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GRPackage) = [:identity, :log10]
|
||||
subplotSupported(::GRPackage) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::QwtPackage) = [
|
||||
:annotation,
|
||||
# :args,
|
||||
:axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -162,6 +275,9 @@ supportedArgs(::QwtPackage) = [
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -191,6 +307,7 @@ supportedArgs(::QwtPackage) = [
|
||||
supportedTypes(::QwtPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedMarkers(::QwtPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supportedScales(::QwtPackage) = [:identity, :log10]
|
||||
subplotSupported(::QwtPackage) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -201,7 +318,7 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color,
|
||||
# :linecolor,
|
||||
# :fill,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
@@ -216,6 +333,9 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
:markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:nbins,
|
||||
# :nc,
|
||||
@@ -243,10 +363,11 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::UnicodePlotsPackage) = [:auto, :left]
|
||||
supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedStyles(::UnicodePlotsPackage) = [:auto, :solid]
|
||||
supportedMarkers(::UnicodePlotsPackage) = [:none, :auto, :ellipse]
|
||||
supportedScales(::UnicodePlotsPackage) = [:identity]
|
||||
subplotSupported(::UnicodePlotsPackage) = true
|
||||
|
||||
|
||||
|
||||
@@ -259,7 +380,7 @@ supportedArgs(::WinstonPackage) = [
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -276,6 +397,9 @@ supportedArgs(::WinstonPackage) = [
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:nbins,
|
||||
# :nc,
|
||||
@@ -310,4 +434,340 @@ supportedScales(::WinstonPackage) = [:identity, :log10]
|
||||
subplotSupported(::WinstonPackage) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::BokehPackage) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:linecolor,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
# :linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :nbins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
:size,
|
||||
:title,
|
||||
# :windowtitle,
|
||||
:x,
|
||||
# :xlabel,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
# :ylabel,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface,
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::BokehPackage) = [:auto, :left]
|
||||
supportedTypes(::BokehPackage) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::BokehPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::BokehPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::BokehPackage) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::BokehPackage) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PlotlyPackage) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:fillalpha,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:linecolor,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
:nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:windowtitle,
|
||||
:x,
|
||||
:xlabel,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:ylabel,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:zcolor,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
:levels,
|
||||
]
|
||||
supportedAxes(::PlotlyPackage) = [:auto, :left]
|
||||
supportedTypes(::PlotlyPackage) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:heatmap, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyPackage) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyPackage) = true
|
||||
stringsSupported(::PlotlyPackage) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PlotlyJSPackage) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:fillalpha,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:linecolor,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
:nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:windowtitle,
|
||||
:x,
|
||||
:xlabel,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:ylabel,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:zcolor,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
:levels,
|
||||
]
|
||||
supportedAxes(::PlotlyJSPackage) = [:auto, :left]
|
||||
supportedTypes(::PlotlyJSPackage) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:heatmap, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyJSPackage) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyJSPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyJSPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyJSPackage) = true
|
||||
stringsSupported(::PlotlyJSPackage) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::GLVisualizePackage) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
# :group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
# :linecolor,
|
||||
# :linestyle,
|
||||
# :linetype,
|
||||
# :linewidth,
|
||||
# :linealpha,
|
||||
# :markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :nbins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
# :size,
|
||||
# :title,
|
||||
# :windowtitle,
|
||||
# :x,
|
||||
# :xlabel,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
# :y,
|
||||
# :ylabel,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::GLVisualizePackage) = [:auto, :left]
|
||||
supportedTypes(::GLVisualizePackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::GLVisualizePackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GLVisualizePackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::GLVisualizePackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GLVisualizePackage) = false
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PGFPlotsPackage) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
# :group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
# :linecolor,
|
||||
# :linestyle,
|
||||
# :linetype,
|
||||
# :linewidth,
|
||||
# :linealpha,
|
||||
# :markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :nbins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
# :size,
|
||||
# :title,
|
||||
# :windowtitle,
|
||||
# :x,
|
||||
# :xlabel,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
# :y,
|
||||
# :ylabel,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::PGFPlotsPackage) = [:auto, :left]
|
||||
supportedTypes(::PGFPlotsPackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::PGFPlotsPackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::PGFPlotsPackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PGFPlotsPackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PGFPlotsPackage) = false
|
||||
|
||||
|
||||
@@ -3,92 +3,77 @@
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# supportedArgs(::[PkgName]Package) = _allArgs
|
||||
supportedArgs(::[PkgName]Package) = [
|
||||
:annotation,
|
||||
# :args,
|
||||
:axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:foreground_color,
|
||||
:group,
|
||||
# :heatmap_c,
|
||||
# :kwargs,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
:nr,
|
||||
# :pos,
|
||||
:smooth,
|
||||
# :ribbon,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:windowtitle,
|
||||
:x,
|
||||
:xlabel,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:ylabel,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
:yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::[PkgName]Package) = _allAxes
|
||||
supportedTypes(::[PkgName]Package) = _allTypes
|
||||
supportedStyles(::[PkgName]Package) = _allStyles
|
||||
supportedMarkers(::[PkgName]Package) = _allMarkers
|
||||
supportedScales(::[PkgName]Package) = _allScales
|
||||
subplotSupported(::[PkgName]Package) = false
|
||||
function _initialize_backend(::[PkgName]Package; kw...)
|
||||
@eval begin
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
# TODO: other initialization that needs to be eval-ed
|
||||
end
|
||||
# TODO: other initialization
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function plot(pkg::[PkgName]Package; kw...)
|
||||
function _create_plot(pkg::[PkgName]Package; kw...)
|
||||
d = Dict(kw)
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
Plot(o, pkg, 0, d, Dict[])
|
||||
Plot(nothing, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function plot!(::[PkgName]Package, plt::Plot; kw...)
|
||||
function _add_series(::[PkgName]Package, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
# TODO: add one series to the underlying package
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function updatePlotItems(plt::Plot{[PkgName]Package}, d::Dict)
|
||||
function _add_annotations{X,Y,V}(plt::Plot{[PkgName]Package}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function buildSubplotObject!(subplt::Subplot{[PkgName]Package})
|
||||
function _before_update_plot(plt::Plot{[PkgName]Package})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{[PkgName]Package}, d::Dict)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{[PkgName]Package}, d::Dict)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{[PkgName]Package}, i::Int)
|
||||
# TODO: return a tuple of (x, y) vectors
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{[PkgName]Package}, xy::Tuple, i::Integer)
|
||||
# TODO: set the plot data from the (x,y) tuple
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{[PkgName]Package}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{[PkgName]Package}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{[PkgName]Package}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{[PkgName]Package})
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
function _initialize_backend(::UnicodePlotsPackage; kw...)
|
||||
@eval begin
|
||||
import UnicodePlots
|
||||
export UnicodePlots
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
|
||||
@@ -9,13 +16,13 @@ function rebuildUnicodePlot!(plt::Plot)
|
||||
|
||||
# figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
|
||||
sargs = plt.seriesargs
|
||||
iargs = plt.initargs
|
||||
iargs = plt.plotargs
|
||||
|
||||
# get the x/y limits
|
||||
if get(iargs, :xlims, :auto) == :auto
|
||||
xlim = [Inf, -Inf]
|
||||
for d in sargs
|
||||
expandLimits!(xlim, d[:x])
|
||||
_expand_limits(xlim, d[:x])
|
||||
end
|
||||
else
|
||||
xmin, xmax = iargs[:xlims]
|
||||
@@ -25,7 +32,7 @@ function rebuildUnicodePlot!(plt::Plot)
|
||||
if get(iargs, :ylims, :auto) == :auto
|
||||
ylim = [Inf, -Inf]
|
||||
for d in sargs
|
||||
expandLimits!(ylim, d[:y])
|
||||
_expand_limits(ylim, d[:y])
|
||||
end
|
||||
else
|
||||
ymin, ymax = iargs[:ylims]
|
||||
@@ -39,7 +46,7 @@ function rebuildUnicodePlot!(plt::Plot)
|
||||
|
||||
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
|
||||
width, height = iargs[:size]
|
||||
o = UnicodePlots.createPlotWindow(x, y; width = width,
|
||||
o = UnicodePlots.Plot(x, y; width = width,
|
||||
height = height,
|
||||
title = iargs[:title],
|
||||
# labels = iargs[:legend],
|
||||
@@ -52,7 +59,7 @@ function rebuildUnicodePlot!(plt::Plot)
|
||||
|
||||
# now use the ! functions to add to the plot
|
||||
for d in sargs
|
||||
addUnicodeSeries!(o, d, iargs[:legend], xlim, ylim)
|
||||
addUnicodeSeries!(o, d, iargs[:legend] != :none, xlim, ylim)
|
||||
end
|
||||
|
||||
# save the object
|
||||
@@ -91,13 +98,13 @@ function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
|
||||
else
|
||||
error("Linestyle $lt not supported by UnicodePlots")
|
||||
end
|
||||
|
||||
|
||||
# get the series data and label
|
||||
x, y = [collect(float(d[s])) for s in (:x, :y)]
|
||||
label = addlegend ? d[:label] : ""
|
||||
|
||||
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
|
||||
color = d[:color] in UnicodePlots.autoColors ? d[:color] : :auto
|
||||
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
|
||||
|
||||
# add the series
|
||||
func(o, x, y; color = color, name = label, style = stepstyle)
|
||||
@@ -112,18 +119,18 @@ end
|
||||
# -------------------------------
|
||||
|
||||
|
||||
function plot(pkg::UnicodePlotsPackage; kw...)
|
||||
function _create_plot(pkg::UnicodePlotsPackage; kw...)
|
||||
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
|
||||
|
||||
# do we want to give a new default size?
|
||||
if !haskey(plt.initargs, :size) || plt.initargs[:size] == _plotDefaults[:size]
|
||||
plt.initargs[:size] = (60,20)
|
||||
if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == _plotDefaults[:size]
|
||||
plt.plotargs[:size] = (60,20)
|
||||
end
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
function _add_series(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
if d[:linetype] in (:sticks, :bar)
|
||||
d = barHack(; d...)
|
||||
@@ -135,10 +142,10 @@ function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
|
||||
function updatePlotItems(plt::Plot{UnicodePlotsPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{UnicodePlotsPackage}, d::Dict)
|
||||
for k in (:title, :xlabel, :ylabel, :xlims, :ylims)
|
||||
if haskey(d, k)
|
||||
plt.initargs[k] = d[k]
|
||||
plt.plotargs[k] = d[k]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -175,7 +182,7 @@ end
|
||||
|
||||
# we don't do very much for subplots... just stack them vertically
|
||||
|
||||
function buildSubplotObject!(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
|
||||
isbefore && return false
|
||||
true
|
||||
end
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
# NOTE: backend should implement `html_body` and `html_head`
|
||||
|
||||
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
|
||||
|
||||
|
||||
function standalone_html(plt::PlottingObject; title::AbstractString = get(plt.plotargs, :window_title, "Plots.jl"))
|
||||
"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>$title</title>
|
||||
$(html_head(plt))
|
||||
</head>
|
||||
<body>
|
||||
$(html_body(plt))
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
end
|
||||
|
||||
function open_browser_window(filename::AbstractString)
|
||||
@osx_only return run(`open $(filename)`)
|
||||
@linux_only return run(`xdg-open $(filename)`)
|
||||
@windows_only return run(`$(ENV["COMSPEC"]) /c start $(filename)`)
|
||||
warn("Unknown OS... cannot open browser window.")
|
||||
end
|
||||
|
||||
function standalone_html_window(plt::PlottingObject; kw...)
|
||||
html = standalone_html(plt; kw...)
|
||||
# println(html)
|
||||
filename = string(tempname(), ".html")
|
||||
output = open(filename, "w")
|
||||
write(output, html)
|
||||
close(output)
|
||||
open_browser_window(filename)
|
||||
end
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
function _initialize_backend(::WinstonPackage; kw...)
|
||||
@eval begin
|
||||
# ENV["WINSTON_OUTPUT"] = "gtk"
|
||||
warn("Winston is no longer supported... many features will likely be broken.")
|
||||
import Winston, Gtk
|
||||
export Winston, Gtk
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -25,14 +33,14 @@
|
||||
:star5 => "asterisk"
|
||||
)
|
||||
|
||||
function preparePlotUpdate(plt::Plot{WinstonPackage})
|
||||
function _before_add_series(plt::Plot{WinstonPackage})
|
||||
Winston.ghf(plt.o)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function plot(pkg::WinstonPackage; kw...)
|
||||
function _create_plot(pkg::WinstonPackage; kw...)
|
||||
d = Dict(kw)
|
||||
wplt = Winston.FramedPlot(title = d[:title], xlabel = d[:xlabel], ylabel = d[:ylabel])
|
||||
|
||||
@@ -56,7 +64,7 @@ function getWinstonItems(plt::Plot)
|
||||
window, canvas, wplt
|
||||
end
|
||||
|
||||
function plot!(::WinstonPackage, plt::Plot; kw...)
|
||||
function _add_series(::WinstonPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
@@ -68,7 +76,7 @@ function plot!(::WinstonPackage, plt::Plot; kw...)
|
||||
|
||||
|
||||
e = Dict()
|
||||
e[:color] = getColor(d[:color])
|
||||
e[:color] = getColor(d[:linecolor])
|
||||
e[:linewidth] = d[:linewidth]
|
||||
e[:kind] = winston_linestyle[d[:linestyle]]
|
||||
e[:symbolkind] = winston_marker[d[:markershape]]
|
||||
@@ -157,7 +165,7 @@ end
|
||||
:yscale => :ylog,
|
||||
)
|
||||
|
||||
function updatePlotItems(plt::Plot{WinstonPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{WinstonPackage}, d::Dict)
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
for k in (:xlabel, :ylabel, :title, :xlims, :ylims)
|
||||
if haskey(d, k)
|
||||
@@ -182,7 +190,7 @@ function createWinstonAnnotationObject(plt::Plot{WinstonPackage}, x, y, val::@co
|
||||
Winston.text(x, y, val)
|
||||
end
|
||||
|
||||
function addAnnotations{X,Y,V}(plt::Plot{WinstonPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{WinstonPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createWinstonAnnotationObject(plt, ann...)
|
||||
end
|
||||
@@ -191,14 +199,14 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function buildSubplotObject!(subplt::Subplot{WinstonPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{WinstonPackage}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function addWinstonLegend(plt::Plot, wplt)
|
||||
if plt.initargs[:legend]
|
||||
if plt.plotargs[:legend] != :none
|
||||
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
|
||||
end
|
||||
end
|
||||
@@ -219,9 +227,9 @@ function Base.display(::PlotsDisplay, plt::Plot{WinstonPackage})
|
||||
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
|
||||
end
|
||||
# initialize window
|
||||
w,h = plt.initargs[:size]
|
||||
w,h = plt.plotargs[:size]
|
||||
canvas = Gtk.GtkCanvasLeaf()
|
||||
window = Gtk.GtkWindowLeaf(canvas, plt.initargs[:windowtitle], w, h)
|
||||
window = Gtk.GtkWindowLeaf(canvas, plt.plotargs[:windowtitle], w, h)
|
||||
plt.o = (window, canvas, wplt)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,88 +1,4 @@
|
||||
|
||||
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
|
||||
const _masterColorList = [
|
||||
0xFFFFFF,
|
||||
0x000000,
|
||||
0x0000FF,
|
||||
0x00FF00,
|
||||
0xFF0000,
|
||||
0x01FFFE,
|
||||
0xFFA6FE,
|
||||
0xFFDB66,
|
||||
0x006401,
|
||||
0x010067,
|
||||
0x95003A,
|
||||
0x007DB5,
|
||||
0xFF00F6,
|
||||
0xFFEEE8,
|
||||
0x774D00,
|
||||
0x90FB92,
|
||||
0x0076FF,
|
||||
0xD5FF00,
|
||||
0xFF937E,
|
||||
0x6A826C,
|
||||
0xFF029D,
|
||||
0xFE8900,
|
||||
0x7A4782,
|
||||
0x7E2DD2,
|
||||
0x85A900,
|
||||
0xFF0056,
|
||||
0xA42400,
|
||||
0x00AE7E,
|
||||
0x683D3B,
|
||||
0xBDC6FF,
|
||||
0x263400,
|
||||
0xBDD393,
|
||||
0x00B917,
|
||||
0x9E008E,
|
||||
0x001544,
|
||||
0xC28C9F,
|
||||
0xFF74A3,
|
||||
0x01D0FF,
|
||||
0x004754,
|
||||
0xE56FFE,
|
||||
0x788231,
|
||||
0x0E4CA1,
|
||||
0x91D0CB,
|
||||
0xBE9970,
|
||||
0x968AE8,
|
||||
0xBB8800,
|
||||
0x43002C,
|
||||
0xDEFF74,
|
||||
0x00FFC6,
|
||||
0xFFE502,
|
||||
0x620E00,
|
||||
0x008F9C,
|
||||
0x98FF52,
|
||||
0x7544B1,
|
||||
0xB500FF,
|
||||
0x00FF78,
|
||||
0xFF6E41,
|
||||
0x005F39,
|
||||
0x6B6882,
|
||||
0x5FAD4E,
|
||||
0xA75740,
|
||||
0xA5FFD2,
|
||||
0xFFB167,
|
||||
0x009BFF,
|
||||
0xE85EBE,
|
||||
]
|
||||
|
||||
|
||||
function darken(c, v=0.1)
|
||||
rgba = convert(RGBA, c)
|
||||
r = max(0, min(rgba.r - v, 1))
|
||||
g = max(0, min(rgba.g - v, 1))
|
||||
b = max(0, min(rgba.b - v, 1))
|
||||
RGBA(r,g,b,rgba.alpha)
|
||||
end
|
||||
function lighten(c, v=0.3)
|
||||
darken(c, -v)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
|
||||
abstract ColorScheme
|
||||
|
||||
getColor(scheme::ColorScheme) = getColor(scheme, 1)
|
||||
@@ -119,6 +35,19 @@ getColor(c) = convertColor(c)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
function darken(c, v=0.1)
|
||||
rgba = convert(RGBA, c)
|
||||
r = max(0, min(rgba.r - v, 1))
|
||||
g = max(0, min(rgba.g - v, 1))
|
||||
b = max(0, min(rgba.b - v, 1))
|
||||
RGBA(r,g,b,rgba.alpha)
|
||||
end
|
||||
function lighten(c, v=0.3)
|
||||
darken(c, -v)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
const _rainbowColors = [colorant"blue", colorant"purple", colorant"green", colorant"orange", colorant"red"]
|
||||
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
|
||||
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
|
||||
@@ -146,28 +75,35 @@ immutable ColorGradient <: ColorScheme
|
||||
colors::Vector{Colorant}
|
||||
values::Vector{Float64}
|
||||
|
||||
function ColorGradient{T<:Colorant,S<:Real}(cs::AVec{T}, vals::AVec{S} = 0:1; alpha = nothing)
|
||||
function ColorGradient{T<:Colorant,S<:Real}(cs::AVec{T}, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
|
||||
if length(cs) == length(vals)
|
||||
return new(convertColor(cs,alpha), collect(vals))
|
||||
end
|
||||
|
||||
# otherwise interpolate evenly between the minval and maxval
|
||||
minval, maxval = minimum(vals), maximum(vals)
|
||||
vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
|
||||
new(convertColor(cs,alpha), vs)
|
||||
# # otherwise interpolate evenly between the minval and maxval
|
||||
# minval, maxval = minimum(vals), maximum(vals)
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
|
||||
# new(convertColor(cs,alpha), vs)
|
||||
|
||||
# interpolate the colors for each value
|
||||
vals = merge(linspace(0, 1, length(cs)), vals)
|
||||
grad = ColorGradient(cs)
|
||||
cs = [getColorZ(grad, z) for z in linspace(0, 1, length(vals))]
|
||||
new(convertColor(cs, alpha), vals)
|
||||
end
|
||||
end
|
||||
|
||||
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
|
||||
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:1; kw...)
|
||||
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
|
||||
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
|
||||
|
||||
# if we passed in the right number of values, create the gradient directly
|
||||
cs = _gradients[s]
|
||||
if vals == 0:0
|
||||
vals = linspace(0, 1, length(cs))
|
||||
end
|
||||
ColorGradient(cs, vals; kw...)
|
||||
end
|
||||
|
||||
function ColorGradient{T<:Real}(cs::AVec{Symbol}, vals::AVec{T} = 0:1; kw...)
|
||||
function ColorGradient{T<:Real}(cs::AVec{Symbol}, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
|
||||
ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
end
|
||||
|
||||
@@ -286,6 +222,16 @@ function convertHexToRGB(h::Unsigned)
|
||||
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
|
||||
end
|
||||
|
||||
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
|
||||
const _masterColorList = [
|
||||
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
|
||||
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
|
||||
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
|
||||
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
|
||||
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
|
||||
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
|
||||
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
|
||||
]
|
||||
const _allColors = map(convertHexToRGB, _masterColorList)
|
||||
const _darkColors = filter(isdark, _allColors)
|
||||
const _lightColors = filter(islight, _allColors)
|
||||
@@ -347,6 +293,10 @@ function get_color_palette(palette, bgcolor::@compat(Union{Colorant,ColorWrapper
|
||||
RGBA[getColorZ(grad, z) for z in zrng]
|
||||
end
|
||||
|
||||
function get_color_palette(palette::Vector{RGBA}, bgcolor::@compat(Union{Colorant,ColorWrapper}), numcolors::Integer)
|
||||
palette
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -382,7 +332,21 @@ end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
# TODO: try to use the algorithms from https://github.com/timothyrenner/ColorBrewer.jl
|
||||
|
||||
make255(x) = round(Int, 255 * x)
|
||||
|
||||
function webcolor(c::Color)
|
||||
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
|
||||
end
|
||||
function webcolor(c::TransparentColor)
|
||||
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
|
||||
end
|
||||
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
|
||||
webcolor(c) = webcolor(convertColor(c))
|
||||
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
# TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function?
|
||||
|
||||
# function getBackgroundRGBColor(c, d::Dict)
|
||||
@@ -415,10 +379,10 @@ function handlePlotColors(::PlottingPackage, d::Dict)
|
||||
end
|
||||
|
||||
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
|
||||
function getSeriesRGBColor(c, initargs::Dict, n::Int)
|
||||
function getSeriesRGBColor(c, plotargs::Dict, n::Int)
|
||||
|
||||
if c == :auto
|
||||
c = autopick(initargs[:color_palette], n)
|
||||
c = autopick(plotargs[:color_palette], n)
|
||||
end
|
||||
|
||||
# c should now be a subtype of ColorScheme
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
|
||||
immutable Shape
|
||||
vertices::AVec
|
||||
end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
|
||||
end
|
||||
|
||||
"interleave 2 vectors into each other (like a zipper's teeth)"
|
||||
function weave(x,y; ordering = Vector[x,y])
|
||||
ret = eltype(x)[]
|
||||
done = false
|
||||
while !done
|
||||
for o in ordering
|
||||
try
|
||||
push!(ret, shift!(o))
|
||||
end
|
||||
# try
|
||||
# push!(ret, shift!(y))
|
||||
# end
|
||||
end
|
||||
done = isempty(x) && isempty(y)
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
|
||||
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
|
||||
function makestar(n; offset = -0.5, radius = 1.0)
|
||||
z1 = offset * π
|
||||
z2 = z1 + π / (n)
|
||||
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
|
||||
Shape(weave(outercircle, innercircle)[1:end-2])
|
||||
end
|
||||
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
|
||||
end
|
||||
|
||||
|
||||
function makecross(; offset = -0.5, radius = 1.0)
|
||||
z2 = offset * π
|
||||
z1 = z2 - π/8
|
||||
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
|
||||
Shape(weave(outercircle, innercircle,
|
||||
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
|
||||
end
|
||||
|
||||
|
||||
const _shapes = @compat Dict(
|
||||
:ellipse => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3),
|
||||
:dtriangle => makeshape(3, offset=0.5),
|
||||
:pentagon => makeshape(5),
|
||||
:hexagon => makeshape(6),
|
||||
:heptagon => makeshape(7),
|
||||
:octagon => makeshape(8),
|
||||
:cross => makecross(offset=-0.25),
|
||||
:xcross => makecross(),
|
||||
:vline => Shape([(0,1),(0,-1)]),
|
||||
:hline => Shape([(1,0),(-1,0)]),
|
||||
)
|
||||
|
||||
for n in [4,5,6,7,8]
|
||||
_shapes[symbol("star$n")] = makestar(n)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
immutable Font
|
||||
family::AbstractString
|
||||
pointsize::Int
|
||||
halign::Symbol
|
||||
valign::Symbol
|
||||
rotation::Float64
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
"Create a Font from a list of unordered features"
|
||||
function font(args...)
|
||||
|
||||
# defaults
|
||||
family = "Helvetica"
|
||||
pointsize = 14
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
rotation = 0.0
|
||||
color = colorant"black"
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if arg == :center
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
halign = arg
|
||||
elseif arg in (:vcenter, :top, :bottom)
|
||||
valign = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: @compat Union{Symbol,AbstractString}
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
catch
|
||||
family = string(arg)
|
||||
end
|
||||
elseif typeof(arg) <: Integer
|
||||
pointsize = arg
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
|
||||
"Wrap a string with font info"
|
||||
immutable PlotText
|
||||
str::@compat(AbstractString)
|
||||
font::Font
|
||||
end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
immutable Stroke
|
||||
width
|
||||
color
|
||||
alpha
|
||||
style
|
||||
end
|
||||
|
||||
function stroke(args...; alpha = nothing)
|
||||
# defaults
|
||||
# width = 1
|
||||
# color = colorant"black"
|
||||
# style = :solid
|
||||
width = nothing
|
||||
color = nothing
|
||||
style = nothing
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
# if arg in _allStyles
|
||||
if allStyles(arg)
|
||||
style = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: @compat Union{Symbol,AbstractString}
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
end
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
|
||||
elseif allAlphas(arg)
|
||||
alpha = arg
|
||||
# elseif typeof(arg) <: Real
|
||||
elseif allReals(arg)
|
||||
width = arg
|
||||
else
|
||||
warn("Unused stroke arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Stroke(width, color, alpha, style)
|
||||
end
|
||||
|
||||
|
||||
immutable Brush
|
||||
size # fillrange, markersize, or any other sizey attribute
|
||||
color
|
||||
alpha
|
||||
end
|
||||
|
||||
function brush(args...; alpha = nothing)
|
||||
# defaults
|
||||
# sz = 1
|
||||
# color = colorant"black"
|
||||
size = nothing
|
||||
color = nothing
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if T <: Colorant
|
||||
color = arg
|
||||
elseif T <: @compat Union{Symbol,AbstractString}
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
end
|
||||
# elseif trueOrAllTrue(a -> typeof(a) <: Real && a > 0 && a < 1, arg)
|
||||
elseif allAlphas(arg)
|
||||
alpha = arg
|
||||
# elseif typeof(arg) <: Real
|
||||
elseif allReals(arg)
|
||||
size = arg
|
||||
else
|
||||
warn("Unused brush arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Brush(size, color, alpha)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"type which represents z-values for colors and sizes (and anything else that might come up)"
|
||||
immutable ZValues
|
||||
values::Vector{Float64}
|
||||
zrange::Tuple{Float64,Float64}
|
||||
end
|
||||
|
||||
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (minimum(values), maximum(values)))
|
||||
ZValues(collect(float(values)), map(Float64, zrange))
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
"represents a contour or surface mesh"
|
||||
immutable Surface{M<:AMat}
|
||||
# x::AVec
|
||||
# y::AVec
|
||||
surf::M
|
||||
end
|
||||
|
||||
Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for xi in x, yi in y])
|
||||
|
||||
Base.Array(surf::Surface) = surf.surf
|
||||
|
||||
for f in (:length, :size)
|
||||
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
|
||||
end
|
||||
Base.copy(surf::Surface) = Surface(copy(surf.surf))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type OHLC{T<:Real}
|
||||
open::T
|
||||
high::T
|
||||
low::T
|
||||
close::T
|
||||
end
|
||||
|
||||
|
||||
# @require FixedSizeArrays begin
|
||||
|
||||
export
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
curve_points,
|
||||
directed_curve
|
||||
|
||||
typealias P2 FixedSizeArrays.Vec{2,Float64}
|
||||
typealias P3 FixedSizeArrays.Vec{3,Float64}
|
||||
|
||||
type BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
|
||||
function Base.call(bc::BezierCurve, t::Real)
|
||||
p = zero(P2)
|
||||
n = length(bc.control_points)-1
|
||||
for i in 0:n
|
||||
p += bc.control_points[i+1] * binomial(n, i) * (1-t)^(n-i) * t^i
|
||||
end
|
||||
p
|
||||
end
|
||||
|
||||
Base.mean(x::Real, y::Real) = 0.5*(x+y)
|
||||
Base.mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps)
|
||||
|
||||
curve_points(curve::BezierCurve, n::Integer = 30; range = [0,1]) = map(curve, linspace(range..., n))
|
||||
|
||||
# build a BezierCurve which leaves point p vertically upwards and arrives point q vertically upwards.
|
||||
# may create a loop if necessary. Assumes the view is [0,1]
|
||||
function directed_curve(p::P2, q::P2; xview = 0:1, yview = 0:1)
|
||||
mn = mean(p, q)
|
||||
diff = q - p
|
||||
|
||||
minx, maxx = minimum(xview), maximum(xview)
|
||||
miny, maxy = minimum(yview), maximum(yview)
|
||||
diffpct = P2(diff[1] / (maxx - minx),
|
||||
diff[2] / (maxy - miny))
|
||||
|
||||
# these points give the initial/final "rise"
|
||||
# vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0)))
|
||||
vertical_offset = P2(0, max(0.15, 0.5norm(diff)))
|
||||
upper_control = p + vertical_offset
|
||||
lower_control = q - vertical_offset
|
||||
|
||||
# try to figure out when to loop around vs just connecting straight
|
||||
# TODO: choose loop direction based on sign of p[1]??
|
||||
# x_close_together = abs(diffpct[1]) <= 0.05
|
||||
p_is_higher = diff[2] <= 0
|
||||
inside_control_points = if p_is_higher
|
||||
# add curve points which will create a loop
|
||||
sgn = mn[1] < 0.5 * (maxx + minx) ? -1 : 1
|
||||
inside_offset = P2(0.3 * (maxx - minx), 0)
|
||||
additional_offset = P2(sgn * diff[1], 0) # make it even loopier
|
||||
[upper_control + sgn * (inside_offset + max(0, additional_offset)),
|
||||
lower_control + sgn * (inside_offset + max(0, -additional_offset))]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
BezierCurve([p, upper_control, inside_control_points..., lower_control, q])
|
||||
end
|
||||
|
||||
# end
|
||||
@@ -37,6 +37,15 @@ end
|
||||
ps(fn::@compat(AbstractString)) = ps(current(), fn)
|
||||
|
||||
|
||||
function tex(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "tex")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("application/x-tex"), plt)
|
||||
close(io)
|
||||
end
|
||||
tex(fn::@compat(AbstractString)) = tex(current(), fn)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -45,6 +54,7 @@ ps(fn::@compat(AbstractString)) = ps(current(), fn)
|
||||
"svg" => svg,
|
||||
"pdf" => pdf,
|
||||
"ps" => ps,
|
||||
"tex" => tex,
|
||||
)
|
||||
|
||||
function getExtension(fn::@compat(AbstractString))
|
||||
@@ -102,3 +112,8 @@ gui(plt::PlottingObject = current()) = display(PlotsDisplay(), plt)
|
||||
|
||||
# override the REPL display to open a gui window
|
||||
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::PlottingObject) = gui(plt)
|
||||
|
||||
# a backup for html... passes to svg
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject)
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ Base.print(io::IO, plt::Plot) = print(io, string(plt))
|
||||
Base.show(io::IO, plt::Plot) = print(io, string(plt))
|
||||
|
||||
getplot(plt::Plot) = plt
|
||||
getinitargs(plt::Plot, idx::Int = 1) = plt.initargs
|
||||
getplotargs(plt::Plot, idx::Int = 1) = plt.plotargs
|
||||
convertSeriesIndex(plt::Plot, n::Int) = n
|
||||
|
||||
# ---------------------------------------------------------
|
||||
@@ -48,9 +48,9 @@ function plot(args...; kw...)
|
||||
preprocessArgs!(d)
|
||||
dumpdict(d, "After plot preprocessing")
|
||||
|
||||
plotargs = getPlotArgs(pkg, d, 1)
|
||||
plotargs = merge(d, getPlotArgs(pkg, d, 1))
|
||||
dumpdict(plotargs, "Plot args")
|
||||
plt = plot(pkg; plotargs...) # create a new, blank plot
|
||||
plt = _create_plot(pkg; plotargs...) # create a new, blank plot
|
||||
|
||||
delete!(d, :background_color)
|
||||
plot!(plt, args...; d...) # add to it
|
||||
@@ -79,6 +79,9 @@ function plot!(plt::Plot, args...; kw...)
|
||||
d = Dict(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
args = _apply_recipe(d, args...; kw...)
|
||||
|
||||
dumpdict(d, "After plot! preprocessing")
|
||||
|
||||
warnOnUnsupportedArgs(plt.backend, d)
|
||||
@@ -87,22 +90,24 @@ function plot!(plt::Plot, args...; kw...)
|
||||
groupargs = get(d, :group, nothing) == nothing ? [] : [extractGroupArgs(d[:group], args...)]
|
||||
|
||||
# just in case the backend needs to set up the plot (make it current or something)
|
||||
preparePlotUpdate(plt)
|
||||
_before_add_series(plt)
|
||||
|
||||
# get the list of dictionaries, one per series
|
||||
kwList, xmeta, ymeta = createKWargsList(plt, groupargs..., args...; d...)
|
||||
|
||||
seriesArgList, xmeta, ymeta = createKWargsList(plt, groupargs..., args...; d...)
|
||||
|
||||
# if we were able to extract guide information from the series inputs, then update the plot
|
||||
# @show xmeta, ymeta
|
||||
updateDictWithMeta(d, plt.initargs, xmeta, true)
|
||||
updateDictWithMeta(d, plt.initargs, ymeta, false)
|
||||
updateDictWithMeta(d, plt.plotargs, xmeta, true)
|
||||
updateDictWithMeta(d, plt.plotargs, ymeta, false)
|
||||
|
||||
# now we can plot the series
|
||||
for (i,di) in enumerate(kwList)
|
||||
for (i,di) in enumerate(seriesArgList)
|
||||
plt.n += 1
|
||||
|
||||
setTicksFromStringVector(d, di, :x, :xticks)
|
||||
setTicksFromStringVector(d, di, :y, :yticks)
|
||||
if !stringsSupported()
|
||||
setTicksFromStringVector(d, di, :x, :xticks)
|
||||
setTicksFromStringVector(d, di, :y, :yticks)
|
||||
end
|
||||
|
||||
# remove plot args
|
||||
for k in keys(_plotDefaults)
|
||||
@@ -111,22 +116,22 @@ function plot!(plt::Plot, args...; kw...)
|
||||
|
||||
dumpdict(di, "Series $i")
|
||||
|
||||
plot!(plt.backend, plt; di...)
|
||||
_add_series(plt.backend, plt; di...)
|
||||
end
|
||||
|
||||
addAnnotations(plt, d)
|
||||
_add_annotations(plt, d)
|
||||
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.initargs, d)
|
||||
dumpdict(plt.initargs, "Updating plot items")
|
||||
updatePlotItems(plt, plt.initargs)
|
||||
merge!(plt.plotargs, d)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
|
||||
updatePositionAndSize(plt, d)
|
||||
_update_plot_pos_size(plt, d)
|
||||
|
||||
current(plt)
|
||||
|
||||
@@ -163,37 +168,57 @@ end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
preparePlotUpdate(plt::Plot) = nothing
|
||||
_before_add_series(plt::Plot) = nothing
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# should we update the x/y label given the meta info during input slicing?
|
||||
function updateDictWithMeta(d::Dict, initargs::Dict, meta::Symbol, isx::Bool)
|
||||
function updateDictWithMeta(d::Dict, plotargs::Dict, meta::Symbol, isx::Bool)
|
||||
lsym = isx ? :xlabel : :ylabel
|
||||
if initargs[lsym] == default(lsym)
|
||||
if plotargs[lsym] == default(lsym)
|
||||
d[lsym] = string(meta)
|
||||
end
|
||||
end
|
||||
updateDictWithMeta(d::Dict, initargs::Dict, meta, isx::Bool) = nothing
|
||||
updateDictWithMeta(d::Dict, plotargs::Dict, meta, isx::Bool) = nothing
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
annotations(::@compat(Void)) = []
|
||||
annotations{X,Y,V}(v::AVec{@compat(Tuple{X,Y,V})}) = v
|
||||
annotations{X,Y,V}(t::@compat(Tuple{X,Y,V})) = [t]
|
||||
annotations(v::AVec{PlotText}) = v
|
||||
annotations(v::AVec) = map(PlotText, v)
|
||||
annotations(anns) = error("Expecting a tuple (or vector of tuples) for annotations: ",
|
||||
"(x, y, annotation)\n got: $(typeof(anns))")
|
||||
|
||||
function addAnnotations(plt::Plot, d::Dict)
|
||||
function _add_annotations(plt::Plot, d::Dict)
|
||||
anns = annotations(get(d, :annotation, nothing))
|
||||
if !isempty(anns)
|
||||
addAnnotations(plt, anns)
|
||||
|
||||
# if we just have a list of PlotText objects, then create (x,y,text) tuples
|
||||
if typeof(anns) <: AVec{PlotText}
|
||||
x, y = plt[plt.n]
|
||||
anns = Tuple{Float64,Float64,PlotText}[(x[i], y[i], t) for (i,t) in enumerate(anns)]
|
||||
end
|
||||
|
||||
_add_annotations(plt, anns)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function Base.copy(plt::Plot)
|
||||
backend(plt.backend)
|
||||
plt2 = plot(; plt.plotargs...)
|
||||
for sargs in plt.seriesargs
|
||||
sargs = filter((k,v) -> haskey(_seriesDefaults,k), sargs)
|
||||
plot!(plt2; sargs...)
|
||||
end
|
||||
plt2
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# create a new "createKWargsList" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
||||
@@ -203,36 +228,59 @@ end
|
||||
|
||||
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
|
||||
|
||||
all3D(d::Dict) = trueOrAllTrue(lt -> lt in (:contour, :surface, :wireframe, :image), get(d, :linetype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::@compat(Void); kw...) = Any[nothing], nothing
|
||||
convertToAnyVector(v::@compat(Void), d::Dict) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer; kw...) = Any[zeros(0) for i in 1:n], nothing
|
||||
convertToAnyVector(n::Integer, d::Dict) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector{T<:Real}(v::AVec{T}; kw...) = Any[v], nothing
|
||||
convertToAnyVector{T<:Real}(v::AVec{T}, d::Dict) = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}; kw...) = Any[v], nothing
|
||||
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::Dict) = Any[v], nothing
|
||||
|
||||
# numeric matrix
|
||||
convertToAnyVector{T<:Real}(v::AMat{T}; kw...) = Any[v[:,i] for i in 1:size(v,2)], nothing
|
||||
function convertToAnyVector{T<:Real}(v::AMat{T}, d::Dict)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function; kw...) = Any[f], nothing
|
||||
convertToAnyVector(f::Function, d::Dict) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::Dict) = Any[s], nothing
|
||||
|
||||
# vector of OHLC
|
||||
convertToAnyVector(v::AVec{OHLC}; kw...) = Any[v], nothing
|
||||
convertToAnyVector(v::AVec{OHLC}, d::Dict) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::Dict) = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
convertToAnyVector(v::AVec; kw...) = Any[vi for vi in v], nothing
|
||||
function convertToAnyVector(v::AVec, d::Dict)
|
||||
if all(x -> typeof(x) <: Real, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# in computeXandY, we take in any of the possible items, convert into proper x/y vectors, then return.
|
||||
# this is also where all the "set x to 1:length(y)" happens, and also where we assert on lengths.
|
||||
computeX(x::@compat(Void), y) = 1:length(y)
|
||||
computeX(x::@compat(Void), y) = 1:size(y,1)
|
||||
computeX(x, y) = copy(x)
|
||||
computeY(x, y::Function) = map(y, x)
|
||||
computeY(x, y) = copy(y)
|
||||
@@ -241,7 +289,7 @@ function computeXandY(x, y)
|
||||
error("If you want to plot the function `$y`, you need to define the x values somehow!")
|
||||
end
|
||||
x, y = computeX(x,y), computeY(x,y)
|
||||
@assert length(x) == length(y)
|
||||
# @assert length(x) == length(y)
|
||||
x, y
|
||||
end
|
||||
|
||||
@@ -251,10 +299,9 @@ end
|
||||
# create n=max(mx,my) series arguments. the shorter list is cycled through
|
||||
# note: everything should flow through this
|
||||
function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
xs, xmeta = convertToAnyVector(x; kw...)
|
||||
ys, ymeta = convertToAnyVector(y; kw...)
|
||||
|
||||
# _debugMode.on && dumpcallstack()
|
||||
kwdict = Dict(kw)
|
||||
xs, xmeta = convertToAnyVector(x, kwdict)
|
||||
ys, ymeta = convertToAnyVector(y, kwdict)
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
@@ -262,7 +309,7 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
for i in 1:max(mx, my)
|
||||
|
||||
# try to set labels using ymeta
|
||||
d = Dict(kw)
|
||||
d = copy(kwdict)
|
||||
if !haskey(d, :label) && ymeta != nothing
|
||||
if isa(ymeta, Symbol)
|
||||
d[:label] = string(ymeta)
|
||||
@@ -275,17 +322,26 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
numUncounted = get(d, :numUncounted, 0)
|
||||
n = plt.n + i + numUncounted
|
||||
dumpdict(d, "before getSeriesArgs")
|
||||
d = getSeriesArgs(plt.backend, getinitargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
|
||||
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
|
||||
dumpdict(d, "after getSeriesArgs")
|
||||
d[:x], d[:y] = computeXandY(xs[mod1(i,mx)], ys[mod1(i,my)])
|
||||
|
||||
lt = d[:linetype]
|
||||
if isa(d[:y], Surface)
|
||||
if lt in (:contour, :surface, :wireframe, :image)
|
||||
z = d[:y]
|
||||
d[:y] = 1:size(z,2)
|
||||
d[lt == :image ? :zcolor : :z] = z
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(d, :idxfilter)
|
||||
d[:x] = d[:x][d[:idxfilter]]
|
||||
d[:y] = d[:y][d[:idxfilter]]
|
||||
end
|
||||
|
||||
# for linetype `line`, need to sort by x values
|
||||
if d[:linetype] == :line
|
||||
if lt == :line
|
||||
# order by x
|
||||
indices = sortperm(d[:x])
|
||||
d[:x] = d[:x][indices]
|
||||
@@ -293,6 +349,14 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
d[:linetype] = :path
|
||||
end
|
||||
|
||||
# map functions to vectors
|
||||
if isa(d[:zcolor], Function)
|
||||
d[:zcolor] = map(d[:zcolor], d[:x])
|
||||
end
|
||||
if isa(d[:fillrange], Function)
|
||||
d[:fillrange] = map(d[:fillrange], d[:x])
|
||||
end
|
||||
|
||||
# cleanup those fields that were used only for generating kw args
|
||||
for k in (:idxfilter, :numUncounted, :dataframe)
|
||||
delete!(d, k)
|
||||
@@ -324,9 +388,23 @@ function createKWargsList(plt::PlottingObject, y; kw...)
|
||||
createKWargsList(plt, nothing, y; kw...)
|
||||
end
|
||||
|
||||
# contours or surfaces... irregular data
|
||||
# 3d line or scatter
|
||||
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, zvec::AVec; kw...)
|
||||
error("TODO: contours or surfaces... irregular data")
|
||||
d = Dict(kw)
|
||||
if !(get(d, :linetype, :none) in _3dTypes)
|
||||
d[:linetype] = :path3d
|
||||
end
|
||||
createKWargsList(plt, x, y; z=zvec, d...)
|
||||
end
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, z::AMat{T}; kw...)
|
||||
d = Dict(kw)
|
||||
if all3D(d)
|
||||
n,m = size(z)
|
||||
createKWargsList(plt, 1:n, 1:m, z; kw...)
|
||||
else
|
||||
createKWargsList(plt, nothing, z; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
# contours or surfaces... function grid
|
||||
@@ -346,13 +424,42 @@ function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec, y::AVec, zmat::
|
||||
@assert x == sort(x)
|
||||
@assert y == sort(y)
|
||||
@assert size(zmat) == (length(x), length(y))
|
||||
surf = Array(Any,1,1)
|
||||
surf[1,1] = convert(Matrix{Float64}, zmat)
|
||||
createKWargsList(plt, x, y; kw..., surface = surf, linetype = :contour)
|
||||
# surf = Surface(convert(Matrix{Float64}, zmat))
|
||||
# surf = Array(Any,1,1)
|
||||
# surf[1,1] = convert(Matrix{Float64}, zmat)
|
||||
d = Dict(kw)
|
||||
d[:z] = Surface(convert(Matrix{Float64}, zmat))
|
||||
if !(get(d, :linetype, :none) in (:contour, :surface, :wireframe))
|
||||
d[:linetype] = :contour
|
||||
end
|
||||
createKWargsList(plt, x, y; d...) #, z = surf)
|
||||
end
|
||||
|
||||
# contours or surfaces... general x, y grid
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, x::AMat{T}, y::AMat{T}, zmat::AMat{T}; kw...)
|
||||
@assert size(zmat) == size(x) == size(y)
|
||||
surf = Surface(convert(Matrix{Float64}, zmat))
|
||||
# surf = Array(Any,1,1)
|
||||
# surf[1,1] = convert(Matrix{Float64}, zmat)
|
||||
d = Dict(kw)
|
||||
d[:z] = Surface(convert(Matrix{Float64}, zmat))
|
||||
if !(get(d, :linetype, :none) in (:contour, :surface, :wireframe))
|
||||
d[:linetype] = :contour
|
||||
end
|
||||
createKWargsList(plt, Any[x], Any[y]; d...) #kw..., z = surf, linetype = :contour)
|
||||
end
|
||||
|
||||
|
||||
function createKWargsList(plt::PlottingObject, surf::Surface; kw...)
|
||||
createKWargsList(plt, 1:size(surf.surf,1), 1:size(surf.surf,2), convert(Matrix{Float64}, surf.surf); kw...)
|
||||
end
|
||||
|
||||
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, surf::Surface; kw...)
|
||||
createKWargsList(plt, x, y, convert(Matrix{Float64}, surf.surf); kw...)
|
||||
end
|
||||
|
||||
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs; kw...)
|
||||
error("Can't pass a Function or Vector{Function} for y without also passing x")
|
||||
createKWargsList(plt, f, xmin(plt), xmax(plt); kw...)
|
||||
end
|
||||
|
||||
# list of functions
|
||||
@@ -363,7 +470,7 @@ end
|
||||
|
||||
# special handling... xmin/xmax with function(s)
|
||||
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs, xmin::Real, xmax::Real; kw...)
|
||||
width = plt.initargs[:size][1]
|
||||
width = get(plt.plotargs, :size, (100,))[1]
|
||||
x = collect(linspace(xmin, xmax, width)) # we don't need more than the width
|
||||
createKWargsList(plt, x, f; kw...)
|
||||
end
|
||||
@@ -376,6 +483,19 @@ createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs,
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
|
||||
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, linspace(umin, umax, numPoints); kw...)
|
||||
|
||||
# special handling... 3D parametric function(s)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
|
||||
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, fz, linspace(umin, umax, numPoints); kw...)
|
||||
|
||||
# (x,y) tuples
|
||||
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::AVec{Tuple{R1,R2}}; kw...)
|
||||
createKWargsList(plt, unzip(xy)...; kw...)
|
||||
end
|
||||
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::Tuple{R1,R2}; kw...)
|
||||
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# special handling... no args... 1 series
|
||||
@@ -386,7 +506,7 @@ function createKWargsList(plt::PlottingObject; kw...)
|
||||
return [], nothing, nothing
|
||||
# error("Called plot/subplot without args... must set y in the keyword args. Example: plot(; y=rand(10))")
|
||||
end
|
||||
|
||||
|
||||
if haskey(d, :x)
|
||||
return createKWargsList(plt, d[:x], d[:y]; kw...)
|
||||
else
|
||||
@@ -396,16 +516,34 @@ end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
"For DataFrame support. Imports DataFrames and defines the necessary methods which support them."
|
||||
function dataframes()
|
||||
@eval import DataFrames
|
||||
|
||||
@eval function createKWargsList(plt::PlottingObject, df::DataFrames.DataFrame, args...; kw...)
|
||||
# @require FixedSizeArrays begin
|
||||
|
||||
unzip{T}(x::AVec{FixedSizeArrays.Vec{2,T}}) = T[xi[1] for xi in x], T[xi[2] for xi in x]
|
||||
unzip{T}(x::FixedSizeArrays.Vec{2,T}) = T[x[1]], T[x[2]]
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, xy::AVec{FixedSizeArrays.Vec{2,T}}; kw...)
|
||||
createKWargsList(plt, unzip(xy)...; kw...)
|
||||
end
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, xy::FixedSizeArrays.Vec{2,T}; kw...)
|
||||
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
|
||||
end
|
||||
|
||||
# end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
|
||||
|
||||
@require DataFrames begin
|
||||
|
||||
function createKWargsList(plt::PlottingObject, df::DataFrames.AbstractDataFrame, args...; kw...)
|
||||
createKWargsList(plt, args...; kw..., dataframe = df)
|
||||
end
|
||||
|
||||
# expecting the column name of a dataframe that was passed in... anything else should error
|
||||
@eval function extractGroupArgs(s::Symbol, df::DataFrames.DataFrame, args...)
|
||||
function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
||||
if haskey(df, s)
|
||||
return extractGroupArgs(df[s])
|
||||
else
|
||||
@@ -413,20 +551,24 @@ function dataframes()
|
||||
end
|
||||
end
|
||||
|
||||
@eval function getDataFrameFromKW(; kw...)
|
||||
for (k,v) in kw
|
||||
if k == :dataframe
|
||||
return v
|
||||
end
|
||||
function getDataFrameFromKW(d::Dict)
|
||||
# for (k,v) in kw
|
||||
# if k == :dataframe
|
||||
# return v
|
||||
# end
|
||||
# end
|
||||
get(d, :dataframe) do
|
||||
error("Missing dataframe argument!")
|
||||
end
|
||||
error("Missing dataframe argument in arguments!")
|
||||
end
|
||||
|
||||
# the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
||||
@eval convertToAnyVector(s::Symbol; kw...) = Any[getDataFrameFromKW(;kw...)[s]], s
|
||||
@eval convertToAnyVector(v::AVec{Symbol}; kw...) = (df = getDataFrameFromKW(;kw...); Any[df[s] for s in v]), v
|
||||
# convertToAnyVector(s::Symbol; kw...) = Any[getDataFrameFromKW(;kw...)[s]], s
|
||||
# convertToAnyVector(v::AVec{Symbol}; kw...) = (df = getDataFrameFromKW(;kw...); Any[df[s] for s in v]), v
|
||||
convertToAnyVector(s::Symbol, d::Dict) = Any[getDataFrameFromKW(d)[s]], s
|
||||
convertToAnyVector(v::AVec{Symbol}, d::Dict) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
|
||||
immutable NoPackage <: PlottingPackage end
|
||||
|
||||
const _backendType = Dict{Symbol, DataType}(:none => NoPackage)
|
||||
const _backendSymbol = Dict{DataType, Symbol}(NoPackage => :none)
|
||||
const _backends = Symbol[]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
|
||||
backends() = _backends
|
||||
backend_name() = CURRENT_BACKEND.sym
|
||||
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
|
||||
macro init_plotting_pkg(s)
|
||||
str = lowercase(string(s))
|
||||
sym = symbol(str)
|
||||
T = symbol(string(s) * "Package")
|
||||
esc(quote
|
||||
immutable $T <: PlottingPackage end
|
||||
export $sym
|
||||
$sym(; kw...) = (default(; kw...); backend(symbol($str)))
|
||||
backend_name(::$T) = symbol($str)
|
||||
push!(_backends, symbol($str))
|
||||
_backendType[symbol($str)] = $T
|
||||
_backendSymbol[$T] = symbol($str)
|
||||
include("backends/" * $str * ".jl")
|
||||
end)
|
||||
end
|
||||
|
||||
@init_plotting_pkg Immerse
|
||||
@init_plotting_pkg Gadfly
|
||||
@init_plotting_pkg PyPlot
|
||||
@init_plotting_pkg Qwt
|
||||
@init_plotting_pkg UnicodePlots
|
||||
@init_plotting_pkg Winston
|
||||
@init_plotting_pkg Bokeh
|
||||
@init_plotting_pkg Plotly
|
||||
@init_plotting_pkg PlotlyJS
|
||||
@init_plotting_pkg GR
|
||||
@init_plotting_pkg GLVisualize
|
||||
@init_plotting_pkg PGFPlots
|
||||
|
||||
include("backends/web.jl")
|
||||
include("backends/supported.jl")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
|
||||
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
|
||||
_update_plot(pkg::PlottingPackage, plt::Plot, d::Dict) = error("_update_plot($pkg, plt, d) is not implemented")
|
||||
_update_plot_pos_size{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing
|
||||
subplot(pkg::PlottingPackage; kw...) = error("subplot($pkg; kw...) is not implemented")
|
||||
subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
type CurrentBackend
|
||||
sym::Symbol
|
||||
pkg::PlottingPackage
|
||||
end
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
|
||||
if Pkg.installed(pkgstr) != nothing
|
||||
return backend(symbol(lowercase(pkgstr)))
|
||||
end
|
||||
end
|
||||
|
||||
# the default if nothing else is installed
|
||||
backend(:plotly)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
"""
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
|
||||
global CURRENT_BACKEND
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
sym = CURRENT_BACKEND.sym
|
||||
if !(sym in _initialized_backends)
|
||||
|
||||
# initialize
|
||||
println("[Plots.jl] Initializing backend: ", sym)
|
||||
|
||||
inst = _backend_instance(sym)
|
||||
try
|
||||
_initialize_backend(inst)
|
||||
catch err
|
||||
warn("Couldn't initialize $sym. (might need to install it?)")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
push!(_initialized_backends, sym)
|
||||
|
||||
end
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
||||
"""
|
||||
Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::PlottingPackage)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
end
|
||||
|
||||
function backend(modname::Symbol)
|
||||
CURRENT_BACKEND.sym = modname
|
||||
CURRENT_BACKEND.pkg = _backend_instance(modname)
|
||||
end
|
||||
@@ -14,102 +14,115 @@ plot(recipe::PlotRecipe, args...; kw...) = plot(getRecipeXY(recipe)..., args...;
|
||||
plot!(recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
|
||||
plot!(plt::Plot, recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)..., args...; getRecipeArgs(recipe)..., kw...)
|
||||
|
||||
num_series(x::AMat) = size(x,2)
|
||||
num_series(x) = 1
|
||||
|
||||
# -------------------------------------------------
|
||||
_apply_recipe(d::Dict; kw...) = ()
|
||||
|
||||
function rotate(x::Real, y::Real, θ::Real; center = (0,0))
|
||||
cx = x - center[1]
|
||||
cy = y - center[2]
|
||||
xrot = cx * cos(θ) - cy * sin(θ)
|
||||
yrot = cy * cos(θ) + cx * sin(θ)
|
||||
xrot + center[1], yrot + center[2]
|
||||
end
|
||||
|
||||
# -------------------------------------------------
|
||||
|
||||
type EllipseRecipe <: PlotRecipe
|
||||
w::Float64
|
||||
h::Float64
|
||||
x::Float64
|
||||
y::Float64
|
||||
θ::Float64
|
||||
end
|
||||
EllipseRecipe(w,h,x,y) = EllipseRecipe(w,h,x,y,0)
|
||||
|
||||
# return x,y coords of a rotated ellipse, centered at the origin
|
||||
function rotatedEllipse(w, h, x, y, θ, rotθ)
|
||||
# # coord before rotation
|
||||
xpre = w * cos(θ)
|
||||
ypre = h * sin(θ)
|
||||
|
||||
# rotate and translate
|
||||
r = rotate(xpre, ypre, rotθ)
|
||||
x + r[1], y + r[2]
|
||||
end
|
||||
|
||||
function getRecipeXY(ep::EllipseRecipe)
|
||||
x, y = unzip([rotatedEllipse(ep.w, ep.h, ep.x, ep.y, u, ep.θ) for u in linspace(0,2π,100)])
|
||||
top = rotate(0, ep.h, ep.θ)
|
||||
right = rotate(ep.w, 0, ep.θ)
|
||||
linex = Float64[top[1], 0, right[1]] + ep.x
|
||||
liney = Float64[top[2], 0, right[2]] + ep.y
|
||||
Any[x, linex], Any[y, liney]
|
||||
end
|
||||
|
||||
function getRecipeArgs(ep::EllipseRecipe)
|
||||
[(:line, (3, [:dot :solid], [:red :blue], :path))]
|
||||
end
|
||||
|
||||
# -------------------------------------------------
|
||||
|
||||
|
||||
"Correlation scatter matrix"
|
||||
function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
|
||||
colors = :redsblues,
|
||||
labels = nothing, kw...)
|
||||
m = size(mat,2)
|
||||
centers = Float64[mean(extrema(mat[:,i])) for i in 1:m]
|
||||
|
||||
# might be a mistake?
|
||||
@assert m <= 20
|
||||
@assert size(corrmat) == (m,m)
|
||||
|
||||
# create a subplot grid, and a gradient from -1 to 1
|
||||
p = subplot(rand(0,m^2); n=m^2, leg=false, grid=false, kw...)
|
||||
cgrad = ColorGradient(colors, [-1,1])
|
||||
|
||||
# make all the plots
|
||||
for i in 1:m
|
||||
for j in 1:m
|
||||
idx = p.layout[i,j]
|
||||
plt = p.plts[idx]
|
||||
if i==j
|
||||
# histogram on diagonal
|
||||
histogram!(plt, mat[:,i], c=:black)
|
||||
i > 1 && plot!(plt, yticks = :none)
|
||||
elseif i < j
|
||||
# annotate correlation value in upper triangle
|
||||
mi, mj = centers[i], centers[j]
|
||||
plot!(plt, [mj], [mi],
|
||||
ann = (mj, mi, text(@sprintf("Corr:\n%0.3f", corrmat[i,j]), 15)),
|
||||
yticks=:none)
|
||||
else
|
||||
# scatter plots in lower triangle; color determined by correlation
|
||||
c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3)
|
||||
scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, smooth=true)
|
||||
end
|
||||
|
||||
if labels != nothing && length(labels) >= m
|
||||
i == m && xlabel!(plt, string(labels[j]))
|
||||
j == 1 && ylabel!(plt, string(labels[i]))
|
||||
end
|
||||
# if it's not a recipe, just do nothing and return the args
|
||||
function _apply_recipe(d::Dict, args...; issubplot=false, kw...)
|
||||
if issubplot && !haskey(d, :n) && !haskey(d, :layout)
|
||||
# put in a sensible default
|
||||
d[:n] = maximum(map(num_series, args))
|
||||
end
|
||||
end
|
||||
|
||||
# link the axes
|
||||
subplot!(p, link = (r,c) -> (true, r!=c))
|
||||
args
|
||||
end
|
||||
|
||||
# # -------------------------------------------------
|
||||
|
||||
# function rotate(x::Real, y::Real, θ::Real; center = (0,0))
|
||||
# cx = x - center[1]
|
||||
# cy = y - center[2]
|
||||
# xrot = cx * cos(θ) - cy * sin(θ)
|
||||
# yrot = cy * cos(θ) + cx * sin(θ)
|
||||
# xrot + center[1], yrot + center[2]
|
||||
# end
|
||||
|
||||
# # -------------------------------------------------
|
||||
|
||||
# type EllipseRecipe <: PlotRecipe
|
||||
# w::Float64
|
||||
# h::Float64
|
||||
# x::Float64
|
||||
# y::Float64
|
||||
# θ::Float64
|
||||
# end
|
||||
# EllipseRecipe(w,h,x,y) = EllipseRecipe(w,h,x,y,0)
|
||||
|
||||
# # return x,y coords of a rotated ellipse, centered at the origin
|
||||
# function rotatedEllipse(w, h, x, y, θ, rotθ)
|
||||
# # # coord before rotation
|
||||
# xpre = w * cos(θ)
|
||||
# ypre = h * sin(θ)
|
||||
|
||||
# # rotate and translate
|
||||
# r = rotate(xpre, ypre, rotθ)
|
||||
# x + r[1], y + r[2]
|
||||
# end
|
||||
|
||||
# function getRecipeXY(ep::EllipseRecipe)
|
||||
# x, y = unzip([rotatedEllipse(ep.w, ep.h, ep.x, ep.y, u, ep.θ) for u in linspace(0,2π,100)])
|
||||
# top = rotate(0, ep.h, ep.θ)
|
||||
# right = rotate(ep.w, 0, ep.θ)
|
||||
# linex = Float64[top[1], 0, right[1]] + ep.x
|
||||
# liney = Float64[top[2], 0, right[2]] + ep.y
|
||||
# Any[x, linex], Any[y, liney]
|
||||
# end
|
||||
|
||||
# function getRecipeArgs(ep::EllipseRecipe)
|
||||
# [(:line, (3, [:dot :solid], [:red :blue], :path))]
|
||||
# end
|
||||
|
||||
# # -------------------------------------------------
|
||||
|
||||
|
||||
# "Correlation scatter matrix"
|
||||
# function corrplot{T<:Real,S<:Real}(mat::AMat{T}, corrmat::AMat{S} = cor(mat);
|
||||
# colors = :redsblues,
|
||||
# labels = nothing, kw...)
|
||||
# m = size(mat,2)
|
||||
# centers = Float64[mean(extrema(mat[:,i])) for i in 1:m]
|
||||
|
||||
# # might be a mistake?
|
||||
# @assert m <= 20
|
||||
# @assert size(corrmat) == (m,m)
|
||||
|
||||
# # create a subplot grid, and a gradient from -1 to 1
|
||||
# p = subplot(rand(0,m^2); n=m^2, leg=false, grid=false, kw...)
|
||||
# cgrad = ColorGradient(colors, [-1,1])
|
||||
|
||||
# # make all the plots
|
||||
# for i in 1:m
|
||||
# for j in 1:m
|
||||
# idx = p.layout[i,j]
|
||||
# plt = p.plts[idx]
|
||||
# if i==j
|
||||
# # histogram on diagonal
|
||||
# histogram!(plt, mat[:,i], c=:black)
|
||||
# i > 1 && plot!(plt, yticks = :none)
|
||||
# elseif i < j
|
||||
# # annotate correlation value in upper triangle
|
||||
# mi, mj = centers[i], centers[j]
|
||||
# plot!(plt, [mj], [mi],
|
||||
# ann = (mj, mi, text(@sprintf("Corr:\n%0.3f", corrmat[i,j]), 15)),
|
||||
# yticks=:none)
|
||||
# else
|
||||
# # scatter plots in lower triangle; color determined by correlation
|
||||
# c = RGBA(RGB(getColorZ(cgrad, corrmat[i,j])), 0.3)
|
||||
# scatter!(plt, mat[:,j], mat[:,i], w=0, ms=3, c=c, smooth=true)
|
||||
# end
|
||||
|
||||
# if labels != nothing && length(labels) >= m
|
||||
# i == m && xlabel!(plt, string(labels[j]))
|
||||
# j == 1 && ylabel!(plt, string(labels[i]))
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
# # link the axes
|
||||
# subplot!(p, link = (r,c) -> (true, r!=c))
|
||||
# end
|
||||
|
||||
|
||||
"Sparsity plot... heatmap of non-zero values of a matrix"
|
||||
function spy{T<:Real}(y::AMat{T}; kw...)
|
||||
@@ -117,3 +130,9 @@ function spy{T<:Real}(y::AMat{T}; kw...)
|
||||
heatmap(J, I; leg=false, yflip=true, nbins=size(y), kw...)
|
||||
end
|
||||
|
||||
"Adds a+bx... straight line over the current plot"
|
||||
function abline!(plt::Plot, a, b; kw...)
|
||||
plot!(plt, [extrema(plt)...], x -> b + a*x; kw...)
|
||||
end
|
||||
|
||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
@@ -81,8 +81,8 @@ Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c
|
||||
Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]]
|
||||
|
||||
# handle "linking" the subplot axes together
|
||||
# each backend should implement the handleLinkInner and expandLimits! methods
|
||||
function linkAxis(subplt::Subplot, isx::Bool)
|
||||
# each backend should implement the _remove_axis and _expand_limits methods
|
||||
function link_axis(subplt::Subplot, isx::Bool)
|
||||
|
||||
# collect the list of plots and the expanded limits for those plots that should be linked on this axis
|
||||
includedPlots = Any[]
|
||||
@@ -104,7 +104,7 @@ function linkAxis(subplt::Subplot, isx::Bool)
|
||||
isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone)
|
||||
push!(includedPlots, (plt, isinner, k))
|
||||
|
||||
expandLimits!(lims[k], plt, isx)
|
||||
_expand_limits(lims[k], plt, isx)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -112,7 +112,7 @@ function linkAxis(subplt::Subplot, isx::Bool)
|
||||
# do the axis adjustments
|
||||
for (plt, isinner, k) in includedPlots
|
||||
if isinner
|
||||
handleLinkInner(plt, isx)
|
||||
_remove_axis(plt, isx)
|
||||
end
|
||||
(isx ? xlims! : ylims!)(plt, lims[k]...)
|
||||
end
|
||||
@@ -128,14 +128,14 @@ Base.print(io::IO, subplt::Subplot) = print(io, string(subplt))
|
||||
Base.show(io::IO, subplt::Subplot) = print(io, string(subplt))
|
||||
|
||||
getplot(subplt::Subplot, idx::Int = subplt.n) = subplt.plts[mod1(idx, subplt.p)]
|
||||
getinitargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).initargs
|
||||
getplotargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).plotargs
|
||||
convertSeriesIndex(subplt::Subplot, n::Int) = ceil(Int, n / subplt.p)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
||||
function validateSubplotSupported()
|
||||
if !subplotSupported()
|
||||
error(CURRENT_BACKEND.sym, " does not support the subplot/subplot! commands at this time. Try one of: ", join(filter(pkg->subplotSupported(backendInstance(pkg)), backends()),", "))
|
||||
error(CURRENT_BACKEND.sym, " does not support the subplot/subplot! commands at this time. Try one of: ", join(filter(pkg->subplotSupported(_backend_instance(pkg)), backends()),", "))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -156,6 +156,9 @@ function subplot(args...; kw...)
|
||||
d = Dict(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
args = _apply_recipe(d, args...; kw..., issubplot=true)
|
||||
|
||||
# figure out the layout
|
||||
layoutarg = get(d, :layout, nothing)
|
||||
if layoutarg != nothing
|
||||
@@ -175,12 +178,12 @@ function subplot(args...; kw...)
|
||||
di = getPlotArgs(pkg, d, i)
|
||||
di[:subplot] = true
|
||||
dumpdict(di, "Plot args (subplot $i)")
|
||||
push!(plts, plot(pkg; di...))
|
||||
push!(plts, _create_plot(pkg; di...))
|
||||
end
|
||||
|
||||
# create the object and do the plotting
|
||||
subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout, d, false, false, false, (r,c) -> (nothing,nothing))
|
||||
subplot!(subplt, args...; kw...)
|
||||
subplot!(subplt, args...; d...)
|
||||
|
||||
subplt
|
||||
end
|
||||
@@ -209,29 +212,8 @@ function subplot{P<:PlottingPackage}(plts::AVec{Plot{P}}, layout::SubplotLayout,
|
||||
n = sum([plt.n for plt in plts])
|
||||
subplt = Subplot(nothing, collect(plts), P(), p, n, layout, Dict(), false, false, false, (r,c) -> (nothing,nothing))
|
||||
|
||||
# preprocessArgs!(d)
|
||||
|
||||
# #
|
||||
# for (i,plt) in enumerate(plts)
|
||||
# di = copy(plt.initargs)
|
||||
|
||||
# for ck in (:background_color, :foreground_color, :color_palette)
|
||||
# # if we have a value to override, do it
|
||||
# if haskey(d, ck)
|
||||
# di[ck] = get_mod(d[ck], i)
|
||||
# end
|
||||
|
||||
|
||||
|
||||
# # build a new dict from the initargs of the plots
|
||||
# iargs = Dict()
|
||||
# for k in keys(_plotDefaults)
|
||||
# iargs[k] = Any[plt.initargs[k] for plt in plts]'
|
||||
# end
|
||||
# merge!(iargs, d)
|
||||
|
||||
preprocessSubplot(subplt, d)
|
||||
postprocessSubplot(subplt, d)
|
||||
_preprocess_subplot(subplt, d)
|
||||
_postprocess_subplot(subplt, d)
|
||||
|
||||
subplt
|
||||
end
|
||||
@@ -241,26 +223,28 @@ end
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function preprocessSubplot(subplt::Subplot, d::Dict)
|
||||
function _preprocess_subplot(subplt::Subplot, d::Dict, args = ())
|
||||
validateSubplotSupported()
|
||||
preprocessArgs!(d)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
args = _apply_recipe(d, args...; d..., issubplot=true)
|
||||
|
||||
dumpdict(d, "After subplot! preprocessing")
|
||||
|
||||
# get the full initargs, overriding any new settings
|
||||
# TODO: subplt.initargs should probably be merged sooner and actually used
|
||||
# get the full plotargs, overriding any new settings
|
||||
# TODO: subplt.plotargs should probably be merged sooner and actually used
|
||||
# for color selection, etc. (i.e. if we overwrite the subplot palettes to [:heat :rainbow])
|
||||
# then we need to overwrite plt[1].initargs[:color_palette] to :heat before it's actually used
|
||||
# then we need to overwrite plt[1].plotargs[:color_palette] to :heat before it's actually used
|
||||
# for color selection!
|
||||
|
||||
# first merge the new args into the subplot's initargs. then process the plot args and merge
|
||||
# those into the plot's initargs. (example... `palette = [:blues :reds]` goes into subplt.initargs,
|
||||
# then the ColorGradient for :blues/:reds is merged into plot 1/2 initargs, which is then used for color selection)
|
||||
# first merge the new args into the subplot's plotargs. then process the plot args and merge
|
||||
# those into the plot's plotargs. (example... `palette = [:blues :reds]` goes into subplt.plotargs,
|
||||
# then the ColorGradient for :blues/:reds is merged into plot 1/2 plotargs, which is then used for color selection)
|
||||
for i in 1:length(subplt.layout)
|
||||
# di = getPlotArgs(backend(), subplt.initargs, i)
|
||||
# merge!(subplt.plts[i].initargs, di)
|
||||
subplt.plts[i].initargs = getPlotArgs(backend(), merge(subplt.plts[i].initargs, d), i)
|
||||
subplt.plts[i].plotargs = getPlotArgs(backend(), merge(subplt.plts[i].plotargs, d), i)
|
||||
end
|
||||
merge!(subplt.initargs, d)
|
||||
merge!(subplt.plotargs, d)
|
||||
|
||||
# process links. TODO: extract to separate function
|
||||
for s in (:linkx, :linky, :linkfunc)
|
||||
@@ -269,43 +253,28 @@ function preprocessSubplot(subplt::Subplot, d::Dict)
|
||||
delete!(d, s)
|
||||
end
|
||||
end
|
||||
|
||||
args
|
||||
end
|
||||
|
||||
function postprocessSubplot(subplt::Subplot, d::Dict)
|
||||
function _postprocess_subplot(subplt::Subplot, d::Dict)
|
||||
# init (after plot creation)
|
||||
if !subplt.initialized
|
||||
subplt.initialized = buildSubplotObject!(subplt, false)
|
||||
subplt.initialized = _create_subplot(subplt, false)
|
||||
end
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
for (i,plt) in enumerate(subplt.plts)
|
||||
|
||||
# # # get the full initargs, overriding any new settings
|
||||
# # di = copy(merge(plt.initargs, d))
|
||||
# di = copy(d)
|
||||
|
||||
# for (k,v) in di
|
||||
# if typeof(v) <: AVec
|
||||
# di[k] = v[mod1(i, length(v))]
|
||||
# elseif typeof(v) <: AMat
|
||||
# m = size(v,2)
|
||||
# di[k] = (size(v,1) == 1 ? v[1, mod1(i, m)] : v[:, mod1(i, m)])
|
||||
# end
|
||||
# end
|
||||
|
||||
# di = merge!(plt.initargs, di)
|
||||
|
||||
di = plt.initargs
|
||||
|
||||
di = plt.plotargs
|
||||
dumpdict(di, "Updating sp $i")
|
||||
updatePlotItems(plt, di)
|
||||
_update_plot(plt, di)
|
||||
end
|
||||
|
||||
updatePositionAndSize(subplt, d)
|
||||
_update_plot_pos_size(subplt, d)
|
||||
|
||||
# handle links
|
||||
subplt.linkx && linkAxis(subplt, true)
|
||||
subplt.linky && linkAxis(subplt, false)
|
||||
subplt.linkx && link_axis(subplt, true)
|
||||
subplt.linky && link_axis(subplt, false)
|
||||
|
||||
# set this to be current
|
||||
current(subplt)
|
||||
@@ -335,14 +304,14 @@ function subplot!(subplt::Subplot, args...; kw...)
|
||||
# validateSubplotSupported()
|
||||
|
||||
d = Dict(kw)
|
||||
preprocessSubplot(subplt, d)
|
||||
args = _preprocess_subplot(subplt, d, args)
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
# note: we call it once before doing the individual plots, and once after
|
||||
# this is because some backends need to set up the subplots and then plot,
|
||||
# and others need to do it the other way around
|
||||
if !subplt.initialized
|
||||
subplt.initialized = buildSubplotObject!(subplt, true)
|
||||
subplt.initialized = _create_subplot(subplt, true)
|
||||
end
|
||||
|
||||
# handle grouping
|
||||
@@ -365,17 +334,6 @@ function subplot!(subplt::Subplot, args...; kw...)
|
||||
plt = getplot(subplt)
|
||||
plt.n += 1
|
||||
|
||||
# # update the plot's initargs for things such as palettes, etc
|
||||
# for (k,v) in subplt.initargs
|
||||
# haskey(_plotDefaults, k) || continue
|
||||
# if typeof(v) <: AVec
|
||||
# plt.initargs[k] = v[mod1(i, length(v))]
|
||||
# elseif typeof(v) <: AMat
|
||||
# m = size(v,2)
|
||||
# plt.initargs[k] = (size(v,1) == 1 ? v[1, mod1(i, m)] : v[:, mod1(i, m)])
|
||||
# end
|
||||
# end
|
||||
|
||||
# cleanup the dictionary that we pass into the plot! command
|
||||
di[:show] = false
|
||||
di[:subplot] = true
|
||||
@@ -384,12 +342,12 @@ function subplot!(subplt::Subplot, args...; kw...)
|
||||
delete!(di, k)
|
||||
end
|
||||
dumpdict(di, "subplot! kwList $i")
|
||||
dumpdict(plt.initargs, "plt.initargs before plotting")
|
||||
dumpdict(plt.plotargs, "plt.plotargs before plotting")
|
||||
|
||||
_plot_from_subplot!(plt; di...)
|
||||
_add_series_subplot(plt; di...)
|
||||
end
|
||||
|
||||
postprocessSubplot(subplt, d)
|
||||
_postprocess_subplot(subplt, d)
|
||||
|
||||
# show it automatically?
|
||||
if haskey(d, :show) && d[:show]
|
||||
@@ -401,18 +359,22 @@ end
|
||||
|
||||
|
||||
|
||||
function _plot_from_subplot!(plt::Plot, args...; kw...)
|
||||
function _add_series_subplot(plt::Plot, args...; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
setTicksFromStringVector(d, d, :x, :xticks)
|
||||
setTicksFromStringVector(d, d, :y, :yticks)
|
||||
|
||||
# dumpdict(d, "Plot from subplot")
|
||||
plot!(plt.backend, plt; d...)
|
||||
_add_series(plt.backend, plt; d...)
|
||||
|
||||
addAnnotations(plt, d)
|
||||
_add_annotations(plt, d)
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function Base.copy(subplt::Subplot)
|
||||
subplot(subplt.plts, subplt.layout, subplt.plotargs)
|
||||
end
|
||||
|
||||
@@ -13,7 +13,7 @@ type Plot{T<:PlottingPackage} <: PlottingObject{T}
|
||||
n::Int # number of series
|
||||
|
||||
# store these just in case
|
||||
initargs::Dict
|
||||
plotargs::Dict
|
||||
seriesargs::Vector{Dict} # args for each series
|
||||
end
|
||||
|
||||
@@ -38,8 +38,8 @@ type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
|
||||
p::Int # number of plots
|
||||
n::Int # number of series
|
||||
layout::L
|
||||
# initargs::Vector{Dict}
|
||||
initargs::Dict
|
||||
# plotargs::Vector{Dict}
|
||||
plotargs::Dict
|
||||
initialized::Bool
|
||||
linkx::Bool
|
||||
linky::Bool
|
||||
@@ -47,148 +47,3 @@ type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
immutable Shape
|
||||
vertices::AVec
|
||||
end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
|
||||
end
|
||||
|
||||
"interleave 2 vectors into each other (like a zipper's teeth)"
|
||||
function weave(x,y; ordering = Vector[x,y])
|
||||
ret = eltype(x)[]
|
||||
done = false
|
||||
while !done
|
||||
for o in ordering
|
||||
try
|
||||
push!(ret, shift!(o))
|
||||
end
|
||||
# try
|
||||
# push!(ret, shift!(y))
|
||||
# end
|
||||
end
|
||||
done = isempty(x) && isempty(y)
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
|
||||
"create a star by weaving together points from an outer and inner circle. `n` is the number of arms"
|
||||
function makestar(n; offset = -0.5, radius = 1.0)
|
||||
z1 = offset * π
|
||||
z2 = z1 + π / (n)
|
||||
outercircle = partialcircle(z1, z1 + 2π, n+1, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, n+1, 0.4radius)
|
||||
Shape(weave(outercircle, innercircle)[1:end-2])
|
||||
end
|
||||
|
||||
"create a shape by picking points around the unit circle. `n` is the number of point/sides, `offset` is the starting angle"
|
||||
function makeshape(n; offset = -0.5, radius = 1.0)
|
||||
z = offset * π
|
||||
Shape(partialcircle(z, z + 2π, n+1, radius)[1:end-1])
|
||||
end
|
||||
|
||||
|
||||
function makecross(; offset = -0.5, radius = 1.0)
|
||||
z2 = offset * π
|
||||
z1 = z2 - π/8
|
||||
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
|
||||
Shape(weave(outercircle, innercircle,
|
||||
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
|
||||
end
|
||||
|
||||
|
||||
const _shapes = @compat Dict(
|
||||
:ellipse => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3),
|
||||
:dtriangle => makeshape(3, offset=0.5),
|
||||
:pentagon => makeshape(5),
|
||||
:hexagon => makeshape(6),
|
||||
:heptagon => makeshape(7),
|
||||
:octagon => makeshape(8),
|
||||
:cross => makecross(offset=-0.25),
|
||||
:xcross => makecross(),
|
||||
)
|
||||
|
||||
for n in [4,5,6,7,8]
|
||||
_shapes[symbol("star$n")] = makestar(n)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
|
||||
immutable Font
|
||||
family::AbstractString
|
||||
pointsize::Int
|
||||
halign::Symbol
|
||||
valign::Symbol
|
||||
rotation::Float64
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
"Create a Font from a list of unordered features"
|
||||
function font(args...)
|
||||
|
||||
# defaults
|
||||
family = "Helvetica"
|
||||
pointsize = 14
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
rotation = 0.0
|
||||
color = colorant"black"
|
||||
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if arg == :center
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
halign = arg
|
||||
elseif arg in (:vcenter, :top, :bottom)
|
||||
valign = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: @compat Union{Symbol,AbstractString}
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
catch
|
||||
family = string(arg)
|
||||
end
|
||||
elseif typeof(arg) <: Integer
|
||||
pointsize = arg
|
||||
elseif typeof(arg) <: Real
|
||||
rotation = convert(Float64, arg)
|
||||
else
|
||||
warn("Unused font arg: $arg ($(typeof(arg)))")
|
||||
end
|
||||
end
|
||||
|
||||
Font(family, pointsize, halign, valign, rotation, color)
|
||||
end
|
||||
|
||||
"Wrap a string with font info"
|
||||
immutable PlotText
|
||||
str::@compat(AbstractString)
|
||||
font::Font
|
||||
end
|
||||
|
||||
function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
end
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type OHLC{T<:Real}
|
||||
open::T
|
||||
high::T
|
||||
low::T
|
||||
close::T
|
||||
end
|
||||
|
||||
@@ -116,6 +116,9 @@ end
|
||||
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
nop() = nothing
|
||||
|
||||
get_mod(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||
get_mod(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||
get_mod(v, idx::Int) = v
|
||||
@@ -131,7 +134,7 @@ maketuple{T,S}(x::@compat(Tuple{T,S})) = x
|
||||
unzip{T,S}(v::AVec{@compat(Tuple{T,S})}) = [vi[1] for vi in v], [vi[2] for vi in v]
|
||||
|
||||
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
|
||||
function expandLimits!(lims, x)
|
||||
function _expand_limits(lims, x)
|
||||
try
|
||||
e1, e2 = extrema(x)
|
||||
lims[1] = min(lims[1], e1)
|
||||
@@ -162,7 +165,6 @@ end
|
||||
|
||||
function replaceAliases!(d::Dict, aliases::Dict)
|
||||
ks = collect(keys(d))
|
||||
# for (k,v) in d
|
||||
for k in ks
|
||||
if haskey(aliases, k)
|
||||
d[aliases[k]] = d[k]
|
||||
@@ -172,7 +174,9 @@ function replaceAliases!(d::Dict, aliases::Dict)
|
||||
end
|
||||
|
||||
createSegments(z) = collect(repmat(z',2,1))[2:end]
|
||||
|
||||
Base.first(c::Colorant) = c
|
||||
Base.first(x::Symbol) = x
|
||||
|
||||
|
||||
sortedkeys(d::Dict) = sort(collect(keys(d)))
|
||||
@@ -186,10 +190,23 @@ function fakedata(sz...)
|
||||
y
|
||||
end
|
||||
|
||||
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
|
||||
|
||||
istuple(::Tuple) = true
|
||||
istuple(::Any) = false
|
||||
isvector(::AVec) = true
|
||||
isvector(::Any) = false
|
||||
ismatrix(::AMat) = true
|
||||
ismatrix(::Any) = false
|
||||
isscalar(::Real) = true
|
||||
isscalar(::Any) = false
|
||||
|
||||
|
||||
|
||||
|
||||
# ticksType{T<:Real,S<:Real}(ticks::@compat(Tuple{T,S})) = :limits
|
||||
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
|
||||
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
|
||||
ticksType{T<:AVec,S<:AVec}(ticks::@compat(Tuple{T,S})) = :ticks_and_labels
|
||||
ticksType(ticks) = :invalid
|
||||
|
||||
@@ -198,6 +215,108 @@ limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
|
||||
limsType(lims) = :invalid
|
||||
|
||||
|
||||
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
|
||||
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]
|
||||
|
||||
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
wraptuple(x::@compat(Tuple)) = x
|
||||
wraptuple(x) = (x,)
|
||||
|
||||
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
|
||||
trueOrAllTrue(f::Function, x) = f(x)
|
||||
|
||||
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
allShapes(arg) = trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg) ||
|
||||
trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
allAlphas(arg) = trueOrAllTrue(a -> (typeof(a) <: Real && a > 0 && a < 1) ||
|
||||
(typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg)
|
||||
allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
|
||||
"""
|
||||
Allows temporary setting of backend and defaults for Plots. Settings apply only for the `do` block. Example:
|
||||
```
|
||||
with(:gadfly, size=(400,400), type=:hist) do
|
||||
plot(rand(10))
|
||||
plot(rand(10))
|
||||
end
|
||||
```
|
||||
"""
|
||||
function with(f::Function, args...; kw...)
|
||||
|
||||
# dict to store old and new keyword args for anything that changes
|
||||
newdefs = Dict(kw)
|
||||
olddefs = Dict()
|
||||
for k in keys(newdefs)
|
||||
olddefs[k] = default(k)
|
||||
end
|
||||
|
||||
# save the backend
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
oldbackend = CURRENT_BACKEND.sym
|
||||
|
||||
for arg in args
|
||||
|
||||
# change backend?
|
||||
if arg in backends()
|
||||
backend(arg)
|
||||
end
|
||||
|
||||
# # TODO: generalize this strategy to allow args as much as possible
|
||||
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
|
||||
# # TODO: can we generalize this enough to also do something similar in the plot commands??
|
||||
|
||||
# k = :linetype
|
||||
# if arg in _allTypes
|
||||
# olddefs[k] = default(k)
|
||||
# newdefs[k] = arg
|
||||
# elseif haskey(_typeAliases, arg)
|
||||
# olddefs[k] = default(k)
|
||||
# newdefs[k] = _typeAliases[arg]
|
||||
# end
|
||||
|
||||
k = :legend
|
||||
if arg in (k, :leg)
|
||||
olddefs[k] = default(k)
|
||||
newdefs[k] = true
|
||||
end
|
||||
|
||||
k = :grid
|
||||
if arg == k
|
||||
olddefs[k] = default(k)
|
||||
newdefs[k] = true
|
||||
end
|
||||
end
|
||||
|
||||
# display(olddefs)
|
||||
# display(newdefs)
|
||||
|
||||
# now set all those defaults
|
||||
default(; newdefs...)
|
||||
|
||||
# call the function
|
||||
ret = f()
|
||||
|
||||
# put the defaults back
|
||||
default(; olddefs...)
|
||||
|
||||
# revert the backend
|
||||
if CURRENT_BACKEND.sym != oldbackend
|
||||
backend(oldbackend)
|
||||
end
|
||||
|
||||
# return the result of the function
|
||||
ret
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -213,8 +332,8 @@ end
|
||||
debugshow(x) = show(x)
|
||||
debugshow(x::AbstractArray) = print(summary(x))
|
||||
|
||||
function dumpdict(d::Dict, prefix = "")
|
||||
_debugMode.on || return
|
||||
function dumpdict(d::Dict, prefix = "", alwaysshow = false)
|
||||
_debugMode.on || alwaysshow || return
|
||||
println()
|
||||
if prefix != ""
|
||||
println(prefix, ":")
|
||||
@@ -316,15 +435,15 @@ function supportGraph(allvals, func)
|
||||
y = ASCIIString[]
|
||||
for val in vals
|
||||
for b in bs
|
||||
supported = func(Plots.backendInstance(b))
|
||||
supported = func(Plots._backend_instance(b))
|
||||
if val in supported
|
||||
push!(x, string(b))
|
||||
push!(y, string(val))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
n = length(vals)
|
||||
|
||||
|
||||
scatter(x,y,
|
||||
m=:rect,
|
||||
ms=10,
|
||||
@@ -345,7 +464,7 @@ function dumpSupportGraphs()
|
||||
for func in (supportGraphArgs, supportGraphTypes, supportGraphStyles,
|
||||
supportGraphMarkers, supportGraphScales, supportGraphAxes)
|
||||
plt = func()
|
||||
png(IMG_DIR * "/supported/$(string(func))")
|
||||
png(joinpath(Pkg.dir("ExamplePlots"), "docs", "examples", "img", "supported", "$(string(func))"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -354,12 +473,22 @@ end
|
||||
|
||||
# Some conversion functions
|
||||
# note: I borrowed these conversion constants from Compose.jl's Measure
|
||||
const INCH_SCALAR = 25.4
|
||||
const PX_SCALAR = 1 / 3.78
|
||||
inch2px(inches::Real) = float(inches * INCH_SCALAR / PX_SCALAR)
|
||||
px2inch(px::Real) = float(px * PX_SCALAR / INCH_SCALAR)
|
||||
inch2mm(inches::Real) = float(inches * INCH_SCALAR)
|
||||
mm2inch(mm::Real) = float(mm / INCH_SCALAR)
|
||||
px2mm(px::Real) = float(px * PX_SCALAR)
|
||||
mm2px(mm::Real) = float(px / PX_SCALAR)
|
||||
const PX_PER_INCH = 100
|
||||
const DPI = PX_PER_INCH
|
||||
const MM_PER_INCH = 25.4
|
||||
const MM_PER_PX = MM_PER_INCH / PX_PER_INCH
|
||||
inch2px(inches::Real) = float(inches * PX_PER_INCH)
|
||||
px2inch(px::Real) = float(px / PX_PER_INCH)
|
||||
inch2mm(inches::Real) = float(inches * MM_PER_INCH)
|
||||
mm2inch(mm::Real) = float(mm / MM_PER_INCH)
|
||||
px2mm(px::Real) = float(px * MM_PER_PX)
|
||||
mm2px(mm::Real) = float(px / MM_PER_PX)
|
||||
|
||||
|
||||
"Smallest x in plot"
|
||||
xmin(plt::Plot) = minimum([minimum(d[:x]) for d in plt.seriesargs])
|
||||
"Largest x in plot"
|
||||
xmax(plt::Plot) = maximum([maximum(d[:x]) for d in plt.seriesargs])
|
||||
|
||||
"Extrema of x-values in plot"
|
||||
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
@@ -1,9 +1,12 @@
|
||||
julia 0.3
|
||||
julia 0.4
|
||||
|
||||
Colors
|
||||
Reexport
|
||||
Requires
|
||||
FactCheck
|
||||
Gadfly
|
||||
Images
|
||||
ImageMagick
|
||||
PyPlot
|
||||
@osx QuartzImageIO
|
||||
GR
|
||||
|
||||
@@ -1,136 +1,45 @@
|
||||
|
||||
# include this first to help with crashing??
|
||||
try
|
||||
@eval using Gtk
|
||||
end
|
||||
using VisualRegressionTests
|
||||
using ExamplePlots
|
||||
|
||||
# don't let pyplot use a gui... it'll crash
|
||||
# note: Agg will set gui -> :none in PyPlot
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
try
|
||||
@eval import PyPlot
|
||||
info("Matplotlib version: $(PyPlot.matplotlib[:__version__])")
|
||||
end
|
||||
|
||||
# macro test_approx_eq_sigma_eps(A, B, sigma, eps)
|
||||
|
||||
include("../docs/example_generation.jl")
|
||||
|
||||
|
||||
# # make and display one plot
|
||||
# function test_examples(pkg::Symbol, idx::Int; debug = true)
|
||||
# Plots._debugMode.on = debug
|
||||
# println("Testing plot: $pkg:$idx:$(examples[idx].header)")
|
||||
# backend(pkg)
|
||||
# backend()
|
||||
# map(eval, examples[idx].exprs)
|
||||
# plt = current()
|
||||
# gui(plt)
|
||||
# plt
|
||||
# end
|
||||
|
||||
using Plots, FactCheck
|
||||
import Images, ImageMagick
|
||||
|
||||
# if !isdefined(ImageMagick, :init_deps)
|
||||
# function ImageMagick.init_deps()
|
||||
# ccall((:MagickWandGenesis,libwand), Void, ())
|
||||
# end
|
||||
# end
|
||||
|
||||
function makeImageWidget(fn)
|
||||
img = Gtk.GtkImageLeaf(fn)
|
||||
vbox = Gtk.GtkBoxLeaf(:v)
|
||||
push!(vbox, Gtk.GtkLabelLeaf(fn))
|
||||
push!(vbox, img)
|
||||
show(img)
|
||||
vbox
|
||||
end
|
||||
|
||||
function replaceReferenceImage(tmpfn, reffn)
|
||||
cmd = `cp $tmpfn $reffn`
|
||||
run(cmd)
|
||||
info("Replaced reference image with: $cmd")
|
||||
end
|
||||
|
||||
"Show a Gtk popup with both images and a confirmation whether we should replace the new image with the old one"
|
||||
function compareToReferenceImage(tmpfn, reffn)
|
||||
@eval import Gtk
|
||||
|
||||
# add the images
|
||||
imgbox = Gtk.GtkBoxLeaf(:h)
|
||||
push!(imgbox, makeImageWidget(tmpfn))
|
||||
push!(imgbox, makeImageWidget(reffn))
|
||||
|
||||
# add the buttons
|
||||
# doNothingButton = Gtk.GtkButtonLeaf("Skip")
|
||||
# replaceReferenceButton = Gtk.GtkButtonLeaf("Replace reference image")
|
||||
# btnbox = Gtk.GtkButtonBoxLeaf(:h)
|
||||
# push!(btnbox, doNothingButton)
|
||||
# push!(btnbox, replaceReferenceButton)
|
||||
|
||||
# # create the window
|
||||
# box = Gtk.GtkBoxLeaf(:v)
|
||||
# push!(box, imgbox)
|
||||
# push!(box, btnbox)
|
||||
win = Gtk.GtkWindowLeaf("Should we make this the new reference image?")
|
||||
push!(win, Gtk.GtkFrameLeaf(imgbox))
|
||||
|
||||
showall(win)
|
||||
|
||||
# now ask the question
|
||||
if Gtk.ask_dialog("Should we make this the new reference image?", "No", "Yes")
|
||||
replaceReferenceImage(tmpfn, reffn)
|
||||
end
|
||||
|
||||
destroy(win)
|
||||
|
||||
# # we'll wait on this condition
|
||||
# c = Condition()
|
||||
# Gtk.on_signal_destroy((x...) -> notify(c), win)
|
||||
|
||||
# Gtk.signal_connect(replaceReferenceButton, "clicked") do widget
|
||||
# replaceReferenceImage(tmpfn, reffn)
|
||||
# notify(c)
|
||||
# end
|
||||
|
||||
# Gtk.signal_connect(doNothingButton, "clicked") do widget
|
||||
# notify(c)
|
||||
# end
|
||||
|
||||
# # wait until a button is clicked, then close the window
|
||||
# Gtk.showall(win)
|
||||
# wait(c)
|
||||
# Gtk.destroy(win)
|
||||
end
|
||||
default(size=(500,300))
|
||||
|
||||
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, sigma = [1,1], eps = 1e-2)
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
|
||||
# first
|
||||
Plots._debugMode.on = debug
|
||||
info("Testing plot: $pkg:$idx:$(PlotExamples.examples[idx].header)")
|
||||
example = ExamplePlots._examples[idx]
|
||||
info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
backend(pkg)
|
||||
backend()
|
||||
|
||||
# ensure consistent results
|
||||
srand(1234)
|
||||
|
||||
# run the example
|
||||
map(eval, PlotExamples.examples[idx].exprs)
|
||||
# reference image directory setup
|
||||
refdir = joinpath(Pkg.dir("ExamplePlots"), "test", "refimg", string(pkg))
|
||||
|
||||
# save the png
|
||||
tmpfn = tempname() * ".png"
|
||||
png(tmpfn)
|
||||
# test function
|
||||
func = (fn, idx) -> begin
|
||||
map(eval, example.exprs)
|
||||
png(fn)
|
||||
end
|
||||
|
||||
# load the saved png
|
||||
tmpimg = Images.load(tmpfn)
|
||||
|
||||
# reference image location
|
||||
# refdir = joinpath(Pkg.dir("Plots"), "test", "refimg", "v$(VERSION.major).$(VERSION.minor)", string(pkg))
|
||||
refdir = joinpath(Pkg.dir("Plots"), "test", "refimg", string(pkg))
|
||||
try
|
||||
run(`mkdir -p $refdir`)
|
||||
catch err
|
||||
@@ -138,45 +47,21 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, sigma = [1
|
||||
end
|
||||
reffn = joinpath(refdir, "ref$idx.png")
|
||||
|
||||
try
|
||||
|
||||
# info("Comparing $tmpfn to reference $reffn")
|
||||
|
||||
# load the reference image
|
||||
refimg = Images.load(reffn)
|
||||
|
||||
# run the comparison test... a difference will throw an error
|
||||
# NOTE: sigma is a 2-length vector with x/y values for the number of pixels
|
||||
# to blur together when comparing images
|
||||
diffpct = Images.test_approx_eq_sigma_eps(tmpimg, refimg, sigma, eps)
|
||||
|
||||
# we passed!
|
||||
info("Reference image $reffn matches. Difference: $diffpct")
|
||||
return true
|
||||
|
||||
catch err
|
||||
warn("Image did not match reference image $reffn. err: $err")
|
||||
showerror(Base.STDERR, err)
|
||||
|
||||
if isinteractive()
|
||||
|
||||
# if we're in interactive mode, open a popup and give us a chance to examine the images
|
||||
warn("Should we make this the new reference image?")
|
||||
compareToReferenceImage(tmpfn, reffn)
|
||||
return
|
||||
|
||||
else
|
||||
|
||||
# if we rejected the image, or if we're in automated tests, throw the error
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
end
|
||||
# the test
|
||||
vtest = VisualTest(func, reffn, idx)
|
||||
test_images(vtest, popup=popup, sigma=sigma, eps=eps)
|
||||
end
|
||||
|
||||
function image_comparison_tests(pkg::Symbol; skip = [], debug = false, sigma = [1,1], eps = 1e-2)
|
||||
for i in 1:length(PlotExamples.examples)
|
||||
function image_comparison_facts(pkg::Symbol;
|
||||
skip = [], # skip these examples (int index)
|
||||
only = nothing, # limit to these examples (int index)
|
||||
debug = false, # print debug information?
|
||||
sigma = [1,1], # number of pixels to "blur"
|
||||
eps = 1e-2) # acceptable error (percent)
|
||||
for i in 1:length(ExamplePlots._examples)
|
||||
i in skip && continue
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) --> true
|
||||
if only == nothing || i in only
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 51 KiB |