Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd7b09552a | |||
| 0b23aa9e7e | |||
| 0caa31bd6b | |||
| cafac135a0 | |||
| 6ac312bd49 | |||
| 489877d6bf | |||
| c09545de64 | |||
| 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(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,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
|
||||
@@ -206,14 +207,13 @@ 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`
|
||||
`:background_color` | `RGB{U8}(1.0,1.0,1.0)` | Plot | `:background`, `:background_colour`, `:bg`, `:bg_color`, `:bgcolor`
|
||||
`:color_palette` | `auto` | Plot | `:palette`
|
||||
`:fill` | `nothing` | Series | `:area`, `:f`
|
||||
`:fillcolor` | `match` | Series | `:fc`, `:fcolor`, `:fillcolors`
|
||||
`:fillopacity` | `nothing` | Series | `:fillopacitys`, `:fo`
|
||||
`:fillalpha` | `nothing` | Series | `:fa`, `:fillalphas`, `:fillopacity`
|
||||
`:fillcolor` | `match` | Series | `:fc`, `:fcolor`, `:fillcolors`, `:fillcolour`
|
||||
`:fillrange` | `nothing` | Series | `:fillranges`, `:fillrng`
|
||||
`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground`
|
||||
`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground`, `:foreground_colour`
|
||||
`:grid` | `true` | Plot |
|
||||
`:group` | `nothing` | Series | `:g`, `:groups`
|
||||
`:guidefont` | `Plots.Font("Helvetica",11,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
|
||||
@@ -222,7 +222,8 @@ Keyword | Default | Type | Aliases
|
||||
`: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`
|
||||
`:linealpha` | `nothing` | Series | `:la`, `:linealphas`, `:lineopacity`
|
||||
`:linecolor` | `auto` | Series | `:c`, `:color`, `:colour`, `:linecolors`
|
||||
`:linestyle` | `solid` | Series | `:linestyles`, `:ls`, `:s`, `:style`
|
||||
`:linetype` | `path` | Series | `:linetypes`, `:lt`, `:t`, `:type`
|
||||
`:linewidth` | `1` | Series | `:linewidths`, `:lw`, `:w`, `:width`
|
||||
@@ -231,18 +232,24 @@ Keyword | Default | Type | Aliases
|
||||
`: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`
|
||||
`:markeralpha` | `nothing` | Series | `:alpha`, `:ma`, `:markeralphas`, `:markeropacity`, `:opacity`
|
||||
`:markercolor` | `match` | Series | `:markercolors`, `:markercolour`, `:mc`, `:mcolor`
|
||||
`:markershape` | `none` | Series | `:markershapes`, `:shape`
|
||||
`:markersize` | `6` | Series | `:markersizes`, `:ms`, `:msize`
|
||||
`:markerstrokealpha` | `nothing` | Series | `:markerstrokealphas`
|
||||
`:markerstrokecolor` | `match` | Series | `:markerstrokecolors`
|
||||
`:markerstrokestyle` | `solid` | Series | `:markerstrokestyles`
|
||||
`:markerstrokewidth` | `1` | Series | `:markerstrokewidths`
|
||||
`:n` | `-1` | Plot |
|
||||
`:nbins` | `100` | Series | `:nb`, `:nbin`, `:nbinss`
|
||||
`:nbins` | `30` | Series | `:nb`, `:nbin`, `:nbinss`
|
||||
`:nc` | `-1` | Plot |
|
||||
`:nlevels` | `15` | Series | `:nlevelss`
|
||||
`:nr` | `-1` | Plot |
|
||||
`:pos` | `(0,0)` | Plot |
|
||||
`:show` | `false` | Plot | `:display`, `:gui`
|
||||
`:size` | `(500,300)` | Plot | `:windowsize`, `:wsize`
|
||||
`:smooth` | `false` | Series | `:reg`, `:regression`, `:smooths`
|
||||
`:surface` | `nothing` | Series | `:surfaces`
|
||||
`:tickfont` | `Plots.Font("Helvetica",8,:hcenter,:vcenter,0.0,RGB{U8}(0.0,0.0,0.0))` | Plot |
|
||||
`:title` | `` | Plot |
|
||||
`:windowtitle` | `Plots.jl` | Plot | `:wtitle`
|
||||
@@ -280,6 +287,9 @@ Type | Desc | Aliases
|
||||
`:hline` | Horizontal line (doesn't use x) |
|
||||
`:vline` | Vertical line (doesn't use x) |
|
||||
`:ohlc` | Open/High/Low/Close chart (expects y is AbstractVector{Plots.OHLC}) |
|
||||
`:contour` | Contour lines (uses z) |
|
||||
`:path3d` | 3D path (uses z) | `:line3d`
|
||||
`:scatter3d` | 3D scatter plot (uses z) |
|
||||
|
||||
|
||||
### Line styles:
|
||||
|
||||
@@ -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: 68 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 28 KiB |
@@ -1,7 +1,5 @@
|
||||
|
||||
if VERSION >= v"0.4-"
|
||||
__precompile__()
|
||||
end
|
||||
__precompile__()
|
||||
|
||||
module Plots
|
||||
|
||||
@@ -10,6 +8,14 @@ using Reexport
|
||||
@reexport using Colors
|
||||
|
||||
export
|
||||
Plot,
|
||||
Subplot,
|
||||
SubplotLayout,
|
||||
GridLayout,
|
||||
FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
# plot_display,
|
||||
@@ -19,6 +25,7 @@ export
|
||||
|
||||
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,18 @@ export
|
||||
vline!,
|
||||
ohlc,
|
||||
ohlc!,
|
||||
pie,
|
||||
pie!,
|
||||
contour,
|
||||
contour!,
|
||||
surface,
|
||||
surface!,
|
||||
wireframe,
|
||||
wireframe!,
|
||||
path3d,
|
||||
path3d!,
|
||||
scatter3d,
|
||||
scatter3d!,
|
||||
|
||||
title!,
|
||||
xlabel!,
|
||||
@@ -62,6 +85,9 @@ export
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
|
||||
colorscheme,
|
||||
@@ -89,8 +115,8 @@ export
|
||||
|
||||
# recipes
|
||||
PlotRecipe,
|
||||
EllipseRecipe,
|
||||
spy,
|
||||
# EllipseRecipe,
|
||||
# spy,
|
||||
corrplot
|
||||
|
||||
# ---------------------------------------------------------
|
||||
@@ -104,6 +130,7 @@ const IMG_DIR = Pkg.dir("Plots") * "/img/"
|
||||
include("types.jl")
|
||||
include("utils.jl")
|
||||
include("colors.jl")
|
||||
include("components.jl")
|
||||
include("plotter.jl")
|
||||
include("args.jl")
|
||||
include("plot.jl")
|
||||
@@ -121,8 +148,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 +162,18 @@ 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)
|
||||
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...)
|
||||
@@ -178,10 +221,10 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
try
|
||||
import DataFrames
|
||||
dataframes()
|
||||
end
|
||||
# try
|
||||
# import DataFrames
|
||||
# dataframes()
|
||||
# end
|
||||
|
||||
# const CURRENT_BACKEND = pickDefaultBackend()
|
||||
|
||||
@@ -194,18 +237,21 @@ end
|
||||
# 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)
|
||||
# function __init__()
|
||||
# # global const CURRENT_BACKEND = pickDefaultBackend()
|
||||
# # global const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
# # auto init dataframes if the import statement doesn't error out
|
||||
# try
|
||||
# @eval import DataFrames
|
||||
# dataframes()
|
||||
# end
|
||||
end
|
||||
# # global CURRENT_BACKEND
|
||||
# # println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym)
|
||||
|
||||
# # # auto init dataframes if the import statement doesn't error out
|
||||
# # try
|
||||
# # @eval import DataFrames
|
||||
# # dataframes()
|
||||
# # end
|
||||
# end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -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}()
|
||||
@@ -170,6 +178,7 @@ _plotDefaults[:tickfont] = font(8)
|
||||
_plotDefaults[:guidefont] = font(11)
|
||||
_plotDefaults[:legendfont] = font(8)
|
||||
_plotDefaults[:grid] = true
|
||||
_plotDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
|
||||
|
||||
|
||||
|
||||
@@ -180,12 +189,6 @@ supportedArgs(::PlottingPackage) = _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 +218,91 @@ 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,
|
||||
: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,
|
||||
: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,
|
||||
)
|
||||
|
||||
# add all pluralized forms to the _keyAliases dict
|
||||
@@ -396,21 +411,32 @@ function processLineArg(d::Dict, arg)
|
||||
# linetype
|
||||
if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
d[:linetype] = arg
|
||||
|
||||
|
||||
# linestyle
|
||||
elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _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)
|
||||
d[:linealpha] = arg
|
||||
|
||||
# linewidth
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Real, 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
|
||||
@@ -425,24 +451,45 @@ function processMarkerArg(d::Dict, arg)
|
||||
elseif trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
d[:markershape] = arg
|
||||
|
||||
# markersize
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Integer, arg)
|
||||
d[:markersize] = arg
|
||||
# stroke style
|
||||
elseif trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
d[:markerstrokestyle] = arg
|
||||
|
||||
# lineopacity
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Real && a >= 0 && a <= 1, arg)
|
||||
d[:markeropacity] = 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)
|
||||
d[:markeralpha] = arg
|
||||
|
||||
# markersize
|
||||
elseif trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
d[:markersize] = 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)
|
||||
|
||||
elseif !handleColors!(d, arg, :fillcolor)
|
||||
d[:fillrange] = arg
|
||||
end
|
||||
end
|
||||
@@ -450,7 +497,7 @@ end
|
||||
"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")
|
||||
@@ -483,6 +530,8 @@ function preprocessArgs!(d::Dict)
|
||||
end
|
||||
delete!(d, :fill)
|
||||
|
||||
# convert into strokes and brushes
|
||||
|
||||
# handle subplot links
|
||||
if haskey(d, :link)
|
||||
l = d[:link]
|
||||
@@ -545,7 +594,7 @@ end
|
||||
|
||||
|
||||
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)
|
||||
@@ -623,7 +672,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 +687,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 +697,24 @@ 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
|
||||
|
||||
# TODO: rebuild
|
||||
|
||||
# set label
|
||||
label = d[:label]
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
# 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
|
||||
@@ -3,12 +3,16 @@
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# 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 +40,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,23 +110,50 @@ 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
|
||||
|
||||
|
||||
@@ -116,39 +166,56 @@ function getMarkerGeom(d::Dict)
|
||||
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)
|
||||
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 +224,7 @@ end
|
||||
function addToGadflyLegend(plt::Plot, d::Dict)
|
||||
|
||||
# add the legend?
|
||||
if plt.initargs[:legend]
|
||||
if plt.plotargs[:legend]
|
||||
gplt = getGadflyContext(plt)
|
||||
|
||||
# add the legend if needed
|
||||
@@ -172,7 +239,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 +269,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 +278,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 +288,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)
|
||||
|
||||
# now save the layers that apply to this series
|
||||
d[:gadflylayers] = layers
|
||||
prepend!(getGadflyContext(plt).layers, layers)
|
||||
prepend!(gplt.layers, layers)
|
||||
end
|
||||
|
||||
|
||||
@@ -245,7 +315,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 +327,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)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -305,7 +375,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 +393,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 +460,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,9 +478,9 @@ 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)
|
||||
@@ -463,7 +538,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 +548,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 +556,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 +572,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 +604,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,8 +651,8 @@ 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]...)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -585,9 +667,10 @@ 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")
|
||||
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<:GadflyOrImmerse}(io::IO, ::$mime, plt::PlottingObject{P})
|
||||
func = getGadflyWriteFunc($mime())
|
||||
dowritemime(io, func, plt)
|
||||
@@ -597,14 +680,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)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
@@ -1,19 +1,6 @@
|
||||
|
||||
# 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 createImmerseFigure(d::Dict)
|
||||
w,h = d[:size]
|
||||
@@ -21,9 +8,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 +24,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 +32,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 +41,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 +67,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 +114,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 +137,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,447 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PlotlyPackage; 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(nothing, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyPackage, plt::Plot; kw...)
|
||||
d = Dict(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(
|
||||
: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(
|
||||
: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(
|
||||
: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(
|
||||
: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()
|
||||
|
||||
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(: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]
|
||||
if d[:legend]
|
||||
d_out[:legend] = Dict(
|
||||
: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(
|
||||
: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()
|
||||
|
||||
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(: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()
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
d_out[:marker] = Dict(
|
||||
:symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])),
|
||||
:opacity => d[:markeralpha],
|
||||
:size => 2 * d[:markersize],
|
||||
:color => webcolor(d[:markercolor], d[:markeralpha]),
|
||||
:line => Dict(
|
||||
: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(
|
||||
: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})
|
||||
isijulia() && return
|
||||
# TODO: write a png to io
|
||||
println("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,48 @@
|
||||
|
||||
# override some methods to use Plotlyjs/Blink
|
||||
|
||||
import Plotlyjs
|
||||
|
||||
function _create_plot(pkg::PlotlyPackage; 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()
|
||||
|
||||
Plot(o, pkg, 0, d, Dict[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
# add to the data array
|
||||
pdict = plotly_series(d)
|
||||
gt = Plotlyjs.GenericTrace(pdict[:type], pdict)
|
||||
push!(plt.o.data, gt)
|
||||
if !isnull(plt.o.window)
|
||||
Plotlyjs.addtraces!(plt.o, gt)
|
||||
end
|
||||
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PlotlyPackage}, d::Dict)
|
||||
pdict = plotly_layout(d)
|
||||
plt.o.layout = Plotlyjs.Layout(pdict)
|
||||
if !isnull(plt.o.window)
|
||||
Plotlyjs.relayout!(plt.o, pdict...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{PlotlyPackage})
|
||||
dump(plt.o)
|
||||
show(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyPackage})
|
||||
error()
|
||||
end
|
||||
@@ -75,46 +75,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 +165,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,15 +173,15 @@ 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
|
||||
|
||||
@@ -169,7 +196,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)
|
||||
|
||||
@@ -179,7 +206,11 @@ function plot(pkg::PyPlotPackage; kw...)
|
||||
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(; 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
|
||||
end
|
||||
|
||||
plt = Plot(wrap, pkg, 0, d, Dict[])
|
||||
@@ -187,22 +218,26 @@ 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])
|
||||
lt = d[:linetype]
|
||||
if lt in _3dTypes && isempty(plt.o.kwargs)
|
||||
push!(plt.o.kwargs, (:projection, "3d"))
|
||||
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 +247,127 @@ 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 isa(c, ColorGradient) && d[:zcolor] != nothing
|
||||
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])
|
||||
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 +377,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)
|
||||
if plt.plotargs[:legend] && haskey(extra_kwargs, :cmap)
|
||||
PyPlot.colorbar(d[:serieshandle])
|
||||
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
|
||||
|
||||
@@ -334,29 +416,30 @@ function Base.getindex(plt::Plot{PyPlotPackage}, i::Integer)
|
||||
# mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PyPlotPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!{X,Y}(plt::Plot{PyPlotPackage}, xy::Tuple{X,Y}, i::Integer)
|
||||
series = plt.seriesargs[i][:serieshandle]
|
||||
x, y = xy
|
||||
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
|
||||
if plt.plotargs[:xlims] == :auto
|
||||
xmin, xmax = ax[:get_xlim]()
|
||||
ax[:set_xlim](min(xmin, minimum(xy[1])), max(xmax, maximum(xy[1])))
|
||||
ax[:set_xlim](min(xmin, minimum(x)), max(xmax, maximum(x)))
|
||||
end
|
||||
if plt.initargs[:ylims] == :auto
|
||||
if plt.plotargs[:ylims] == :auto
|
||||
ymin, ymax = ax[:get_ylim]()
|
||||
ax[:set_ylim](min(ymin, minimum(xy[2])), max(ymax, maximum(xy[2])))
|
||||
ax[:set_ylim](min(ymin, minimum(y)), max(ymax, maximum(y)))
|
||||
end
|
||||
|
||||
# getLeftAxis(plt)[:relim]()
|
||||
# getRightAxis(plt)[:relim]()
|
||||
# for mapping in getGadflyMappings(plt, i)
|
||||
# mapping[:x], mapping[:y] = xy
|
||||
# end
|
||||
plt
|
||||
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
|
||||
|
||||
@@ -390,7 +473,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 +486,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 +515,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 +544,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 +571,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 +580,12 @@ 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)
|
||||
|
||||
nr = nrows(l)
|
||||
for (i,(r,c)) in enumerate(l)
|
||||
@@ -512,10 +595,11 @@ 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, [])
|
||||
end
|
||||
|
||||
subplt.o = PyPlotFigWrapper(fig)
|
||||
# subplt.o = PyPlotFigWrapper(fig, [])
|
||||
subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, [])
|
||||
true
|
||||
end
|
||||
|
||||
@@ -528,26 +612,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 +639,26 @@ 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
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# function addPyPlotLegend(plt::Plot)
|
||||
function addPyPlotLegend(plt::Plot, ax)
|
||||
if plt.initargs[:legend]
|
||||
if plt.plotargs[:legend]
|
||||
# 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)
|
||||
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
|
||||
fontsize = plt.plotargs[:legendfont].pointsize
|
||||
# framealpha = 0.6
|
||||
)
|
||||
leg[:set_zorder](1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -581,7 +666,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 +675,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
|
||||
|
||||
@@ -658,10 +744,11 @@ 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
|
||||
|
||||
@@ -70,7 +70,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 +79,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 +131,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 +139,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 +154,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 +182,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 +211,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 +228,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 +270,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,13 +1,33 @@
|
||||
|
||||
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,
|
||||
@@ -16,11 +36,14 @@ supportedArgs(::GadflyPackage) = [
|
||||
:linestyle,
|
||||
:linetype,
|
||||
:linewidth,
|
||||
:lineopacity,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeropacity,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -45,18 +68,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 +95,7 @@ supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
|
||||
supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
|
||||
supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
|
||||
supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
|
||||
subplotSupported(::ImmersePackage) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -77,7 +105,7 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:annotation,
|
||||
:axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -92,6 +120,9 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -117,22 +148,25 @@ 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,
|
||||
]
|
||||
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
|
||||
|
||||
|
||||
@@ -145,7 +179,7 @@ supportedArgs(::QwtPackage) = [
|
||||
# :args,
|
||||
:axis,
|
||||
:background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -162,6 +196,9 @@ supportedArgs(::QwtPackage) = [
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
:n,
|
||||
:nbins,
|
||||
:nc,
|
||||
@@ -191,6 +228,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 +239,7 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color,
|
||||
# :linecolor,
|
||||
# :fill,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
@@ -216,6 +254,9 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
:markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:nbins,
|
||||
# :nc,
|
||||
@@ -247,6 +288,7 @@ supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppost, :sticks
|
||||
supportedStyles(::UnicodePlotsPackage) = [:auto, :solid]
|
||||
supportedMarkers(::UnicodePlotsPackage) = [:none, :auto, :ellipse]
|
||||
supportedScales(::UnicodePlotsPackage) = [:identity]
|
||||
subplotSupported(::UnicodePlotsPackage) = true
|
||||
|
||||
|
||||
|
||||
@@ -259,7 +301,7 @@ supportedArgs(::WinstonPackage) = [
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
@@ -276,6 +318,9 @@ supportedArgs(::WinstonPackage) = [
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:nbins,
|
||||
# :nc,
|
||||
@@ -310,4 +355,205 @@ 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(::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
|
||||
|
||||
@@ -5,90 +5,68 @@
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# 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 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)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{[PkgName]Package}, xy::Tuple, i::Integer)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y = xy
|
||||
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})
|
||||
|
||||
@@ -9,13 +9,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 +25,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 +39,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],
|
||||
@@ -97,7 +97,7 @@ function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
|
||||
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.autoColors ? d[:linecolor] : :auto
|
||||
|
||||
# add the series
|
||||
func(o, x, y; color = color, name = label, style = stepstyle)
|
||||
@@ -112,18 +112,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 +135,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 +175,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
|
||||
|
||||
@@ -25,14 +25,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 +56,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 +68,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 +157,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 +182,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 +191,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]
|
||||
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
|
||||
end
|
||||
end
|
||||
@@ -219,9 +219,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)]
|
||||
@@ -286,6 +215,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 +286,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 +325,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 +372,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,243 @@
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
style = arg
|
||||
elseif T <: Colorant
|
||||
color = arg
|
||||
elseif T <: @compat Union{Symbol,AbstractString}
|
||||
try
|
||||
color = parse(Colorant, string(arg))
|
||||
end
|
||||
elseif typeof(arg) <: Real
|
||||
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 typeof(arg) <: Real
|
||||
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
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type OHLC{T<:Real}
|
||||
open::T
|
||||
high::T
|
||||
low::T
|
||||
close::T
|
||||
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))
|
||||
|
||||
@@ -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,18 +168,18 @@ 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
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@@ -184,16 +189,27 @@ annotations{X,Y,V}(t::@compat(Tuple{X,Y,V})) = [t]
|
||||
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)
|
||||
_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
|
||||
@@ -221,11 +237,25 @@ convertToAnyVector{T<:Real}(v::AMat{T}; kw...) = Any[v[:,i] for i in 1:size(v,2)
|
||||
# function
|
||||
convertToAnyVector(f::Function; kw...) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface; kw...) = Any[s], nothing
|
||||
|
||||
# vector of OHLC
|
||||
convertToAnyVector(v::AVec{OHLC}; kw...) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}; kw...) = 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; kw...)
|
||||
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
|
||||
Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
@@ -241,7 +271,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
|
||||
|
||||
@@ -254,8 +284,6 @@ function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
xs, xmeta = convertToAnyVector(x; kw...)
|
||||
ys, ymeta = convertToAnyVector(y; kw...)
|
||||
|
||||
# _debugMode.on && dumpcallstack()
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
ret = Any[]
|
||||
@@ -275,7 +303,7 @@ 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)])
|
||||
|
||||
@@ -324,9 +352,13 @@ 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
|
||||
|
||||
# contours or surfaces... function grid
|
||||
@@ -346,9 +378,38 @@ 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...)
|
||||
@@ -363,7 +424,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
|
||||
@@ -386,7 +447,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
|
||||
@@ -429,4 +490,3 @@ end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
|
||||
|
||||
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 GLVisualizePackage <: PlottingPackage end
|
||||
immutable NoPackage <: PlottingPackage end
|
||||
|
||||
typealias GadflyOrImmerse @compat(Union{GadflyPackage, ImmersePackage})
|
||||
|
||||
@@ -14,21 +18,31 @@ export
|
||||
immerse,
|
||||
pyplot,
|
||||
qwt,
|
||||
unicodeplots
|
||||
unicodeplots,
|
||||
bokeh,
|
||||
plotly,
|
||||
glvisualize
|
||||
# winston
|
||||
|
||||
gadfly() = backend(:gadfly)
|
||||
immerse() = backend(:immerse)
|
||||
pyplot() = backend(:pyplot)
|
||||
qwt() = backend(:qwt)
|
||||
unicodeplots() = backend(:unicodeplots)
|
||||
# winston() = backend(:winston)
|
||||
gadfly() = backend(:gadfly)
|
||||
immerse() = backend(:immerse)
|
||||
pyplot() = backend(:pyplot)
|
||||
qwt() = backend(:qwt)
|
||||
unicodeplots() = backend(:unicodeplots)
|
||||
bokeh() = backend(:bokeh)
|
||||
plotly() = backend(:plotly)
|
||||
glvisualize() = backend(:glvisualize)
|
||||
# winston() = backend(:winston)
|
||||
|
||||
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(::GLVisualizePackage) = :glvisualize
|
||||
backend_name(::NoPackage) = :none
|
||||
|
||||
include("backends/supported.jl")
|
||||
|
||||
@@ -39,16 +53,22 @@ 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/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,7 +77,7 @@ subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, s
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse]
|
||||
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly]
|
||||
const INITIALIZED_BACKENDS = Set{Symbol}()
|
||||
backends() = BACKENDS
|
||||
|
||||
@@ -69,8 +89,12 @@ function backendInstance(sym::Symbol)
|
||||
sym == :pyplot && return PyPlotPackage()
|
||||
sym == :immerse && return ImmersePackage()
|
||||
sym == :winston && return WinstonPackage()
|
||||
sym == :bokeh && return BokehPackage()
|
||||
sym == :plotly && return PlotlyPackage()
|
||||
sym == :glvisualize && return GLVisualizePackage()
|
||||
sym == :none && return NoPackage()
|
||||
error("Unsupported backend $sym")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
type CurrentBackend
|
||||
@@ -82,41 +106,13 @@ CurrentBackend(sym::Symbol) = CurrentBackend(sym, backendInstance(sym))
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
try
|
||||
if Pkg.installed("Immerse") != nothing
|
||||
return CurrentBackend(:immerse)
|
||||
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "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,7 +121,11 @@ 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)
|
||||
@@ -143,8 +143,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 +166,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 +199,63 @@ 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 == :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
|
||||
@@ -222,13 +280,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 +299,12 @@ 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 == :glvisualize
|
||||
CURRENT_BACKEND.pkg = GLVisualizePackage()
|
||||
else
|
||||
error("Unknown backend $modname. Choose from: $BACKENDS")
|
||||
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...)
|
||||
|
||||
@@ -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,7 +128,7 @@ 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)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
@@ -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,6 +190,18 @@ 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
|
||||
@@ -198,6 +214,89 @@ 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]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
"""
|
||||
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 +312,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, ":")
|
||||
@@ -354,12 +453,14 @@ 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)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
julia 0.3
|
||||
julia 0.4
|
||||
|
||||
Colors
|
||||
Reexport
|
||||
@@ -7,3 +7,4 @@ Gadfly
|
||||
Images
|
||||
ImageMagick
|
||||
PyPlot
|
||||
@osx QuartzImageIO
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
|
||||
# include this first to help with crashing??
|
||||
try
|
||||
@eval using Gtk
|
||||
end
|
||||
# # include this first to help with crashing??
|
||||
# try
|
||||
# @eval using Gtk
|
||||
# catch err
|
||||
# warn("Gtk not loaded. err: $err")
|
||||
# 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")
|
||||
|
||||
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
|
||||
# import Images, ImageMagick
|
||||
|
||||
# if !isdefined(ImageMagick, :init_deps)
|
||||
# function ImageMagick.init_deps()
|
||||
@@ -37,99 +29,75 @@ import Images, ImageMagick
|
||||
# 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 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
|
||||
# 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
|
||||
# "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)
|
||||
|
||||
# add the images
|
||||
imgbox = Gtk.GtkBoxLeaf(:h)
|
||||
push!(imgbox, makeImageWidget(tmpfn))
|
||||
push!(imgbox, makeImageWidget(reffn))
|
||||
# # 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)
|
||||
# win = Gtk.GtkWindowLeaf("Should we make this the new reference image?")
|
||||
# push!(win, Gtk.GtkFrameLeaf(imgbox))
|
||||
|
||||
# # 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)
|
||||
|
||||
showall(win)
|
||||
# # now ask the question
|
||||
# if Gtk.ask_dialog("Should we make this the new reference image?", "No", "Yes")
|
||||
# replaceReferenceImage(tmpfn, reffn)
|
||||
# end
|
||||
|
||||
# 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
|
||||
# destroy(win)
|
||||
# end
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
# test function
|
||||
func = (fn, idx) -> begin
|
||||
map(eval, example.exprs)
|
||||
png(fn)
|
||||
end
|
||||
|
||||
# run the example
|
||||
map(eval, PlotExamples.examples[idx].exprs)
|
||||
# map(eval, PlotExamples._examples[idx].exprs)
|
||||
|
||||
# save the png
|
||||
tmpfn = tempname() * ".png"
|
||||
png(tmpfn)
|
||||
# # save the png
|
||||
# tmpfn = tempname() * ".png"
|
||||
# png(tmpfn)
|
||||
|
||||
# load the saved png
|
||||
tmpimg = Images.load(tmpfn)
|
||||
# # 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))
|
||||
# reference image directory setup
|
||||
refdir = joinpath(Pkg.dir("Plots"), "test", "refimg", string(pkg))
|
||||
try
|
||||
run(`mkdir -p $refdir`)
|
||||
@@ -138,45 +106,50 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, sigma = [1
|
||||
end
|
||||
reffn = joinpath(refdir, "ref$idx.png")
|
||||
|
||||
try
|
||||
# the test
|
||||
vtest = VisualTest(func, reffn, idx)
|
||||
test_images(vtest, popup=popup, sigma=sigma, eps=eps)
|
||||
|
||||
# info("Comparing $tmpfn to reference $reffn")
|
||||
# try
|
||||
|
||||
# # info("Comparing $tmpfn to reference $reffn")
|
||||
|
||||
# load the reference image
|
||||
refimg = Images.load(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)
|
||||
# # 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
|
||||
# # 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)
|
||||
# catch err
|
||||
# warn("Image did not match reference image $reffn. err: $err")
|
||||
# # showerror(Base.STDERR, err)
|
||||
|
||||
if isinteractive()
|
||||
# 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
|
||||
# # 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)
|
||||
# # println("exited")
|
||||
# return
|
||||
|
||||
else
|
||||
# else
|
||||
|
||||
# if we rejected the image, or if we're in automated tests, throw the error
|
||||
rethrow(err)
|
||||
end
|
||||
# # if we rejected the image, or if we're in automated tests, throw the error
|
||||
# rethrow(err)
|
||||
# end
|
||||
|
||||
end
|
||||
# end
|
||||
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 = [], debug = false, sigma = [1,1], eps = 1e-2)
|
||||
for i in 1:length(ExamplePlots._examples)
|
||||
i in skip && continue
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) --> true
|
||||
@fact image_comparison_tests(pkg, i, debug=debug, sigma=sigma, eps=eps) |> success --> true
|
||||
end
|
||||
end
|
||||
|
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
@@ -1,23 +1,23 @@
|
||||
module PlotsTests
|
||||
|
||||
|
||||
# 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
|
||||
catch err
|
||||
warn("Couldn't import PyPlot: $err")
|
||||
end
|
||||
# # 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
|
||||
# catch err
|
||||
# warn("Couldn't import PyPlot: $err")
|
||||
# end
|
||||
|
||||
|
||||
using Plots
|
||||
using FactCheck
|
||||
# using Plots
|
||||
# using FactCheck
|
||||
|
||||
# note: wrap first include in a try block because of the ImageMagick init_deps bug
|
||||
try
|
||||
include("imgcomp.jl")
|
||||
end
|
||||
# # note: wrap first include in a try block because of the ImageMagick init_deps bug
|
||||
# try
|
||||
# include("imgcomp.jl")
|
||||
# end
|
||||
include("imgcomp.jl")
|
||||
|
||||
# don't actually show the plots
|
||||
@@ -30,7 +30,7 @@ default(show=false)
|
||||
# gadfly()
|
||||
# backend()
|
||||
|
||||
img_eps = 1e-2
|
||||
img_eps = 5e-2
|
||||
|
||||
facts("Gadfly") do
|
||||
@fact gadfly() --> Plots.GadflyPackage()
|
||||
@@ -40,27 +40,23 @@ facts("Gadfly") do
|
||||
|
||||
# plot(x::AVec, y::AVec; kw...) # one line (will assert length(x) == length(y))
|
||||
@fact plot(Int[1,2,3], rand(3)) --> not(nothing)
|
||||
@fact_throws plot(1:5, 1:4)
|
||||
# @fact_throws plot(1:5, 1:4)
|
||||
|
||||
# plot(x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1))
|
||||
@fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
|
||||
@fact_throws(plot!(rand(10), rand(9,2)))
|
||||
# @fact_throws(plot!(rand(10), rand(9,2)))
|
||||
|
||||
# plot(x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y))
|
||||
@fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
|
||||
|
||||
if VERSION >= v"0.4-"
|
||||
image_comparison_tests(:gadfly, skip=[4,19], eps=img_eps)
|
||||
end
|
||||
image_comparison_facts(:gadfly, skip=[4,6,19,23,24], eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
if VERSION >= v"0.4-"
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotPackage()
|
||||
@fact backend() --> Plots.PyPlotPackage()
|
||||
image_comparison_tests(:pyplot, skip=[19,21], eps=img_eps)
|
||||
end
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotPackage()
|
||||
@fact backend() --> Plots.PyPlotPackage()
|
||||
image_comparison_facts(:pyplot, skip=[10,19,21,23], eps=img_eps)
|
||||
end
|
||||
|
||||
|
||||
@@ -117,7 +113,7 @@ end
|
||||
# @fact backend() --> Plots.PyPlotPackage()
|
||||
# @fact typeof(plot(1:10)) --> Plots.Plot{Plots.PyPlotPackage}
|
||||
|
||||
# # image_comparison_tests(:pyplot, skip=[19])
|
||||
# # image_comparison_facts(:pyplot, skip=[19])
|
||||
# end
|
||||
# catch err
|
||||
# warn("Skipped PyPlot due to: ", string(err))
|
||||
|
||||