Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8ed79a6bb | |||
| cca730d927 | |||
| 0693cb7840 | |||
| 3f1958cce1 | |||
| fb708bed90 | |||
| 1636587a82 | |||
| 1f1ccd81bb | |||
| 5efb0eb582 | |||
| be5f71c123 | |||
| a0df6bfc12 | |||
| 2ab0dc20d7 | |||
| 175ce3613a | |||
| eecb5c3754 | |||
| b34360901f | |||
| 21bbd21ae9 | |||
| 0b403a4c5d | |||
| 1d1e1beca5 | |||
| 3d4d844e72 | |||
| 1f9aa72bdb | |||
| c29f68e35d | |||
| c7c10e769d | |||
| 7264c01b85 | |||
| 97faa7413f | |||
| 7531c48e38 | |||
| 16799d8b75 | |||
| 901115ed10 | |||
| 596ca08446 | |||
| 4d864d8cad | |||
| c458a35670 | |||
| c203bfe5ad | |||
| 8b2a838388 | |||
| b08212e2f9 | |||
| b5f08838b3 | |||
| 5501605a1f | |||
| 7a5197df63 | |||
| 09d45aa64b | |||
| 552810359e | |||
| a68a6885d0 | |||
| b32589f7e7 | |||
| 2e6b8a067d | |||
| 581fdfdfe0 | |||
| 8e4ff39738 | |||
| f568803af2 | |||
| 6db06857ba |
@@ -17,7 +17,7 @@ script:
|
||||
# - 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.add("Cairo"); Pkg.build("Cairo")'
|
||||
- julia -e 'ENV["PYTHON"] = ""; Pkg.add("PyPlot"); Pkg.build("PyPlot")'
|
||||
- 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())'
|
||||
|
||||
@@ -1,419 +0,0 @@
|
||||
|
||||
module PlotExamples
|
||||
|
||||
using Plots
|
||||
using Colors
|
||||
using Compat
|
||||
|
||||
const DOCDIR = Pkg.dir("Plots") * "/docs"
|
||||
const IMGDIR = Pkg.dir("Plots") * "/img"
|
||||
|
||||
"""
|
||||
Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
|
||||
"""
|
||||
type PlotExample
|
||||
header::@compat(AbstractString)
|
||||
desc::@compat(AbstractString)
|
||||
exprs::Vector{Expr}
|
||||
end
|
||||
|
||||
|
||||
|
||||
# the examples we'll run for each
|
||||
const examples = PlotExample[
|
||||
PlotExample("Lines",
|
||||
"A simple line plot of the columns.",
|
||||
[
|
||||
:(plot(Plots.fakedata(50,5), w=3))
|
||||
]),
|
||||
PlotExample("Functions, adding data, and animations",
|
||||
"Plot multiple functions. You can also put the function first, or use the form `plot(f, xmin, xmax)` where f is a Function or AbstractVector{Function}.\n\nGet series data: `x, y = plt[i]`. Set series data: `plt[i] = (x,y)`. Add to the series with `push!`/`append!`.\n\nEasily build animations. (`convert` or `ffmpeg` must be available to generate the animation.) Use command `gif(anim, filename, fps=15)` to save the animation.",
|
||||
[
|
||||
:(p = plot([sin,cos], zeros(0), leg=false)),
|
||||
:(anim = Animation()),
|
||||
:(for x in linspace(0, 10π, 100)
|
||||
push!(p, x, Float64[sin(x), cos(x)])
|
||||
frame(anim)
|
||||
end)
|
||||
]),
|
||||
PlotExample("Parametric plots",
|
||||
"Plot function pair (x(u), y(u)).",
|
||||
[
|
||||
:(plot(sin, x->sin(2x), 0, 2π, line=4, leg=false, fill=(0,:orange)))
|
||||
]),
|
||||
PlotExample("Colors",
|
||||
"Access predefined palettes (or build your own with the `colorscheme` method). Line/marker colors are auto-generated from the plot's palette, unless overridden. Set the `z` argument to turn on series gradients.",
|
||||
[
|
||||
:(y = rand(100)),
|
||||
:(plot(0:10:100,rand(11,4),lab="lines",w=3, palette=:grays, fill=(0.5,:auto))),
|
||||
:(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!`",
|
||||
[
|
||||
:(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", 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.",
|
||||
[
|
||||
:(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...",
|
||||
[
|
||||
:(plot(rand(100)/3, reg=true, fill=(0,:green)))
|
||||
]),
|
||||
PlotExample("",
|
||||
"and add to it later.",
|
||||
[
|
||||
:(scatter!(rand(100), markersize=6, c=:orange))
|
||||
]),
|
||||
PlotExample("Heatmaps",
|
||||
"",
|
||||
[
|
||||
:(heatmap(randn(10000),randn(10000), nbins=20))
|
||||
]),
|
||||
PlotExample("Line types",
|
||||
"",
|
||||
[
|
||||
:(types = intersect(supportedTypes(), [:line, :path, :steppre, :steppost, :sticks, :scatter])'),
|
||||
:(n = length(types)),
|
||||
:(x = Vector[sort(rand(20)) for i in 1:n]),
|
||||
:(y = rand(20,n)),
|
||||
:(plot(x, y, line=(types,3), lab=map(string,types), ms=15))
|
||||
]),
|
||||
PlotExample("Line styles",
|
||||
"",
|
||||
[
|
||||
:(styles = setdiff(supportedStyles(), [:auto])'),
|
||||
:(plot(cumsum(randn(20,length(styles)),1), style=:auto, label=map(string,styles), w=5))
|
||||
]),
|
||||
PlotExample("Marker types",
|
||||
"",
|
||||
[
|
||||
:(markers = setdiff(supportedMarkers(), [:none,:auto,Shape])'),
|
||||
:(n = length(markers)),
|
||||
:(x = linspace(0,10,n+2)[2:end-1]),
|
||||
:(y = repmat(reverse(x)', n, 1)),
|
||||
:(scatter(x, y, m=(8,:auto), lab=map(string,markers), bg=:linen))
|
||||
]),
|
||||
PlotExample("Bar",
|
||||
"x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)",
|
||||
[
|
||||
:(bar(randn(999)))
|
||||
]),
|
||||
PlotExample("Histogram",
|
||||
"",
|
||||
[
|
||||
:(histogram(randn(1000), nbins=20))
|
||||
]),
|
||||
PlotExample("Subplots",
|
||||
"""
|
||||
subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion.
|
||||
You can define the layout with keyword params... either set the number of plots `n` (and optionally number of rows `nr` or
|
||||
number of columns `nc`), or you can set the layout directly with `layout`.
|
||||
""",
|
||||
[
|
||||
:(subplot(randn(100,5), layout=[1,1,3], t=[:line :hist :scatter :step :bar], nbins=10, leg=false))
|
||||
]),
|
||||
PlotExample("Adding to subplots",
|
||||
"Note here the automatic grid layout, as well as the order in which new series are added to the plots.",
|
||||
[
|
||||
:(subplot(Plots.fakedata(100,10), n=4, palette=[:grays :blues :heat :lightrainbow], bg=[:orange :pink :darkblue :black]))
|
||||
]),
|
||||
PlotExample("",
|
||||
"",
|
||||
[
|
||||
:(subplot!(Plots.fakedata(100,10)))
|
||||
]),
|
||||
PlotExample("Open/High/Low/Close",
|
||||
"Create an OHLC chart. Pass in a vector of OHLC objects as your `y` argument. Adjust the tick width with arg `markersize`.",
|
||||
[
|
||||
:(n=20),
|
||||
:(hgt=rand(n)+1),
|
||||
:(bot=randn(n)),
|
||||
:(openpct=rand(n)),
|
||||
:(closepct=rand(n)),
|
||||
:(y = [OHLC(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]),
|
||||
:(ohlc(y; markersize=8))
|
||||
]),
|
||||
PlotExample("Annotations",
|
||||
"Currently only text annotations are supported. Pass in a tuple or vector-of-tuples: (x,y,text). `annotate!(ann)` is shorthand for `plot!(; annotation=ann)`",
|
||||
[
|
||||
:(y = rand(10)),
|
||||
:(plot(y, ann=(3,y[3],text("this is #3",:left)))),
|
||||
:(annotate!([(5,y[5],text("this is #5",16,:red,:center)),
|
||||
(10,y[10],text("this is #10",:right,20,"courier"))]))
|
||||
]),
|
||||
PlotExample("Custom Markers",
|
||||
"A `Plots.Shape` is a light wrapper around vertices of a polygon. For supported backends, pass arbitrary polygons as the marker shapes. Note: The center is (0,0) and the size is expected to be rougly the area of the unit circle.",
|
||||
[
|
||||
:(verts = [(-1.0,1.0),(-1.28,0.6),(-0.2,-1.4),(0.2,-1.4),(1.28,0.6),(1.0,1.0),
|
||||
(-1.0,1.0),(-0.2,-0.6),(0.0,-0.2),(-0.4,0.6),(1.28,0.6),(0.2,-1.4),
|
||||
(-0.2,-1.4),(0.6,0.2),(-0.2,0.2),(0.0,-0.2),(0.2,0.2),(-0.2,-0.6)])
|
||||
:(plot(0.1:0.2:0.9, 0.7rand(5)+0.15,
|
||||
l=(3,:dash,:lightblue),
|
||||
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))
|
||||
])
|
||||
|
||||
]
|
||||
|
||||
|
||||
function createStringOfMarkDownCodeValues(arr, prefix = "")
|
||||
string("`", prefix, join(sort(map(string, arr)), "`, `$prefix"), "`")
|
||||
end
|
||||
createStringOfMarkDownSymbols(arr) = isempty(arr) ? "" : createStringOfMarkDownCodeValues(arr, ":")
|
||||
|
||||
|
||||
function generate_markdown(pkgname::Symbol)
|
||||
|
||||
# set up the backend, and don't show the plots by default
|
||||
pkg = backend(pkgname)
|
||||
# default(:show, false)
|
||||
|
||||
# mkdir if necessary
|
||||
try
|
||||
mkdir("$IMGDIR/$pkgname")
|
||||
end
|
||||
|
||||
# open the markdown file
|
||||
md = open("$DOCDIR/$(pkgname)_examples.md", "w")
|
||||
|
||||
write(md, "## Examples for backend: $pkgname\n\n")
|
||||
|
||||
write(md, "### Initialize\n\n```julia\nusing Plots\n$(pkgname)()\n```\n\n")
|
||||
|
||||
|
||||
for (i,example) in enumerate(examples)
|
||||
|
||||
try
|
||||
|
||||
# we want to always produce consistent results
|
||||
srand(1234)
|
||||
|
||||
# run the code
|
||||
map(eval, example.exprs)
|
||||
|
||||
# # save the png
|
||||
# imgname = "$(pkgname)_example_$i.png"
|
||||
|
||||
# NOTE: uncomment this to overwrite the images as well
|
||||
if i == 2
|
||||
imgname = "$(pkgname)_example_$i.gif"
|
||||
gif(anim, "$IMGDIR/$pkgname/$imgname", fps=15)
|
||||
else
|
||||
imgname = "$(pkgname)_example_$i.png"
|
||||
png("$IMGDIR/$pkgname/$imgname")
|
||||
end
|
||||
|
||||
# write out the header, description, code block, and image link
|
||||
write(md, "### $(example.header)\n\n")
|
||||
write(md, "$(example.desc)\n\n")
|
||||
write(md, "```julia\n$(join(map(string, example.exprs), "\n"))\n```\n\n")
|
||||
write(md, "\n\n")
|
||||
|
||||
catch ex
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i failed with: $ex")
|
||||
end
|
||||
|
||||
#
|
||||
end
|
||||
|
||||
write(md, "- Supported arguments: $(createStringOfMarkDownCodeValues(supportedArgs(pkg)))\n")
|
||||
write(md, "- Supported values for axis: $(createStringOfMarkDownSymbols(supportedAxes(pkg)))\n")
|
||||
write(md, "- Supported values for linetype: $(createStringOfMarkDownSymbols(supportedTypes(pkg)))\n")
|
||||
write(md, "- Supported values for linestyle: $(createStringOfMarkDownSymbols(supportedStyles(pkg)))\n")
|
||||
write(md, "- Supported values for marker: $(createStringOfMarkDownSymbols(supportedMarkers(pkg)))\n")
|
||||
write(md, "- Is `subplot`/`subplot!` supported? $(subplotSupported(pkg) ? "Yes" : "No")\n\n")
|
||||
|
||||
write(md, "(Automatically generated: $(now()))")
|
||||
close(md)
|
||||
|
||||
end
|
||||
|
||||
|
||||
# make and display one plot
|
||||
function test_examples(pkgname::Symbol, idx::Int; debug = true)
|
||||
Plots._debugMode.on = debug
|
||||
println("Testing plot: $pkgname:$idx:$(examples[idx].header)")
|
||||
backend(pkgname)
|
||||
backend()
|
||||
map(eval, examples[idx].exprs)
|
||||
plt = current()
|
||||
gui(plt)
|
||||
plt
|
||||
end
|
||||
|
||||
# generate all plots and create a dict mapping idx --> plt
|
||||
function test_examples(pkgname::Symbol; debug = false)
|
||||
Plots._debugMode.on = debug
|
||||
plts = Dict()
|
||||
for i in 1:length(examples)
|
||||
# if examples[i].header == "Subplots" && !subplotSupported()
|
||||
# break
|
||||
# end
|
||||
|
||||
try
|
||||
plt = test_examples(pkgname, i, debug=debug)
|
||||
plts[i] = plt
|
||||
catch ex
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i:$(examples[i].header) failed with: $ex")
|
||||
end
|
||||
end
|
||||
plts
|
||||
end
|
||||
|
||||
# axis # :left or :right
|
||||
# color # can be a string ("red") or a symbol (:red) or a ColorsTypes.jl
|
||||
# # Colorant (RGB(1,0,0)) or :auto (which lets the package pick)
|
||||
# label # string or symbol, applies to that line, may go in a legend
|
||||
# width # width of a line
|
||||
# linetype # :line, :step, :stepinverted, :sticks, :scatter, :none, :heatmap, :hexbin, :hist, :bar
|
||||
# linestyle # :solid, :dash, :dot, :dashdot, :dashdotdot
|
||||
# marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle,
|
||||
# # :cross, :xcross, :star1, :star2, :hexagon
|
||||
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
||||
# markersize # size of the marker
|
||||
# nbins # number of bins for heatmap/hexbin and histograms
|
||||
# heatmap_c # color cutoffs for Qwt heatmaps
|
||||
# fill # fill value for area plots
|
||||
# title # string or symbol, title of the plot
|
||||
# xlabel # string or symbol, label on the bottom (x) axis
|
||||
# ylabel # string or symbol, label on the left (y) axis
|
||||
# yrightlabel # string or symbol, label on the right (y) axis
|
||||
# reg # true or false, add a regression line for each line
|
||||
# size # (Int,Int), resize the enclosing window
|
||||
# pos # (Int,Int), move the enclosing window to this position
|
||||
# windowtitle # string or symbol, set the title of the enclosing windowtitle
|
||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
||||
|
||||
|
||||
|
||||
@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})",
|
||||
:contour => "Contour lines (uses z)",
|
||||
:path3d => "3D path (uses z)",
|
||||
:scatter3d => "3D scatter plot (uses z)",
|
||||
)
|
||||
|
||||
function buildReadme()
|
||||
readme = readall("$DOCDIR/readme_template.md")
|
||||
|
||||
# build keyword arg table
|
||||
table = "Keyword | Default | Type | Aliases \n---- | ---- | ---- | ----\n"
|
||||
allseries = merge(Plots._seriesDefaults, @compat(Dict(:line=>nothing, :marker=>nothing, :fill=>nothing)))
|
||||
allplots = merge(Plots._plotDefaults, @compat(Dict(:xaxis=>nothing, :yaxis=>nothing)))
|
||||
alldefs = merge(allseries, allplots)
|
||||
for k in Plots.sortedkeys(alldefs)
|
||||
# for d in (Plots._seriesDefaults, Plots._plotDefaults)
|
||||
# for k in Plots.sortedkeys(d)
|
||||
aliasstr = createStringOfMarkDownSymbols(aliases(Plots._keyAliases, k))
|
||||
table = string(table, "`:$k` | `$(alldefs[k])` | $(haskey(allseries,k) ? "Series" : "Plot") | $aliasstr \n")
|
||||
# end
|
||||
end
|
||||
readme = replace(readme, "[[KEYWORD_ARGS_TABLE]]", table)
|
||||
|
||||
# build linetypes table
|
||||
table = "Type | Desc | Aliases\n---- | ---- | ----\n"
|
||||
for lt in Plots._allTypes
|
||||
aliasstr = createStringOfMarkDownSymbols(aliases(Plots._typeAliases, lt))
|
||||
table = string(table, "`:$lt` | $(_ltdesc[lt]) | $aliasstr \n")
|
||||
end
|
||||
readme = replace(readme, "[[LINETYPES_TABLE]]", table)
|
||||
|
||||
# build linestyles table
|
||||
table = "Type | Aliases\n---- | ----\n"
|
||||
for s in Plots._allStyles
|
||||
aliasstr = createStringOfMarkDownSymbols(aliases(Plots._styleAliases, s))
|
||||
table = string(table, "`:$s` | $aliasstr \n")
|
||||
end
|
||||
readme = replace(readme, "[[LINESTYLES_TABLE]]", table)
|
||||
|
||||
# build markers table
|
||||
table = "Type | Aliases\n---- | ----\n"
|
||||
for s in Plots._allMarkers
|
||||
aliasstr = createStringOfMarkDownSymbols(aliases(Plots._markerAliases, s))
|
||||
table = string(table, "`:$s` | $aliasstr \n")
|
||||
end
|
||||
readme = replace(readme, "[[MARKERS_TABLE]]", table)
|
||||
|
||||
readme_fn = Pkg.dir("Plots") * "/README.md"
|
||||
f = open(readme_fn, "w")
|
||||
write(f, readme)
|
||||
close(f)
|
||||
|
||||
gadfly()
|
||||
Plots.dumpSupportGraphs()
|
||||
end
|
||||
|
||||
default(size=(500,300))
|
||||
|
||||
# run it!
|
||||
# note: generate separately so it's easy to comment out
|
||||
# @osx_only generate_markdown(:unicodeplots)
|
||||
# generate_markdown(:qwt)
|
||||
# generate_markdown(:gadfly)
|
||||
# generate_markdown(:pyplot)
|
||||
# generate_markdown(:immerse)
|
||||
# generate_markdown(:winston)
|
||||
|
||||
|
||||
end # module
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
# Plots
|
||||
|
||||
[](https://travis-ci.org/tbreloff/Plots.jl)
|
||||
[](http://pkg.julialang.org/?pkg=Plots&ver=0.3)
|
||||
[](http://pkg.julialang.org/?pkg=Plots&ver=0.4)
|
||||
<!-- [](https://coveralls.io/r/tbreloff/Plots.jl?branch=master) -->
|
||||
<!-- [](http://codecov.io/github/tbreloff/Plots.jl?branch=master) -->
|
||||
|
||||
#### Author: Thomas Breloff (@tbreloff)
|
||||
|
||||
Plots is a plotting API and toolset. My goals with the package are:
|
||||
|
||||
- **Intuitive**. Start generating complex plots without reading volumes of documentation. Commands should "just work".
|
||||
- **Concise**. Less code means fewer mistakes and more efficient development/analysis.
|
||||
- **Flexible**. Produce your favorite plots from your favorite package, but quicker and simpler.
|
||||
- **Consistent**. Don't commit to one graphics package. Use the same code and access the strengths of all backends.
|
||||
- **Lightweight**. Very few dependencies, since backends are loaded and initialized dynamically.
|
||||
|
||||
Use the preprocessing pipeline in Plots to fully describe your visualization before it calls the backend code. This maintains modularity and allows for efficient separation of front end code, algorithms, and backend graphics. New graphical backends can be added with minimal effort.
|
||||
|
||||
Check out the [summary graphs](img/supported/supported.md) for the features that each backend supports.
|
||||
|
||||
Please add wishlist items, bugs, or any other comments/questions to the issues list.
|
||||
|
||||
## Examples for each implemented backend:
|
||||
|
||||
- [Gadfly.jl/Immerse.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/gadfly_examples.md)
|
||||
- [PyPlot.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/pyplot_examples.md)
|
||||
- [UnicodePlots.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/unicodeplots_examples.md)
|
||||
- [Qwt.jl](https://github.com/tbreloff/ExamplePlots.jl/tree/master/docs/qwt_examples.md)
|
||||
|
||||
Also check out the many [IJulia notebooks](http://nbviewer.ipython.org/github/tbreloff/ExamplePlots.jl/tree/master/examples/) with many examples.
|
||||
|
||||
## Installation
|
||||
|
||||
First, add the package
|
||||
|
||||
```julia
|
||||
Pkg.add("Plots")
|
||||
|
||||
# if you want the latest features:
|
||||
Pkg.checkout("Plots")
|
||||
|
||||
# or for the bleeding edge:
|
||||
Pkg.checkout("Plots", "dev")
|
||||
```
|
||||
|
||||
then get any plotting packages you need (obviously, you should get at least one backend).
|
||||
|
||||
```julia
|
||||
Pkg.add("Gadfly")
|
||||
Pkg.add("Immerse")
|
||||
Pkg.add("PyPlot")
|
||||
Pkg.add("UnicodePlots")
|
||||
Pkg.add("Qwt")
|
||||
Pkg.add("Bokeh")
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
Load it in. The underlying plotting backends are not imported until `backend()` is called (which happens
|
||||
on your first call to `plot` or `subplot`). This means that you don't need any backends to be installed when you call `using Plots`.
|
||||
|
||||
Plots will try to figure out a good default backend for you automatically based on what backends are installed.
|
||||
|
||||
```julia
|
||||
using Plots
|
||||
```
|
||||
|
||||
Do a plot in Gadfly (inspired by [this example](http://gadflyjl.org/geom_point.html)), then save a png:
|
||||
|
||||
```julia
|
||||
gadfly() # switch to Gadfly as a backend
|
||||
dataframes() # turn on support for DataFrames inputs
|
||||
|
||||
# load some data
|
||||
using RDatasets
|
||||
iris = dataset("datasets", "iris");
|
||||
|
||||
# This will bring up a browser window with the plot. Add a semicolon at the end to skip display.
|
||||
scatter(iris, :SepalLength, :SepalWidth, group=:Species, m=([:+ :d :s], 12), smooth=0.99, bg=:black)
|
||||
|
||||
# save a png (equivalent to png("gadfly1.png") and savefig("gadfly1.png"))
|
||||
png("gadfly1")
|
||||
```
|
||||
|
||||

|
||||
|
||||
## API
|
||||
|
||||
Call `backend(backend::Symbol)` or the shorthands (`gadfly()`, `qwt()`, `unicodeplots()`, etc) to set the current plotting backend.
|
||||
Subsequent commands are converted into the relevant plotting commands for that package:
|
||||
|
||||
```julia
|
||||
gadfly()
|
||||
plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)`
|
||||
qwt()
|
||||
plot(1:10) # this effectively calls `Qwt.plot(1:10)`
|
||||
```
|
||||
|
||||
Use `plot` to create a new plot object, and `plot!` to add to an existing one:
|
||||
|
||||
```julia
|
||||
plot(args...; kw...) # creates a new plot window, and sets it to be the `current`
|
||||
plot!(args...; kw...) # adds to the `current`
|
||||
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
|
||||
```
|
||||
|
||||
Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity.
|
||||
There are many ways to pass in data to the plot functions... some examples:
|
||||
|
||||
- Vector-like (subtypes of AbstractArray{T,1})
|
||||
- Matrix-like (subtypes of AbstractArray{T,2})
|
||||
- Vectors of Vectors
|
||||
- Functions
|
||||
- Vectors of Functions
|
||||
- DataFrames with column symbols (initialize with `dataframes()`)
|
||||
|
||||
In general, you can pass in a `y` only, or an `x` and `y`, both of whatever type(s) you want, and Plots will slice up the data as needed.
|
||||
For matrices, data is split by columns. For functions, data is mapped. For DataFrames, a Symbol/Symbols in place of x/y will map to
|
||||
the relevant column(s).
|
||||
|
||||
Here are some example usages... remember you can always use `plot!` to update an existing plot, and that, unless specified, you will update the `current()`.
|
||||
|
||||
```julia
|
||||
plot() # empty plot object
|
||||
plot(4) # initialize with 4 empty series
|
||||
plot(rand(10)) # plot 1 series... x = 1:10
|
||||
plot(rand(10,5)) # plot 5 series... x = 1:10
|
||||
plot(rand(10), rand(10)) # plot 1 series
|
||||
plot(rand(10,5), rand(10)) # plot 5 series... y is the same for all
|
||||
plot(sin, rand(10)) # y = sin(x)
|
||||
plot(rand(10), sin) # same... y = sin(x)
|
||||
plot([sin,cos], 0:0.1:π) # plot 2 series, sin(x) and cos(x)
|
||||
plot([sin,cos], 0, π) # plot sin and cos on the range [0, π]
|
||||
plot(1:10, Any[rand(10), sin]) # plot 2 series, y = rand(10) for the first, y = sin(x) for the second... x = 1:10 for both
|
||||
plot(dataset("Ecdat", "Airline"), :Cost) # plot from a DataFrame (call `dataframes()` first to import DataFrames and initialize)
|
||||
```
|
||||
|
||||
All plot methods accept a number of keyword arguments (see the tables below), which follow some rules:
|
||||
- Many arguments have aliases which are replaced during preprocessing. `c` is the same as `color`, `m` is the same as `marker`, etc. You can choose how verbose you'd like to be. (see the tables below)
|
||||
- There are some special arguments (`xaxis`, `yaxis`, `line`, `marker`, `fill` and the aliases `l`, `m`, `f`) which magically set many related things at once. (see the __Tip__ below)
|
||||
- If the argument is a "matrix-type", then each column will map to a series, cycling through columns if there are fewer columns than series. Anything else will apply the argument value to every series.
|
||||
- Many arguments accept many different types... for example the `color` (also `markercolor`, `fillcolor`, etc) argument will accept strings or symbols with a color name, or any `Colors.Colorant`, or a `ColorScheme`, or a symbol representing a `ColorGradient`, or an AbstractVector of colors/symbols/etc...
|
||||
|
||||
You can update certain plot settings after plot creation (not supported on all backends):
|
||||
|
||||
```julia
|
||||
plot!(title = "New Title", xlabel = "New xlabel", ylabel = "New ylabel")
|
||||
plot!(xlims = (0, 5.5), ylims = (-2.2, 6), xticks = 0:0.5:10, yticks = [0,1,5,10])
|
||||
|
||||
# using shorthands:
|
||||
xaxis!("mylabel", :log10, :flip)
|
||||
```
|
||||
|
||||
With `subplot`, create multiple plots at once, with flexible layout options:
|
||||
|
||||
```julia
|
||||
y = rand(100,3)
|
||||
subplot(y; n = 3) # create an automatic grid, and let it figure out the shape
|
||||
subplot(y; n = 3, nr = 1) # create an automatic grid, but fix the number of rows
|
||||
subplot(y; n = 3, nc = 1) # create an automatic grid, but fix the number of columns
|
||||
subplot(y; layout = [1, 2]) # explicit layout. Lists the number of plots in each row
|
||||
```
|
||||
|
||||
__Tip__: You can call `subplot!(args...; kw...)` to add to an existing subplot.
|
||||
|
||||
__Tip__: Calling `subplot!` on a `Plot` object, or `plot!` on a `Subplot` object will throw an error.
|
||||
|
||||
Shorthands:
|
||||
|
||||
```julia
|
||||
scatter(args...; kw...) = plot(args...; kw..., linetype = :scatter)
|
||||
scatter!(args...; kw...) = plot!(args...; kw..., linetype = :scatter)
|
||||
bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap)
|
||||
sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse)
|
||||
hline(args...; kw...) = plot(args...; kw..., linetype = :hline)
|
||||
hline!(args...; kw...) = plot!(args...; kw..., linetype = :hline)
|
||||
vline(args...; kw...) = plot(args...; kw..., linetype = :vline)
|
||||
vline!(args...; kw...) = plot!(args...; kw..., linetype = :vline)
|
||||
ohlc(args...; kw...) = plot(args...; kw..., linetype = :ohlc)
|
||||
ohlc!(args...; kw...) = plot!(args...; kw..., linetype = :ohlc)
|
||||
|
||||
title!(s::AbstractString) = plot!(title = s)
|
||||
xlabel!(s::AbstractString) = plot!(xlabel = s)
|
||||
ylabel!(s::AbstractString) = plot!(ylabel = s)
|
||||
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(xlims = lims)
|
||||
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}) = plot!(ylims = lims)
|
||||
xticks!{T<:Real}(v::AVec{T}) = plot!(xticks = v)
|
||||
yticks!{T<:Real}(v::AVec{T}) = plot!(yticks = v)
|
||||
xflip!(flip::Bool = true) = plot!(xflip = flip)
|
||||
yflip!(flip::Bool = true) = plot!(yflip = flip)
|
||||
xaxis!(args...) = plot!(xaxis = args)
|
||||
yaxis!(args...) = plot!(yaxis = args)
|
||||
annotate!(anns) = plot!(annotation = anns)
|
||||
```
|
||||
|
||||
### Keyword arguments:
|
||||
|
||||
[[KEYWORD_ARGS_TABLE]]
|
||||
|
||||
### Plot types:
|
||||
|
||||
[[LINETYPES_TABLE]]
|
||||
|
||||
### Line styles:
|
||||
|
||||
[[LINESTYLES_TABLE]]
|
||||
|
||||
### Markers:
|
||||
|
||||
[[MARKERS_TABLE]]
|
||||
|
||||
__Tip__: With supported backends, you can pass a `Plots.Shape` object for the `marker`/`markershape` arguments. `Shape` takes a vector of 2-tuples in the constructor, defining the points of the polygon's shape in a unit-scaled coordinate space. To make a square, for example, you could do `Shape([(1,1),(1,-1),(-1,-1),(-1,1)])`
|
||||
|
||||
__Tip__: You can see the default value for a given argument with `default(arg::Symbol)`, and set the default value with `default(arg::Symbol, value)` or `default(; kw...)`. For example set the default window size and whether we should show a legend with `default(size=(600,400), leg=false)`.
|
||||
|
||||
__Tip__: There are some helper arguments you can set: `xaxis`, `yaxis`, `line`, `marker`, `fill`. These go through special preprocessing to extract values into individual arguments. The order doesn't matter, and if you pass a single value it's equivalent to wrapping it in a Tuple. Examples:
|
||||
|
||||
```
|
||||
plot(y, xaxis = ("mylabel", :log, :flip, (-1,1))) # this sets the `xlabel`, `xscale`, `xflip`, and `xlims` arguments automatically
|
||||
plot(y, line = (:bar, :blue, :dot, 10)) # this sets the `linetype`, `color`, `linestyle`, and `linewidth` arguments automatically
|
||||
plot(y, marker = (:rect, :red, 10)) # this sets the `markershape`, `markercolor`, and `markersize` arguments automatically
|
||||
plot(y, fill = (:green, 10)) # this sets the `fillcolor` and `fillrange` arguments automatically
|
||||
# Note: `fillrange` can be:
|
||||
a number (fill to horizontal line)
|
||||
a vector of numbers (different for each data point)
|
||||
a tuple of vectors (fill a band)
|
||||
```
|
||||
|
||||
__Tip__: When plotting multiple lines, you can set all series to use the same value, or pass in a matrix to cycle through values. Example:
|
||||
|
||||
```julia
|
||||
plot(rand(100,4); color = [:red RGB(0,0,1)], # (Matrix) lines 1 and 3 are red, lines 2 and 4 are blue
|
||||
axis = :auto, # lines 1 and 3 are on the left axis, lines 2 and 4 are on the right
|
||||
markershape = [:rect, :star] # (Vector) ALL lines are passed the vector [:rect, :star1]
|
||||
width = 5) # all lines have a width of 5
|
||||
```
|
||||
|
||||
__Tip__: Not all features are supported for each backend, but you can see what's supported by calling the functions: `supportedArgs()`, `supportedAxes()`, `supportedTypes()`, `supportedStyles()`, `supportedMarkers()`, `subplotSupported()`
|
||||
|
||||
__Tip__: Call `gui()` to display the plot in a window. Interactivity depends on backend. Plotting at the REPL (without semicolon) implicitly calls `gui()`.
|
||||
|
||||
### Animations
|
||||
|
||||
Animations are created in 3 steps (see example #2):
|
||||
- Initialize an `Animation` object.
|
||||
- Save each frame of the animation with `frame(anim)`.
|
||||
- Convert the frames to an animated gif with `gif(anim, filename, fps=15)`
|
||||
|
||||
|
||||
## TODO features:
|
||||
|
||||
- [x] Plot vectors/matrices/functions
|
||||
- [x] Plot DataFrames
|
||||
- [x] Histograms
|
||||
- [x] Grouping
|
||||
- [x] Annotations
|
||||
- [x] Scales
|
||||
- [x] Categorical Inputs (strings, etc... for hist, bar? or can split one series into multiple?)
|
||||
- [x] Custom markers
|
||||
- [x] Animations
|
||||
- [x] Subplots
|
||||
- [ ] Contours
|
||||
- [ ] Boxplots
|
||||
- [ ] 3D plotting
|
||||
- [ ] Scenes/Drawing
|
||||
- [ ] Graphs
|
||||
- [ ] Interactivity (GUIs)
|
||||
|
||||
## TODO backends:
|
||||
|
||||
- [x] Gadfly.jl
|
||||
- [x] Immerse.jl
|
||||
- [x] PyPlot.jl
|
||||
- [x] UnicodePlots.jl
|
||||
- [x] Qwt.jl
|
||||
- [x] Winston.jl (deprecated)
|
||||
- [ ] GLPlot.jl
|
||||
- [ ] Bokeh.jl
|
||||
- [ ] Vega.jl
|
||||
- [ ] Gaston.jl
|
||||
- [ ] Plotly.jl
|
||||
- [ ] GoogleCharts.jl
|
||||
- [ ] PLplot.jl
|
||||
- [ ] TextPlots.jl
|
||||
- [ ] ASCIIPlots.jl
|
||||
- [ ] Sparklines.jl
|
||||
- [ ] Hinton.jl
|
||||
- [ ] ImageTerm.jl
|
||||
- [ ] GraphViz.jl
|
||||
- [ ] TikzGraphs.jl
|
||||
- [ ] GraphLayout.jl
|
||||
|
||||
## More information on backends (both supported and unsupported)
|
||||
|
||||
See the wiki at: https://github.com/JuliaPlot/juliaplot_docs/wiki
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 28 KiB |
@@ -1,23 +0,0 @@
|
||||
## Supported keyword arguments
|
||||
|
||||

|
||||
|
||||
## Supported plot types
|
||||
|
||||

|
||||
|
||||
## Supported markers
|
||||
|
||||

|
||||
|
||||
## Supported line styles
|
||||
|
||||

|
||||
|
||||
## Supported scales
|
||||
|
||||

|
||||
|
||||
## Supported axes
|
||||
|
||||

|
||||
@@ -1,333 +0,0 @@
|
||||
|
||||
|
||||
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 BokehPackage <: PlottingPackage end
|
||||
immutable PlotlyPackage <: PlottingPackage end
|
||||
immutable GRPackage <: PlottingPackage end
|
||||
immutable GLVisualizePackage <: PlottingPackage end
|
||||
immutable NoPackage <: PlottingPackage end
|
||||
|
||||
typealias GadflyOrImmerse @compat(Union{GadflyPackage, ImmersePackage})
|
||||
|
||||
export
|
||||
gadfly,
|
||||
immerse,
|
||||
pyplot,
|
||||
qwt,
|
||||
unicodeplots,
|
||||
bokeh,
|
||||
plotly,
|
||||
gr,
|
||||
glvisualize
|
||||
# winston
|
||||
|
||||
gadfly(; kw...) = (default(; kw...); backend(:gadfly))
|
||||
immerse(; kw...) = (default(; kw...); backend(:immerse))
|
||||
pyplot(; kw...) = (default(; kw...); backend(:pyplot))
|
||||
qwt(; kw...) = (default(; kw...); backend(:qwt))
|
||||
unicodeplots(; kw...) = (default(; kw...); backend(:unicodeplots))
|
||||
bokeh(; kw...) = (default(; kw...); backend(:bokeh))
|
||||
plotly(; kw...) = (default(; kw...); backend(:plotly))
|
||||
gr(; kw...) = (default(; kw...); backend(:gr))
|
||||
glvisualize(; kw...) = (default(; kw...); backend(:glvisualize))
|
||||
# winston(; kw...) = (default(; kw...); backend(:winston))
|
||||
|
||||
backend_name(::GadflyPackage) = :gadfly
|
||||
backend_name(::ImmersePackage) = :immerse
|
||||
backend_name(::PyPlotPackage) = :pyplot
|
||||
backend_name(::UnicodePlotsPackage) = :unicodeplots
|
||||
backend_name(::QwtPackage) = :qwt
|
||||
backend_name(::BokehPackage) = :bokeh
|
||||
backend_name(::PlotlyPackage) = :plotly
|
||||
backend_name(::GRPackage) = :gr
|
||||
backend_name(::GLVisualizePackage) = :glvisualize
|
||||
backend_name(::NoPackage) = :none
|
||||
|
||||
include("backends/supported.jl")
|
||||
|
||||
include("backends/qwt.jl")
|
||||
include("backends/gadfly.jl")
|
||||
include("backends/unicodeplots.jl")
|
||||
include("backends/pyplot.jl")
|
||||
include("backends/immerse.jl")
|
||||
include("backends/winston.jl")
|
||||
|
||||
include("backends/web.jl")
|
||||
include("backends/bokeh.jl")
|
||||
include("backends/plotly.jl")
|
||||
include("backends/gr.jl")
|
||||
|
||||
include("backends/glvisualize.jl")
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
|
||||
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
|
||||
_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")
|
||||
|
||||
_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")
|
||||
# Base.display(pkg::PlottingPackage, subplt::Subplot) = error("display($pkg, subplt) is not implemented")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh, :plotly, :gr]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
backends() = BACKENDS
|
||||
|
||||
|
||||
function _backend_instance(sym::Symbol)
|
||||
sym == :qwt && return QwtPackage()
|
||||
sym == :gadfly && return GadflyPackage()
|
||||
sym == :unicodeplots && return UnicodePlotsPackage()
|
||||
sym == :pyplot && return PyPlotPackage()
|
||||
sym == :immerse && return ImmersePackage()
|
||||
sym == :winston && return WinstonPackage()
|
||||
sym == :bokeh && return BokehPackage()
|
||||
sym == :plotly && return PlotlyPackage()
|
||||
sym == :gr && return GRPackage()
|
||||
sym == :glvisualize && return GLVisualizePackage()
|
||||
sym == :none && return NoPackage()
|
||||
error("Unsupported backend $sym")
|
||||
end
|
||||
|
||||
|
||||
type CurrentBackend
|
||||
sym::Symbol
|
||||
pkg::PlottingPackage
|
||||
end
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function pickDefaultBackend()
|
||||
for pkgstr in ("PyPlot", "Immerse", "Qwt", "Gadfly", "GR", "UnicodePlots", "Bokeh", "GLVisualize")
|
||||
if Pkg.installed(pkgstr) != nothing
|
||||
return backend(symbol(lowercase(pkgstr)))
|
||||
end
|
||||
end
|
||||
backend(:plotly)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
"""
|
||||
Returns the current plotting package name. Initializes package on first call.
|
||||
"""
|
||||
function backend()
|
||||
|
||||
global CURRENT_BACKEND
|
||||
if CURRENT_BACKEND.sym == :none
|
||||
pickDefaultBackend()
|
||||
end
|
||||
|
||||
currentBackendSymbol = CURRENT_BACKEND.sym
|
||||
if !(currentBackendSymbol in _initialized_backends)
|
||||
|
||||
# initialize
|
||||
println("[Plots.jl] Initializing backend: ", CURRENT_BACKEND.sym)
|
||||
if currentBackendSymbol == :qwt
|
||||
try
|
||||
@eval import Qwt
|
||||
@eval export Qwt
|
||||
catch err
|
||||
warn("Couldn't import Qwt. Install it with: Pkg.clone(\"https://github.com/tbreloff/Qwt.jl.git\")\n (Note: also requires pyqt and pyqwt).")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :gadfly
|
||||
try
|
||||
@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\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :unicodeplots
|
||||
try
|
||||
@eval import UnicodePlots
|
||||
@eval export UnicodePlots
|
||||
catch err
|
||||
warn("Couldn't import UnicodePlots. Install it with: Pkg.add(\"UnicodePlots\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :pyplot
|
||||
try
|
||||
@eval import PyPlot
|
||||
@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"
|
||||
# PyPlot.gui[1] = :qt_pyqt4
|
||||
# PyPlot.switch_backend("Qt4Agg")
|
||||
|
||||
# only turn on the gui if we want it
|
||||
if PyPlot.gui != :none
|
||||
PyPlot.pygui(true)
|
||||
end
|
||||
|
||||
end
|
||||
catch err
|
||||
warn("Couldn't import PyPlot. Install it with: Pkg.add(\"PyPlot\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :immerse
|
||||
try
|
||||
@eval import Immerse, Gadfly, Compose, Gtk
|
||||
@eval export Immerse, Gadfly, Compose, Gtk
|
||||
@eval include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl"))
|
||||
catch err
|
||||
# error("Couldn't import Immerse. Install it with: Pkg.add(\"Immerse\").\n Error: ", err)
|
||||
warn("Couldn't import Immerse. Install it with: Pkg.add(\"Immerse\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :bokeh
|
||||
try
|
||||
@eval import Bokeh
|
||||
@eval export Bokeh
|
||||
catch err
|
||||
warn("Couldn't import Bokeh. Install it with: Pkg.add(\"Bokeh\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :plotly
|
||||
try
|
||||
@eval begin
|
||||
import JSON
|
||||
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
|
||||
|
||||
############################
|
||||
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
|
||||
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
# the first script is some hack I needed to do in order for the notebook
|
||||
# to not complain about Plotly being undefined
|
||||
display("text/html", """
|
||||
<script type="text/javascript">
|
||||
require=requirejs=define=undefined;
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(open(readall, _js_path, "r"))
|
||||
</script>
|
||||
""")
|
||||
# display("text/html", "<p>Plotly javascript loaded.</p>")
|
||||
end
|
||||
# end borrowing (thanks :)
|
||||
###########################
|
||||
|
||||
try
|
||||
include(joinpath(Pkg.dir("Plots"), "src", "backends", "plotly_blink.jl"))
|
||||
catch err
|
||||
warn("Error including PlotlyJS: $err\n Note: Will fall back to built-in display.")
|
||||
end
|
||||
|
||||
end
|
||||
catch err
|
||||
warn("Couldn't setup Plotly")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :gr
|
||||
try
|
||||
@eval import GR
|
||||
catch err
|
||||
warn("Couldn't import GR. Install it with: Pkg.add(\"GR\").")
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :glvisualize
|
||||
try
|
||||
@eval import GLVisualize
|
||||
@eval export GLVisualize
|
||||
catch err
|
||||
warn("Couldn't setup GLVisualize")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
elseif currentBackendSymbol == :winston
|
||||
warn("Winston support is deprecated and broken. Try another backend: $BACKENDS")
|
||||
try
|
||||
@eval ENV["WINSTON_OUTPUT"] = "gtk"
|
||||
@eval import Winston, Gtk
|
||||
@eval export Winston, Gtk
|
||||
catch err
|
||||
warn("Couldn't import Winston. Install it with: Pkg.add(\"Winston\").")
|
||||
rethrow(err)
|
||||
end
|
||||
|
||||
else
|
||||
error("Unknown backend $currentBackendSymbol. Choose from: $BACKENDS")
|
||||
end
|
||||
push!(_initialized_backends, currentBackendSymbol)
|
||||
|
||||
end
|
||||
CURRENT_BACKEND.pkg
|
||||
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()
|
||||
elseif modname == :gadfly
|
||||
CURRENT_BACKEND.pkg = GadflyPackage()
|
||||
elseif modname == :unicodeplots
|
||||
CURRENT_BACKEND.pkg = UnicodePlotsPackage()
|
||||
elseif modname == :pyplot
|
||||
CURRENT_BACKEND.pkg = PyPlotPackage()
|
||||
elseif modname == :immerse
|
||||
CURRENT_BACKEND.pkg = ImmersePackage()
|
||||
elseif modname == :winston
|
||||
CURRENT_BACKEND.pkg = WinstonPackage()
|
||||
elseif modname == :bokeh
|
||||
CURRENT_BACKEND.pkg = BokehPackage()
|
||||
elseif modname == :plotly
|
||||
CURRENT_BACKEND.pkg = PlotlyPackage()
|
||||
elseif modname == :gr
|
||||
CURRENT_BACKEND.pkg = GRPackage()
|
||||
elseif modname == :glvisualize
|
||||
CURRENT_BACKEND.pkg = GLVisualizePackage()
|
||||
else
|
||||
error("Unknown backend $modname. Choose from: $BACKENDS")
|
||||
end
|
||||
|
||||
# update the symbol
|
||||
CURRENT_BACKEND.sym = modname
|
||||
# println("[Plots.jl] Switched to backend: ", modname)
|
||||
|
||||
# return the package
|
||||
CURRENT_BACKEND.pkg
|
||||
end
|
||||
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 31 KiB |
@@ -1,21 +0,0 @@
|
||||
|
||||
|
||||
function testplot_line1()
|
||||
plot(rand(100,3))
|
||||
end
|
||||
|
||||
function testplot_fn1()
|
||||
plot(0:0.01:4π, [sin,cos])
|
||||
end
|
||||
|
||||
function testplot_guides1()
|
||||
plot(rand(10); title="TITLE", xlabel="XLABEL", ylabel="YLABEL", background_color=:red)
|
||||
end
|
||||
|
||||
function testplot_points1()
|
||||
plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8)
|
||||
end
|
||||
|
||||
function testplot_points2()
|
||||
plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8, markercolors=[:red,:blue])
|
||||
end
|
||||
@@ -10,120 +10,127 @@ using Requires
|
||||
using FixedSizeArrays
|
||||
|
||||
export
|
||||
Plot,
|
||||
Subplot,
|
||||
SubplotLayout,
|
||||
GridLayout,
|
||||
FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
AbstractPlot,
|
||||
Plot,
|
||||
Subplot,
|
||||
SubplotLayout,
|
||||
GridLayout,
|
||||
RowsLayout,
|
||||
FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
subplot,
|
||||
subplot!,
|
||||
plot,
|
||||
plot!,
|
||||
subplot,
|
||||
subplot!,
|
||||
|
||||
current,
|
||||
default,
|
||||
with,
|
||||
|
||||
scatter,
|
||||
scatter!,
|
||||
bar,
|
||||
bar!,
|
||||
histogram,
|
||||
histogram!,
|
||||
density,
|
||||
density!,
|
||||
heatmap,
|
||||
heatmap!,
|
||||
hexbin,
|
||||
hexbin!,
|
||||
sticks,
|
||||
sticks!,
|
||||
hline,
|
||||
hline!,
|
||||
vline,
|
||||
vline!,
|
||||
ohlc,
|
||||
ohlc!,
|
||||
pie,
|
||||
pie!,
|
||||
contour,
|
||||
contour!,
|
||||
surface,
|
||||
surface!,
|
||||
wireframe,
|
||||
wireframe!,
|
||||
path3d,
|
||||
path3d!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
scatter3d,
|
||||
scatter3d!,
|
||||
abline!,
|
||||
current,
|
||||
default,
|
||||
with,
|
||||
|
||||
title!,
|
||||
xlabel!,
|
||||
ylabel!,
|
||||
xlims!,
|
||||
ylims!,
|
||||
xticks!,
|
||||
yticks!,
|
||||
annotate!,
|
||||
xflip!,
|
||||
yflip!,
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
scatter,
|
||||
scatter!,
|
||||
bar,
|
||||
bar!,
|
||||
histogram,
|
||||
histogram!,
|
||||
histogram2d,
|
||||
histogram2d!,
|
||||
density,
|
||||
density!,
|
||||
heatmap,
|
||||
heatmap!,
|
||||
hexbin,
|
||||
hexbin!,
|
||||
sticks,
|
||||
sticks!,
|
||||
hline,
|
||||
hline!,
|
||||
vline,
|
||||
vline!,
|
||||
ohlc,
|
||||
ohlc!,
|
||||
pie,
|
||||
pie!,
|
||||
contour,
|
||||
contour!,
|
||||
surface,
|
||||
surface!,
|
||||
wireframe,
|
||||
wireframe!,
|
||||
path3d,
|
||||
path3d!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
scatter3d,
|
||||
scatter3d!,
|
||||
abline!,
|
||||
|
||||
savefig,
|
||||
png,
|
||||
gui,
|
||||
title!,
|
||||
xlabel!,
|
||||
ylabel!,
|
||||
xlims!,
|
||||
ylims!,
|
||||
zlims!,
|
||||
xticks!,
|
||||
yticks!,
|
||||
annotate!,
|
||||
xflip!,
|
||||
yflip!,
|
||||
xaxis!,
|
||||
yaxis!,
|
||||
|
||||
backend,
|
||||
backends,
|
||||
backend_name,
|
||||
aliases,
|
||||
dataframes,
|
||||
savefig,
|
||||
png,
|
||||
gui,
|
||||
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
backend,
|
||||
backends,
|
||||
backend_name,
|
||||
aliases,
|
||||
dataframes,
|
||||
|
||||
colorscheme,
|
||||
ColorScheme,
|
||||
ColorGradient,
|
||||
ColorVector,
|
||||
ColorWrapper,
|
||||
ColorFunction,
|
||||
ColorZFunction,
|
||||
getColor,
|
||||
getColorZ,
|
||||
Shape,
|
||||
text,
|
||||
font,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
|
||||
debugplots,
|
||||
colorscheme,
|
||||
ColorScheme,
|
||||
ColorGradient,
|
||||
ColorVector,
|
||||
ColorWrapper,
|
||||
ColorFunction,
|
||||
ColorZFunction,
|
||||
getColor,
|
||||
getColorZ,
|
||||
|
||||
supportedArgs,
|
||||
supportedAxes,
|
||||
supportedTypes,
|
||||
supportedStyles,
|
||||
supportedMarkers,
|
||||
subplotSupported,
|
||||
debugplots,
|
||||
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
@animate,
|
||||
@gif,
|
||||
supportedArgs,
|
||||
supportedAxes,
|
||||
supportedTypes,
|
||||
supportedStyles,
|
||||
supportedMarkers,
|
||||
subplotSupported,
|
||||
|
||||
# recipes
|
||||
PlotRecipe,
|
||||
# EllipseRecipe,
|
||||
# spy,
|
||||
corrplot
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
@animate,
|
||||
@gif,
|
||||
|
||||
# recipes
|
||||
PlotRecipe,
|
||||
# EllipseRecipe,
|
||||
spy,
|
||||
arcdiagram,
|
||||
chorddiagram
|
||||
# corrplot
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
@@ -132,10 +139,12 @@ include("types.jl")
|
||||
include("utils.jl")
|
||||
include("colors.jl")
|
||||
include("components.jl")
|
||||
include("plotter2.jl")
|
||||
include("backends.jl")
|
||||
include("args.jl")
|
||||
include("plot.jl")
|
||||
include("series_args.jl")
|
||||
include("subplot.jl")
|
||||
include("layouts.jl")
|
||||
include("recipes.jl")
|
||||
include("animation.jl")
|
||||
include("output.jl")
|
||||
@@ -149,6 +158,8 @@ bar(args...; kw...) = plot(args...; kw..., linetype = :bar)
|
||||
bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar)
|
||||
histogram(args...; kw...) = plot(args...; kw..., linetype = :hist)
|
||||
histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist)
|
||||
histogram2d(args...; kw...) = plot(args...; kw..., linetype = :hist2d)
|
||||
histogram2d!(args...; kw...) = plot!(args...; kw..., linetype = :hist2d)
|
||||
density(args...; kw...) = plot(args...; kw..., linetype = :density)
|
||||
density!(args...; kw...) = plot!(args...; kw..., linetype = :density)
|
||||
heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap)
|
||||
@@ -179,18 +190,20 @@ 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...)
|
||||
xlabel!(s::@compat(AbstractString); kw...) = plot!(; xlabel = s, kw...)
|
||||
ylabel!(s::@compat(AbstractString); kw...) = plot!(; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(lims::@compat(Tuple{T,S}); kw...) = plot!(; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(lims::@compat(Tuple{T,S}); kw...) = plot!(; ylims = lims, kw...)
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
|
||||
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...)
|
||||
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...)
|
||||
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
|
||||
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
|
||||
zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmin,zmax), kw...)
|
||||
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...)
|
||||
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...)
|
||||
xticks!{T<:Real,S<:@compat(AbstractString)}(
|
||||
xticks!{T<:Real,S<:AbstractString}(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:@compat(AbstractString)}(
|
||||
yticks!{T<:Real,S<:AbstractString}(
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...)
|
||||
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...)
|
||||
@@ -199,18 +212,20 @@ yflip!(flip::Bool = true; kw...) = plot!(; yflip = flip
|
||||
xaxis!(args...; kw...) = plot!(; xaxis = args, kw...)
|
||||
yaxis!(args...; kw...) = plot!(; yaxis = args, kw...)
|
||||
|
||||
title!(plt::Plot, s::@compat(AbstractString); kw...) = plot!(plt; title = s, kw...)
|
||||
xlabel!(plt::Plot, s::@compat(AbstractString); kw...) = plot!(plt; xlabel = s, kw...)
|
||||
ylabel!(plt::Plot, s::@compat(AbstractString); kw...) = plot!(plt; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(plt::Plot, lims::@compat(Tuple{T,S}); kw...) = plot!(plt; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(plt::Plot, lims::@compat(Tuple{T,S}); kw...) = plot!(plt; ylims = lims, kw...)
|
||||
title!(plt::Plot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
|
||||
xlabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
|
||||
ylabel!(plt::Plot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
|
||||
xlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...)
|
||||
ylims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...)
|
||||
zlims!{T<:Real,S<:Real}(plt::Plot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...)
|
||||
xlims!(plt::Plot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
|
||||
ylims!(plt::Plot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
|
||||
zlims!(plt::Plot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
|
||||
xticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...)
|
||||
yticks!{T<:Real}(plt::Plot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...)
|
||||
xticks!{T<:Real,S<:@compat(AbstractString)}(plt::Plot,
|
||||
xticks!{T<:Real,S<:AbstractString}(plt::Plot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...)
|
||||
yticks!{T<:Real,S<:@compat(AbstractString)}(plt::Plot,
|
||||
yticks!{T<:Real,S<:AbstractString}(plt::Plot,
|
||||
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...)
|
||||
annotate!(plt::Plot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
annotate!{T<:Tuple}(plt::Plot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...)
|
||||
@@ -230,8 +245,11 @@ function __init__()
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
@eval import IJulia
|
||||
IJulia.display_dict(plt::PlottingObject) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
|
||||
IJulia.display_dict(plt::AbstractPlot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt))
|
||||
end
|
||||
|
||||
setup_dataframes()
|
||||
setup_atom()
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -9,7 +9,7 @@ function Animation()
|
||||
Animation(tmpdir, ASCIIString[])
|
||||
end
|
||||
|
||||
function frame{P<:PlottingObject}(anim::Animation, plt::P=current())
|
||||
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
const _allAxes = [:auto, :left, :right]
|
||||
@compat const _axesAliases = Dict(
|
||||
@compat const _axesAliases = KW(
|
||||
:a => :auto,
|
||||
:l => :left,
|
||||
:r => :right
|
||||
@@ -10,10 +10,10 @@ const _allAxes = [:auto, :left, :right]
|
||||
const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe]
|
||||
const _allTypes = vcat([
|
||||
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
|
||||
:heatmap, :hexbin, :hist, :density, :bar, :hline, :vline, :ohlc,
|
||||
:contour, :pie
|
||||
:heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc,
|
||||
:contour, :pie, :shape
|
||||
], _3dTypes)
|
||||
@compat const _typeAliases = Dict(
|
||||
@compat const _typeAliases = KW(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
:l => :line,
|
||||
@@ -35,15 +35,18 @@ const _allTypes = vcat([
|
||||
:line3d => :path3d,
|
||||
:surf => :surface,
|
||||
:wire => :wireframe,
|
||||
:shapes => :shape,
|
||||
:poly => :shape,
|
||||
:polygon => :shape,
|
||||
)
|
||||
|
||||
ishistlike(lt::Symbol) = lt in (:hist, :density)
|
||||
islinelike(lt::Symbol) = lt in (:line, :path, :steppre, :steppost)
|
||||
isheatmaplike(lt::Symbol) = lt in (:heatmap, :hexbin)
|
||||
like_histogram(linetype::Symbol) = linetype in (:hist, :density)
|
||||
like_line(linetype::Symbol) = linetype in (:line, :path, :steppre, :steppost)
|
||||
like_surface(linetype::Symbol) = linetype in (:contour, :heatmap, :surface, :wireframe)
|
||||
|
||||
|
||||
const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
@compat const _styleAliases = Dict(
|
||||
@compat const _styleAliases = KW(
|
||||
:a => :auto,
|
||||
:s => :solid,
|
||||
:d => :dash,
|
||||
@@ -54,7 +57,7 @@ const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
# const _allMarkers = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle,
|
||||
# :cross, :xcross, :star5, :star8, :hexagon, :octagon, Shape]
|
||||
const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
|
||||
@compat const _markerAliases = Dict(
|
||||
@compat const _markerAliases = KW(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
:a => :auto,
|
||||
@@ -95,14 +98,14 @@ const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
|
||||
)
|
||||
|
||||
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
@compat const _scaleAliases = Dict(
|
||||
@compat const _scaleAliases = KW(
|
||||
:none => :identity,
|
||||
:log => :log10,
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
const _seriesDefaults = Dict{Symbol, Any}()
|
||||
const _seriesDefaults = KW()
|
||||
|
||||
# series-specific
|
||||
_seriesDefaults[:axis] = :left
|
||||
@@ -129,7 +132,7 @@ _seriesDefaults[:markerstrokecolor] = :match
|
||||
_seriesDefaults[:markerstrokealpha] = nothing
|
||||
# _seriesDefaults[:ribbon] = nothing
|
||||
# _seriesDefaults[:ribboncolor] = :match
|
||||
_seriesDefaults[:nbins] = 30 # number of bins for heatmaps and hists
|
||||
_seriesDefaults[:nbins] = 30 # number of bins for hists
|
||||
_seriesDefaults[:smooth] = false # regression line?
|
||||
_seriesDefaults[:group] = nothing # groupby vector
|
||||
# _seriesDefaults[:annotation] = nothing # annotation tuple(s)... (x,y,annotation)
|
||||
@@ -143,7 +146,7 @@ _seriesDefaults[:levels] = 15
|
||||
_seriesDefaults[:orientation] = :vertical
|
||||
|
||||
|
||||
const _plotDefaults = Dict{Symbol, Any}()
|
||||
const _plotDefaults = KW()
|
||||
|
||||
# plot globals
|
||||
_plotDefaults[:title] = ""
|
||||
@@ -156,6 +159,7 @@ _plotDefaults[:background_color] = colorant"white"
|
||||
_plotDefaults[:foreground_color] = :auto
|
||||
_plotDefaults[:xlims] = :auto
|
||||
_plotDefaults[:ylims] = :auto
|
||||
_plotDefaults[:zlims] = :auto
|
||||
_plotDefaults[:xticks] = :auto
|
||||
_plotDefaults[:yticks] = :auto
|
||||
_plotDefaults[:xscale] = :identity
|
||||
@@ -186,7 +190,7 @@ _plotDefaults[:overwrite_figure] = false
|
||||
# TODO: x/y scales
|
||||
|
||||
const _allArgs = sort(collect(union(keys(_seriesDefaults), keys(_plotDefaults))))
|
||||
supportedArgs(::PlottingPackage) = error("supportedArgs not defined") #_allArgs
|
||||
supportedArgs(::AbstractBackend) = error("supportedArgs not defined") #_allArgs
|
||||
supportedArgs() = supportedArgs(backend())
|
||||
|
||||
|
||||
@@ -201,7 +205,7 @@ autopick(notarr, idx::Integer) = notarr
|
||||
autopick_ignore_none_auto(arr::AVec, idx::Integer) = autopick(setdiff(arr, [:none, :auto]), idx)
|
||||
autopick_ignore_none_auto(notarr, idx::Integer) = notarr
|
||||
|
||||
function aliasesAndAutopick(d::Dict, sym::Symbol, aliases::Dict, options::AVec, plotIndex::Int)
|
||||
function aliasesAndAutopick(d::KW, sym::Symbol, aliases::KW, options::AVec, plotIndex::Int)
|
||||
if d[sym] == :auto
|
||||
d[sym] = autopick_ignore_none_auto(options, plotIndex)
|
||||
elseif haskey(aliases, d[sym])
|
||||
@@ -209,7 +213,7 @@ function aliasesAndAutopick(d::Dict, sym::Symbol, aliases::Dict, options::AVec,
|
||||
end
|
||||
end
|
||||
|
||||
function aliases(aliasMap::Dict, val)
|
||||
function aliases(aliasMap::KW, val)
|
||||
# sort(vcat(val, collect(keys(filter((k,v)-> v==val, aliasMap)))))
|
||||
sortedkeys(filter((k,v)-> v==val, aliasMap))
|
||||
end
|
||||
@@ -218,7 +222,7 @@ end
|
||||
|
||||
# Alternate args
|
||||
|
||||
@compat const _keyAliases = Dict(
|
||||
@compat const _keyAliases = KW(
|
||||
:c => :linecolor,
|
||||
:color => :linecolor,
|
||||
:colour => :linecolor,
|
||||
@@ -298,6 +302,9 @@ end
|
||||
:ylim => :ylims,
|
||||
:ylimit => :ylims,
|
||||
:ylimits => :ylims,
|
||||
:zlim => :zlims,
|
||||
:zlimit => :zlims,
|
||||
:zlimits => :zlims,
|
||||
:xtick => :xticks,
|
||||
:ytick => :yticks,
|
||||
:windowsize => :size,
|
||||
@@ -365,7 +372,7 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
function handleColors!(d::Dict, arg, csym::Symbol)
|
||||
function handleColors!(d::KW, arg, csym::Symbol)
|
||||
try
|
||||
if arg == :auto
|
||||
d[csym] = :auto
|
||||
@@ -380,7 +387,7 @@ end
|
||||
|
||||
# given one value (:log, or :flip, or (-1,1), etc), set the appropriate arg
|
||||
# TODO: use trueOrAllTrue for subplots which can pass vectors for these
|
||||
function processAxisArg(d::Dict, axisletter::@compat(AbstractString), arg)
|
||||
function processAxisArg(d::KW, axisletter::@compat(AbstractString), arg)
|
||||
T = typeof(arg)
|
||||
# if T <: Symbol
|
||||
|
||||
@@ -413,7 +420,7 @@ function processAxisArg(d::Dict, axisletter::@compat(AbstractString), arg)
|
||||
end
|
||||
|
||||
|
||||
function processLineArg(d::Dict, arg)
|
||||
function processLineArg(d::KW, arg)
|
||||
|
||||
# linetype
|
||||
# if trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
@@ -454,7 +461,7 @@ function processLineArg(d::Dict, arg)
|
||||
end
|
||||
|
||||
|
||||
function processMarkerArg(d::Dict, arg)
|
||||
function processMarkerArg(d::KW, arg)
|
||||
|
||||
# markershape
|
||||
# if trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg)
|
||||
@@ -498,7 +505,7 @@ function processMarkerArg(d::Dict, arg)
|
||||
end
|
||||
|
||||
|
||||
function processFillArg(d::Dict, arg)
|
||||
function processFillArg(d::KW, arg)
|
||||
|
||||
if typeof(arg) <: Brush
|
||||
arg.size == nothing || (d[:fillrange] = arg.size)
|
||||
@@ -516,7 +523,7 @@ function processFillArg(d::Dict, arg)
|
||||
d[:fillalpha] = arg
|
||||
|
||||
elseif !handleColors!(d, arg, :fillcolor)
|
||||
|
||||
|
||||
d[:fillrange] = arg
|
||||
end
|
||||
end
|
||||
@@ -527,7 +534,7 @@ _replace_markershape(shape) = shape
|
||||
|
||||
|
||||
"Handle all preprocessing of args... break out colors/sizes/etc and replace aliases."
|
||||
function preprocessArgs!(d::Dict)
|
||||
function preprocessArgs!(d::KW)
|
||||
replaceAliases!(d, _keyAliases)
|
||||
|
||||
# handle axis args
|
||||
@@ -633,7 +640,7 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
function warnOnUnsupportedArgs(pkg::PlottingPackage, d::Dict)
|
||||
function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW)
|
||||
for k in sortedkeys(d)
|
||||
if (!(k in supportedArgs(pkg))
|
||||
&& k != :subplot
|
||||
@@ -643,11 +650,11 @@ function warnOnUnsupportedArgs(pkg::PlottingPackage, d::Dict)
|
||||
end
|
||||
end
|
||||
|
||||
_markershape_supported(pkg::PlottingPackage, shape::Symbol) = shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::PlottingPackage, shape::Shape) = Shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::PlottingPackage, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
|
||||
function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
|
||||
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
|
||||
(d[:axis] in supportedAxes(pkg)
|
||||
|| warn("axis $(d[:axis]) is unsupported with $pkg. Choose from: $(supportedAxes(pkg))"))
|
||||
(d[:linetype] == :none
|
||||
@@ -662,7 +669,7 @@ function warnOnUnsupported(pkg::PlottingPackage, d::Dict)
|
||||
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
|
||||
end
|
||||
|
||||
function warnOnUnsupportedScales(pkg::PlottingPackage, d::Dict)
|
||||
function warnOnUnsupportedScales(pkg::AbstractBackend, d::KW)
|
||||
for k in (:xscale, :yscale)
|
||||
if haskey(d, k)
|
||||
d[k] in supportedScales(pkg) || warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supportedScales(pkg))")
|
||||
@@ -686,7 +693,7 @@ getArgValue(v, idx) = v
|
||||
|
||||
# given an argument key (k), we want to extract the argument value for this index.
|
||||
# if nothing is set (or container is empty), return the default.
|
||||
function setDictValue(d_in::Dict, d_out::Dict, k::Symbol, idx::Int, defaults::Dict)
|
||||
function setDictValue(d_in::KW, d_out::KW, k::Symbol, idx::Int, defaults::KW)
|
||||
if haskey(d_in, k) && !(typeof(d_in[k]) <: @compat(Union{AbstractArray, Tuple}) && isempty(d_in[k]))
|
||||
d_out[k] = getArgValue(d_in[k], idx)
|
||||
else
|
||||
@@ -710,9 +717,9 @@ convertLegendValue(val::Bool) = val ? :best : :none
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# build the argument dictionary for the plot
|
||||
function getPlotArgs(pkg::PlottingPackage, kw, idx::Int; set_defaults = true)
|
||||
kwdict = Dict(kw)
|
||||
d = Dict()
|
||||
function getPlotArgs(pkg::AbstractBackend, kw, idx::Int; set_defaults = true)
|
||||
kwdict = KW(kw)
|
||||
d = KW()
|
||||
|
||||
# add defaults?
|
||||
if set_defaults
|
||||
@@ -747,9 +754,9 @@ end
|
||||
|
||||
|
||||
# build the argument dictionary for a series
|
||||
function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt
|
||||
kwdict = Dict(kw)
|
||||
d = Dict()
|
||||
function getSeriesArgs(pkg::AbstractBackend, plotargs::KW, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt
|
||||
kwdict = KW(kw)
|
||||
d = KW()
|
||||
|
||||
# add defaults?
|
||||
for k in keys(_seriesDefaults)
|
||||
@@ -802,5 +809,3 @@ function getSeriesArgs(pkg::PlottingPackage, plotargs::Dict, kw, commandIndex::I
|
||||
|
||||
d
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
immutable NoPackage <: PlottingPackage end
|
||||
immutable NoBackend <: AbstractBackend end
|
||||
|
||||
const _backendType = Dict{Symbol, DataType}(:none => NoPackage)
|
||||
const _backendSymbol = Dict{DataType, Symbol}(NoPackage => :none)
|
||||
const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
|
||||
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
|
||||
const _backends = Symbol[]
|
||||
const _initialized_backends = Set{Symbol}()
|
||||
|
||||
@@ -10,12 +10,12 @@ backends() = _backends
|
||||
backend_name() = CURRENT_BACKEND.sym
|
||||
_backend_instance(sym::Symbol) = haskey(_backendType, sym) ? _backendType[sym]() : error("Unsupported backend $sym")
|
||||
|
||||
macro init_plotting_pkg(s)
|
||||
macro init_backend(s)
|
||||
str = lowercase(string(s))
|
||||
sym = symbol(str)
|
||||
T = symbol(string(s) * "Package")
|
||||
T = symbol(string(s) * "Backend")
|
||||
esc(quote
|
||||
immutable $T <: PlottingPackage end
|
||||
immutable $T <: AbstractBackend end
|
||||
export $sym
|
||||
$sym(; kw...) = (default(; kw...); backend(symbol($str)))
|
||||
backend_name(::$T) = symbol($str)
|
||||
@@ -26,18 +26,18 @@ macro init_plotting_pkg(s)
|
||||
end)
|
||||
end
|
||||
|
||||
@init_plotting_pkg Immerse
|
||||
@init_plotting_pkg Gadfly
|
||||
@init_plotting_pkg PyPlot
|
||||
@init_plotting_pkg Qwt
|
||||
@init_plotting_pkg UnicodePlots
|
||||
@init_plotting_pkg Winston
|
||||
@init_plotting_pkg Bokeh
|
||||
@init_plotting_pkg Plotly
|
||||
@init_plotting_pkg PlotlyJS
|
||||
@init_plotting_pkg GR
|
||||
@init_plotting_pkg GLVisualize
|
||||
@init_plotting_pkg PGFPlots
|
||||
@init_backend Immerse
|
||||
@init_backend Gadfly
|
||||
@init_backend PyPlot
|
||||
@init_backend Qwt
|
||||
@init_backend UnicodePlots
|
||||
@init_backend Winston
|
||||
@init_backend Bokeh
|
||||
@init_backend Plotly
|
||||
@init_backend PlotlyJS
|
||||
@init_backend GR
|
||||
@init_backend GLVisualize
|
||||
@init_backend PGFPlots
|
||||
|
||||
include("backends/web.jl")
|
||||
include("backends/supported.jl")
|
||||
@@ -45,19 +45,19 @@ include("backends/supported.jl")
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
plot(pkg::PlottingPackage; kw...) = error("plot($pkg; kw...) is not implemented")
|
||||
plot!(pkg::PlottingPackage, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
|
||||
_update_plot(pkg::PlottingPackage, plt::Plot, d::Dict) = error("_update_plot($pkg, plt, d) is not implemented")
|
||||
_update_plot_pos_size{P<:PlottingPackage}(plt::PlottingObject{P}, d::Dict) = nothing
|
||||
subplot(pkg::PlottingPackage; kw...) = error("subplot($pkg; kw...) is not implemented")
|
||||
subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
|
||||
plot(pkg::AbstractBackend; kw...) = error("plot($pkg; kw...) is not implemented")
|
||||
plot!(pkg::AbstractBackend, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented")
|
||||
_update_plot(pkg::AbstractBackend, plt::Plot, d::KW) = error("_update_plot($pkg, plt, d) is not implemented")
|
||||
_update_plot_pos_size{P<:AbstractBackend}(plt::AbstractPlot{P}, d::KW) = nothing
|
||||
subplot(pkg::AbstractBackend; kw...) = error("subplot($pkg; kw...) is not implemented")
|
||||
subplot!(pkg::AbstractBackend, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented")
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
type CurrentBackend
|
||||
sym::Symbol
|
||||
pkg::PlottingPackage
|
||||
pkg::AbstractBackend
|
||||
end
|
||||
CurrentBackend(sym::Symbol) = CurrentBackend(sym, _backend_instance(sym))
|
||||
|
||||
@@ -92,7 +92,7 @@ function backend()
|
||||
|
||||
# initialize
|
||||
println("[Plots.jl] Initializing backend: ", sym)
|
||||
|
||||
|
||||
inst = _backend_instance(sym)
|
||||
try
|
||||
_initialize_backend(inst)
|
||||
@@ -110,7 +110,7 @@ end
|
||||
"""
|
||||
Set the plot backend.
|
||||
"""
|
||||
function backend(pkg::PlottingPackage)
|
||||
function backend(pkg::AbstractBackend)
|
||||
CURRENT_BACKEND.sym = backend_name(pkg)
|
||||
CURRENT_BACKEND.pkg = pkg
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
function _initialize_backend(::BokehPackage; kw...)
|
||||
function _initialize_backend(::BokehBackend; kw...)
|
||||
@eval begin
|
||||
warn("Bokeh is no longer supported... many features will likely be broken.")
|
||||
import Bokeh
|
||||
@@ -18,23 +18,23 @@ end
|
||||
# bokehcolor(cs::ColorScheme) = bokehcolor(getColor(cs))
|
||||
|
||||
|
||||
const _glyphtypes = Dict(
|
||||
const _glyphtypes = KW(
|
||||
:ellipse => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
:dtriangle => :InvertedTriangle,
|
||||
# :pentagon =>
|
||||
# :hexagon =>
|
||||
# :heptagon =>
|
||||
# :octagon =>
|
||||
# :pentagon =>
|
||||
# :hexagon =>
|
||||
# :heptagon =>
|
||||
# :octagon =>
|
||||
:cross => :Cross,
|
||||
:xcross => :X,
|
||||
:star5 => :Asterisk,
|
||||
)
|
||||
|
||||
|
||||
function bokeh_glyph_type(d::Dict)
|
||||
function bokeh_glyph_type(d::KW)
|
||||
lt = d[:linetype]
|
||||
mt = d[:markershape]
|
||||
if lt == :scatter && mt == :none
|
||||
@@ -64,8 +64,8 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::BokehPackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::BokehBackend; kw...)
|
||||
d = KW(kw)
|
||||
|
||||
# dumpdict(d, "plot", true)
|
||||
|
||||
@@ -81,20 +81,20 @@ function _create_plot(pkg::BokehPackage; kw...)
|
||||
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
|
||||
extra_args = KW() # 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[])
|
||||
Plot(bplt, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::BokehPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::BokehBackend, plt::Plot; kw...)
|
||||
d = KW(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
|
||||
@@ -114,22 +114,22 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{BokehPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{BokehBackend}, d::KW)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{BokehPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{BokehBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{BokehPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{BokehBackend}, i::Int)
|
||||
series = plt.o.datacolumns[i].data
|
||||
series[:x], series[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{BokehPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{BokehBackend}, xy::Tuple, i::Integer)
|
||||
series = plt.o.datacolumns[i].data
|
||||
series[:x], series[:y] = xy
|
||||
plt
|
||||
@@ -138,7 +138,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{BokehPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{BokehBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
@@ -146,31 +146,31 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{BokehPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{BokehBackend}, 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)
|
||||
function _expand_limits(lims, plt::Plot{BokehBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{BokehPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{BokehBackend}, 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})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
||||
# TODO: write a png to io
|
||||
warn("mime png not implemented")
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{BokehPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
|
||||
Bokeh.showplot(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{BokehPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
|
||||
# TODO: display/show the subplot
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
function _initialize_backend(::GLVisualizePackage; kw...)
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
@@ -13,37 +13,31 @@ end
|
||||
|
||||
immutable GLScreenWrapper
|
||||
window
|
||||
render
|
||||
end
|
||||
|
||||
function _create_plot(pkg::GLVisualizePackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::GLVisualizeBackend; kw...)
|
||||
d = KW(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[])
|
||||
w=GLVisualize.glscreen()
|
||||
@async GLVisualize.renderloop(w)
|
||||
Plot(GLScreenWrapper(w), pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::GLVisualizePackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::GLVisualizeBackend, plt::Plot; kw...)
|
||||
d = KW(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)
|
||||
|
||||
x,y,z=map(Float32,d[:x]), map(Float32,d[:y]), map(Float32,d[:z].surf)
|
||||
GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface),plt.o.window)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GLVisualizePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GLVisualizeBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
@@ -51,28 +45,28 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{GLVisualizePackage})
|
||||
function _before_update_plot(plt::Plot{GLVisualizeBackend})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{GLVisualizePackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{GLVisualizeBackend}, d::KW)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{GLVisualizePackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{GLVisualizeBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{GLVisualizePackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{GLVisualizeBackend}, 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)
|
||||
function Base.setindex!(plt::Plot{GLVisualizeBackend}, xy::Tuple, i::Integer)
|
||||
# TODO:
|
||||
# series = plt.o.lines[i]
|
||||
# series.x, series.y = xy
|
||||
@@ -81,25 +75,25 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{GLVisualizePackage})
|
||||
function _create_subplot(subplt::Subplot{GLVisualizeBackend})
|
||||
# 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)
|
||||
function _expand_limits(lims, plt::Plot{GLVisualizeBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{GLVisualizePackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{GLVisualizeBackend}, 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})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
||||
# TODO: write a png to io
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GLVisualizePackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GLVisualizeBackend})
|
||||
# TODO: display/show the plot
|
||||
|
||||
# NOTE: I think maybe this should be empty? We can start with the assumption that creating
|
||||
@@ -107,6 +101,6 @@ function Base.display(::PlotsDisplay, plt::Plot{GLVisualizePackage})
|
||||
# wouldn't actually need to do anything
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizePackage})
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizeBackend})
|
||||
# TODO: display/show the subplot
|
||||
end
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
|
||||
# https://github.com/jheinen/GR.jl
|
||||
|
||||
function _initialize_backend(::GRPackage; kw...)
|
||||
function _initialize_backend(::GRBackend; kw...)
|
||||
@eval begin
|
||||
import GR
|
||||
export GR
|
||||
end
|
||||
end
|
||||
|
||||
const gr_linetype = Dict(
|
||||
const gr_linetype = KW(
|
||||
:auto => 1, :solid => 1, :dash => 2, :dot => 3, :dashdot => 4,
|
||||
:dashdotdot => -1 )
|
||||
|
||||
const gr_markertype = Dict(
|
||||
const gr_markertype = KW(
|
||||
:auto => 1, :none => -1, :ellipse => -1, :rect => -7, :diamond => -13,
|
||||
:utriangle => -3, :dtriangle => -5, :pentagon => -21, :hexagon => -22,
|
||||
:heptagon => -23, :octagon => -24, :cross => 2, :xcross => 5,
|
||||
:star4 => -25, :star5 => -26, :star6 => -27, :star7 => -28, :star8 => -29,
|
||||
:vline => -30, :hline => -31 )
|
||||
|
||||
const gr_halign = Dict(:left => 1, :hcenter => 2, :right => 3)
|
||||
const gr_valign = Dict(:top => 1, :vcenter => 3, :bottom => 5)
|
||||
const gr_halign = KW(:left => 1, :hcenter => 2, :right => 3)
|
||||
const gr_valign = KW(:top => 1, :vcenter => 3, :bottom => 5)
|
||||
|
||||
const gr_font_family = Dict(
|
||||
"times" => 1, "helvetica" => 5, "courier" => 9, "bookman" => 14,
|
||||
@@ -89,7 +89,7 @@ function gr_polyline(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
function gr_display(plt::Plot{GRBackend}, clear=true, update=true,
|
||||
subplot=[0, 1, 0, 1])
|
||||
d = plt.plotargs
|
||||
|
||||
@@ -98,36 +98,36 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
mwidth, mheight, width, height = GR.inqdspsize()
|
||||
w, h = d[:size]
|
||||
viewport = zeros(4)
|
||||
vp = float(subplot)
|
||||
if w > h
|
||||
ratio = float(h) / w
|
||||
msize = mwidth * w / width
|
||||
GR.setwsviewport(0, msize, 0, msize * ratio)
|
||||
GR.setwswindow(0, 1, 0, ratio)
|
||||
viewport[1] = subplot[1] + 0.125 * (subplot[2] - subplot[1])
|
||||
viewport[2] = subplot[1] + 0.95 * (subplot[2] - subplot[1])
|
||||
viewport[3] = ratio * (subplot[3] + 0.125 * (subplot[4] - subplot[3]))
|
||||
viewport[4] = ratio * (subplot[3] + 0.95 * (subplot[4] - subplot[3]))
|
||||
vp[3] *= ratio
|
||||
vp[4] *= ratio
|
||||
else
|
||||
ratio = float(w) / h
|
||||
msize = mheight * h / height
|
||||
GR.setwsviewport(0, msize * ratio, 0, msize)
|
||||
GR.setwswindow(0, ratio, 0, 1)
|
||||
viewport[1] = ratio * (subplot[1] + 0.125 * (subplot[2] - subplot[1]))
|
||||
viewport[2] = ratio * (subplot[1] + 0.95 * (subplot[2] - subplot[1]))
|
||||
viewport[3] = subplot[3] + 0.125 * (subplot[4] - subplot[3])
|
||||
viewport[4] = subplot[3] + 0.95 * (subplot[4] - subplot[3])
|
||||
vp[1] *= ratio
|
||||
vp[2] *= ratio
|
||||
end
|
||||
viewport[1] = vp[1] + 0.125 * (vp[2] - vp[1])
|
||||
viewport[2] = vp[1] + 0.95 * (vp[2] - vp[1])
|
||||
viewport[3] = vp[3] + 0.125 * (vp[4] - vp[3])
|
||||
if w > h
|
||||
viewport[3] += (1 - (subplot[4] - subplot[3])^2) * 0.02
|
||||
end
|
||||
viewport[4] = vp[3] + 0.95 * (vp[4] - vp[3])
|
||||
|
||||
if haskey(d, :background_color)
|
||||
GR.savestate()
|
||||
GR.selntran(0)
|
||||
GR.setfillintstyle(GR.INTSTYLE_SOLID)
|
||||
GR.setfillcolorind(gr_getcolorind(d[:background_color]))
|
||||
if w > h
|
||||
GR.fillrect(subplot[1], subplot[2], ratio*subplot[3], ratio*subplot[4])
|
||||
else
|
||||
GR.fillrect(ratio*subplot[1], ratio*subplot[2], subplot[3], subplot[4])
|
||||
end
|
||||
GR.fillrect(vp[1], vp[2], vp[3], vp[4])
|
||||
GR.selntran(1)
|
||||
GR.restorestate()
|
||||
c = getColor(d[:background_color])
|
||||
@@ -145,6 +145,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
cmap = false
|
||||
axes_2d = true
|
||||
grid_flag = get(d, :grid, true)
|
||||
outside_ticks = false
|
||||
|
||||
for axis = 1:2
|
||||
xmin = ymin = typemax(Float64)
|
||||
@@ -160,7 +161,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
x, y = 1:size(p[:y], 1), p[:y]
|
||||
elseif p[:linetype] in [:hist, :density]
|
||||
x, y = Base.hist(p[:y])
|
||||
elseif p[:linetype] in [:heatmap, :hexbin]
|
||||
elseif p[:linetype] in [:hist2d, :hexbin]
|
||||
E = zeros(length(p[:x]),2)
|
||||
E[:,1] = p[:x]
|
||||
E[:,2] = p[:y]
|
||||
@@ -176,12 +177,15 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
xmin, xmax, ymin, ymax = 0, 1, 0, 1
|
||||
x, y = p[:x], p[:y]
|
||||
else
|
||||
if p[:linetype] in [:contour, :surface]
|
||||
if p[:linetype] in [:contour, :surface, :heatmap]
|
||||
cmap = true
|
||||
end
|
||||
if p[:linetype] in [:surface, :wireframe, :path3d, :scatter3d]
|
||||
axes_2d = false
|
||||
end
|
||||
if p[:linetype] == :heatmap
|
||||
outside_ticks = true
|
||||
end
|
||||
x, y = p[:x], p[:y]
|
||||
end
|
||||
if p[:linetype] != :pie
|
||||
@@ -267,6 +271,9 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
GR.setlinewidth(1)
|
||||
GR.setlinecolorind(fg)
|
||||
ticksize = 0.0075 * diag
|
||||
if outside_ticks
|
||||
ticksize = -ticksize
|
||||
end
|
||||
if grid_flag && fg == 1
|
||||
GR.grid(xtick, ytick, 0, 0, majorx, majory)
|
||||
end
|
||||
@@ -285,14 +292,14 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), min(ratio, 1), d[:title])
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), vp[4], d[:title])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :xlabel, "") != ""
|
||||
GR.savestate()
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), 0, d[:xlabel])
|
||||
GR.text(0.5 * (viewport[1] + viewport[2]), vp[3], d[:xlabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :ylabel, "") != ""
|
||||
@@ -300,7 +307,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.setcharup(-1, 0)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(0, 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
|
||||
GR.text(vp[1], 0.5 * (viewport[3] + viewport[4]), d[:ylabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
if get(d, :yrightlabel, "") != ""
|
||||
@@ -308,7 +315,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
|
||||
GR.setcharup(1, 0)
|
||||
GR.settextcolorind(fg)
|
||||
GR.text(1, 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
|
||||
GR.text(vp[2], 0.5 * (viewport[3] + viewport[4]), d[:yrightlabel])
|
||||
GR.restorestate()
|
||||
end
|
||||
|
||||
@@ -423,7 +430,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
GR.polyline([xy, xy], [ymin, ymax])
|
||||
end
|
||||
end
|
||||
elseif p[:linetype] in [:heatmap, :hexbin]
|
||||
elseif p[:linetype] in [:hist2d, :hexbin]
|
||||
E = zeros(length(p[:x]),2)
|
||||
E[:,1] = p[:x]
|
||||
E[:,2] = p[:y]
|
||||
@@ -497,6 +504,18 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
viewport[3], viewport[4])
|
||||
GR.colormap()
|
||||
end
|
||||
elseif p[:linetype] == :heatmap
|
||||
x, y, z = p[:x], p[:y], p[:z].surf
|
||||
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
|
||||
GR.setspace(zmin, zmax, 0, 90)
|
||||
GR.setcolormap(GR.COLORMAP_COOLWARM)
|
||||
z = reshape(z, length(x) * length(y))
|
||||
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
|
||||
if cmap
|
||||
GR.setviewport(viewport[2] + 0.02, viewport[2] + 0.05,
|
||||
viewport[3], viewport[4])
|
||||
GR.colormap()
|
||||
end
|
||||
elseif p[:linetype] in [:path3d, :scatter3d]
|
||||
x, y, z = p[:x], p[:y], p[:z]
|
||||
zmin, zmax = GR.adjustrange(minimum(z), maximum(z))
|
||||
@@ -666,7 +685,7 @@ function gr_display(plt::Plot{GRPackage}, clear=true, update=true,
|
||||
update && GR.updatews()
|
||||
end
|
||||
|
||||
function gr_display(subplt::Subplot{GRPackage})
|
||||
function gr_display(subplt::Subplot{GRBackend})
|
||||
clear = true
|
||||
update = false
|
||||
l = enumerate(subplt.layout)
|
||||
@@ -682,18 +701,18 @@ function gr_display(subplt::Subplot{GRPackage})
|
||||
end
|
||||
end
|
||||
|
||||
function _create_plot(pkg::GRPackage; kw...)
|
||||
d = Dict(kw)
|
||||
Plot(nothing, pkg, 0, d, Dict[])
|
||||
function _create_plot(pkg::GRBackend; kw...)
|
||||
d = KW(kw)
|
||||
Plot(nothing, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
function _add_series(::GRPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::GRBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GRPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{GRBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
if haskey(plt.plotargs, :anns)
|
||||
append!(plt.plotargs[:anns], anns)
|
||||
else
|
||||
@@ -703,26 +722,26 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{GRPackage})
|
||||
function _before_update_plot(plt::Plot{GRBackend})
|
||||
end
|
||||
|
||||
function _update_plot(plt::Plot{GRPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{GRBackend}, d::KW)
|
||||
for k in (:title, :xlabel, :ylabel)
|
||||
haskey(d, k) && (plt.plotargs[k] = d[k])
|
||||
end
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{GRPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{GRBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.getindex(plt::Plot{GRPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{GRBackend}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{GRPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{GRBackend}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
plt
|
||||
@@ -730,21 +749,21 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{GRPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{GRBackend}, isbefore::Bool)
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{GRPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{GRBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{GRPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{GRBackend}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{GRPackage})
|
||||
function Base.writemime(io::IO, m::MIME"image/png", plt::AbstractPlot{GRBackend})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "png"
|
||||
gr_display(plt)
|
||||
@@ -752,7 +771,7 @@ function Base.writemime(io::IO, m::MIME"image/png", plt::PlottingObject{GRPackag
|
||||
write(io, readall("gks.png"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::PlottingObject{GRPackage})
|
||||
function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::AbstractPlot{GRBackend})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "svg"
|
||||
gr_display(plt)
|
||||
@@ -760,11 +779,11 @@ function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::PlottingObject{GRPa
|
||||
write(io, readall("gks.svg"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{GRPackage})
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::AbstractPlot{GRBackend})
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"application/pdf", plt::PlottingObject{GRPackage})
|
||||
function Base.writemime(io::IO, m::MIME"application/pdf", plt::AbstractPlot{GRBackend})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "pdf"
|
||||
gr_display(plt)
|
||||
@@ -772,7 +791,7 @@ function Base.writemime(io::IO, m::MIME"application/pdf", plt::PlottingObject{GR
|
||||
write(io, readall("gks.pdf"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"application/postscript", plt::PlottingObject{GRPackage})
|
||||
function Base.writemime(io::IO, m::MIME"application/postscript", plt::AbstractPlot{GRBackend})
|
||||
GR.emergencyclosegks()
|
||||
ENV["GKS_WSTYPE"] = "ps"
|
||||
gr_display(plt)
|
||||
@@ -780,11 +799,11 @@ function Base.writemime(io::IO, m::MIME"application/postscript", plt::PlottingOb
|
||||
write(io, readall("gks.ps"))
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GRPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{GRBackend})
|
||||
gr_display(plt)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GRPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{GRBackend})
|
||||
gr_display(plt)
|
||||
true
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
function _initialize_backend(::ImmersePackage; kw...)
|
||||
function _initialize_backend(::ImmerseBackend; kw...)
|
||||
@eval begin
|
||||
import Immerse, Gadfly, Compose, Gtk
|
||||
export Immerse, Gadfly, Compose, Gtk
|
||||
@@ -9,7 +9,7 @@ function _initialize_backend(::ImmersePackage; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
function createImmerseFigure(d::Dict)
|
||||
function createImmerseFigure(d::KW)
|
||||
w,h = d[:size]
|
||||
figidx = Immerse.figure(; name = d[:windowtitle], width = w, height = h)
|
||||
Immerse.Figure(figidx)
|
||||
@@ -19,27 +19,27 @@ end
|
||||
|
||||
|
||||
# create a blank Gadfly.Plot object
|
||||
function _create_plot(pkg::ImmersePackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::ImmerseBackend; kw...)
|
||||
d = KW(kw)
|
||||
|
||||
# create the underlying Gadfly.Plot object
|
||||
gplt = createGadflyPlotObject(d)
|
||||
|
||||
# save both the Immerse.Figure and the Gadfly.Plot
|
||||
Plot((nothing,gplt), pkg, 0, d, Dict[])
|
||||
Plot((nothing,gplt), pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
# plot one data series
|
||||
function _add_series(::ImmersePackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::ImmerseBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
addGadflySeries!(plt, d)
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
function _update_plot(plt::Plot{ImmersePackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{ImmerseBackend}, d::KW)
|
||||
updateGadflyGuides(plt, d)
|
||||
updateGadflyPlotTheme(plt, d)
|
||||
end
|
||||
@@ -48,7 +48,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{ImmersePackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
||||
end
|
||||
@@ -58,12 +58,12 @@ end
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{ImmersePackage}, i::Integer)
|
||||
function Base.getindex(plt::Plot{ImmerseBackend}, i::Integer)
|
||||
mapping = getGadflyMappings(plt, i)[1]
|
||||
mapping[:x], mapping[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{ImmersePackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{ImmerseBackend}, xy::Tuple, i::Integer)
|
||||
for mapping in getGadflyMappings(plt, i)
|
||||
mapping[:x], mapping[:y] = xy
|
||||
end
|
||||
@@ -74,12 +74,12 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
function _create_subplot(subplt::Subplot{ImmersePackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
|
||||
return false
|
||||
# isbefore && return false
|
||||
end
|
||||
|
||||
function showSubplotObject(subplt::Subplot{ImmersePackage})
|
||||
function showSubplotObject(subplt::Subplot{ImmerseBackend})
|
||||
# create the Gtk window with vertical box vsep
|
||||
d = getplotargs(subplt,1)
|
||||
w,h = d[:size]
|
||||
@@ -121,13 +121,13 @@ function showSubplotObject(subplt::Subplot{ImmersePackage})
|
||||
end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{ImmersePackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
gplt = getGadflyContext(plt)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{ImmersePackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
|
||||
for l in getGadflyContext(plt).layers
|
||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
||||
end
|
||||
@@ -136,11 +136,11 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
getGadflyContext(plt::Plot{ImmersePackage}) = plt.o[2]
|
||||
getGadflyContext(subplt::Subplot{ImmersePackage}) = buildGadflySubplotContext(subplt)
|
||||
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
|
||||
getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{ImmersePackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
|
||||
|
||||
fig, gplt = plt.o
|
||||
if fig == nothing
|
||||
@@ -154,7 +154,7 @@ function Base.display(::PlotsDisplay, plt::Plot{ImmersePackage})
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{ImmersePackage})
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
|
||||
|
||||
# if we haven't created the window yet, do it
|
||||
if subplt.o == nothing
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/sisl/PGFPlots.jl
|
||||
|
||||
function _initialize_backend(::PGFPlotsPackage; kw...)
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
@@ -12,22 +12,22 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PGFPlotsPackage; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
function _create_plot(pkg::PGFPlotsBackend; kw...)
|
||||
d = KW(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[])
|
||||
Plot(nothing, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PGFPlotsPackage, plt::Plot; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
function _add_series(::PGFPlotsBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
# TODO: add one series to the underlying package
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsBackend}, 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)
|
||||
@@ -38,26 +38,26 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{PGFPlotsPackage})
|
||||
function _before_update_plot(plt::Plot{PGFPlotsBackend})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PGFPlotsPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{PGFPlotsBackend}, d::KW)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{PGFPlotsPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{PGFPlotsBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{PGFPlotsPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{PGFPlotsBackend}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PGFPlotsPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{PGFPlotsBackend}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
plt
|
||||
@@ -65,16 +65,16 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{PGFPlotsPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{PGFPlotsBackend}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{PGFPlotsPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{PGFPlotsBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{PGFPlotsPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{PGFPlotsBackend}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
@@ -84,24 +84,24 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
################# This is the important method to implement!!! #################
|
||||
function _make_pgf_plot(plt::Plot{PGFPlotsPackage})
|
||||
function _make_pgf_plot(plt::Plot{PGFPlotsBackend})
|
||||
# TODO: convert plt.plotargs and plt.seriesargs into PGFPlots calls
|
||||
# TODO: return the PGFPlots object
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, mime::MIME"image/png", plt::PlottingObject{PGFPlotsPackage})
|
||||
function Base.writemime(io::IO, mime::MIME"image/png", plt::AbstractPlot{PGFPlotsBackend})
|
||||
plt.o = _make_pgf_plot(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
end
|
||||
|
||||
# function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PGFPlotsPackage})
|
||||
# function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot{PGFPlotsBackend})
|
||||
# end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::PlottingObject{PGFPlotsPackage})
|
||||
function Base.display(::PlotsDisplay, plt::AbstractPlot{PGFPlotsBackend})
|
||||
plt.o = _make_pgf_plot(plt)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsPackage})
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsBackend})
|
||||
# # TODO: display/show the subplot
|
||||
# end
|
||||
|
||||
@@ -1,31 +1,35 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
function _initialize_backend(::PlotlyPackage; kw...)
|
||||
function _initialize_backend(::PlotlyBackend; kw...)
|
||||
@eval begin
|
||||
import JSON
|
||||
JSON._print(io::IO, state::JSON.State, dt::Union{Date,DateTime}) = print(io, '"', dt, '"')
|
||||
|
||||
############################
|
||||
# borrowed from https://github.com/spencerlyon2/Plotlyjs.jl/blob/master/src/display.jl
|
||||
_js_path = joinpath(Pkg.dir("Plots"), "deps", "plotly-latest.min.js")
|
||||
_js_path = Pkg.dir("Plots", "deps", "plotly-latest.min.js")
|
||||
_js_code = open(readall, _js_path, "r")
|
||||
|
||||
# borrowed from https://github.com/plotly/plotly.py/blob/2594076e29584ede2d09f2aa40a8a195b3f3fc66/plotly/offline/offline.py#L64-L71 c/o @spencerlyon2
|
||||
_js_script = """
|
||||
<script type='text/javascript'>
|
||||
define('plotly', function(require, exports, module) {
|
||||
$(_js_code)
|
||||
});
|
||||
require(['plotly'], function(Plotly) {
|
||||
window.Plotly = Plotly;
|
||||
});
|
||||
</script>
|
||||
"""
|
||||
|
||||
# if we're in IJulia call setupnotebook to load js and css
|
||||
if isijulia()
|
||||
# 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>")
|
||||
display("text/html", _js_script)
|
||||
end
|
||||
# end borrowing (thanks :)
|
||||
###########################
|
||||
|
||||
# if isatom()
|
||||
# import Atom
|
||||
# Atom.@msg evaljs(_js_code)
|
||||
# end
|
||||
|
||||
end
|
||||
# TODO: other initialization
|
||||
@@ -33,22 +37,22 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PlotlyPackage; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
function _create_plot(pkg::PlotlyBackend; kw...)
|
||||
d = KW(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[])
|
||||
Plot(nothing, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyPackage, plt::Plot; kw...)
|
||||
d = Dict{Symbol,Any}(kw)
|
||||
function _add_series(::PlotlyBackend, plt::Plot; kw...)
|
||||
d = KW(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})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PlotlyBackend}, 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)
|
||||
@@ -59,26 +63,26 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{PlotlyPackage})
|
||||
function _before_update_plot(plt::Plot{PlotlyBackend})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PlotlyPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{PlotlyBackend}, d::KW)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{PlotlyPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{PlotlyBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{PlotlyPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{PlotlyBackend}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PlotlyPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{PlotlyBackend}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
plt
|
||||
@@ -86,16 +90,16 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{PlotlyPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{PlotlyBackend}, 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)
|
||||
function _expand_limits(lims, plt::Plot{PlotlyBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{PlotlyPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{PlotlyBackend}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
@@ -113,7 +117,7 @@ end
|
||||
# _plotDefaults[:yflip] = false
|
||||
|
||||
function plotlyfont(font::Font, color = font.color)
|
||||
Dict{Symbol,Any}(
|
||||
KW(
|
||||
:family => font.family,
|
||||
:size => round(Int, font.pointsize*1.4),
|
||||
:color => webcolor(color),
|
||||
@@ -121,7 +125,7 @@ function plotlyfont(font::Font, color = font.color)
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, val::Union{AbstractString,Symbol})
|
||||
Dict{Symbol,Any}(
|
||||
KW(
|
||||
:text => val,
|
||||
:xref => "x",
|
||||
:x => x,
|
||||
@@ -132,7 +136,7 @@ function get_annotation_dict(x, y, val::Union{AbstractString,Symbol})
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, ptxt::PlotText)
|
||||
merge(get_annotation_dict(x, y, ptxt.str), Dict{Symbol,Any}(
|
||||
merge(get_annotation_dict(x, y, ptxt.str), KW(
|
||||
:font => plotlyfont(ptxt.font),
|
||||
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
|
||||
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
|
||||
@@ -156,8 +160,8 @@ flipsym(isx::Bool) = symbol((isx ? "x" : "y") * "flip")
|
||||
scalesym(isx::Bool) = symbol((isx ? "x" : "y") * "scale")
|
||||
labelsym(isx::Bool) = symbol((isx ? "x" : "y") * "label")
|
||||
|
||||
function plotlyaxis(d::Dict, isx::Bool)
|
||||
ax = Dict{Symbol,Any}(
|
||||
function plotlyaxis(d::KW, isx::Bool)
|
||||
ax = KW(
|
||||
:title => d[labelsym(isx)],
|
||||
:showgrid => d[:grid],
|
||||
:zeroline => false,
|
||||
@@ -206,10 +210,10 @@ function plotlyaxis(d::Dict, isx::Bool)
|
||||
ax
|
||||
end
|
||||
|
||||
# function get_plot_json(plt::Plot{PlotlyPackage})
|
||||
# function get_plot_json(plt::Plot{PlotlyBackend})
|
||||
# d = plt.plotargs
|
||||
function plotly_layout(d::Dict)
|
||||
d_out = Dict{Symbol,Any}()
|
||||
function plotly_layout(d::KW)
|
||||
d_out = KW()
|
||||
|
||||
bgcolor = webcolor(d[:background_color])
|
||||
fgcolor = webcolor(d[:foreground_color])
|
||||
@@ -217,7 +221,7 @@ function plotly_layout(d::Dict)
|
||||
# set the fields for the plot
|
||||
d_out[:title] = d[:title]
|
||||
d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor)
|
||||
d_out[:margin] = Dict{Symbol,Any}(:l=>35, :b=>30, :r=>8, :t=>20)
|
||||
d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20)
|
||||
d_out[:plot_bgcolor] = bgcolor
|
||||
d_out[:paper_bgcolor] = bgcolor
|
||||
|
||||
@@ -228,7 +232,7 @@ function plotly_layout(d::Dict)
|
||||
# legend
|
||||
d_out[:showlegend] = d[:legend] != :none
|
||||
if d[:legend] != :none
|
||||
d_out[:legend] = Dict{Symbol,Any}(
|
||||
d_out[:legend] = KW(
|
||||
:bgcolor => bgcolor,
|
||||
:bordercolor => fgcolor,
|
||||
:font => plotlyfont(d[:legendfont]),
|
||||
@@ -244,17 +248,17 @@ function plotly_layout(d::Dict)
|
||||
d_out
|
||||
end
|
||||
|
||||
function get_plot_json(plt::Plot{PlotlyPackage})
|
||||
function get_plot_json(plt::Plot{PlotlyBackend})
|
||||
JSON.json(plotly_layout(plt.plotargs))
|
||||
end
|
||||
|
||||
|
||||
function plotly_colorscale(grad::ColorGradient)
|
||||
[[grad.values[i], webcolor(grad.colors[i])] for i in 1:length(grad.colors)]
|
||||
function plotly_colorscale(grad::ColorGradient, alpha = nothing)
|
||||
[[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)]
|
||||
end
|
||||
plotly_colorscale(c) = plotly_colorscale(ColorGradient(:bluesreds))
|
||||
plotly_colorscale(c, alpha = nothing) = plotly_colorscale(ColorGradient(:bluesreds), alpha)
|
||||
|
||||
const _plotly_markers = Dict{Symbol,Any}(
|
||||
const _plotly_markers = KW(
|
||||
:rect => "square",
|
||||
:xcross => "x",
|
||||
:utriangle => "triangle-up",
|
||||
@@ -265,8 +269,8 @@ const _plotly_markers = Dict{Symbol,Any}(
|
||||
)
|
||||
|
||||
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
|
||||
function plotly_series(d::Dict; plot_index = nothing)
|
||||
d_out = Dict{Symbol,Any}()
|
||||
function plotly_series(d::KW; plot_index = nothing)
|
||||
d_out = KW()
|
||||
|
||||
x, y = collect(d[:x]), collect(d[:y])
|
||||
d_out[:name] = d[:label]
|
||||
@@ -296,7 +300,7 @@ function plotly_series(d::Dict; plot_index = nothing)
|
||||
d_out[:type] = "bar"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif lt == :heatmap
|
||||
elseif lt == :hist2d
|
||||
d_out[:type] = "histogram2d"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
if isa(d[:nbins], Tuple)
|
||||
@@ -316,16 +320,26 @@ function plotly_series(d::Dict; plot_index = nothing)
|
||||
d_out[:histnorm] = "probability density"
|
||||
end
|
||||
|
||||
elseif lt in (:contour, :surface, :wireframe)
|
||||
d_out[:type] = lt == :wireframe ? :surface : string(lt)
|
||||
elseif lt == :heatmap
|
||||
d_out[:type] = "heatmap"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:z] = d[:z].surf
|
||||
# d_out[:showscale] = d[:legend]
|
||||
if lt == :contour
|
||||
d_out[:ncontours] = d[:levels]
|
||||
d_out[:contours] = Dict{Symbol,Any}(:coloring => d[:fillrange] != nothing ? "fill" : "lines")
|
||||
end
|
||||
d_out[:colorscale] = plotly_colorscale(d[lt == :contour ? :linecolor : :fillcolor])
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
elseif lt == :contour
|
||||
d_out[:type] = "contour"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:z] = d[:z].surf
|
||||
# d_out[:showscale] = d[:colorbar] != :none
|
||||
d_out[:ncontours] = d[:levels]
|
||||
d_out[:contours] = KW(:coloring => d[:fillrange] != nothing ? "fill" : "lines")
|
||||
d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha])
|
||||
|
||||
elseif lt in (:surface, :wireframe)
|
||||
d_out[:type] = "surface"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:z] = d[:z].surf
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
elseif lt == :pie
|
||||
d_out[:type] = "pie"
|
||||
@@ -345,30 +359,37 @@ function plotly_series(d::Dict; plot_index = nothing)
|
||||
|
||||
else
|
||||
warn("Plotly: linetype $lt isn't supported.")
|
||||
return Dict{Symbol,Any}()
|
||||
return KW()
|
||||
end
|
||||
|
||||
# add "marker"
|
||||
if hasmarker
|
||||
d_out[:marker] = Dict{Symbol,Any}(
|
||||
d_out[:marker] = KW(
|
||||
:symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])),
|
||||
:opacity => d[:markeralpha],
|
||||
:size => 2 * d[:markersize],
|
||||
:color => webcolor(d[:markercolor], d[:markeralpha]),
|
||||
:line => Dict{Symbol,Any}(
|
||||
:line => KW(
|
||||
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
|
||||
:width => d[:markerstrokewidth],
|
||||
),
|
||||
)
|
||||
|
||||
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
|
||||
if d[:zcolor] != nothing
|
||||
d_out[:marker][:color] = d[:zcolor]
|
||||
d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor])
|
||||
# d_out[:marker][:color] = d[:zcolor]
|
||||
# d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor], d[:markeralpha])
|
||||
# d_out[:showscale] = true
|
||||
grad = ColorGradient(d[:markercolor], alpha=d[:markeralpha])
|
||||
zmin, zmax = extrema(d[:zcolor])
|
||||
d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:zcolor]]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# add "line"
|
||||
if hasline
|
||||
d_out[:line] = Dict{Symbol,Any}(
|
||||
d_out[:line] = KW(
|
||||
:color => webcolor(d[:linecolor], d[:linealpha]),
|
||||
:width => d[:linewidth],
|
||||
:shape => if lt == :steppre
|
||||
@@ -393,12 +414,12 @@ function plotly_series(d::Dict; plot_index = nothing)
|
||||
end
|
||||
|
||||
# get a list of dictionaries, each representing the series params
|
||||
function get_series_json(plt::Plot{PlotlyPackage})
|
||||
function get_series_json(plt::Plot{PlotlyBackend})
|
||||
JSON.json(map(plotly_series, plt.seriesargs))
|
||||
end
|
||||
|
||||
function get_series_json(subplt::Subplot{PlotlyPackage})
|
||||
ds = Dict[]
|
||||
function get_series_json(subplt::Subplot{PlotlyBackend})
|
||||
ds = KW[]
|
||||
for (i,plt) in enumerate(subplt.plts)
|
||||
for d in plt.seriesargs
|
||||
push!(ds, plotly_series(d, plot_index = i))
|
||||
@@ -409,28 +430,36 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function html_head(plt::PlottingObject{PlotlyPackage})
|
||||
function html_head(plt::AbstractPlot{PlotlyBackend})
|
||||
"<script src=\"$(Pkg.dir("Plots","deps","plotly-latest.min.js"))\"></script>"
|
||||
end
|
||||
|
||||
function html_body(plt::Plot{PlotlyPackage}, style = nothing)
|
||||
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
|
||||
if style == nothing
|
||||
w, h = plt.plotargs[:size]
|
||||
style = "width:$(w)px;height:$(h)px;"
|
||||
end
|
||||
uuid = Base.Random.uuid4()
|
||||
"""
|
||||
html = """
|
||||
<div id=\"$(uuid)\" style=\"$(style)\"></div>
|
||||
<script>
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(get_series_json(plt)), $(get_plot_json(plt)));
|
||||
</script>
|
||||
"""
|
||||
# @show html
|
||||
html
|
||||
end
|
||||
|
||||
function js_body(plt::Plot{PlotlyBackend}, uuid)
|
||||
js = """
|
||||
PLOT = document.getElementById('$(uuid)');
|
||||
Plotly.plot(PLOT, $(get_series_json(plt)), $(get_plot_json(plt)));
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
|
||||
function html_body(subplt::Subplot{PlotlyPackage})
|
||||
function html_body(subplt::Subplot{PlotlyBackend})
|
||||
w, h = subplt.plts[1].plotargs[:size]
|
||||
html = ["<div style=\"width:$(w)px;height:$(h)px;\">"]
|
||||
nr = nrows(subplt.layout)
|
||||
@@ -457,18 +486,19 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{PlotlyPackage})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{PlotlyBackend})
|
||||
warn("todo: png")
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject{PlotlyPackage})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot{PlotlyBackend})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
# write(io, html_body(plt))
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::PlottingObject{PlotlyPackage})
|
||||
function Base.display(::PlotsDisplay, plt::AbstractPlot{PlotlyBackend})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{PlotlyPackage})
|
||||
# function Base.display(::PlotsDisplay, plt::Subplot{PlotlyBackend})
|
||||
# # TODO: display/show the subplot
|
||||
# end
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
function _initialize_backend(::PlotlyJSPackage; kw...)
|
||||
function _initialize_backend(::PlotlyJSBackend; kw...)
|
||||
@eval begin
|
||||
import PlotlyJS
|
||||
export PlotlyJS
|
||||
end
|
||||
|
||||
for (mime, fmt) in PlotlyJS._mimeformats
|
||||
@eval Base.writemime(io::IO, m::MIME{symbol($mime)}, p::Plot{PlotlyJSPackage}) = writemime(io, m, p.o)
|
||||
@eval Base.writemime(io::IO, m::MIME{symbol($mime)}, p::Plot{PlotlyJSBackend}) = writemime(io, m, p.o)
|
||||
end
|
||||
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
IJulia.display_dict(plt::PlottingObject{PlotlyJSPackage}) = IJulia.display_dict(plt.o)
|
||||
IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::PlotlyJSPackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::PlotlyJSBackend; kw...)
|
||||
d = KW(kw)
|
||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
# o = PlotlyJS.Plot(PlotlyJS.GenericTrace[], PlotlyJS.Layout(),
|
||||
@@ -29,12 +29,12 @@ function _create_plot(pkg::PlotlyJSPackage; kw...)
|
||||
# o = T(PlotlyJS.Plot())
|
||||
o = PlotlyJS.plot()
|
||||
|
||||
Plot(o, pkg, 0, d, Dict[])
|
||||
Plot(o, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::PlotlyJSPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::PlotlyJSBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
syncplot = plt.o
|
||||
|
||||
# dumpdict(d, "addseries", true)
|
||||
@@ -44,6 +44,7 @@ function _add_series(::PlotlyJSPackage, plt::Plot; kw...)
|
||||
typ = pop!(pdict, :type)
|
||||
gt = PlotlyJS.GenericTrace(typ; pdict...)
|
||||
PlotlyJS.addtraces!(syncplot, gt)
|
||||
# PlotlyJS.addtraces!(syncplot.plot, gt)
|
||||
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
@@ -53,7 +54,7 @@ end
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PlotlyJSPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PlotlyJSBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
# set or add to the annotation_list
|
||||
if !haskey(plt.plotargs, :annotation_list)
|
||||
plt.plotargs[:annotation_list] = Any[]
|
||||
@@ -63,66 +64,66 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{PlotlyJSPackage})
|
||||
function _before_update_plot(plt::Plot{PlotlyJSBackend})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{PlotlyJSPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{PlotlyJSBackend}, d::KW)
|
||||
pdict = plotly_layout(d)
|
||||
# dumpdict(pdict, "pdict updateplot", true)
|
||||
syncplot = plt.o
|
||||
w,h = d[:size]
|
||||
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
|
||||
# PlotlyJS.relayout!(syncplot.plot, pdict, width = w, height = h)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{PlotlyJSPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{PlotlyJSBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{PlotlyJSPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{PlotlyJSBackend}, i::Int)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{PlotlyJSPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{PlotlyJSBackend}, xy::Tuple, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
d[:x], d[:y] = xy
|
||||
# TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
|
||||
# PlotlyJS.restyle!(plt.o, i, plotly_series(d))
|
||||
PlotlyJS.restyle!(plt.o, i, Dict(:x=>(d[:x],), :y=>(d[:y],)))
|
||||
PlotlyJS.restyle!(plt.o, i, KW(:x=>(d[:x],), :y=>(d[:y],)))
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{PlotlyJSPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{PlotlyJSBackend}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{PlotlyJSPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{PlotlyJSBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{PlotlyJSPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{PlotlyJSBackend}, isx::Bool)
|
||||
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::PlottingObject{PlotlyJSPackage})
|
||||
function Base.writemime(io::IO, m::MIME"text/html", plt::AbstractPlot{PlotlyJSBackend})
|
||||
Base.writemime(io, m, plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSBackend})
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSBackend})
|
||||
error()
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
function _initialize_backend(::PyPlotPackage)
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval begin
|
||||
import PyPlot
|
||||
export PyPlot
|
||||
@@ -149,9 +149,9 @@ function getRightAxis(wrap::PyPlotAxisWrapper)
|
||||
wrap.rightax
|
||||
end
|
||||
|
||||
getLeftAxis(plt::Plot{PyPlotPackage}) = getLeftAxis(plt.o)
|
||||
getRightAxis(plt::Plot{PyPlotPackage}) = getRightAxis(plt.o)
|
||||
getAxis(plt::Plot{PyPlotPackage}, axis::Symbol) = (axis == :right ? getRightAxis : getLeftAxis)(plt)
|
||||
getLeftAxis(plt::Plot{PyPlotBackend}) = getLeftAxis(plt.o)
|
||||
getRightAxis(plt::Plot{PyPlotBackend}) = getRightAxis(plt.o)
|
||||
getAxis(plt::Plot{PyPlotBackend}, 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)
|
||||
@@ -164,18 +164,19 @@ function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol)
|
||||
# in the 2-axis case we need to get: <rightaxis>[:<func>]
|
||||
ax = getAxis(plt, axis)
|
||||
# ax[:set_ylabel](plt.plotargs[:yrightlabel])
|
||||
fmap = @compat Dict(
|
||||
fmap = KW(
|
||||
:hist => :hist,
|
||||
:density => :hist,
|
||||
:sticks => :bar,
|
||||
:bar => :bar,
|
||||
:heatmap => :hexbin,
|
||||
:hist2d => :hexbin,
|
||||
:hexbin => :hexbin,
|
||||
:scatter => :scatter,
|
||||
:contour => :contour,
|
||||
:scatter3d => :scatter,
|
||||
:surface => :plot_surface,
|
||||
:wireframe => :plot_wireframe,
|
||||
:heatmap => :pcolor,
|
||||
# :surface => pycolors.pymember("LinearSegmentedColormap")[:from_list]
|
||||
)
|
||||
return ax[get(fmap, linetype, :plot)]
|
||||
@@ -195,7 +196,7 @@ function updateAxisColors(ax, fgcolor)
|
||||
end
|
||||
|
||||
|
||||
function handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Bool)
|
||||
function handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Bool)
|
||||
if smooth
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
ax[:plot](xs, ys,
|
||||
@@ -205,7 +206,7 @@ function handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Bool)
|
||||
)
|
||||
end
|
||||
end
|
||||
handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Real) = handleSmooth(plt, ax, d, true)
|
||||
handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Real) = handleSmooth(plt, ax, d, true)
|
||||
|
||||
|
||||
|
||||
@@ -213,17 +214,17 @@ handleSmooth(plt::Plot{PyPlotPackage}, ax, d::Dict, smooth::Real) = handleSmooth
|
||||
# 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)
|
||||
makePyPlotCurrent(plt::Plot{PyPlotBackend}) = plt.o == nothing ? nothing : makePyPlotCurrent(plt.o)
|
||||
|
||||
|
||||
function _before_add_series(plt::Plot{PyPlotPackage})
|
||||
function _before_add_series(plt::Plot{PyPlotBackend})
|
||||
makePyPlotCurrent(plt)
|
||||
end
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
function pyplot_figure(plotargs::Dict)
|
||||
function pyplot_figure(plotargs::KW)
|
||||
w,h = map(px2inch, plotargs[:size])
|
||||
bgcolor = getPyPlotColor(plotargs[:background_color])
|
||||
|
||||
@@ -266,9 +267,9 @@ 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 _create_plot(pkg::PyPlotPackage; kw...)
|
||||
function _create_plot(pkg::PyPlotBackend; kw...)
|
||||
# create the figure
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
|
||||
# standalone plots will create a figure, but not if part of a subplot (do it later)
|
||||
if haskey(d, :subplot)
|
||||
@@ -283,13 +284,13 @@ function _create_plot(pkg::PyPlotPackage; kw...)
|
||||
pyplot_3d_setup!(wrap, d)
|
||||
end
|
||||
|
||||
plt = Plot(wrap, pkg, 0, d, Dict[])
|
||||
plt = Plot(wrap, pkg, 0, d, KW[])
|
||||
plt
|
||||
end
|
||||
|
||||
|
||||
function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(pkg::PyPlotBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
|
||||
# 3D plots have a different underlying Axes object in PyPlot
|
||||
lt = d[:linetype]
|
||||
@@ -299,11 +300,13 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
|
||||
# handle mismatched x/y sizes, as PyPlot doesn't like that
|
||||
x, y = d[:x], d[:y]
|
||||
nx, ny = map(length, (x,y))
|
||||
if nx < ny
|
||||
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
if !isa(get(d, :z, nothing), Surface)
|
||||
nx, ny = map(length, (x,y))
|
||||
if nx < ny
|
||||
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
|
||||
else
|
||||
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
|
||||
end
|
||||
end
|
||||
|
||||
ax = getAxis(plt, d[:axis])
|
||||
@@ -334,7 +337,7 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
# lt = d[:linetype]
|
||||
extra_kwargs = Dict()
|
||||
extra_kwargs = KW()
|
||||
|
||||
plotfunc = getPyPlotFunction(plt, d[:axis], lt)
|
||||
|
||||
@@ -344,14 +347,14 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
# NOTE: this is unsupported because it does the wrong thing... it shifts the whole axis
|
||||
# extra_kwargs[:bottom] = d[:fill]
|
||||
|
||||
if ishistlike(lt)
|
||||
if like_histogram(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)
|
||||
elseif lt in (:hist2d, :hexbin)
|
||||
extra_kwargs[:gridsize] = d[:nbins]
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor])
|
||||
|
||||
@@ -370,6 +373,9 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
extra_kwargs[:linewidth] = d[:linewidth]
|
||||
extra_kwargs[:edgecolor] = getPyPlotColor(d[:linecolor], d[:linealpha])
|
||||
|
||||
elseif lt == :heatmap
|
||||
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
else
|
||||
|
||||
extra_kwargs[:linestyle] = getPyPlotLineStyle(lt, d[:linestyle])
|
||||
@@ -418,7 +424,7 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
# end
|
||||
|
||||
# set these for all types
|
||||
if !(lt in (:contour,:surface,:wireframe))
|
||||
if !(lt in (:contour,:surface,:wireframe,:heatmap))
|
||||
if !(lt in (:scatter, :scatter3d))
|
||||
extra_kwargs[:color] = color
|
||||
extra_kwargs[:linewidth] = d[:linewidth]
|
||||
@@ -428,7 +434,7 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
# do the plot
|
||||
d[:serieshandle] = if ishistlike(lt)
|
||||
d[:serieshandle] = if like_histogram(lt)
|
||||
plotfunc(d[:y]; extra_kwargs...)[1]
|
||||
|
||||
elseif lt == :contour
|
||||
@@ -452,21 +458,29 @@ function _add_series(pkg::PyPlotPackage, plt::Plot; kw...)
|
||||
handle
|
||||
|
||||
elseif lt in (:surface,:wireframe)
|
||||
x, y, z = d[:x], d[:y], Array(d[:z])
|
||||
x, y, z = Array(d[:x]), Array(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)
|
||||
|
||||
elseif lt in (:scatter, :hist2d, :hexbin)
|
||||
plotfunc(d[:x], d[:y]; extra_kwargs...)
|
||||
else
|
||||
|
||||
elseif lt == :heatmap
|
||||
x, y, z = d[:x], d[:y], d[:z].surf'
|
||||
plotfunc(heatmap_edges(x), heatmap_edges(y), z; extra_kwargs...)
|
||||
|
||||
else # plot
|
||||
plotfunc(d[:x], d[:y]; extra_kwargs...)[1]
|
||||
end
|
||||
|
||||
# smoothing
|
||||
handleSmooth(plt, ax, d, d[:smooth])
|
||||
|
||||
# add the colorbar legend
|
||||
@@ -496,7 +510,7 @@ end
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
|
||||
function Base.getindex(plt::Plot{PyPlotPackage}, i::Integer)
|
||||
function Base.getindex(plt::Plot{PyPlotBackend}, i::Integer)
|
||||
series = plt.seriesargs[i][:serieshandle]
|
||||
try
|
||||
return series[:get_data]()
|
||||
@@ -528,7 +542,7 @@ function minmaxseries(ds, vec, axis)
|
||||
end
|
||||
|
||||
# TODO: this needs to handle one-sided fixed limits
|
||||
function set_lims!(plt::Plot{PyPlotPackage}, axis::Symbol)
|
||||
function set_lims!(plt::Plot{PyPlotBackend}, axis::Symbol)
|
||||
ax = getAxis(plt, axis)
|
||||
if plt.plotargs[:xlims] == :auto
|
||||
ax[:set_xlim](minmaxseries(plt.seriesargs, :x, axis)...)
|
||||
@@ -536,9 +550,12 @@ function set_lims!(plt::Plot{PyPlotPackage}, axis::Symbol)
|
||||
if plt.plotargs[:ylims] == :auto
|
||||
ax[:set_ylim](minmaxseries(plt.seriesargs, :y, axis)...)
|
||||
end
|
||||
if plt.plotargs[:zlims] == :auto && haskey(ax, :set_zlim)
|
||||
ax[:set_zlim](minmaxseries(plt.seriesargs, :z, axis)...)
|
||||
end
|
||||
end
|
||||
|
||||
function Base.setindex!{X,Y}(plt::Plot{PyPlotPackage}, xy::Tuple{X,Y}, i::Integer)
|
||||
function Base.setindex!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer)
|
||||
d = plt.seriesargs[i]
|
||||
series = d[:serieshandle]
|
||||
x, y = xy
|
||||
@@ -553,27 +570,32 @@ function Base.setindex!{X,Y}(plt::Plot{PyPlotPackage}, xy::Tuple{X,Y}, i::Intege
|
||||
plt
|
||||
end
|
||||
|
||||
function Base.setindex!{X,Y,Z}(plt::Plot{PyPlotPackage}, xyz::Tuple{X,Y,Z}, i::Integer)
|
||||
function Base.setindex!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer)
|
||||
warn("setindex not implemented for xyz")
|
||||
plt
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
function addPyPlotLims(ax, lims, isx::Bool)
|
||||
lims == :auto && return
|
||||
ltype = limsType(lims)
|
||||
if ltype == :limits
|
||||
if isx
|
||||
isfinite(lims[1]) && ax[:set_xlim](left = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_xlim](right = lims[2])
|
||||
function addPyPlotLims(ax, lims, dimension)
|
||||
lims == :auto && return
|
||||
ltype = limsType(lims)
|
||||
if ltype == :limits
|
||||
if dimension == :xlim
|
||||
isfinite(lims[1]) && ax[:set_xlim](left = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_xlim](right = lims[2])
|
||||
elseif dimension == :ylim
|
||||
isfinite(lims[1]) && ax[:set_ylim](bottom = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_ylim](top = lims[2])
|
||||
elseif dimension == :zlim && haskey(ax, :set_zlim)
|
||||
isfinite(lims[1]) && ax[:set_zlim](bottom = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_zlim](top = lims[2])
|
||||
else
|
||||
error("Invalid argument at position 3: $dimension")
|
||||
end
|
||||
else
|
||||
isfinite(lims[1]) && ax[:set_ylim](bottom = lims[1])
|
||||
isfinite(lims[2]) && ax[:set_ylim](top = lims[2])
|
||||
error("Invalid input for $dimension: ", lims)
|
||||
end
|
||||
else
|
||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
||||
end
|
||||
end
|
||||
|
||||
function addPyPlotTicks(ax, ticks, isx::Bool)
|
||||
@@ -593,13 +615,14 @@ function addPyPlotTicks(ax, ticks, isx::Bool)
|
||||
end
|
||||
end
|
||||
|
||||
usingRightAxis(plt::Plot{PyPlotPackage}) = any(args -> args[:axis] in (:right,:auto), plt.seriesargs)
|
||||
usingRightAxis(plt::Plot{PyPlotBackend}) = any(args -> args[:axis] in (:right,:auto), plt.seriesargs)
|
||||
|
||||
function _update_plot(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{PyPlotBackend}, d::KW)
|
||||
figorax = plt.o
|
||||
ax = getLeftAxis(figorax)
|
||||
# PyPlot.sca(ax)
|
||||
|
||||
|
||||
# title and axis labels
|
||||
# haskey(d, :title) && PyPlot.title(d[:title])
|
||||
haskey(d, :title) && ax[:set_title](d[:title])
|
||||
@@ -617,8 +640,9 @@ function _update_plot(plt::Plot{PyPlotPackage}, d::Dict)
|
||||
haskey(d, :yscale) && applyPyPlotScale(ax, d[:yscale], false)
|
||||
|
||||
# limits and ticks
|
||||
haskey(d, :xlims) && addPyPlotLims(ax, d[:xlims], true)
|
||||
haskey(d, :ylims) && addPyPlotLims(ax, d[:ylims], false)
|
||||
haskey(d, :xlims) && addPyPlotLims(ax, d[:xlims], :xlim)
|
||||
haskey(d, :ylims) && addPyPlotLims(ax, d[:ylims], :ylim)
|
||||
haskey(d, :zlims) && addPyPlotLims(ax, d[:zlims], :zlim)
|
||||
haskey(d, :xticks) && addPyPlotTicks(ax, d[:xticks], true)
|
||||
haskey(d, :yticks) && addPyPlotTicks(ax, d[:yticks], false)
|
||||
|
||||
@@ -674,13 +698,13 @@ end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::@compat(AbstractString))
|
||||
function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::@compat(AbstractString))
|
||||
ax = getLeftAxis(plt)
|
||||
ax[:annotate](val, xy = (x,y))
|
||||
end
|
||||
|
||||
|
||||
function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::PlotText)
|
||||
function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::PlotText)
|
||||
ax = getLeftAxis(plt)
|
||||
ax[:annotate](val.str,
|
||||
xy = (x,y),
|
||||
@@ -693,7 +717,7 @@ function createPyPlotAnnotationObject(plt::Plot{PyPlotPackage}, x, y, val::PlotT
|
||||
)
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PyPlotPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{PyPlotBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createPyPlotAnnotationObject(plt, ann...)
|
||||
end
|
||||
@@ -702,7 +726,7 @@ end
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# NOTE: pyplot needs to build before
|
||||
function _create_subplot(subplt::Subplot{PyPlotPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{PyPlotBackend}, isbefore::Bool)
|
||||
l = subplt.layout
|
||||
|
||||
# w,h = map(px2inch, getplotargs(subplt,1)[:size])
|
||||
@@ -731,16 +755,16 @@ end
|
||||
|
||||
# this will be called internally, when creating a subplot from existing plots
|
||||
# NOTE: if I ever need to "Rebuild a "ubplot from individual Plot's"... this is what I should use!
|
||||
function subplot(plts::AVec{Plot{PyPlotPackage}}, layout::SubplotLayout, d::Dict)
|
||||
function subplot(plts::AVec{Plot{PyPlotBackend}}, layout::SubplotLayout, d::KW)
|
||||
validateSubplotSupported()
|
||||
|
||||
p = length(layout)
|
||||
n = sum([plt.n for plt in plts])
|
||||
|
||||
pkg = PyPlotPackage()
|
||||
newplts = Plot{PyPlotPackage}[_create_plot(pkg; subplot=true, plt.plotargs...) for plt in plts]
|
||||
pkg = PyPlotBackend()
|
||||
newplts = Plot{PyPlotBackend}[_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))
|
||||
subplt = Subplot(nothing, newplts, PyPlotBackend(), p, n, layout, d, true, false, false, (r,c) -> (nothing,nothing))
|
||||
|
||||
_preprocess_subplot(subplt, d)
|
||||
_create_subplot(subplt, true)
|
||||
@@ -757,7 +781,7 @@ function subplot(plts::AVec{Plot{PyPlotPackage}}, layout::SubplotLayout, d::Dict
|
||||
end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{PyPlotBackend}, isx::Bool)
|
||||
if isx
|
||||
plot!(plt, xticks=zeros(0), xlabel="")
|
||||
else
|
||||
@@ -765,14 +789,14 @@ function _remove_axis(plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
end
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{PyPlotPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{PyPlotBackend}, isx::Bool)
|
||||
pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]()
|
||||
_expand_limits(lims, pltlims)
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
const _pyplot_legend_pos = Dict(
|
||||
const _pyplot_legend_pos = KW(
|
||||
:right => "right",
|
||||
:left => "center left",
|
||||
:top => "upper center",
|
||||
@@ -784,7 +808,7 @@ function addPyPlotLegend(plt::Plot, ax)
|
||||
leg = plt.plotargs[:legend]
|
||||
if leg != :none
|
||||
# gotta do this to ensure both axes are included
|
||||
args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:heatmap,:hline,:vline,:contour, :surface, :wireframe, :path3d, :scatter3d)), plt.seriesargs)
|
||||
args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:hist2d,:hline,:vline,:contour,:surface,:wireframe,:heatmap,:path3d,:scatter3d)), plt.seriesargs)
|
||||
args = filter(x -> x[:label] != "", args)
|
||||
if length(args) > 0
|
||||
leg = ax[:legend]([d[:serieshandle] for d in args],
|
||||
@@ -798,14 +822,14 @@ function addPyPlotLegend(plt::Plot, ax)
|
||||
end
|
||||
end
|
||||
|
||||
function finalizePlot(plt::Plot{PyPlotPackage})
|
||||
function finalizePlot(plt::Plot{PyPlotBackend})
|
||||
ax = getLeftAxis(plt)
|
||||
addPyPlotLegend(plt, ax)
|
||||
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
|
||||
PyPlot.draw()
|
||||
end
|
||||
|
||||
function finalizePlot(subplt::Subplot{PyPlotPackage})
|
||||
function finalizePlot(subplt::Subplot{PyPlotBackend})
|
||||
fig = subplt.o.fig
|
||||
for (i,plt) in enumerate(subplt.plts)
|
||||
ax = getLeftAxis(plt)
|
||||
@@ -818,20 +842,20 @@ end
|
||||
|
||||
# # allow for writing any supported mime
|
||||
# for mime in keys(PyPlot.aggformats)
|
||||
# @eval function Base.writemime(io::IO, m::MIME{symbol{$mime}}, plt::Plot{PyPlotPackage})
|
||||
# @eval function Base.writemime(io::IO, m::MIME{symbol{$mime}}, plt::Plot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
# writemime(io, m, getfig(plt.o))
|
||||
# end
|
||||
# end
|
||||
|
||||
# function Base.writemime(io::IO, m::@compat(Union{MIME"image/svg+xml", MIME"image/png"}, plt::Plot{PyPlotPackage})
|
||||
# function Base.writemime(io::IO, m::@compat(Union{MIME"image/svg+xml", MIME"image/png"}, plt::Plot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
# writemime(io, m, getfig(plt.o))
|
||||
# end
|
||||
|
||||
|
||||
# NOTE: to bring up a GUI window in IJulia, need some extra steps
|
||||
function Base.display(::PlotsDisplay, plt::PlottingObject{PyPlotPackage})
|
||||
function Base.display(::PlotsDisplay, plt::AbstractPlot{PyPlotBackend})
|
||||
finalizePlot(plt)
|
||||
if isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
display(getfig(plt.o))
|
||||
@@ -846,7 +870,7 @@ function Base.display(::PlotsDisplay, plt::PlottingObject{PyPlotPackage})
|
||||
end
|
||||
|
||||
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{PyPlotPackage})
|
||||
# function Base.display(::PlotsDisplay, subplt::Subplot{PyPlotBackend})
|
||||
# finalizePlot(subplt)
|
||||
# PyPlot.ion()
|
||||
# PyPlot.figure(getfig(subplt.o).o[:number])
|
||||
@@ -857,13 +881,13 @@ end
|
||||
|
||||
# # allow for writing any supported mime
|
||||
# for mime in (MIME"image/png", MIME"application/pdf", MIME"application/postscript")
|
||||
# @eval function Base.writemime(io::IO, ::$mime, plt::PlottingObject{PyPlotPackage})
|
||||
# @eval function Base.writemime(io::IO, ::$mime, plt::AbstractPlot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
# writemime(io, $mime(), getfig(plt.o))
|
||||
# end
|
||||
# end
|
||||
|
||||
const _pyplot_mimeformats = @compat Dict(
|
||||
const _pyplot_mimeformats = Dict(
|
||||
"application/eps" => "eps",
|
||||
"image/eps" => "eps",
|
||||
"application/pdf" => "pdf",
|
||||
@@ -874,7 +898,7 @@ const _pyplot_mimeformats = @compat Dict(
|
||||
|
||||
|
||||
for (mime, fmt) in _pyplot_mimeformats
|
||||
@eval function Base.writemime(io::IO, ::MIME{symbol($mime)}, plt::PlottingObject{PyPlotPackage})
|
||||
@eval function Base.writemime(io::IO, ::MIME{symbol($mime)}, plt::AbstractPlot{PyPlotBackend})
|
||||
finalizePlot(plt)
|
||||
fig = getfig(plt.o)
|
||||
fig.o["canvas"][:print_figure](io,
|
||||
@@ -889,7 +913,7 @@ for (mime, fmt) in _pyplot_mimeformats
|
||||
end
|
||||
|
||||
|
||||
# function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotPackage})
|
||||
# function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotBackend})
|
||||
# finalizePlot(subplt)
|
||||
# writemime(io, m, getfig(subplt.o))
|
||||
# end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
function _initialize_backend(::QwtPackage; kw...)
|
||||
function _initialize_backend(::QwtBackend; kw...)
|
||||
@eval begin
|
||||
warn("Qwt is no longer supported... many features will likely be broken.")
|
||||
import Qwt
|
||||
@@ -11,7 +11,7 @@ end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
@compat const _qwtAliases = Dict(
|
||||
@compat const _qwtAliases = KW(
|
||||
:nbins => :heatmap_n,
|
||||
:fillrange => :fillto,
|
||||
:linewidth => :width,
|
||||
@@ -24,7 +24,7 @@ end
|
||||
:star8 => :star2,
|
||||
)
|
||||
|
||||
function fixcolors(d::Dict)
|
||||
function fixcolors(d::KW)
|
||||
for (k,v) in d
|
||||
if typeof(v) <: ColorScheme
|
||||
d[k] = getColor(v)
|
||||
@@ -38,8 +38,8 @@ function replaceQwtAliases(d, s)
|
||||
end
|
||||
end
|
||||
|
||||
function adjustQwtKeywords(plt::Plot{QwtPackage}, iscreating::Bool; kw...)
|
||||
d = Dict(kw)
|
||||
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
d = KW(kw)
|
||||
lt = d[:linetype]
|
||||
if lt == :scatter
|
||||
d[:linetype] = :none
|
||||
@@ -73,20 +73,20 @@ function adjustQwtKeywords(plt::Plot{QwtPackage}, iscreating::Bool; kw...)
|
||||
|
||||
d[:x] = collect(d[:x])
|
||||
d[:y] = collect(d[:y])
|
||||
|
||||
|
||||
d
|
||||
end
|
||||
|
||||
function _create_plot(pkg::QwtPackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::QwtBackend; kw...)
|
||||
d = KW(kw)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot")
|
||||
o = Qwt.plot(zeros(0,0); d..., show=false)
|
||||
plt = Plot(o, pkg, 0, d, Dict[])
|
||||
plt = Plot(o, pkg, 0, d, KW[])
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_series(::QwtPackage, plt::Plot; kw...)
|
||||
function _add_series(::QwtBackend, plt::Plot; kw...)
|
||||
d = adjustQwtKeywords(plt, false; kw...)
|
||||
fixcolors(d)
|
||||
dumpdict(d,"\n\n!!! plot!")
|
||||
@@ -98,12 +98,12 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function updateLimsAndTicks(plt::Plot{QwtPackage}, d::Dict, isx::Bool)
|
||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
lims = get(d, isx ? :xlims : :ylims, nothing)
|
||||
ticks = get(d, isx ? :xticks : :yticks, nothing)
|
||||
w = plt.o.widget
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
||||
|
||||
if typeof(lims) <: @compat(Union{Tuple,AVec}) && length(lims) == 2
|
||||
if isx
|
||||
plt.o.autoscale_x = false
|
||||
@@ -138,7 +138,7 @@ function updateLimsAndTicks(plt::Plot{QwtPackage}, d::Dict, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot(plt::Plot{QwtPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{QwtBackend}, d::KW)
|
||||
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])
|
||||
@@ -146,7 +146,7 @@ function _update_plot(plt::Plot{QwtPackage}, d::Dict)
|
||||
updateLimsAndTicks(plt, d, false)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{QwtPackage}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, d::KW)
|
||||
haskey(d, :size) && Qwt.resizewidget(plt.o, d[:size]...)
|
||||
haskey(d, :pos) && Qwt.movewidget(plt.o, d[:pos]...)
|
||||
end
|
||||
@@ -155,7 +155,7 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
|
||||
function addLineMarker(plt::Plot{QwtPackage}, d::Dict)
|
||||
function addLineMarker(plt::Plot{QwtBackend}, d::KW)
|
||||
for yi in d[:y]
|
||||
marker = Qwt.QWT.QwtPlotMarker()
|
||||
ishorizontal = (d[:linetype] == :hline)
|
||||
@@ -189,7 +189,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::@compat(AbstractString))
|
||||
marker[:attach](plt.o.widget)
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{QwtPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createQwtAnnotation(plt, ann...)
|
||||
end
|
||||
@@ -199,12 +199,12 @@ end
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{QwtPackage}, i::Int)
|
||||
function Base.getindex(plt::Plot{QwtBackend}, i::Int)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{QwtPackage}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{QwtBackend}, xy::Tuple, i::Integer)
|
||||
series = plt.o.lines[i]
|
||||
series.x, series.y = xy
|
||||
plt
|
||||
@@ -213,12 +213,12 @@ end
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# savepng(::QwtPackage, plt::PlottingObject, fn::@compat(AbstractString), args...) = Qwt.savepng(plt.o, fn)
|
||||
# savepng(::QwtBackend, plt::AbstractPlot, fn::@compat(AbstractString), args...) = Qwt.savepng(plt.o, fn)
|
||||
|
||||
# -------------------------------
|
||||
|
||||
# create the underlying object (each backend will do this differently)
|
||||
function _create_subplot(subplt::Subplot{QwtPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
|
||||
isbefore && return false
|
||||
i = 0
|
||||
rows = Any[]
|
||||
@@ -240,26 +240,26 @@ function _create_subplot(subplt::Subplot{QwtPackage}, isbefore::Bool)
|
||||
true
|
||||
end
|
||||
|
||||
function _expand_limits(lims, plt::Plot{QwtPackage}, isx::Bool)
|
||||
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
|
||||
for series in plt.o.lines
|
||||
_expand_limits(lims, isx ? series.x : series.y)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _remove_axis(plt::Plot{QwtPackage}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtPackage})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
|
||||
write(io, readall("/tmp/dfskjdhfkh.png"))
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtPackage})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
||||
for plt in subplt.plts
|
||||
Qwt.refresh(plt.o)
|
||||
end
|
||||
@@ -268,15 +268,14 @@ function Base.writemime(io::IO, ::MIME"image/png", subplt::Subplot{QwtPackage})
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{QwtPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
|
||||
Qwt.refresh(plt.o)
|
||||
Qwt.showwidget(plt.o)
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{QwtPackage})
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
|
||||
for plt in subplt.plts
|
||||
Qwt.refresh(plt.o)
|
||||
end
|
||||
Qwt.showwidget(subplt.o)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
supportedAxes(::PlottingPackage) = [:left]
|
||||
supportedTypes(::PlottingPackage) = []
|
||||
supportedStyles(::PlottingPackage) = [:solid]
|
||||
supportedMarkers(::PlottingPackage) = [:none]
|
||||
supportedScales(::PlottingPackage) = [:identity]
|
||||
subplotSupported(::PlottingPackage) = false
|
||||
stringsSupported(::PlottingPackage) = false
|
||||
supportedAxes(::AbstractBackend) = [:left]
|
||||
supportedTypes(::AbstractBackend) = []
|
||||
supportedStyles(::AbstractBackend) = [:solid]
|
||||
supportedMarkers(::AbstractBackend) = [:none]
|
||||
supportedScales(::AbstractBackend) = [:identity]
|
||||
subplotSupported(::AbstractBackend) = false
|
||||
stringsSupported(::AbstractBackend) = false
|
||||
|
||||
supportedAxes() = supportedAxes(backend())
|
||||
supportedTypes() = supportedTypes(backend())
|
||||
@@ -19,7 +19,7 @@ stringsSupported() = stringsSupported(backend())
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
supportedArgs(::GadflyPackage) = [
|
||||
supportedArgs(::GadflyBackend) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
@@ -78,32 +78,32 @@ supportedArgs(::GadflyPackage) = [
|
||||
# :surface,
|
||||
:levels,
|
||||
]
|
||||
supportedAxes(::GadflyPackage) = [:auto, :left]
|
||||
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, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GadflyPackage) = true
|
||||
supportedAxes(::GadflyBackend) = [:auto, :left]
|
||||
supportedTypes(::GadflyBackend) = [:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :hist2d, :hexbin, :hist, :bar,
|
||||
:hline, :vline, :contour, :shape]
|
||||
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GadflyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
supportedArgs(::ImmersePackage) = supportedArgs(GadflyPackage())
|
||||
supportedAxes(::ImmersePackage) = supportedAxes(GadflyPackage())
|
||||
supportedTypes(::ImmersePackage) = supportedTypes(GadflyPackage())
|
||||
supportedStyles(::ImmersePackage) = supportedStyles(GadflyPackage())
|
||||
supportedMarkers(::ImmersePackage) = supportedMarkers(GadflyPackage())
|
||||
supportedScales(::ImmersePackage) = supportedScales(GadflyPackage())
|
||||
subplotSupported(::ImmersePackage) = true
|
||||
supportedArgs(::ImmerseBackend) = supportedArgs(GadflyBackend())
|
||||
supportedAxes(::ImmerseBackend) = supportedAxes(GadflyBackend())
|
||||
supportedTypes(::ImmerseBackend) = supportedTypes(GadflyBackend())
|
||||
supportedStyles(::ImmerseBackend) = supportedStyles(GadflyBackend())
|
||||
supportedMarkers(::ImmerseBackend) = supportedMarkers(GadflyBackend())
|
||||
supportedScales(::ImmerseBackend) = supportedScales(GadflyBackend())
|
||||
subplotSupported(::ImmerseBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::PyPlotPackage) = [
|
||||
supportedArgs(::PyPlotBackend) = [
|
||||
:annotation,
|
||||
:axis,
|
||||
:background_color,
|
||||
@@ -145,6 +145,7 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:y,
|
||||
:ylabel,
|
||||
:ylims,
|
||||
:zlims,
|
||||
:yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
@@ -164,22 +165,22 @@ supportedArgs(::PyPlotPackage) = [
|
||||
:markeralpha,
|
||||
:overwrite_figure,
|
||||
]
|
||||
supportedAxes(::PyPlotPackage) = _allAxes
|
||||
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, :ln, :log2, :log10]
|
||||
subplotSupported(::PyPlotPackage) = true
|
||||
supportedAxes(::PyPlotBackend) = _allAxes
|
||||
supportedTypes(::PyPlotBackend) = [:none, :line, :path, :steppre, :steppost, #:sticks,
|
||||
:scatter, :hist2d, :hexbin, :hist, :density, :bar,
|
||||
:hline, :vline, :contour, :path3d, :scatter3d, :surface, :wireframe, :heatmap]
|
||||
supportedStyles(::PyPlotBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
# supportedMarkers(::PyPlotBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :hexagon]
|
||||
supportedMarkers(::PyPlotBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::PyPlotBackend) = [:identity, :ln, :log2, :log10]
|
||||
subplotSupported(::PyPlotBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::GRPackage) = [
|
||||
supportedArgs(::GRBackend) = [
|
||||
:annotation,
|
||||
:axis,
|
||||
:background_color,
|
||||
@@ -238,22 +239,22 @@ supportedArgs(::GRPackage) = [
|
||||
:linealpha,
|
||||
:markeralpha,
|
||||
]
|
||||
supportedAxes(::GRPackage) = _allAxes
|
||||
supportedTypes(::GRPackage) = [:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :heatmap, :hexbin, :hist, :density, :bar,
|
||||
:hline, :vline, :contour, :path3d, :scatter3d, :surface,
|
||||
supportedAxes(::GRBackend) = _allAxes
|
||||
supportedTypes(::GRBackend) = [:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :hist2d, :hexbin, :hist, :density, :bar,
|
||||
:hline, :vline, :contour, :heatmap, :path3d, :scatter3d, :surface,
|
||||
:wireframe, :ohlc, :pie]
|
||||
supportedStyles(::GRPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GRPackage) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GRPackage) = [:identity, :log10]
|
||||
subplotSupported(::GRPackage) = true
|
||||
supportedStyles(::GRBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GRBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GRBackend) = [:identity, :log10]
|
||||
subplotSupported(::GRBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::QwtPackage) = [
|
||||
supportedArgs(::QwtBackend) = [
|
||||
:annotation,
|
||||
# :args,
|
||||
:axis,
|
||||
@@ -304,16 +305,16 @@ supportedArgs(::QwtPackage) = [
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
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
|
||||
supportedTypes(::QwtBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :hist2d, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedMarkers(::QwtBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supportedScales(::QwtBackend) = [:identity, :log10]
|
||||
subplotSupported(::QwtBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
supportedArgs(::UnicodePlotsPackage) = [
|
||||
supportedArgs(::UnicodePlotsBackend) = [
|
||||
# :annotation,
|
||||
# :args,
|
||||
# :axis,
|
||||
@@ -362,12 +363,12 @@ supportedArgs(::UnicodePlotsPackage) = [
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::UnicodePlotsPackage) = [:auto, :left]
|
||||
supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedStyles(::UnicodePlotsPackage) = [:auto, :solid]
|
||||
supportedMarkers(::UnicodePlotsPackage) = [:none, :auto, :ellipse]
|
||||
supportedScales(::UnicodePlotsPackage) = [:identity]
|
||||
subplotSupported(::UnicodePlotsPackage) = true
|
||||
supportedAxes(::UnicodePlotsBackend) = [:auto, :left]
|
||||
supportedTypes(::UnicodePlotsBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :hist2d, :hexbin, :hist, :bar, :hline, :vline]
|
||||
supportedStyles(::UnicodePlotsBackend) = [:auto, :solid]
|
||||
supportedMarkers(::UnicodePlotsBackend) = [:none, :auto, :ellipse]
|
||||
supportedScales(::UnicodePlotsBackend) = [:identity]
|
||||
subplotSupported(::UnicodePlotsBackend) = true
|
||||
|
||||
|
||||
|
||||
@@ -375,7 +376,7 @@ subplotSupported(::UnicodePlotsPackage) = true
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
supportedArgs(::WinstonPackage) = [
|
||||
supportedArgs(::WinstonBackend) = [
|
||||
:annotation,
|
||||
# :args,
|
||||
# :axis,
|
||||
@@ -426,19 +427,19 @@ supportedArgs(::WinstonPackage) = [
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::WinstonPackage) = [:auto, :left]
|
||||
supportedTypes(::WinstonPackage) = [:none, :line, :path, :sticks, :scatter, :hist, :bar]
|
||||
supportedStyles(::WinstonPackage) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::WinstonPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supportedScales(::WinstonPackage) = [:identity, :log10]
|
||||
subplotSupported(::WinstonPackage) = false
|
||||
supportedAxes(::WinstonBackend) = [:auto, :left]
|
||||
supportedTypes(::WinstonBackend) = [:none, :line, :path, :sticks, :scatter, :hist, :bar]
|
||||
supportedStyles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::WinstonBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supportedScales(::WinstonBackend) = [:identity, :log10]
|
||||
subplotSupported(::WinstonBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
supportedArgs(::BokehPackage) = [
|
||||
supportedArgs(::BokehBackend) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
@@ -494,17 +495,17 @@ supportedArgs(::BokehPackage) = [
|
||||
# :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
|
||||
supportedAxes(::BokehBackend) = [:auto, :left]
|
||||
supportedTypes(::BokehBackend) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :hist2d, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::BokehBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::BokehBackend) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::BokehBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PlotlyPackage) = [
|
||||
supportedArgs(::PlotlyBackend) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
@@ -560,21 +561,21 @@ supportedArgs(::PlotlyPackage) = [
|
||||
: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,
|
||||
supportedAxes(::PlotlyBackend) = [:auto, :left]
|
||||
supportedTypes(::PlotlyBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:hist2d, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyPackage) = true
|
||||
stringsSupported(::PlotlyPackage) = true
|
||||
supportedScales(::PlotlyBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyBackend) = true
|
||||
stringsSupported(::PlotlyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PlotlyJSPackage) = [
|
||||
supportedArgs(::PlotlyJSBackend) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
@@ -630,20 +631,85 @@ supportedArgs(::PlotlyJSPackage) = [
|
||||
:grid,
|
||||
:levels,
|
||||
]
|
||||
supportedAxes(::PlotlyJSPackage) = [:auto, :left]
|
||||
supportedTypes(::PlotlyJSPackage) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:heatmap, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyJSPackage) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyJSPackage) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
supportedAxes(::PlotlyJSBackend) = [:auto, :left]
|
||||
supportedTypes(::PlotlyJSBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:hist2d, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyJSBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyJSBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyJSPackage) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyJSPackage) = true
|
||||
stringsSupported(::PlotlyJSPackage) = true
|
||||
supportedScales(::PlotlyJSBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyJSBackend) = true
|
||||
stringsSupported(::PlotlyJSBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::GLVisualizePackage) = [
|
||||
supportedArgs(::GLVisualizeBackend) = [
|
||||
# :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(::GLVisualizeBackend) = [:auto, :left]
|
||||
supportedTypes(::GLVisualizeBackend) = [:surface] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::GLVisualizeBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GLVisualizeBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::GLVisualizeBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GLVisualizeBackend) = false
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PGFPlotsBackend) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
@@ -699,75 +765,9 @@ supportedArgs(::GLVisualizePackage) = [
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::GLVisualizePackage) = [:auto, :left]
|
||||
supportedTypes(::GLVisualizePackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::GLVisualizePackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GLVisualizePackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::GLVisualizePackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GLVisualizePackage) = false
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
supportedArgs(::PGFPlotsPackage) = [
|
||||
# :annotation,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
# :group,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
# :linecolor,
|
||||
# :linestyle,
|
||||
# :linetype,
|
||||
# :linewidth,
|
||||
# :linealpha,
|
||||
# :markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :nbins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
# :size,
|
||||
# :title,
|
||||
# :windowtitle,
|
||||
# :x,
|
||||
# :xlabel,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
# :y,
|
||||
# :ylabel,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::PGFPlotsPackage) = [:auto, :left]
|
||||
supportedTypes(::PGFPlotsPackage) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::PGFPlotsPackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::PGFPlotsPackage) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PGFPlotsPackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PGFPlotsPackage) = false
|
||||
|
||||
supportedAxes(::PGFPlotsBackend) = [:auto, :left]
|
||||
supportedTypes(::PGFPlotsBackend) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :hist2d, :hexbin, :hist, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::PGFPlotsBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PGFPlotsBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PGFPlotsBackend) = false
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
function _initialize_backend(::[PkgName]Package; kw...)
|
||||
function _initialize_backend(::[PkgName]AbstractBackend; kw...)
|
||||
@eval begin
|
||||
import [PkgName]
|
||||
export [PkgName]
|
||||
@@ -14,22 +14,22 @@ end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
function _create_plot(pkg::[PkgName]Package; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::[PkgName]AbstractBackend; kw...)
|
||||
d = KW(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[])
|
||||
Plot(nothing, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
|
||||
function _add_series(::[PkgName]Package, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::[PkgName]AbstractBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
# TODO: add one series to the underlying package
|
||||
push!(plt.seriesargs, d)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{[PkgName]Package}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{[PkgName]AbstractBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
# TODO: add the annotation to the plot
|
||||
end
|
||||
@@ -37,53 +37,53 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _before_update_plot(plt::Plot{[PkgName]Package})
|
||||
function _before_update_plot(plt::Plot{[PkgName]AbstractBackend})
|
||||
end
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot(plt::Plot{[PkgName]Package}, d::Dict)
|
||||
function _update_plot(plt::Plot{[PkgName]AbstractBackend}, d::KW)
|
||||
end
|
||||
|
||||
function _update_plot_pos_size(plt::PlottingObject{[PkgName]Package}, d::Dict)
|
||||
function _update_plot_pos_size(plt::AbstractPlot{[PkgName]AbstractBackend}, d::KW)
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
function Base.getindex(plt::Plot{[PkgName]Package}, i::Int)
|
||||
function Base.getindex(plt::Plot{[PkgName]AbstractBackend}, i::Int)
|
||||
# TODO: return a tuple of (x, y) vectors
|
||||
end
|
||||
|
||||
function Base.setindex!(plt::Plot{[PkgName]Package}, xy::Tuple, i::Integer)
|
||||
function Base.setindex!(plt::Plot{[PkgName]AbstractBackend}, xy::Tuple, i::Integer)
|
||||
# TODO: set the plot data from the (x,y) tuple
|
||||
plt
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{[PkgName]Package}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{[PkgName]AbstractBackend}, 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)
|
||||
function _expand_limits(lims, plt::Plot{[PkgName]AbstractBackend}, isx::Bool)
|
||||
# TODO: call expand limits for each plot data
|
||||
end
|
||||
|
||||
function _remove_axis(plt::Plot{[PkgName]Package}, isx::Bool)
|
||||
function _remove_axis(plt::Plot{[PkgName]AbstractBackend}, 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})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{[PkgName]AbstractBackend})
|
||||
# TODO: write a png to io
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{[PkgName]Package})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{[PkgName]AbstractBackend})
|
||||
# TODO: display/show the plot
|
||||
end
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{[PkgName]Package})
|
||||
function Base.display(::PlotsDisplay, plt::Subplot{[PkgName]AbstractBackend})
|
||||
# TODO: display/show the subplot
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
function _initialize_backend(::UnicodePlotsPackage; kw...)
|
||||
function _initialize_backend(::UnicodePlotsBackend; kw...)
|
||||
@eval begin
|
||||
import UnicodePlots
|
||||
export UnicodePlots
|
||||
@@ -68,7 +68,7 @@ end
|
||||
|
||||
|
||||
# add a single series
|
||||
function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
|
||||
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
|
||||
|
||||
# get the function, or special handling for step/bar/hist
|
||||
lt = d[:linetype]
|
||||
@@ -111,7 +111,7 @@ function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
|
||||
end
|
||||
|
||||
|
||||
function handlePlotColors(::UnicodePlotsPackage, d::Dict)
|
||||
function handlePlotColors(::UnicodePlotsBackend, d::KW)
|
||||
# TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette
|
||||
d[:color_palette] = [RGB(0,0,0)]
|
||||
end
|
||||
@@ -119,8 +119,8 @@ end
|
||||
# -------------------------------
|
||||
|
||||
|
||||
function _create_plot(pkg::UnicodePlotsPackage; kw...)
|
||||
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
|
||||
function _create_plot(pkg::UnicodePlotsBackend; kw...)
|
||||
plt = Plot(nothing, pkg, 0, KW(kw), KW[])
|
||||
|
||||
# do we want to give a new default size?
|
||||
if !haskey(plt.plotargs, :size) || plt.plotargs[:size] == _plotDefaults[:size]
|
||||
@@ -130,8 +130,8 @@ function _create_plot(pkg::UnicodePlotsPackage; kw...)
|
||||
plt
|
||||
end
|
||||
|
||||
function _add_series(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::UnicodePlotsBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
if d[:linetype] in (:sticks, :bar)
|
||||
d = barHack(; d...)
|
||||
elseif d[:linetype] == :hist
|
||||
@@ -142,7 +142,7 @@ function _add_series(::UnicodePlotsPackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
|
||||
function _update_plot(plt::Plot{UnicodePlotsPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{UnicodePlotsBackend}, d::KW)
|
||||
for k in (:title, :xlabel, :ylabel, :xlims, :ylims)
|
||||
if haskey(d, k)
|
||||
plt.plotargs[k] = d[k]
|
||||
@@ -154,7 +154,7 @@ end
|
||||
# -------------------------------
|
||||
|
||||
# since this is such a hack, it's only callable using `png`... should error during normal `writemime`
|
||||
function png(plt::PlottingObject{UnicodePlotsPackage}, fn::@compat(AbstractString))
|
||||
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "png")
|
||||
|
||||
# make some whitespace and show the plot
|
||||
@@ -182,22 +182,21 @@ end
|
||||
|
||||
# we don't do very much for subplots... just stack them vertically
|
||||
|
||||
function _create_subplot(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{UnicodePlotsBackend}, isbefore::Bool)
|
||||
isbefore && return false
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{UnicodePlotsPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{UnicodePlotsBackend})
|
||||
rebuildUnicodePlot!(plt)
|
||||
show(plt.o)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsPackage})
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend})
|
||||
for plt in subplt.plts
|
||||
gui(plt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# 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"))
|
||||
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.plotargs, :window_title, "Plots.jl"))
|
||||
"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -26,7 +26,7 @@ function open_browser_window(filename::AbstractString)
|
||||
warn("Unknown OS... cannot open browser window.")
|
||||
end
|
||||
|
||||
function standalone_html_window(plt::PlottingObject; kw...)
|
||||
function standalone_html_window(plt::AbstractPlot; kw...)
|
||||
html = standalone_html(plt; kw...)
|
||||
# println(html)
|
||||
filename = string(tempname(), ".html")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
function _initialize_backend(::WinstonPackage; kw...)
|
||||
function _initialize_backend(::WinstonBackend; kw...)
|
||||
@eval begin
|
||||
# ENV["WINSTON_OUTPUT"] = "gtk"
|
||||
warn("Winston is no longer supported... many features will likely be broken.")
|
||||
@@ -16,13 +16,13 @@ end
|
||||
|
||||
|
||||
## dictionaries for conversion of Plots.jl names to Winston ones.
|
||||
@compat const winston_linestyle = Dict(:solid=>"solid",
|
||||
@compat const winston_linestyle = KW(:solid=>"solid",
|
||||
:dash=>"dash",
|
||||
:dot=>"dotted",
|
||||
:dashdot=>"dotdashed"
|
||||
)
|
||||
|
||||
@compat const winston_marker = Dict(:none=>".",
|
||||
@compat const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:ellipse=>"circle",
|
||||
:diamond=>"diamond",
|
||||
@@ -33,23 +33,23 @@ end
|
||||
:star5 => "asterisk"
|
||||
)
|
||||
|
||||
function _before_add_series(plt::Plot{WinstonPackage})
|
||||
function _before_add_series(plt::Plot{WinstonBackend})
|
||||
Winston.ghf(plt.o)
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _create_plot(pkg::WinstonPackage; kw...)
|
||||
d = Dict(kw)
|
||||
function _create_plot(pkg::WinstonBackend; kw...)
|
||||
d = KW(kw)
|
||||
wplt = Winston.FramedPlot(title = d[:title], xlabel = d[:xlabel], ylabel = d[:ylabel])
|
||||
|
||||
Plot(wplt, pkg, 0, d, Dict[])
|
||||
|
||||
Plot(wplt, pkg, 0, d, KW[])
|
||||
end
|
||||
|
||||
copy_remove(d::Dict, s::Symbol) = delete!(copy(d), s)
|
||||
copy_remove(d::KW, s::Symbol) = delete!(copy(d), s)
|
||||
|
||||
function addRegressionLineWinston(d::Dict, wplt)
|
||||
function addRegressionLineWinston(d::KW, wplt)
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
|
||||
end
|
||||
@@ -64,8 +64,8 @@ function getWinstonItems(plt::Plot)
|
||||
window, canvas, wplt
|
||||
end
|
||||
|
||||
function _add_series(::WinstonPackage, plt::Plot; kw...)
|
||||
d = Dict(kw)
|
||||
function _add_series(::WinstonBackend, plt::Plot; kw...)
|
||||
d = KW(kw)
|
||||
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
@@ -75,7 +75,7 @@ function _add_series(::WinstonPackage, plt::Plot; kw...)
|
||||
end
|
||||
|
||||
|
||||
e = Dict()
|
||||
e = KW()
|
||||
e[:color] = getColor(d[:linecolor])
|
||||
e[:linewidth] = d[:linewidth]
|
||||
e[:kind] = winston_linestyle[d[:linestyle]]
|
||||
@@ -88,7 +88,7 @@ function _add_series(::WinstonPackage, plt::Plot; kw...)
|
||||
|
||||
|
||||
|
||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar
|
||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :hist2d, :hexbin, :hist, :bar
|
||||
if d[:linetype] == :none
|
||||
Winston.add(wplt, Winston.Points(d[:x], d[:y]; copy_remove(e, :kind)..., color=getColor(d[:markercolor])))
|
||||
|
||||
@@ -123,7 +123,7 @@ function _add_series(::WinstonPackage, plt::Plot; kw...)
|
||||
# elseif d[:linetype] == :dots
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif d[:linetype] == :heatmap
|
||||
# elseif d[:linetype] == :hist2d
|
||||
# fn = Winston.XXX
|
||||
|
||||
# elseif d[:linetype] == :hexbin
|
||||
@@ -158,14 +158,14 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@compat const _winstonNames = Dict(
|
||||
@compat const _winstonNames = KW(
|
||||
:xlims => :xrange,
|
||||
:ylims => :yrange,
|
||||
:xscale => :xlog,
|
||||
:yscale => :ylog,
|
||||
)
|
||||
|
||||
function _update_plot(plt::Plot{WinstonPackage}, d::Dict)
|
||||
function _update_plot(plt::Plot{WinstonBackend}, d::KW)
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
for k in (:xlabel, :ylabel, :title, :xlims, :ylims)
|
||||
if haskey(d, k)
|
||||
@@ -186,11 +186,11 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonPackage}, x, y, val::@compat(AbstractString))
|
||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::@compat(AbstractString))
|
||||
Winston.text(x, y, val)
|
||||
end
|
||||
|
||||
function _add_annotations{X,Y,V}(plt::Plot{WinstonPackage}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
|
||||
for ann in anns
|
||||
createWinstonAnnotationObject(plt, ann...)
|
||||
end
|
||||
@@ -199,7 +199,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _create_subplot(subplt::Subplot{WinstonPackage}, isbefore::Bool)
|
||||
function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
|
||||
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
||||
end
|
||||
|
||||
@@ -211,14 +211,14 @@ function addWinstonLegend(plt::Plot, wplt)
|
||||
end
|
||||
end
|
||||
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{WinstonPackage})
|
||||
function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
addWinstonLegend(plt, wplt)
|
||||
writemime(io, "image/png", wplt)
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, plt::Plot{WinstonPackage})
|
||||
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
|
||||
|
||||
window, canvas, wplt = getWinstonItems(plt)
|
||||
|
||||
@@ -240,6 +240,6 @@ function Base.display(::PlotsDisplay, plt::Plot{WinstonPackage})
|
||||
end
|
||||
|
||||
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{WinstonPackage})
|
||||
function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
|
||||
# TODO: display/show the Subplot object
|
||||
end
|
||||
|
||||
@@ -52,7 +52,7 @@ const _rainbowColors = [colorant"blue", colorant"purple", colorant"green", color
|
||||
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
|
||||
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
|
||||
|
||||
@compat const _gradients = Dict(
|
||||
@compat const _gradients = KW(
|
||||
:blues => [colorant"lightblue", colorant"darkblue"],
|
||||
:reds => [colorant"lightpink", colorant"darkred"],
|
||||
:greens => [colorant"lightgreen", colorant"darkgreen"],
|
||||
@@ -72,14 +72,14 @@ const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcya
|
||||
|
||||
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
|
||||
immutable ColorGradient <: ColorScheme
|
||||
colors::Vector{Colorant}
|
||||
values::Vector{Float64}
|
||||
colors::Vector
|
||||
values::Vector
|
||||
|
||||
function ColorGradient{T<:Colorant,S<:Real}(cs::AVec{T}, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
|
||||
function ColorGradient{S<:Real}(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing)
|
||||
if length(cs) == length(vals)
|
||||
return new(convertColor(cs,alpha), collect(vals))
|
||||
end
|
||||
|
||||
|
||||
# # otherwise interpolate evenly between the minval and maxval
|
||||
# minval, maxval = minimum(vals), maximum(vals)
|
||||
# vs = Float64[interpolate(minval, maxval, w) for w in linspace(0, 1, length(cs))]
|
||||
@@ -103,9 +103,13 @@ function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...)
|
||||
ColorGradient(cs, vals; kw...)
|
||||
end
|
||||
|
||||
function ColorGradient{T<:Real}(cs::AVec{Symbol}, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
|
||||
ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
end
|
||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = linspace(0, 1, length(cs)); kw...)
|
||||
# ColorGradient(map(convertColor, cs), vals; kw...)
|
||||
# end
|
||||
|
||||
# function ColorGradient(grad::ColorGradient; alpha = nothing)
|
||||
# ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
||||
# end
|
||||
|
||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
||||
|
||||
@@ -347,10 +351,9 @@ webcolor(c, α) = webcolor(convertColor(getColor(c), α))
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
# TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function?
|
||||
# TODO: allow the setting of the algorithm, either by passing a symbol (:colordiff, :fixed, etc) or a function?
|
||||
|
||||
# function getBackgroundRGBColor(c, d::Dict)
|
||||
function handlePlotColors(::PlottingPackage, d::Dict)
|
||||
function handlePlotColors(::AbstractBackend, d::KW)
|
||||
if :background_color in supportedArgs()
|
||||
bgcolor = convertColor(d[:background_color])
|
||||
else
|
||||
@@ -365,7 +368,7 @@ function handlePlotColors(::PlottingPackage, d::Dict)
|
||||
|
||||
|
||||
# set the foreground color (text, ticks, gridlines) to be white or black depending
|
||||
# on how dark the background is.
|
||||
# on how dark the background is.
|
||||
fgcolor = get(d, :foreground_color, :auto)
|
||||
fgcolor = if fgcolor == :auto
|
||||
isdark(bgcolor) ? colorant"white" : colorant"black"
|
||||
@@ -379,7 +382,7 @@ function handlePlotColors(::PlottingPackage, d::Dict)
|
||||
end
|
||||
|
||||
# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically
|
||||
function getSeriesRGBColor(c, plotargs::Dict, n::Int)
|
||||
function getSeriesRGBColor(c, plotargs::KW, n::Int)
|
||||
|
||||
if c == :auto
|
||||
c = autopick(plotargs[:color_palette], n)
|
||||
|
||||
@@ -1,8 +1,51 @@
|
||||
|
||||
export
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
curve_points,
|
||||
directed_curve
|
||||
|
||||
typealias P2 FixedSizeArrays.Vec{2,Float64}
|
||||
typealias P3 FixedSizeArrays.Vec{3,Float64}
|
||||
|
||||
|
||||
immutable Shape
|
||||
vertices::AVec
|
||||
end
|
||||
|
||||
Shape(x, y) = Shape(collect(zip(x, y)))
|
||||
|
||||
get_xs(shape::Shape) = Float64[v[1] for v in shape.vertices]
|
||||
get_ys(shape::Shape) = Float64[v[2] for v in shape.vertices]
|
||||
|
||||
function scale(shape::Shape, x, y=x)
|
||||
sx, sy = shape_coords(shape)
|
||||
Shape(sx .* x, sy .* y)
|
||||
end
|
||||
|
||||
function translate(shape::Shape, x, y=x)
|
||||
sx, sy = shape_coords(shape)
|
||||
Shape(sx .+ x, sy .+ y)
|
||||
end
|
||||
|
||||
function shape_coords(shape::Shape)
|
||||
unzip(shape.vertices)
|
||||
end
|
||||
|
||||
function shape_coords(shapes::AVec{Shape})
|
||||
length(shapes) == 0 && return zeros(0), zeros(0)
|
||||
xs = map(get_xs, shapes)
|
||||
ys = map(get_ys, shapes)
|
||||
x, y = unzip(shapes[1].vertices)
|
||||
for shape in shapes[2:end]
|
||||
tmpx, tmpy = unzip(shape.vertices)
|
||||
x = vcat(x, NaN, tmpx)
|
||||
y = vcat(y, NaN, tmpy)
|
||||
end
|
||||
x, y
|
||||
end
|
||||
|
||||
"get an array of tuples of points on a circle with radius `r`"
|
||||
function partialcircle(start_θ, end_θ, n = 20, r=1)
|
||||
@compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)]
|
||||
@@ -48,12 +91,12 @@ function makecross(; offset = -0.5, radius = 1.0)
|
||||
z1 = z2 - π/8
|
||||
outercircle = partialcircle(z1, z1 + 2π, 9, radius)
|
||||
innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius)
|
||||
Shape(weave(outercircle, innercircle,
|
||||
Shape(weave(outercircle, innercircle,
|
||||
ordering=Vector[outercircle,innercircle,outercircle])[1:end-2])
|
||||
end
|
||||
|
||||
|
||||
const _shapes = @compat Dict(
|
||||
const _shapes = KW(
|
||||
:ellipse => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
@@ -87,7 +130,7 @@ end
|
||||
|
||||
"Create a Font from a list of unordered features"
|
||||
function font(args...)
|
||||
|
||||
|
||||
# defaults
|
||||
family = "Helvetica"
|
||||
pointsize = 14
|
||||
@@ -232,8 +275,10 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
abstract AbstractSurface
|
||||
|
||||
"represents a contour or surface mesh"
|
||||
immutable Surface{M<:AMat}
|
||||
immutable Surface{M<:AMat} <: AbstractSurface
|
||||
# x::AVec
|
||||
# y::AVec
|
||||
surf::M
|
||||
@@ -248,6 +293,12 @@ for f in (:length, :size)
|
||||
end
|
||||
Base.copy(surf::Surface) = Surface(copy(surf.surf))
|
||||
|
||||
|
||||
"For the case of representing a surface as a function of x/y... can possibly avoid allocations."
|
||||
immutable SurfaceFunction <: AbstractSurface
|
||||
f::Function
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
type OHLC{T<:Real}
|
||||
@@ -260,16 +311,6 @@ end
|
||||
|
||||
# @require FixedSizeArrays begin
|
||||
|
||||
export
|
||||
P2,
|
||||
P3,
|
||||
BezierCurve,
|
||||
curve_points,
|
||||
directed_curve
|
||||
|
||||
typealias P2 FixedSizeArrays.Vec{2,Float64}
|
||||
typealias P3 FixedSizeArrays.Vec{3,Float64}
|
||||
|
||||
type BezierCurve{T <: FixedSizeArrays.Vec}
|
||||
control_points::Vector{T}
|
||||
end
|
||||
@@ -298,7 +339,7 @@ end
|
||||
miny, maxy = minimum(yview), maximum(yview)
|
||||
diffpct = P2(diff[1] / (maxx - minx),
|
||||
diff[2] / (maxy - miny))
|
||||
|
||||
|
||||
# these points give the initial/final "rise"
|
||||
# vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0)))
|
||||
vertical_offset = P2(0, max(0.15, 0.5norm(diff)))
|
||||
@@ -319,7 +360,7 @@ end
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
|
||||
BezierCurve([p, upper_control, inside_control_points..., lower_control, q])
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# GridLayout
|
||||
# -----------------------------------------------------------
|
||||
|
||||
"Simple grid, indices are row-major."
|
||||
immutable GridLayout <: SubplotLayout
|
||||
nr::Int
|
||||
nc::Int
|
||||
end
|
||||
|
||||
Base.length(layout::GridLayout) = layout.nr * layout.nc
|
||||
Base.start(layout::GridLayout) = 1
|
||||
Base.done(layout::GridLayout, state) = state > length(layout)
|
||||
function Base.next(layout::GridLayout, state)
|
||||
r = div(state-1, layout.nc) + 1
|
||||
c = mod1(state, layout.nc)
|
||||
(r,c), state + 1
|
||||
end
|
||||
|
||||
nrows(layout::GridLayout) = layout.nr
|
||||
ncols(layout::GridLayout) = layout.nc
|
||||
ncols(layout::GridLayout, row::Int) = layout.nc
|
||||
|
||||
# get the plot index given row and column
|
||||
Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# RowsLayout
|
||||
# -----------------------------------------------------------
|
||||
|
||||
"Number of plots per row"
|
||||
immutable RowsLayout <: SubplotLayout
|
||||
numplts::Int
|
||||
rowcounts::AbstractVector{Int}
|
||||
end
|
||||
|
||||
Base.length(layout::RowsLayout) = layout.numplts
|
||||
Base.start(layout::RowsLayout) = 1
|
||||
Base.done(layout::RowsLayout, state) = state > length(layout)
|
||||
function Base.next(layout::RowsLayout, state)
|
||||
r = 1
|
||||
c = 0
|
||||
for i = 1:state
|
||||
c += 1
|
||||
if c > layout.rowcounts[r]
|
||||
r += 1
|
||||
c = 1
|
||||
end
|
||||
end
|
||||
(r,c), state + 1
|
||||
end
|
||||
|
||||
nrows(layout::RowsLayout) = length(layout.rowcounts)
|
||||
ncols(layout::RowsLayout, row::Int) = row < 1 ? 0 : (row > nrows(layout) ? 0 : layout.rowcounts[row])
|
||||
|
||||
# get the plot index given row and column
|
||||
Base.getindex(layout::RowsLayout, r::Int, c::Int) = sum(layout.rowcounts[1:r-1]) + c
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# FlexLayout
|
||||
# -----------------------------------------------------------
|
||||
|
||||
"Flexible, nested layout with optional size percentages."
|
||||
immutable FlexLayout <: SubplotLayout
|
||||
n::Int
|
||||
grid::Matrix # Nested layouts. Each position
|
||||
# can be a plot index or another FlexLayout
|
||||
widths::Vector{Float64}
|
||||
heights::Vector{Float64}
|
||||
end
|
||||
|
||||
typealias IntOrFlex Union{Int,FlexLayout}
|
||||
|
||||
Base.length(layout::FlexLayout) = layout.n
|
||||
Base.start(layout::FlexLayout) = 1
|
||||
Base.done(layout::FlexLayout, state) = state > length(layout)
|
||||
function Base.next(layout::FlexLayout, state)
|
||||
# TODO: change this method to return more info
|
||||
# TODO: might consider multiple iterator types.. some backends might have an easier time row-by-row for example
|
||||
error()
|
||||
r = 1
|
||||
c = 0
|
||||
for i = 1:state
|
||||
c += 1
|
||||
if c > layout.rowcounts[r]
|
||||
r += 1
|
||||
c = 1
|
||||
end
|
||||
end
|
||||
(r,c), state + 1
|
||||
end
|
||||
|
||||
nrows(layout::FlexLayout) = size(layout.grid, 1)
|
||||
ncols(layout::FlexLayout, row::Int) = size(layout.grid, 2)
|
||||
|
||||
# get the plot index given row and column
|
||||
Base.getindex(layout::FlexLayout, r::Int, c::Int) = layout.grid[r,c]
|
||||
|
||||
# -----------------------------------------------------------
|
||||
|
||||
# we're taking in a nested structure of some kind... parse it out and build a FlexLayout
|
||||
function subplotlayout(mat::AbstractVecOrMat; widths = nothing, heights = nothing)
|
||||
n = 0
|
||||
nr, nc = size(mat)
|
||||
grid = Array(IntOrFlex, nr, nc)
|
||||
for i=1:nr, j=1:nc
|
||||
v = mat[i,j]
|
||||
|
||||
if isa(v, Integer)
|
||||
grid[i,j] = Int(v)
|
||||
n += 1
|
||||
|
||||
elseif isa(v, Tuple)
|
||||
warn("need to handle tuples somehow... (idx, sizepct)")
|
||||
grid[i,j] = nothing
|
||||
|
||||
elseif v == nothing
|
||||
grid[i,j] = nothing
|
||||
|
||||
elseif isa(v, AbstractVecOrMat)
|
||||
grid[i,j] = layout(v)
|
||||
n += grid[i,j].n
|
||||
|
||||
else
|
||||
error("How do we process? $v")
|
||||
end
|
||||
end
|
||||
|
||||
if widths == nothing
|
||||
widths = ones(nc) ./ nc
|
||||
end
|
||||
if heights == nothing
|
||||
heights = ones(nr) ./ nr
|
||||
end
|
||||
|
||||
FlexLayout(n, grid, widths, heights)
|
||||
end
|
||||
|
||||
|
||||
function subplotlayout(sz::Tuple{Int,Int})
|
||||
GridLayout(sz...)
|
||||
end
|
||||
|
||||
function subplotlayout(rowcounts::AVec{Int})
|
||||
RowsLayout(sum(rowcounts), rowcounts)
|
||||
end
|
||||
|
||||
function subplotlayout(numplts::Int, nr::Int, nc::Int)
|
||||
|
||||
# figure out how many rows/columns we need
|
||||
if nr == -1
|
||||
if nc == -1
|
||||
nr = round(Int, sqrt(numplts))
|
||||
nc = ceil(Int, numplts / nr)
|
||||
else
|
||||
nr = ceil(Int, numplts / nc)
|
||||
end
|
||||
else
|
||||
nc = ceil(Int, numplts / nr)
|
||||
end
|
||||
|
||||
# if it's a perfect rectangle, just create a grid
|
||||
if numplts == nr * nc
|
||||
return GridLayout(nr, nc)
|
||||
end
|
||||
|
||||
# create the rowcounts vector
|
||||
i = 0
|
||||
rowcounts = Int[]
|
||||
for r in 1:nr
|
||||
cnt = min(nc, numplts - i)
|
||||
push!(rowcounts, cnt)
|
||||
i += cnt
|
||||
end
|
||||
|
||||
RowsLayout(numplts, rowcounts)
|
||||
end
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
|
||||
defaultOutputFormat(plt::PlottingObject) = "png"
|
||||
defaultOutputFormat(plt::AbstractPlot) = "png"
|
||||
|
||||
function png(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
function png(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "png")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("image/png"), plt)
|
||||
@@ -10,7 +10,7 @@ function png(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
end
|
||||
png(fn::@compat(AbstractString)) = png(current(), fn)
|
||||
|
||||
function svg(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
function svg(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "svg")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
@@ -19,7 +19,7 @@ end
|
||||
svg(fn::@compat(AbstractString)) = svg(current(), fn)
|
||||
|
||||
|
||||
function pdf(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
function pdf(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "pdf")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("application/pdf"), plt)
|
||||
@@ -28,7 +28,7 @@ end
|
||||
pdf(fn::@compat(AbstractString)) = pdf(current(), fn)
|
||||
|
||||
|
||||
function ps(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
function ps(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "ps")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("application/postscript"), plt)
|
||||
@@ -37,7 +37,7 @@ end
|
||||
ps(fn::@compat(AbstractString)) = ps(current(), fn)
|
||||
|
||||
|
||||
function tex(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
function tex(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
fn = addExtension(fn, "tex")
|
||||
io = open(fn, "w")
|
||||
writemime(io, MIME("application/x-tex"), plt)
|
||||
@@ -78,8 +78,8 @@ function addExtension(fn::@compat(AbstractString), ext::@compat(AbstractString))
|
||||
end
|
||||
end
|
||||
|
||||
function savefig(plt::PlottingObject, fn::@compat(AbstractString))
|
||||
|
||||
function savefig(plt::AbstractPlot, fn::@compat(AbstractString))
|
||||
|
||||
# get the extension
|
||||
local ext
|
||||
try
|
||||
@@ -100,20 +100,52 @@ savefig(fn::@compat(AbstractString)) = savefig(current(), fn)
|
||||
|
||||
|
||||
# savepng(args...; kw...) = savepng(current(), args...; kw...)
|
||||
# savepng(plt::PlottingObject, fn::@compat(AbstractString); kw...) = (io = open(fn, "w"); writemime(io, MIME("image/png"), plt); close(io))
|
||||
# savepng(plt::AbstractPlot, fn::@compat(AbstractString); kw...) = (io = open(fn, "w"); writemime(io, MIME("image/png"), plt); close(io))
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
gui(plt::PlottingObject = current()) = display(PlotsDisplay(), plt)
|
||||
gui(plt::AbstractPlot = current()) = display(PlotsDisplay(), plt)
|
||||
|
||||
|
||||
# override the REPL display to open a gui window
|
||||
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::PlottingObject) = gui(plt)
|
||||
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::AbstractPlot) = gui(plt)
|
||||
|
||||
# a backup for html... passes to svg
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::PlottingObject)
|
||||
function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot)
|
||||
writemime(io, MIME("image/svg+xml"), plt)
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Atom PlotPane
|
||||
# ---------------------------------------------------------
|
||||
|
||||
function setup_atom()
|
||||
# @require Atom begin
|
||||
if isatom()
|
||||
# @eval import Atom, Media
|
||||
@eval import Atom
|
||||
|
||||
# connects the render function
|
||||
for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend)
|
||||
Atom.Media.media(AbstractPlot{T}, Atom.Media.Plot)
|
||||
end
|
||||
# Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot)
|
||||
|
||||
# Atom.displaysize(::AbstractPlot) = (535, 379)
|
||||
# Atom.displaytitle(plt::AbstractPlot) = "Plots.jl (backend: $(backend(plt)))"
|
||||
|
||||
# this is like "display"... sends an html div with the plot to the PlotPane
|
||||
function Atom.Media.render(pane::Atom.PlotPane, plt::AbstractPlot)
|
||||
Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
end
|
||||
|
||||
|
||||
# function Atom.Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
|
||||
# html = Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt))))
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
|
||||
type CurrentPlot
|
||||
nullableplot::Nullable{PlottingObject}
|
||||
nullableplot::Nullable{AbstractPlot}
|
||||
end
|
||||
const CURRENT_PLOT = CurrentPlot(Nullable{PlottingObject}())
|
||||
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())
|
||||
|
||||
isplotnull() = isnull(CURRENT_PLOT.nullableplot)
|
||||
|
||||
function current()
|
||||
if isplotnull()
|
||||
error("No current plot/subplot")
|
||||
end
|
||||
get(CURRENT_PLOT.nullableplot)
|
||||
if isplotnull()
|
||||
error("No current plot/subplot")
|
||||
end
|
||||
get(CURRENT_PLOT.nullableplot)
|
||||
end
|
||||
current(plot::PlottingObject) = (CURRENT_PLOT.nullableplot = Nullable(plot))
|
||||
current(plot::AbstractPlot) = (CURRENT_PLOT.nullableplot = Nullable(plot))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -32,9 +32,9 @@ convertSeriesIndex(plt::Plot, n::Int) = n
|
||||
The main plot command. Use `plot` to create a new plot object, and `plot!` to add to an existing one:
|
||||
|
||||
```
|
||||
plot(args...; kw...) # creates a new plot window, and sets it to be the current
|
||||
plot!(args...; kw...) # adds to the `current`
|
||||
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
|
||||
plot(args...; kw...) # creates a new plot window, and sets it to be the current
|
||||
plot!(args...; kw...) # adds to the `current`
|
||||
plot!(plotobj, args...; kw...) # adds to the plot `plotobj`
|
||||
```
|
||||
|
||||
There are lots of ways to pass in data, and lots of keyword arguments... just try it and it will likely work as expected.
|
||||
@@ -43,127 +43,207 @@ When you pass in matrices, it splits by columns. See the documentation for more
|
||||
|
||||
# this creates a new plot with args/kw and sets it to be the current plot
|
||||
function plot(args...; kw...)
|
||||
pkg = backend()
|
||||
d = Dict(kw)
|
||||
preprocessArgs!(d)
|
||||
dumpdict(d, "After plot preprocessing")
|
||||
pkg = backend()
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
dumpdict(d, "After plot preprocessing")
|
||||
|
||||
plotargs = merge(d, getPlotArgs(pkg, d, 1))
|
||||
dumpdict(plotargs, "Plot args")
|
||||
plt = _create_plot(pkg; plotargs...) # create a new, blank plot
|
||||
plotargs = merge(d, getPlotArgs(pkg, d, 1))
|
||||
dumpdict(plotargs, "Plot args")
|
||||
plt = _create_plot(pkg; plotargs...) # create a new, blank plot
|
||||
|
||||
delete!(d, :background_color)
|
||||
plot!(plt, args...; d...) # add to it
|
||||
delete!(d, :background_color)
|
||||
plot!(plt, args...; d...) # add to it
|
||||
end
|
||||
|
||||
|
||||
|
||||
# this adds to the current plot, or creates a new plot if none are current
|
||||
function plot!(args...; kw...)
|
||||
local plt
|
||||
try
|
||||
plt = current()
|
||||
catch
|
||||
return plot(args...; kw...)
|
||||
end
|
||||
plot!(current(), args...; kw...)
|
||||
end
|
||||
|
||||
# not allowed:
|
||||
function plot!(subplt::Subplot, args...; kw...)
|
||||
error("Can't call plot! on a Subplot!")
|
||||
local plt
|
||||
try
|
||||
plt = current()
|
||||
catch
|
||||
return plot(args...; kw...)
|
||||
end
|
||||
plot!(current(), args...; kw...)
|
||||
end
|
||||
|
||||
# this adds to a specific plot... most plot commands will flow through here
|
||||
function plot!(plt::Plot, args...; kw...)
|
||||
d = Dict(kw)
|
||||
preprocessArgs!(d)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
args = _apply_recipe(d, args...; kw...)
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
args = _apply_recipe(d, args...; kw...)
|
||||
|
||||
dumpdict(d, "After plot! preprocessing")
|
||||
dumpdict(d, "After plot! preprocessing")
|
||||
# @show groupargs map(typeof, args)
|
||||
|
||||
warnOnUnsupportedArgs(plt.backend, d)
|
||||
warnOnUnsupportedArgs(plt.backend, d)
|
||||
|
||||
# grouping
|
||||
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)
|
||||
_before_add_series(plt)
|
||||
|
||||
# just in case the backend needs to set up the plot (make it current or something)
|
||||
_before_add_series(plt)
|
||||
# # grouping
|
||||
# groupargs = get(d, :group, nothing) == nothing ? [nothing] : [extractGroupArgs(d[:group], args...)]
|
||||
# # @show groupargs
|
||||
|
||||
# get the list of dictionaries, one per series
|
||||
seriesArgList, xmeta, ymeta = createKWargsList(plt, groupargs..., args...; d...)
|
||||
# TODO: get the GroupBy object (or nothing), and loop through the groups, doing the following section many times
|
||||
# dumpdict(d, "before", true)
|
||||
groupby = if haskey(d, :group)
|
||||
extractGroupArgs(d[:group], args...)
|
||||
else
|
||||
nothing
|
||||
end
|
||||
# dumpdict(d, "after", true)
|
||||
# @show groupby map(typeof, args)
|
||||
|
||||
# if we were able to extract guide information from the series inputs, then update the plot
|
||||
# @show xmeta, ymeta
|
||||
updateDictWithMeta(d, plt.plotargs, xmeta, true)
|
||||
updateDictWithMeta(d, plt.plotargs, ymeta, false)
|
||||
_add_series(plt, d, groupby, args...)
|
||||
|
||||
# now we can plot the series
|
||||
for (i,di) in enumerate(seriesArgList)
|
||||
plt.n += 1
|
||||
#
|
||||
# # get the list of dictionaries, one per series
|
||||
# @show groupargs map(typeof, args)
|
||||
# dumpdict(d, "before process_inputs")
|
||||
# process_inputs(plt, d, groupargs..., args...)
|
||||
# dumpdict(d, "after process_inputs", true)
|
||||
# seriesArgList, xmeta, ymeta = build_series_args(plt, d)
|
||||
# # seriesArgList, xmeta, ymeta = build_series_args(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.plotargs, xmeta, true)
|
||||
# updateDictWithMeta(d, plt.plotargs, ymeta, false)
|
||||
#
|
||||
# # now we can plot the series
|
||||
# for (i,di) in enumerate(seriesArgList)
|
||||
# plt.n += 1
|
||||
#
|
||||
# if !stringsSupported()
|
||||
# setTicksFromStringVector(d, di, :x, :xticks)
|
||||
# setTicksFromStringVector(d, di, :y, :yticks)
|
||||
# end
|
||||
#
|
||||
# # remove plot args
|
||||
# for k in keys(_plotDefaults)
|
||||
# delete!(di, k)
|
||||
# end
|
||||
#
|
||||
# dumpdict(di, "Series $i")
|
||||
#
|
||||
# _add_series(plt.backend, plt; di...)
|
||||
# end
|
||||
|
||||
if !stringsSupported()
|
||||
setTicksFromStringVector(d, di, :x, :xticks)
|
||||
setTicksFromStringVector(d, di, :y, :yticks)
|
||||
_add_annotations(plt, d)
|
||||
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.plotargs, d)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
|
||||
# remove plot args
|
||||
for k in keys(_plotDefaults)
|
||||
delete!(di, k)
|
||||
_update_plot_pos_size(plt, d)
|
||||
|
||||
current(plt)
|
||||
|
||||
# NOTE: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
# # do we want to show it?
|
||||
if haskey(d, :show) && d[:show]
|
||||
gui()
|
||||
end
|
||||
|
||||
dumpdict(di, "Series $i")
|
||||
plt
|
||||
end
|
||||
|
||||
_add_series(plt.backend, plt; di...)
|
||||
end
|
||||
# handle the grouping
|
||||
function _add_series(plt::Plot, d::KW, groupby::GroupBy, args...)
|
||||
starting_n = plt.n
|
||||
for (i, glab) in enumerate(groupby.groupLabels)
|
||||
tmpd = copy(d)
|
||||
tmpd[:numUncounted] = plt.n - starting_n
|
||||
_add_series(plt, tmpd, nothing, args...;
|
||||
idxfilter = groupby.groupIds[i],
|
||||
grouplabel = string(glab))
|
||||
end
|
||||
end
|
||||
|
||||
_add_annotations(plt, d)
|
||||
filter_data(v::AVec, idxfilter::AVec{Int}) = v[idxfilter]
|
||||
filter_data(v, idxfilter) = v
|
||||
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
function filter_data!(d::KW, idxfilter)
|
||||
for s in (:x, :y, :z)
|
||||
d[s] = filter_data(get(d, s, nothing), idxfilter)
|
||||
end
|
||||
end
|
||||
|
||||
# no grouping
|
||||
function _add_series(plt::Plot, d::KW, ::Void, args...;
|
||||
idxfilter = nothing,
|
||||
grouplabel = "")
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.plotargs, d)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
# get the list of dictionaries, one per series
|
||||
dumpdict(d, "before process_inputs")
|
||||
process_inputs(plt, d, args...)
|
||||
dumpdict(d, "after process_inputs")
|
||||
|
||||
_update_plot_pos_size(plt, d)
|
||||
if idxfilter != nothing
|
||||
# add the group name as the label if there isn't one passed in
|
||||
get!(d, :label, grouplabel)
|
||||
# filter the data
|
||||
filter_data!(d, idxfilter)
|
||||
end
|
||||
|
||||
current(plt)
|
||||
seriesArgList, xmeta, ymeta = build_series_args(plt, d) #, idxfilter)
|
||||
# seriesArgList, xmeta, ymeta = build_series_args(plt, groupargs..., args...; d...)
|
||||
|
||||
# NOTE: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
# # do we want to show it?
|
||||
if haskey(d, :show) && d[:show]
|
||||
gui()
|
||||
end
|
||||
# if we were able to extract guide information from the series inputs, then update the plot
|
||||
# @show xmeta, ymeta
|
||||
updateDictWithMeta(d, plt.plotargs, xmeta, true)
|
||||
updateDictWithMeta(d, plt.plotargs, ymeta, false)
|
||||
|
||||
plt
|
||||
# now we can plot the series
|
||||
for (i,di) in enumerate(seriesArgList)
|
||||
plt.n += 1
|
||||
|
||||
if !stringsSupported()
|
||||
setTicksFromStringVector(d, di, :x, :xticks)
|
||||
setTicksFromStringVector(d, di, :y, :yticks)
|
||||
end
|
||||
|
||||
# remove plot args
|
||||
for k in keys(_plotDefaults)
|
||||
delete!(di, k)
|
||||
end
|
||||
|
||||
dumpdict(di, "Series $i")
|
||||
|
||||
_add_series(plt.backend, plt; di...)
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# if x or y are a vector of strings, we should create a list of unique strings,
|
||||
# and map x/y to be the index of the string... then set the x/y tick labels
|
||||
function setTicksFromStringVector(d::Dict, di::Dict, sym::Symbol, ticksym::Symbol)
|
||||
# if the x or y values are strings, set ticks to the unique values, and x/y to the indices of the ticks
|
||||
function setTicksFromStringVector(d::KW, di::KW, sym::Symbol, ticksym::Symbol)
|
||||
# if the x or y values are strings, set ticks to the unique values, and x/y to the indices of the ticks
|
||||
|
||||
v = di[sym]
|
||||
isa(v, AbstractArray) || return
|
||||
v = di[sym]
|
||||
isa(v, AbstractArray) || return
|
||||
|
||||
T = eltype(v)
|
||||
if T <: @compat(AbstractString) || (!isempty(T.types) && all(x -> x <: @compat(AbstractString), T.types))
|
||||
T = eltype(v)
|
||||
if T <: @compat(AbstractString) || (!isempty(T.types) && all(x -> x <: @compat(AbstractString), T.types))
|
||||
ticks = unique(di[sym])
|
||||
di[sym] = Int[findnext(ticks, v, 1) for v in di[sym]]
|
||||
|
||||
ticks = unique(di[sym])
|
||||
di[sym] = Int[findnext(ticks, v, 1) for v in di[sym]]
|
||||
|
||||
if !haskey(d, ticksym) || d[ticksym] == :auto
|
||||
d[ticksym] = (collect(1:length(ticks)), UTF8String[t for t in ticks])
|
||||
if !haskey(d, ticksym) || d[ticksym] == :auto
|
||||
d[ticksym] = (collect(1:length(ticks)), UTF8String[t for t in ticks])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
@@ -173,13 +253,13 @@ _before_add_series(plt::Plot) = nothing
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# should we update the x/y label given the meta info during input slicing?
|
||||
function updateDictWithMeta(d::Dict, plotargs::Dict, meta::Symbol, isx::Bool)
|
||||
lsym = isx ? :xlabel : :ylabel
|
||||
if plotargs[lsym] == default(lsym)
|
||||
d[lsym] = string(meta)
|
||||
end
|
||||
function updateDictWithMeta(d::KW, plotargs::KW, meta::Symbol, isx::Bool)
|
||||
lsym = isx ? :xlabel : :ylabel
|
||||
if plotargs[lsym] == default(lsym)
|
||||
d[lsym] = string(meta)
|
||||
end
|
||||
end
|
||||
updateDictWithMeta(d::Dict, plotargs::Dict, meta, isx::Bool) = nothing
|
||||
updateDictWithMeta(d::KW, plotargs::KW, meta, isx::Bool) = nothing
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@@ -191,384 +271,31 @@ annotations(v::AVec) = map(PlotText, v)
|
||||
annotations(anns) = error("Expecting a tuple (or vector of tuples) for annotations: ",
|
||||
"(x, y, annotation)\n got: $(typeof(anns))")
|
||||
|
||||
function _add_annotations(plt::Plot, d::Dict)
|
||||
anns = annotations(get(d, :annotation, nothing))
|
||||
if !isempty(anns)
|
||||
function _add_annotations(plt::Plot, d::KW)
|
||||
anns = annotations(get(d, :annotation, nothing))
|
||||
if !isempty(anns)
|
||||
|
||||
# if we just have a list of PlotText objects, then create (x,y,text) tuples
|
||||
if typeof(anns) <: AVec{PlotText}
|
||||
x, y = plt[plt.n]
|
||||
anns = Tuple{Float64,Float64,PlotText}[(x[i], y[i], t) for (i,t) in enumerate(anns)]
|
||||
# if we just have a list of PlotText objects, then create (x,y,text) tuples
|
||||
if typeof(anns) <: AVec{PlotText}
|
||||
x, y = plt[plt.n]
|
||||
anns = Tuple{Float64,Float64,PlotText}[(x[i], y[i], t) for (i,t) in enumerate(anns)]
|
||||
end
|
||||
|
||||
_add_annotations(plt, anns)
|
||||
end
|
||||
|
||||
_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
|
||||
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
|
||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
|
||||
|
||||
all3D(d::Dict) = trueOrAllTrue(lt -> lt in (:contour, :surface, :wireframe, :image), get(d, :linetype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::@compat(Void), d::Dict) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, d::Dict) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector{T<:Real}(v::AVec{T}, d::Dict) = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::Dict) = Any[v], nothing
|
||||
|
||||
# numeric matrix
|
||||
function convertToAnyVector{T<:Real}(v::AMat{T}, d::Dict)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, d::Dict) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::Dict) = Any[s], nothing
|
||||
|
||||
# vector of OHLC
|
||||
convertToAnyVector(v::AVec{OHLC}, d::Dict) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::Dict) = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, d::Dict)
|
||||
if all(x -> typeof(x) <: Real, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# in computeXandY, we take in any of the possible items, convert into proper x/y vectors, then return.
|
||||
# this is also where all the "set x to 1:length(y)" happens, and also where we assert on lengths.
|
||||
computeX(x::@compat(Void), y) = 1:size(y,1)
|
||||
computeX(x, y) = copy(x)
|
||||
computeY(x, y::Function) = map(y, x)
|
||||
computeY(x, y) = copy(y)
|
||||
function computeXandY(x, y)
|
||||
if x == nothing && isa(y, Function)
|
||||
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)
|
||||
x, y
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# create n=max(mx,my) series arguments. the shorter list is cycled through
|
||||
# note: everything should flow through this
|
||||
function createKWargsList(plt::PlottingObject, x, y; kw...)
|
||||
kwdict = Dict(kw)
|
||||
xs, xmeta = convertToAnyVector(x, kwdict)
|
||||
ys, ymeta = convertToAnyVector(y, kwdict)
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
ret = Any[]
|
||||
for i in 1:max(mx, my)
|
||||
|
||||
# try to set labels using ymeta
|
||||
d = copy(kwdict)
|
||||
if !haskey(d, :label) && ymeta != nothing
|
||||
if isa(ymeta, Symbol)
|
||||
d[:label] = string(ymeta)
|
||||
elseif isa(ymeta, AVec{Symbol})
|
||||
d[:label] = string(ymeta[mod1(i,length(ymeta))])
|
||||
end
|
||||
end
|
||||
|
||||
# build the series arg dict
|
||||
numUncounted = get(d, :numUncounted, 0)
|
||||
n = plt.n + i + numUncounted
|
||||
dumpdict(d, "before getSeriesArgs")
|
||||
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
|
||||
dumpdict(d, "after getSeriesArgs")
|
||||
d[:x], d[:y] = computeXandY(xs[mod1(i,mx)], ys[mod1(i,my)])
|
||||
|
||||
lt = d[:linetype]
|
||||
if isa(d[:y], Surface)
|
||||
if lt in (:contour, :surface, :wireframe, :image)
|
||||
z = d[:y]
|
||||
d[:y] = 1:size(z,2)
|
||||
d[lt == :image ? :zcolor : :z] = z
|
||||
end
|
||||
end
|
||||
|
||||
if haskey(d, :idxfilter)
|
||||
d[:x] = d[:x][d[:idxfilter]]
|
||||
d[:y] = d[:y][d[:idxfilter]]
|
||||
end
|
||||
|
||||
# for linetype `line`, need to sort by x values
|
||||
if lt == :line
|
||||
# order by x
|
||||
indices = sortperm(d[:x])
|
||||
d[:x] = d[:x][indices]
|
||||
d[:y] = d[:y][indices]
|
||||
d[:linetype] = :path
|
||||
end
|
||||
|
||||
# map functions to vectors
|
||||
if isa(d[:zcolor], Function)
|
||||
d[:zcolor] = map(d[:zcolor], d[:x])
|
||||
end
|
||||
if isa(d[:fillrange], Function)
|
||||
d[:fillrange] = map(d[:fillrange], d[:x])
|
||||
end
|
||||
|
||||
# cleanup those fields that were used only for generating kw args
|
||||
for k in (:idxfilter, :numUncounted, :dataframe)
|
||||
delete!(d, k)
|
||||
end
|
||||
|
||||
# add it to our series list
|
||||
push!(ret, d)
|
||||
end
|
||||
|
||||
ret, xmeta, ymeta
|
||||
end
|
||||
|
||||
# handle grouping
|
||||
function createKWargsList(plt::PlottingObject, groupby::GroupBy, args...; kw...)
|
||||
ret = Any[]
|
||||
for (i,glab) in enumerate(groupby.groupLabels)
|
||||
# TODO: don't automatically overwrite labels
|
||||
kwlist, xmeta, ymeta = createKWargsList(plt, args...; kw...,
|
||||
idxfilter = groupby.groupIds[i],
|
||||
label = string(glab),
|
||||
numUncounted = length(ret)) # we count the idx from plt.n + numUncounted + i
|
||||
append!(ret, kwlist)
|
||||
end
|
||||
ret, nothing, nothing # TODO: handle passing meta through
|
||||
end
|
||||
|
||||
# pass it off to the x/y version
|
||||
function createKWargsList(plt::PlottingObject, y; kw...)
|
||||
createKWargsList(plt, nothing, y; kw...)
|
||||
end
|
||||
|
||||
# 3d line or scatter
|
||||
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, zvec::AVec; kw...)
|
||||
d = Dict(kw)
|
||||
if !(get(d, :linetype, :none) in _3dTypes)
|
||||
d[:linetype] = :path3d
|
||||
end
|
||||
createKWargsList(plt, x, y; z=zvec, d...)
|
||||
end
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, z::AMat{T}; kw...)
|
||||
d = Dict(kw)
|
||||
if all3D(d)
|
||||
n,m = size(z)
|
||||
createKWargsList(plt, 1:n, 1:m, z; kw...)
|
||||
else
|
||||
createKWargsList(plt, nothing, z; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
# contours or surfaces... function grid
|
||||
function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, zf::Function; kw...)
|
||||
# only allow sorted x/y for now
|
||||
# TODO: auto sort x/y/z properly
|
||||
@assert x == sort(x)
|
||||
@assert y == sort(y)
|
||||
surface = Float64[zf(xi, yi) for xi in x, yi in y]
|
||||
createKWargsList(plt, x, y, surface; kw...) # passes it to the zmat version
|
||||
end
|
||||
|
||||
# contours or surfaces... matrix grid
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec, y::AVec, zmat::AMat{T}; kw...)
|
||||
# only allow sorted x/y for now
|
||||
# TODO: auto sort x/y/z properly
|
||||
@assert x == sort(x)
|
||||
@assert y == sort(y)
|
||||
@assert size(zmat) == (length(x), length(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, 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...)
|
||||
createKWargsList(plt, f, xmin(plt), xmax(plt); kw...)
|
||||
end
|
||||
|
||||
# list of functions
|
||||
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs, x; kw...)
|
||||
@assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
|
||||
createKWargsList(plt, x, f; kw...)
|
||||
end
|
||||
|
||||
# special handling... xmin/xmax with function(s)
|
||||
function createKWargsList(plt::PlottingObject, f::FuncOrFuncs, xmin::Real, xmax::Real; kw...)
|
||||
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
|
||||
|
||||
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
|
||||
mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs]
|
||||
|
||||
# special handling... xmin/xmax with parametric function(s)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec{T}; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...)
|
||||
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, linspace(umin, umax, numPoints); kw...)
|
||||
|
||||
# special handling... 3D parametric function(s)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
|
||||
createKWargsList{T<:Real}(plt::PlottingObject, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs; kw...) = createKWargsList(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u); kw...)
|
||||
createKWargsList(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000; kw...) = createKWargsList(plt, fx, fy, fz, linspace(umin, umax, numPoints); kw...)
|
||||
|
||||
# (x,y) tuples
|
||||
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::AVec{Tuple{R1,R2}}; kw...)
|
||||
createKWargsList(plt, unzip(xy)...; kw...)
|
||||
end
|
||||
function createKWargsList{R1<:Real,R2<:Real}(plt::PlottingObject, xy::Tuple{R1,R2}; kw...)
|
||||
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# special handling... no args... 1 series
|
||||
function createKWargsList(plt::PlottingObject; kw...)
|
||||
d = Dict(kw)
|
||||
if !haskey(d, :y)
|
||||
# assume we just want to create an empty plot object which can be added to later
|
||||
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
|
||||
return createKWargsList(plt, d[:y]; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
# @require FixedSizeArrays begin
|
||||
|
||||
unzip{T}(x::AVec{FixedSizeArrays.Vec{2,T}}) = T[xi[1] for xi in x], T[xi[2] for xi in x]
|
||||
unzip{T}(x::FixedSizeArrays.Vec{2,T}) = T[x[1]], T[x[2]]
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, xy::AVec{FixedSizeArrays.Vec{2,T}}; kw...)
|
||||
createKWargsList(plt, unzip(xy)...; kw...)
|
||||
end
|
||||
|
||||
function createKWargsList{T<:Real}(plt::PlottingObject, xy::FixedSizeArrays.Vec{2,T}; kw...)
|
||||
createKWargsList(plt, [xy[1]], [xy[2]]; kw...)
|
||||
end
|
||||
|
||||
# end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
|
||||
|
||||
@require DataFrames begin
|
||||
|
||||
function createKWargsList(plt::PlottingObject, df::DataFrames.AbstractDataFrame, args...; kw...)
|
||||
createKWargsList(plt, args...; kw..., dataframe = df)
|
||||
end
|
||||
|
||||
# expecting the column name of a dataframe that was passed in... anything else should error
|
||||
function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
||||
if haskey(df, s)
|
||||
return extractGroupArgs(df[s])
|
||||
else
|
||||
error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
|
||||
end
|
||||
end
|
||||
|
||||
function getDataFrameFromKW(d::Dict)
|
||||
# for (k,v) in kw
|
||||
# if k == :dataframe
|
||||
# return v
|
||||
# end
|
||||
# end
|
||||
get(d, :dataframe) do
|
||||
error("Missing dataframe argument!")
|
||||
end
|
||||
end
|
||||
|
||||
# the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
||||
# convertToAnyVector(s::Symbol; kw...) = Any[getDataFrameFromKW(;kw...)[s]], s
|
||||
# convertToAnyVector(v::AVec{Symbol}; kw...) = (df = getDataFrameFromKW(;kw...); Any[df[s] for s in v]), v
|
||||
convertToAnyVector(s::Symbol, d::Dict) = Any[getDataFrameFromKW(d)[s]], s
|
||||
convertToAnyVector(v::AVec{Symbol}, d::Dict) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
# TODO: there should be a distinction between an object that will manage a full plot, vs a component of a plot.
|
||||
# the PlotRecipe as currently implemented is more of a "custom component"
|
||||
# a recipe should fully describe the plotting command(s) and call them, likewise for updating.
|
||||
# actually... maybe those should explicitly derive from PlottingObject???
|
||||
# a recipe should fully describe the plotting command(s) and call them, likewise for updating.
|
||||
# actually... maybe those should explicitly derive from AbstractPlot???
|
||||
|
||||
abstract PlotRecipe
|
||||
|
||||
@@ -17,10 +17,10 @@ plot!(plt::Plot, recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe)
|
||||
num_series(x::AMat) = size(x,2)
|
||||
num_series(x) = 1
|
||||
|
||||
_apply_recipe(d::Dict; kw...) = ()
|
||||
_apply_recipe(d::KW; kw...) = ()
|
||||
|
||||
# if it's not a recipe, just do nothing and return the args
|
||||
function _apply_recipe(d::Dict, args...; issubplot=false, kw...)
|
||||
function _apply_recipe(d::KW, args...; issubplot=false, kw...)
|
||||
if issubplot && !haskey(d, :n) && !haskey(d, :layout)
|
||||
# put in a sensible default
|
||||
d[:n] = maximum(map(num_series, args))
|
||||
@@ -28,106 +28,59 @@ function _apply_recipe(d::Dict, args...; issubplot=false, kw...)
|
||||
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
|
||||
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
|
||||
|
||||
# # -------------------------------------------------
|
||||
|
||||
# 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...)
|
||||
I,J,V = findnz(y)
|
||||
heatmap(J, I; leg=false, yflip=true, nbins=size(y), kw...)
|
||||
function spy{T<:Real}(z::AMat{T}; kw...)
|
||||
# I,J,V = findnz(z)
|
||||
# heatmap(J, I; leg=false, yflip=true, kw...)
|
||||
heatmap(map(zi->float(zi!=0), z); leg=false, yflip=true, kw...)
|
||||
end
|
||||
|
||||
"Adds a+bx... straight line over the current plot"
|
||||
@@ -135,4 +88,190 @@ function abline!(plt::Plot, a, b; kw...)
|
||||
plot!(plt, [extrema(plt)...], x -> b + a*x; kw...)
|
||||
end
|
||||
|
||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
|
||||
# =================================================
|
||||
# Arc and chord diagrams
|
||||
|
||||
"Takes an adjacency matrix and returns source, destiny and weight lists"
|
||||
function mat2list{T}(mat::AbstractArray{T,2})
|
||||
nrow, ncol = size(mat) # rows are sources and columns are destinies
|
||||
|
||||
nosymmetric = !issym(mat) # plots only triu for symmetric matrices
|
||||
nosparse = !issparse(mat) # doesn't plot zeros from a sparse matrix
|
||||
|
||||
L = length(mat)
|
||||
|
||||
source = Array(Int, L)
|
||||
destiny = Array(Int, L)
|
||||
weight = Array(T, L)
|
||||
|
||||
idx = 1
|
||||
for i in 1:nrow, j in 1:ncol
|
||||
value = mat[i, j]
|
||||
if !isnan(value) && ( nosparse || value != zero(T) ) # TODO: deal with Nullable
|
||||
|
||||
if i < j
|
||||
source[idx] = i
|
||||
destiny[idx] = j
|
||||
weight[idx] = value
|
||||
idx += 1
|
||||
elseif nosymmetric && (i > j)
|
||||
source[idx] = i
|
||||
destiny[idx] = j
|
||||
weight[idx] = value
|
||||
idx += 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
resize!(source, idx-1), resize!(destiny, idx-1), resize!(weight, idx-1)
|
||||
end
|
||||
|
||||
# -------------------------------------------------
|
||||
# Arc Diagram
|
||||
|
||||
curvecolor(value, min, max, grad) = getColorZ(grad, (value-min)/(max-min))
|
||||
|
||||
"Plots a clockwise arc, from source to destiny, colored by weight"
|
||||
function arc!(source, destiny, weight, min, max, grad)
|
||||
radius = (destiny - source) / 2
|
||||
arc = Plots.partialcircle(0, π, 30, radius)
|
||||
x, y = Plots.unzip(arc)
|
||||
plot!(x .+ radius .+ source, y, line = (curvecolor(weight, min, max, grad), 0.5, 2), legend=false)
|
||||
end
|
||||
|
||||
"""
|
||||
`arcdiagram(source, destiny, weight[, grad])`
|
||||
|
||||
Plots an arc diagram, form `source` to `destiny` (clockwise), using `weight` to determine the colors.
|
||||
"""
|
||||
function arcdiagram(source, destiny, weight; kargs...)
|
||||
|
||||
args = KW(kargs)
|
||||
grad = pop!(args, :grad, ColorGradient([colorant"darkred", colorant"darkblue"]))
|
||||
|
||||
if length(source) == length(destiny) == length(weight)
|
||||
|
||||
vertices = unique(vcat(source, destiny))
|
||||
sort!(vertices)
|
||||
|
||||
xmin, xmax = extrema(vertices)
|
||||
plot(xlim=(xmin - 0.5, xmax + 0.5), legend=false)
|
||||
|
||||
wmin,wmax = extrema(weight)
|
||||
|
||||
for (i, j, value) in zip(source,destiny,weight)
|
||||
arc!(i, j, value, wmin, wmax, grad)
|
||||
end
|
||||
|
||||
scatter!(vertices, zeros(length(vertices)); legend=false, args...)
|
||||
|
||||
else
|
||||
|
||||
throw(ArgumentError("source, destiny and weight should have the same length"))
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
`arcdiagram(mat[, grad])`
|
||||
|
||||
Plots an arc diagram from an adjacency matrix, form rows to columns (clockwise),
|
||||
using the values on the matrix as weights to determine the colors.
|
||||
Doesn't show edges with value zero if the input is sparse.
|
||||
For simmetric matrices, only the upper triangular values are used.
|
||||
"""
|
||||
arcdiagram{T}(mat::AbstractArray{T,2}; kargs...) = arcdiagram(mat2list(mat)...; kargs...)
|
||||
|
||||
# -------------------------------------------------
|
||||
# Chord diagram
|
||||
|
||||
arcshape(θ1, θ2) = Shape(vcat(Plots.partialcircle(θ1, θ2, 15, 1.1),
|
||||
reverse(Plots.partialcircle(θ1, θ2, 15, 0.9))))
|
||||
|
||||
colorlist(grad, ::Void) = :darkgray
|
||||
|
||||
function colorlist(grad, z)
|
||||
zmin, zmax = extrema(z)
|
||||
RGBA{Float64}[getColorZ(grad, (zi-zmin)/(zmax-zmin)) for zi in z]'
|
||||
end
|
||||
|
||||
"""
|
||||
`chorddiagram(source, destiny, weight[, grad, zcolor, group])`
|
||||
|
||||
Plots a chord diagram, form `source` to `destiny`,
|
||||
using `weight` to determine the edge colors using `grad`.
|
||||
`zcolor` or `group` can be used to determine the node colors.
|
||||
"""
|
||||
function chorddiagram(source, destiny, weight; kargs...)
|
||||
|
||||
args = KW(kargs)
|
||||
grad = pop!(args, :grad, ColorGradient([colorant"darkred", colorant"darkblue"]))
|
||||
zcolor= pop!(args, :zcolor, nothing)
|
||||
group = pop!(args, :group, nothing)
|
||||
|
||||
if zcolor !== nothing && group !== nothing
|
||||
throw(ErrorException("group and zcolor can not be used together."))
|
||||
end
|
||||
|
||||
if length(source) == length(destiny) == length(weight)
|
||||
|
||||
plt = plot(xlim=(-2,2), ylim=(-2,2), legend=false, grid=false,
|
||||
xticks=nothing, yticks=nothing,
|
||||
xlim=(-1.2,1.2), ylim=(-1.2,1.2))
|
||||
|
||||
nodemin, nodemax = extrema(vcat(source, destiny))
|
||||
|
||||
weightmin, weightmax = extrema(weight)
|
||||
|
||||
A = 1.5π # Filled space
|
||||
B = 0.5π # White space (empirical)
|
||||
|
||||
Δα = A / nodemax
|
||||
Δβ = B / nodemax
|
||||
|
||||
δ = Δα + Δβ
|
||||
|
||||
for i in 1:length(source)
|
||||
curve = BezierCurve(P2[ (cos((source[i ]-1)*δ + 0.5Δα), sin((source[i ]-1)*δ + 0.5Δα)), (0,0),
|
||||
(cos((destiny[i]-1)*δ + 0.5Δα), sin((destiny[i]-1)*δ + 0.5Δα)) ])
|
||||
plot!(curve_points(curve), line = (Plots.curvecolor(weight[i], weightmin, weightmax, grad), 1, 1))
|
||||
end
|
||||
|
||||
if group === nothing
|
||||
c = colorlist(grad, zcolor)
|
||||
elseif length(group) == nodemax
|
||||
|
||||
idx = collect(0:(nodemax-1))
|
||||
|
||||
for g in group
|
||||
plot!([arcshape(n*δ, n*δ + Δα) for n in idx[group .== g]]; args...)
|
||||
end
|
||||
|
||||
return plt
|
||||
|
||||
else
|
||||
throw(ErrorException("group should the ", nodemax, " elements."))
|
||||
end
|
||||
|
||||
plot!([arcshape(n*δ, n*δ + Δα) for n in 0:(nodemax-1)]; mc=c, args...)
|
||||
|
||||
return plt
|
||||
|
||||
else
|
||||
throw(ArgumentError("source, destiny and weight should have the same length"))
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
`chorddiagram(mat[, grad, zcolor, group])`
|
||||
|
||||
Plots a chord diagram from an adjacency matrix,
|
||||
using the values on the matrix as weights to determine edge colors.
|
||||
Doesn't show edges with value zero if the input is sparse.
|
||||
For simmetric matrices, only the upper triangular values are used.
|
||||
`zcolor` or `group` can be used to determine the node colors.
|
||||
"""
|
||||
chorddiagram(mat::AbstractMatrix; kargs...) = chorddiagram(mat2list(mat)...; kargs...)
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
|
||||
# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems].
|
||||
# Special handling for: no args, xmin/xmax, parametric, dataframes
|
||||
# Then once inputs have been converted, build the series args, map functions, etc.
|
||||
# This should cut down on boilerplate code and allow more focused dispatch on type
|
||||
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now
|
||||
|
||||
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
|
||||
|
||||
all3D(d::KW) = trueOrAllTrue(lt -> lt in (:contour, :heatmap, :surface, :wireframe), get(d, :linetype, :none))
|
||||
|
||||
# missing
|
||||
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing
|
||||
|
||||
# fixed number of blank series
|
||||
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
|
||||
|
||||
# numeric vector
|
||||
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing
|
||||
|
||||
# string vector
|
||||
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing
|
||||
|
||||
# numeric matrix
|
||||
function convertToAnyVector{T<:Number}(v::AMat{T}, d::KW)
|
||||
if all3D(d)
|
||||
Any[Surface(v)]
|
||||
else
|
||||
Any[v[:,i] for i in 1:size(v,2)]
|
||||
end, nothing
|
||||
end
|
||||
|
||||
# function
|
||||
convertToAnyVector(f::Function, d::KW) = Any[f], nothing
|
||||
|
||||
# surface
|
||||
convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
|
||||
|
||||
# vector of OHLC
|
||||
convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
|
||||
|
||||
# dates
|
||||
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing
|
||||
|
||||
# list of things (maybe other vectors, functions, or something else)
|
||||
function convertToAnyVector(v::AVec, d::KW)
|
||||
if all(x -> typeof(x) <: Number, v)
|
||||
# all real numbers wrap the whole vector as one item
|
||||
Any[convert(Vector{Float64}, v)], nothing
|
||||
else
|
||||
# something else... treat each element as an item
|
||||
vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing
|
||||
# Any[vi for vi in v], nothing
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array
|
||||
# result in that array being shared. push!, etc will add too many items to that array
|
||||
|
||||
compute_x(x::Void, y::Void, z) = 1:size(z,1)
|
||||
compute_x(x::Void, y, z) = 1:size(y,1)
|
||||
compute_x(x::Function, y, z) = map(x, y)
|
||||
compute_x(x, y, z) = copy(x)
|
||||
|
||||
# compute_y(x::Void, y::Function, z) = error()
|
||||
compute_y(x::Void, y::Void, z) = 1:size(z,2)
|
||||
compute_y(x, y::Function, z) = map(y, x)
|
||||
compute_y(x, y, z) = copy(y)
|
||||
|
||||
compute_z(x, y, z::Function) = map(z, x, y)
|
||||
compute_z(x, y, z::AbstractMatrix) = Surface(z)
|
||||
compute_z(x, y, z::Void) = nothing
|
||||
compute_z(x, y, z) = copy(z)
|
||||
|
||||
@noinline function compute_xyz(x, y, z)
|
||||
x = compute_x(x,y,z)
|
||||
y = compute_y(x,y,z)
|
||||
z = compute_z(x,y,z)
|
||||
x, y, z
|
||||
end
|
||||
|
||||
# not allowed
|
||||
compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
||||
compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
||||
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# create n=max(mx,my) series arguments. the shorter list is cycled through
|
||||
# note: everything should flow through this
|
||||
function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter)
|
||||
x, y, z = map(a -> pop!(kw, a, nothing), (:x, :y, :z))
|
||||
if nothing == x == y == z
|
||||
return [], nothing, nothing
|
||||
end
|
||||
|
||||
xs, xmeta = convertToAnyVector(x, kw)
|
||||
ys, ymeta = convertToAnyVector(y, kw)
|
||||
zs, zmeta = convertToAnyVector(z, kw)
|
||||
|
||||
# if idxfilter != nothing
|
||||
# xs = filter_data(xs, idxfilter)
|
||||
# ys = filter_data(ys, idxfilter)
|
||||
# zs = filter_data(zs, idxfilter)
|
||||
# # # filter the data
|
||||
# # for sym in (:x, :y, :z)
|
||||
# # @show "before" sym, d[sym], idxfilter
|
||||
# # d[sym] = filter_data(get(d, sym, nothing), idxfilter)
|
||||
# # @show "after" sym, d[sym], idxfilter
|
||||
# # end
|
||||
# end
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
mz = length(zs)
|
||||
ret = Any[]
|
||||
for i in 1:max(mx, my, mz)
|
||||
|
||||
# try to set labels using ymeta
|
||||
d = copy(kw)
|
||||
if !haskey(d, :label) && ymeta != nothing
|
||||
if isa(ymeta, Symbol)
|
||||
d[:label] = string(ymeta)
|
||||
elseif isa(ymeta, AVec{Symbol})
|
||||
d[:label] = string(ymeta[mod1(i,length(ymeta))])
|
||||
end
|
||||
end
|
||||
|
||||
# build the series arg dict
|
||||
numUncounted = pop!(d, :numUncounted, 0)
|
||||
commandIndex = i + numUncounted
|
||||
n = plt.n + i
|
||||
|
||||
dumpdict(d, "before getSeriesArgs")
|
||||
# @show numUncounted i n commandIndex convertSeriesIndex(plt, n)
|
||||
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n)
|
||||
dumpdict(d, "after getSeriesArgs")
|
||||
|
||||
# @show map(typeof, (xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]))
|
||||
d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)])
|
||||
# @show map(typeof, (d[:x], d[:y], d[:z]))
|
||||
|
||||
|
||||
# # NOTE: this should be handled by the time it gets here
|
||||
lt = d[:linetype]
|
||||
# if isa(d[:y], Surface)
|
||||
# if lt in (:contour, :heatmap, :surface, :wireframe)
|
||||
# z = d[:y]
|
||||
# d[:y] = 1:size(z,2)
|
||||
# d[:z] = z
|
||||
# end
|
||||
# end
|
||||
|
||||
# if haskey(d, :idxfilter)
|
||||
# idxfilter = pop!(d, :idxfilter)
|
||||
# d[:x] = d[:x][idxfilter]
|
||||
# d[:y] = d[:y][idxfilter]
|
||||
# end
|
||||
|
||||
# for linetype `line`, need to sort by x values
|
||||
if lt == :line
|
||||
# order by x
|
||||
indices = sortperm(d[:x])
|
||||
d[:x] = d[:x][indices]
|
||||
d[:y] = d[:y][indices]
|
||||
d[:linetype] = :path
|
||||
end
|
||||
|
||||
# map functions to vectors
|
||||
if isa(d[:zcolor], Function)
|
||||
d[:zcolor] = map(d[:zcolor], d[:x])
|
||||
end
|
||||
if isa(d[:fillrange], Function)
|
||||
d[:fillrange] = map(d[:fillrange], d[:x])
|
||||
end
|
||||
|
||||
# cleanup those fields that were used only for generating kw args
|
||||
# delete!(d, :dataframe)
|
||||
# for k in (:idxfilter, :numUncounted, :dataframe)
|
||||
# delete!(d, k)
|
||||
# end
|
||||
|
||||
# add it to our series list
|
||||
push!(ret, d)
|
||||
end
|
||||
|
||||
ret, xmeta, ymeta
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# process_inputs
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# These methods take a plot and the keyword arguments, and processes the input
|
||||
# arguments (x/y/z, group, etc), populating the KW dict with appropriate values.
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 0 arguments
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# don't do anything
|
||||
function process_inputs(plt::AbstractPlot, d::KW)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 1 argument
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# no special handling... assume x and z are nothing
|
||||
function process_inputs(plt::AbstractPlot, d::KW, y)
|
||||
d[:y] = y
|
||||
end
|
||||
|
||||
# matrix... is it z or y?
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, mat::AMat{T})
|
||||
if all3D(d)
|
||||
n,m = size(mat)
|
||||
d[:x], d[:y], d[:z] = 1:n, 1:m, mat
|
||||
else
|
||||
d[:y] = mat
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# plotting arbitrary shapes/polygons
|
||||
function process_inputs(plt::AbstractPlot, d::KW, shape::Shape)
|
||||
d[:x], d[:y] = shape_coords(shape)
|
||||
d[:linetype] = :shape
|
||||
end
|
||||
function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape})
|
||||
d[:x], d[:y] = shape_coords(shapes)
|
||||
d[:linetype] = :shape
|
||||
end
|
||||
function process_inputs(plt::AbstractPlot, d::KW, shapes::AMat{Shape})
|
||||
x, y = [], []
|
||||
for j in 1:size(shapes, 2)
|
||||
tmpx, tmpy = shape_coords(vec(shapes[:,j]))
|
||||
push!(x, tmpx)
|
||||
push!(y, tmpy)
|
||||
end
|
||||
d[:x], d[:y] = x, y
|
||||
d[:linetype] = :shape
|
||||
end
|
||||
|
||||
|
||||
# function without range... use the current range of the x-axis
|
||||
function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs)
|
||||
process_inputs(plt, d, f, xmin(plt), xmax(plt))
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 2 arguments
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function process_inputs(plt::AbstractPlot, d::KW, x, y)
|
||||
d[:x], d[:y] = x, y
|
||||
end
|
||||
|
||||
# if functions come first, just swap the order (not to be confused with parametric functions...
|
||||
# as there would be more than one function passed in)
|
||||
function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, x)
|
||||
@assert !(typeof(x) <: FuncOrFuncs) # otherwise we'd hit infinite recursion here
|
||||
process_inputs(plt, d, x, f)
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# 3 arguments
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# no special handling... just pass them through
|
||||
function process_inputs(plt::AbstractPlot, d::KW, x, y, z)
|
||||
d[:x], d[:y], d[:z] = x, y, z
|
||||
end
|
||||
|
||||
# 3d line or scatter
|
||||
function process_inputs(plt::AbstractPlot, d::KW, x::AVec, y::AVec, zvec::AVec)
|
||||
# default to path3d if we haven't set a 3d linetype
|
||||
if !(get(d, :linetype, :none) in _3dTypes)
|
||||
d[:linetype] = :path3d
|
||||
end
|
||||
d[:x], d[:y], d[:z] = x, y, zvec
|
||||
end
|
||||
|
||||
# surface-like... function
|
||||
function process_inputs(plt::AbstractPlot, d::KW, x::AVec, y::AVec, zf::Function)
|
||||
x, y = sort(x), sort(y)
|
||||
d[:z] = Surface(zf, x, y) # TODO: replace with SurfaceFunction when supported
|
||||
d[:x], d[:y] = x, y
|
||||
end
|
||||
|
||||
# surface-like... matrix grid
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, x::AVec, y::AVec, zmat::AMat{T})
|
||||
@assert size(zmat) == (length(x), length(y))
|
||||
if !issorted(x) || !issorted(y)
|
||||
x_idx = sortperm(x)
|
||||
y_idx = sortperm(y)
|
||||
x, y = x[x_idx], y[y_idx]
|
||||
zmat = zmat[x_idx, y_idx]
|
||||
end
|
||||
d[:x], d[:y], d[:z] = x, y, Surface{Matrix{Float64}}(zmat)
|
||||
if !like_surface(get(d, :linetype, :none))
|
||||
d[:linetype] = :contour
|
||||
end
|
||||
end
|
||||
|
||||
# surfaces-like... general x, y grid
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, x::AMat{T}, y::AMat{T}, zmat::AMat{T})
|
||||
@assert size(zmat) == size(x) == size(y)
|
||||
# d[:x], d[:y], d[:z] = Any[x], Any[y], Surface{Matrix{Float64}}(zmat)
|
||||
d[:x], d[:y], d[:z] = map(Surface{Matrix{Float64}}, (x, y, zmat))
|
||||
if !like_surface(get(d, :linetype, :none))
|
||||
d[:linetype] = :contour
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Parametric functions
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# special handling... xmin/xmax with function(s)
|
||||
function process_inputs(plt::AbstractPlot, d::KW, f::FuncOrFuncs, xmin::Number, xmax::Number)
|
||||
width = get(plt.plotargs, :size, (100,))[1]
|
||||
x = linspace(xmin, xmax, width)
|
||||
process_inputs(plt, d, x, f)
|
||||
end
|
||||
|
||||
# special handling... xmin/xmax with parametric function(s)
|
||||
process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
|
||||
process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u))
|
||||
process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, linspace(umin, umax, numPoints))
|
||||
|
||||
# special handling... 3D parametric function(s)
|
||||
process_inputs{T<:Number}(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec{T}) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
|
||||
process_inputs{T<:Number}(plt::AbstractPlot, d::KW, u::AVec{T}, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs) = process_inputs(plt, d, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u))
|
||||
process_inputs(plt::AbstractPlot, d::KW, fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints::Int = 1000) = process_inputs(plt, d, fx, fy, fz, linspace(umin, umax, numPoints))
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Lists of tuples and FixedSizeArrays
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# if we get an unhandled tuple, just splat it in
|
||||
function process_inputs(plt::AbstractPlot, d::KW, tup::Tuple)
|
||||
process_inputs(plt, d, tup...)
|
||||
end
|
||||
|
||||
# (x,y) tuples
|
||||
function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::AVec{Tuple{R1,R2}})
|
||||
process_inputs(plt, d, unzip(xy)...)
|
||||
end
|
||||
function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2})
|
||||
process_inputs(plt, d, [xy[1]], [xy[2]])
|
||||
end
|
||||
|
||||
# (x,y,z) tuples
|
||||
function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{Tuple{R1,R2,R3}})
|
||||
process_inputs(plt, d, unzip(xyz)...)
|
||||
end
|
||||
function process_inputs{R1<:Number,R2<:Number,R3<:Number}(plt::AbstractPlot, d::KW, xyz::Tuple{R1,R2,R3})
|
||||
process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
|
||||
end
|
||||
|
||||
# 2D FixedSizeArrays
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}})
|
||||
process_inputs(plt, d, unzip(xy)...)
|
||||
end
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T})
|
||||
process_inputs(plt, d, [xy[1]], [xy[2]])
|
||||
end
|
||||
|
||||
# 3D FixedSizeArrays
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}})
|
||||
process_inputs(plt, d, unzip(xyz)...)
|
||||
end
|
||||
function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::FixedSizeArrays.Vec{3,T})
|
||||
process_inputs(plt, d, [xyz[1]], [xyz[2]], [xyz[3]])
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# handle grouping
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# function process_inputs(plt::AbstractPlot, d::KW, groupby::GroupBy, args...)
|
||||
# ret = Any[]
|
||||
# error("unfinished after series reorg")
|
||||
# for (i,glab) in enumerate(groupby.groupLabels)
|
||||
# # TODO: don't automatically overwrite labels
|
||||
# kwlist, xmeta, ymeta = process_inputs(plt, d, args...,
|
||||
# idxfilter = groupby.groupIds[i],
|
||||
# label = string(glab),
|
||||
# numUncounted = length(ret)) # we count the idx from plt.n + numUncounted + i
|
||||
# append!(ret, kwlist)
|
||||
# end
|
||||
# ret, nothing, nothing # TODO: handle passing meta through
|
||||
# end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function setup_dataframes()
|
||||
@require DataFrames begin
|
||||
|
||||
get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg]
|
||||
get_data(df::DataFrames.AbstractDataFrame, arg) = arg
|
||||
|
||||
function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...)
|
||||
# d[:dataframe] = df
|
||||
process_inputs(plt, d, map(arg -> get_data(df, arg), args)...)
|
||||
end
|
||||
|
||||
# expecting the column name of a dataframe that was passed in... anything else should error
|
||||
function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
||||
if haskey(df, s)
|
||||
return extractGroupArgs(df[s])
|
||||
else
|
||||
error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
|
||||
end
|
||||
end
|
||||
|
||||
# function getDataFrameFromKW(d::KW)
|
||||
# get(d, :dataframe) do
|
||||
# error("Missing dataframe argument!")
|
||||
# end
|
||||
# end
|
||||
|
||||
# # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
||||
# convertToAnyVector(s::Symbol, d::KW) = Any[getDataFrameFromKW(d)[s]], s
|
||||
# convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,132 +1,18 @@
|
||||
|
||||
function subplotlayout(sz::@compat(Tuple{Int,Int}))
|
||||
GridLayout(sz...)
|
||||
end
|
||||
|
||||
function subplotlayout(rowcounts::AVec{Int})
|
||||
FlexLayout(sum(rowcounts), rowcounts)
|
||||
end
|
||||
|
||||
function subplotlayout(numplts::Int, nr::Int, nc::Int)
|
||||
|
||||
# figure out how many rows/columns we need
|
||||
if nr == -1
|
||||
if nc == -1
|
||||
nr = round(Int, sqrt(numplts))
|
||||
nc = ceil(Int, numplts / nr)
|
||||
else
|
||||
nr = ceil(Int, numplts / nc)
|
||||
end
|
||||
else
|
||||
nc = ceil(Int, numplts / nr)
|
||||
end
|
||||
|
||||
# if it's a perfect rectangle, just create a grid
|
||||
if numplts == nr * nc
|
||||
return GridLayout(nr, nc)
|
||||
end
|
||||
|
||||
# create the rowcounts vector
|
||||
i = 0
|
||||
rowcounts = Int[]
|
||||
for r in 1:nr
|
||||
cnt = min(nc, numplts - i)
|
||||
push!(rowcounts, cnt)
|
||||
i += cnt
|
||||
end
|
||||
|
||||
FlexLayout(numplts, rowcounts)
|
||||
end
|
||||
|
||||
|
||||
|
||||
Base.length(layout::FlexLayout) = layout.numplts
|
||||
Base.start(layout::FlexLayout) = 1
|
||||
Base.done(layout::FlexLayout, state) = state > length(layout)
|
||||
function Base.next(layout::FlexLayout, state)
|
||||
r = 1
|
||||
c = 0
|
||||
for i = 1:state
|
||||
c += 1
|
||||
if c > layout.rowcounts[r]
|
||||
r += 1
|
||||
c = 1
|
||||
end
|
||||
end
|
||||
(r,c), state + 1
|
||||
end
|
||||
|
||||
nrows(layout::FlexLayout) = length(layout.rowcounts)
|
||||
ncols(layout::FlexLayout, row::Int) = row < 1 ? 0 : (row > nrows(layout) ? 0 : layout.rowcounts[row])
|
||||
|
||||
# get the plot index given row and column
|
||||
Base.getindex(layout::FlexLayout, r::Int, c::Int) = sum(layout.rowcounts[1:r-1]) + c
|
||||
|
||||
Base.length(layout::GridLayout) = layout.nr * layout.nc
|
||||
Base.start(layout::GridLayout) = 1
|
||||
Base.done(layout::GridLayout, state) = state > length(layout)
|
||||
function Base.next(layout::GridLayout, state)
|
||||
r = div(state-1, layout.nc) + 1
|
||||
c = mod1(state, layout.nc)
|
||||
(r,c), state + 1
|
||||
end
|
||||
|
||||
nrows(layout::GridLayout) = layout.nr
|
||||
ncols(layout::GridLayout) = layout.nc
|
||||
ncols(layout::GridLayout, row::Int) = layout.nc
|
||||
|
||||
# get the plot index given row and column
|
||||
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 _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[]
|
||||
# lims = [Inf, -Inf]
|
||||
lims = Dict{Int,Any}() # maps column to xlim
|
||||
for (i,(r,c)) in enumerate(subplt.layout)
|
||||
|
||||
# shouldlink will be a bool or nothing. if nothing, then use linkx/y (which is true if we get to this code)
|
||||
shouldlink = subplt.linkfunc(r,c)[isx ? 1 : 2]
|
||||
if shouldlink == nothing || shouldlink
|
||||
plt = subplt.plts[i]
|
||||
|
||||
# if we don't have this
|
||||
k = isx ? c : r
|
||||
if (firstone = !haskey(lims, k))
|
||||
lims[k] = [Inf, -Inf]
|
||||
end
|
||||
|
||||
isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone)
|
||||
push!(includedPlots, (plt, isinner, k))
|
||||
|
||||
_expand_limits(lims[k], plt, isx)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# do the axis adjustments
|
||||
for (plt, isinner, k) in includedPlots
|
||||
if isinner
|
||||
_remove_axis(plt, isx)
|
||||
end
|
||||
(isx ? xlims! : ylims!)(plt, lims[k]...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
Base.string(subplt::Subplot) = "Subplot{$(subplt.backend) p=$(subplt.p) n=$(subplt.n)}"
|
||||
Base.print(io::IO, subplt::Subplot) = print(io, string(subplt))
|
||||
Base.show(io::IO, subplt::Subplot) = print(io, string(subplt))
|
||||
|
||||
function Base.copy(subplt::Subplot)
|
||||
subplot(subplt.plts, subplt.layout, subplt.plotargs)
|
||||
end
|
||||
|
||||
Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]]
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
getplot(subplt::Subplot, idx::Int = subplt.n) = subplt.plts[mod1(idx, subplt.p)]
|
||||
getplotargs(subplt::Subplot, idx::Int) = getplot(subplt, idx).plotargs
|
||||
convertSeriesIndex(subplt::Subplot, n::Int) = ceil(Int, n / subplt.p)
|
||||
@@ -153,7 +39,7 @@ Create a series of plots:
|
||||
"""
|
||||
function subplot(args...; kw...)
|
||||
validateSubplotSupported()
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
preprocessArgs!(d)
|
||||
|
||||
# for plotting recipes, swap out the args and update the parameter dictionary
|
||||
@@ -194,7 +80,7 @@ end
|
||||
|
||||
# grid layout
|
||||
function subplot{P}(plt1::Plot{P}, plts::Plot{P}...; kw...)
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
layout = subplotlayout(length(plts)+1, get(d, :nr, -1), get(d, :nc, -1))
|
||||
subplot(vcat(plt1, plts...), layout, d)
|
||||
end
|
||||
@@ -202,15 +88,15 @@ end
|
||||
# explicit layout
|
||||
function subplot{P,I<:Integer}(pltsPerRow::AVec{I}, plt1::Plot{P}, plts::Plot{P}...; kw...)
|
||||
layout = subplotlayout(pltsPerRow)
|
||||
subplot(vcat(plt1, plts...), layout, Dict(kw))
|
||||
subplot(vcat(plt1, plts...), layout, KW(kw))
|
||||
end
|
||||
|
||||
# this will be called internally
|
||||
function subplot{P<:PlottingPackage}(plts::AVec{Plot{P}}, layout::SubplotLayout, d::Dict)
|
||||
function subplot{P<:AbstractBackend}(plts::AVec{Plot{P}}, layout::SubplotLayout, d::KW)
|
||||
validateSubplotSupported()
|
||||
p = length(layout)
|
||||
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))
|
||||
subplt = Subplot(nothing, collect(plts), P(), p, n, layout, KW(), false, false, false, (r,c) -> (nothing,nothing))
|
||||
|
||||
_preprocess_subplot(subplt, d)
|
||||
_postprocess_subplot(subplt, d)
|
||||
@@ -223,7 +109,7 @@ end
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _preprocess_subplot(subplt::Subplot, d::Dict, args = ())
|
||||
function _preprocess_subplot(subplt::Subplot, d::KW, args = ())
|
||||
validateSubplotSupported()
|
||||
preprocessArgs!(d)
|
||||
|
||||
@@ -257,7 +143,7 @@ function _preprocess_subplot(subplt::Subplot, d::Dict, args = ())
|
||||
args
|
||||
end
|
||||
|
||||
function _postprocess_subplot(subplt::Subplot, d::Dict)
|
||||
function _postprocess_subplot(subplt::Subplot, d::KW)
|
||||
# init (after plot creation)
|
||||
if !subplt.initialized
|
||||
subplt.initialized = _create_subplot(subplt, false)
|
||||
@@ -303,49 +189,63 @@ end
|
||||
function subplot!(subplt::Subplot, args...; kw...)
|
||||
# validateSubplotSupported()
|
||||
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
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,
|
||||
# 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 = _create_subplot(subplt, true)
|
||||
end
|
||||
|
||||
# handle grouping
|
||||
group = get(d, :group, nothing)
|
||||
if group == nothing
|
||||
groupargs = []
|
||||
# # handle grouping
|
||||
# group = get(d, :group, nothing)
|
||||
# if group == nothing
|
||||
# groupargs = []
|
||||
# else
|
||||
# groupargs = [extractGroupArgs(d[:group], args...)]
|
||||
# delete!(d, :group)
|
||||
# end
|
||||
|
||||
groupby = if haskey(d, :group)
|
||||
extractGroupArgs(d[:group], args...)
|
||||
else
|
||||
groupargs = [extractGroupArgs(d[:group], args...)]
|
||||
delete!(d, :group)
|
||||
nothing
|
||||
end
|
||||
# dumpdict(d, "after", true)
|
||||
# @show groupby map(typeof, args)
|
||||
|
||||
_add_series_subplot(subplt, d, groupby, args...)
|
||||
|
||||
kwList, xmeta, ymeta = createKWargsList(subplt, groupargs..., args...; d...)
|
||||
|
||||
# TODO: something useful with meta info?
|
||||
|
||||
for (i,di) in enumerate(kwList)
|
||||
|
||||
subplt.n += 1
|
||||
plt = getplot(subplt)
|
||||
plt.n += 1
|
||||
|
||||
# cleanup the dictionary that we pass into the plot! command
|
||||
di[:show] = false
|
||||
di[:subplot] = true
|
||||
for k in (:title, :xlabel, :xticks, :xlims, :xscale, :xflip,
|
||||
:ylabel, :yticks, :ylims, :yscale, :yflip)
|
||||
delete!(di, k)
|
||||
end
|
||||
dumpdict(di, "subplot! kwList $i")
|
||||
dumpdict(plt.plotargs, "plt.plotargs before plotting")
|
||||
|
||||
_add_series_subplot(plt; di...)
|
||||
end
|
||||
# process_inputs(subplt, d, groupargs..., args...)
|
||||
#
|
||||
# # TODO: filter the data
|
||||
#
|
||||
# kwList, xmeta, ymeta = build_series_args(subplt, d)
|
||||
# # kwList, xmeta, ymeta = build_series_args(subplt, groupargs..., args...; d...)
|
||||
#
|
||||
# # TODO: something useful with meta info?
|
||||
#
|
||||
# for (i,di) in enumerate(kwList)
|
||||
#
|
||||
# subplt.n += 1
|
||||
# plt = getplot(subplt)
|
||||
# plt.n += 1
|
||||
#
|
||||
# # cleanup the dictionary that we pass into the plot! command
|
||||
# di[:show] = false
|
||||
# di[:subplot] = true
|
||||
# for k in (:title, :xlabel, :xticks, :xlims, :xscale, :xflip,
|
||||
# :ylabel, :yticks, :ylims, :yscale, :yflip)
|
||||
# delete!(di, k)
|
||||
# end
|
||||
# dumpdict(di, "subplot! kwList $i")
|
||||
# dumpdict(plt.plotargs, "plt.plotargs before plotting")
|
||||
#
|
||||
# _add_series_subplot(plt; di...)
|
||||
# end
|
||||
|
||||
_postprocess_subplot(subplt, d)
|
||||
|
||||
@@ -358,23 +258,109 @@ function subplot!(subplt::Subplot, args...; kw...)
|
||||
end
|
||||
|
||||
|
||||
# not allowed:
|
||||
function plot!(subplt::Subplot, args...; kw...)
|
||||
error("Can't call plot! on a Subplot!")
|
||||
end
|
||||
|
||||
function _add_series_subplot(plt::Plot, args...; kw...)
|
||||
d = Dict(kw)
|
||||
|
||||
# given a fully processed KW, add the series to the Plot
|
||||
function _add_series_subplot(plt::Plot, d::KW)
|
||||
setTicksFromStringVector(d, d, :x, :xticks)
|
||||
setTicksFromStringVector(d, d, :y, :yticks)
|
||||
|
||||
# this is the actual call to the backend
|
||||
_add_series(plt.backend, plt; d...)
|
||||
|
||||
|
||||
_add_annotations(plt, d)
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
end
|
||||
|
||||
|
||||
# handle the grouping... add a series for each group
|
||||
function _add_series_subplot(subplt::Subplot, d::KW, groupby::GroupBy, args...)
|
||||
starting_n = subplt.n
|
||||
for (i, glab) in enumerate(groupby.groupLabels)
|
||||
tmpd = copy(d)
|
||||
tmpd[:numUncounted] = subplt.n - starting_n
|
||||
_add_series_subplot(subplt, tmpd, nothing, args...;
|
||||
idxfilter = groupby.groupIds[i],
|
||||
grouplabel = string(glab))
|
||||
end
|
||||
end
|
||||
|
||||
# process, filter, and add to the correct plot
|
||||
function _add_series_subplot(subplt::Subplot, d::KW, ::Void, args...;
|
||||
idxfilter = nothing,
|
||||
grouplabel = "")
|
||||
process_inputs(subplt, d, args...)
|
||||
|
||||
if idxfilter != nothing
|
||||
# add the group name as the label if there isn't one passed in
|
||||
get!(d, :label, grouplabel)
|
||||
# filter the data
|
||||
filter_data!(d, idxfilter)
|
||||
end
|
||||
|
||||
kwList, xmeta, ymeta = build_series_args(subplt, d)
|
||||
|
||||
# TODO: something useful with meta info?
|
||||
|
||||
for (i,di) in enumerate(kwList)
|
||||
|
||||
subplt.n += 1
|
||||
plt = getplot(subplt)
|
||||
plt.n += 1
|
||||
|
||||
# cleanup the dictionary that we pass into the plot! command
|
||||
di[:show] = false
|
||||
di[:subplot] = true
|
||||
for k in (:title, :xlabel, :xticks, :xlims, :xscale, :xflip,
|
||||
:ylabel, :yticks, :ylims, :yscale, :yflip)
|
||||
delete!(di, k)
|
||||
end
|
||||
dumpdict(di, "subplot! kwList $i")
|
||||
dumpdict(plt.plotargs, "plt.plotargs before plotting")
|
||||
|
||||
_add_series_subplot(plt, di)
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function Base.copy(subplt::Subplot)
|
||||
subplot(subplt.plts, subplt.layout, subplt.plotargs)
|
||||
# handle "linking" the subplot axes together
|
||||
# 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[]
|
||||
# lims = [Inf, -Inf]
|
||||
lims = Dict{Int,Any}() # maps column to xlim
|
||||
for (i,(r,c)) in enumerate(subplt.layout)
|
||||
|
||||
# shouldlink will be a bool or nothing. if nothing, then use linkx/y (which is true if we get to this code)
|
||||
shouldlink = subplt.linkfunc(r,c)[isx ? 1 : 2]
|
||||
if shouldlink == nothing || shouldlink
|
||||
plt = subplt.plts[i]
|
||||
|
||||
# if we don't have this
|
||||
k = isx ? c : r
|
||||
if (firstone = !haskey(lims, k))
|
||||
lims[k] = [Inf, -Inf]
|
||||
end
|
||||
|
||||
isinner = (isx && r < nrows(subplt.layout)) || (!isx && !firstone)
|
||||
push!(includedPlots, (plt, isinner, k))
|
||||
|
||||
_expand_limits(lims[k], plt, isx)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# do the axis adjustments
|
||||
for (plt, isinner, k) in includedPlots
|
||||
if isinner
|
||||
_remove_axis(plt, isx)
|
||||
end
|
||||
(isx ? xlims! : ylims!)(plt, lims[k]...)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,47 +3,45 @@ typealias AVec AbstractVector
|
||||
typealias AMat AbstractMatrix
|
||||
|
||||
immutable PlotsDisplay <: Display end
|
||||
|
||||
abstract PlottingPackage
|
||||
abstract PlottingObject{T<:PlottingPackage}
|
||||
|
||||
type Plot{T<:PlottingPackage} <: PlottingObject{T}
|
||||
o # the underlying object
|
||||
backend::T
|
||||
n::Int # number of series
|
||||
abstract AbstractBackend
|
||||
abstract AbstractPlot{T<:AbstractBackend}
|
||||
|
||||
# store these just in case
|
||||
plotargs::Dict
|
||||
seriesargs::Vector{Dict} # args for each series
|
||||
typealias KW Dict{Symbol,Any}
|
||||
# -----------------------------------------------------------
|
||||
# Plot
|
||||
# -----------------------------------------------------------
|
||||
|
||||
type Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
o # the backend's plot object
|
||||
backend::T # the backend type
|
||||
n::Int # number of series
|
||||
plotargs::KW # arguments for the whole plot
|
||||
seriesargs::Vector{KW} # arguments for each series
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# Layout
|
||||
# -----------------------------------------------------------
|
||||
|
||||
abstract SubplotLayout
|
||||
|
||||
immutable GridLayout <: SubplotLayout
|
||||
nr::Int
|
||||
nc::Int
|
||||
end
|
||||
# -----------------------------------------------------------
|
||||
# Subplot
|
||||
# -----------------------------------------------------------
|
||||
|
||||
immutable FlexLayout <: SubplotLayout
|
||||
numplts::Int
|
||||
rowcounts::AbstractVector{Int}
|
||||
end
|
||||
|
||||
|
||||
type Subplot{T<:PlottingPackage, L<:SubplotLayout} <: PlottingObject{T}
|
||||
o # the underlying object
|
||||
plts::Vector{Plot{T}} # the individual plots
|
||||
backend::T
|
||||
p::Int # number of plots
|
||||
n::Int # number of series
|
||||
layout::L
|
||||
# plotargs::Vector{Dict}
|
||||
plotargs::Dict
|
||||
initialized::Bool
|
||||
linkx::Bool
|
||||
linky::Bool
|
||||
linkfunc::Function # maps (row,column) -> (BoolOrNothing, BoolOrNothing)... if xlink/ylink are nothing, then use subplt.linkx/y
|
||||
type Subplot{T<:AbstractBackend, L<:SubplotLayout} <: AbstractPlot{T}
|
||||
o # the underlying object
|
||||
plts::Vector{Plot{T}} # the individual plots
|
||||
backend::T
|
||||
p::Int # number of plots
|
||||
n::Int # number of series
|
||||
layout::L
|
||||
plotargs::KW
|
||||
initialized::Bool
|
||||
linkx::Bool
|
||||
linky::Bool
|
||||
linkfunc::Function # maps (row,column) -> (BoolOrNothing, BoolOrNothing)... if xlink/ylink are nothing, then use subplt.linkx/y
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,7 @@ A hacky replacement for a histogram when the backend doesn't support histograms
|
||||
Convert it into a bar chart with the appropriate x/y values.
|
||||
"""
|
||||
function histogramHack(; kw...)
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
|
||||
# we assume that the y kwarg is set with the data to be binned, and nbins is also defined
|
||||
edges, midpoints, buckets, counts = binData(d[:y], d[:nbins])
|
||||
@@ -35,7 +35,7 @@ A hacky replacement for a bar graph when the backend doesn't support bars direct
|
||||
Convert it into a line chart with fillrange set.
|
||||
"""
|
||||
function barHack(; kw...)
|
||||
d = Dict(kw)
|
||||
d = KW(kw)
|
||||
midpoints = d[:x]
|
||||
heights = d[:y]
|
||||
fillrange = d[:fillrange] == nothing ? 0.0 : d[:fillrange]
|
||||
@@ -75,7 +75,7 @@ A hacky replacement for a sticks graph when the backend doesn't support sticks d
|
||||
Convert it into a line chart that traces the sticks, and a scatter that sets markers at the points.
|
||||
"""
|
||||
function sticksHack(; kw...)
|
||||
dLine = Dict(kw)
|
||||
dLine = KW(kw)
|
||||
dScatter = copy(dLine)
|
||||
|
||||
# these are the line vertices
|
||||
@@ -121,17 +121,24 @@ 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
|
||||
get_mod(v, idx::Int) = v
|
||||
|
||||
makevec(v::AVec) = v
|
||||
makevec{T}(v::T) = T[v]
|
||||
|
||||
"duplicate a single value, or pass the 2-tuple through"
|
||||
maketuple(x::Real) = (x,x)
|
||||
maketuple(x::Real) = (x,x)
|
||||
maketuple{T,S}(x::@compat(Tuple{T,S})) = x
|
||||
|
||||
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
|
||||
mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs]
|
||||
|
||||
unzip{T,S}(v::AVec{@compat(Tuple{T,S})}) = [vi[1] for vi in v], [vi[2] for vi in v]
|
||||
unzip{T,S}(xy::AVec{Tuple{T,S}}) = [x[1] for x in xy], [y[2] for y in xy]
|
||||
unzip{T,S,R}(xyz::AVec{Tuple{T,S,R}}) = [x[1] for x in xyz], [y[2] for y in xyz], [z[3] for z in xyz]
|
||||
unzip{T}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = T[x[1] for x in xy], T[y[2] for y in xy]
|
||||
unzip{T}(xy::FixedSizeArrays.Vec{2,T}) = T[xy[1]], T[xy[2]]
|
||||
unzip{T}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = T[x[1] for x in xyz], T[y[2] for y in xyz], T[z[3] for z in xyz]
|
||||
unzip{T}(xyz::FixedSizeArrays.Vec{3,T}) = T[xyz[1]], T[xyz[2]], T[xyz[3]]
|
||||
|
||||
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
|
||||
function _expand_limits(lims, x)
|
||||
@@ -163,7 +170,7 @@ function replaceType(vec, val)
|
||||
push!(vec, val)
|
||||
end
|
||||
|
||||
function replaceAliases!(d::Dict, aliases::Dict)
|
||||
function replaceAliases!(d::KW, aliases::KW)
|
||||
ks = collect(keys(d))
|
||||
for k in ks
|
||||
if haskey(aliases, k)
|
||||
@@ -181,6 +188,13 @@ Base.first(x::Symbol) = x
|
||||
|
||||
sortedkeys(d::Dict) = sort(collect(keys(d)))
|
||||
|
||||
"create an (n+1) list of the outsides of heatmap rectangles"
|
||||
function heatmap_edges(v::AVec)
|
||||
vmin, vmax = extrema(v)
|
||||
extra = 0.5 * (vmax-vmin) / (length(v)-1)
|
||||
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
|
||||
end
|
||||
|
||||
|
||||
function fakedata(sz...)
|
||||
y = zeros(sz...)
|
||||
@@ -191,31 +205,32 @@ function fakedata(sz...)
|
||||
end
|
||||
|
||||
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
|
||||
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
|
||||
|
||||
istuple(::Tuple) = true
|
||||
istuple(::Any) = false
|
||||
istuple(::Any) = false
|
||||
isvector(::AVec) = true
|
||||
isvector(::Any) = false
|
||||
isvector(::Any) = false
|
||||
ismatrix(::AMat) = true
|
||||
ismatrix(::Any) = false
|
||||
ismatrix(::Any) = false
|
||||
isscalar(::Real) = true
|
||||
isscalar(::Any) = false
|
||||
isscalar(::Any) = false
|
||||
|
||||
|
||||
|
||||
|
||||
# ticksType{T<:Real,S<:Real}(ticks::@compat(Tuple{T,S})) = :limits
|
||||
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
|
||||
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
|
||||
ticksType{T<:AVec,S<:AVec}(ticks::@compat(Tuple{T,S})) = :ticks_and_labels
|
||||
ticksType(ticks) = :invalid
|
||||
ticksType{T<:Real}(ticks::AVec{T}) = :ticks
|
||||
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels
|
||||
ticksType{T<:AVec,S<:AVec}(ticks::@compat(Tuple{T,S})) = :ticks_and_labels
|
||||
ticksType(ticks) = :invalid
|
||||
|
||||
limsType{T<:Real,S<:Real}(lims::@compat(Tuple{T,S})) = :limits
|
||||
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
|
||||
limsType(lims) = :invalid
|
||||
limsType{T<:Real,S<:Real}(lims::@compat(Tuple{T,S})) = :limits
|
||||
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}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng]
|
||||
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng]
|
||||
|
||||
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
|
||||
@@ -228,14 +243,14 @@ wraptuple(x) = (x,)
|
||||
trueOrAllTrue(f::Function, x::AbstractArray) = all(f, x)
|
||||
trueOrAllTrue(f::Function, x) = f(x)
|
||||
|
||||
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
allShapes(arg) = trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg) ||
|
||||
trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
allAlphas(arg) = trueOrAllTrue(a -> (typeof(a) <: Real && a > 0 && a < 1) ||
|
||||
(typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg)
|
||||
allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
|
||||
allLineTypes(arg) = trueOrAllTrue(a -> get(_typeAliases, a, a) in _allTypes, arg)
|
||||
allStyles(arg) = trueOrAllTrue(a -> get(_styleAliases, a, a) in _allStyles, arg)
|
||||
allShapes(arg) = trueOrAllTrue(a -> get(_markerAliases, a, a) in _allMarkers, arg) ||
|
||||
trueOrAllTrue(a -> isa(a, Shape), arg)
|
||||
allAlphas(arg) = trueOrAllTrue(a -> (typeof(a) <: Real && a > 0 && a < 1) ||
|
||||
(typeof(a) <: AbstractFloat && (a == zero(typeof(a)) || a == one(typeof(a)))), arg)
|
||||
allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg)
|
||||
allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -250,10 +265,17 @@ end
|
||||
```
|
||||
"""
|
||||
function with(f::Function, args...; kw...)
|
||||
newdefs = KW(kw)
|
||||
|
||||
if :canvas in args
|
||||
newdefs[:xticks] = nothing
|
||||
newdefs[:yticks] = nothing
|
||||
newdefs[:grid] = false
|
||||
newdefs[:legend] = false
|
||||
end
|
||||
|
||||
# dict to store old and new keyword args for anything that changes
|
||||
newdefs = Dict(kw)
|
||||
olddefs = Dict()
|
||||
olddefs = KW()
|
||||
for k in keys(newdefs)
|
||||
olddefs[k] = default(k)
|
||||
end
|
||||
@@ -332,7 +354,7 @@ end
|
||||
debugshow(x) = show(x)
|
||||
debugshow(x::AbstractArray) = print(summary(x))
|
||||
|
||||
function dumpdict(d::Dict, prefix = "", alwaysshow = false)
|
||||
function dumpdict(d::KW, prefix = "", alwaysshow = false)
|
||||
_debugMode.on || alwaysshow || return
|
||||
println()
|
||||
if prefix != ""
|
||||
@@ -419,11 +441,11 @@ end
|
||||
# used in updating an existing series
|
||||
|
||||
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
|
||||
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + maximum(v))
|
||||
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
|
||||
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v)
|
||||
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + maximum(v))
|
||||
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
|
||||
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
|
||||
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
@@ -443,22 +465,15 @@ function supportGraph(allvals, func)
|
||||
end
|
||||
end
|
||||
n = length(vals)
|
||||
|
||||
scatter(x,y,
|
||||
m=:rect,
|
||||
ms=10,
|
||||
size=(300,100+18*n),
|
||||
# xticks=(collect(1:length(bs)), bs),
|
||||
leg=false
|
||||
)
|
||||
scatter(x, y, m=:rect, ms=10, size=(300,100+18*n), leg=false)
|
||||
end
|
||||
|
||||
supportGraphArgs() = supportGraph(_allArgs, supportedArgs)
|
||||
supportGraphTypes() = supportGraph(_allTypes, supportedTypes)
|
||||
supportGraphStyles() = supportGraph(_allStyles, supportedStyles)
|
||||
supportGraphArgs() = supportGraph(_allArgs, supportedArgs)
|
||||
supportGraphTypes() = supportGraph(_allTypes, supportedTypes)
|
||||
supportGraphStyles() = supportGraph(_allStyles, supportedStyles)
|
||||
supportGraphMarkers() = supportGraph(_allMarkers, supportedMarkers)
|
||||
supportGraphScales() = supportGraph(_allScales, supportedScales)
|
||||
supportGraphAxes() = supportGraph(_allAxes, supportedAxes)
|
||||
supportGraphScales() = supportGraph(_allScales, supportedScales)
|
||||
supportGraphAxes() = supportGraph(_allAxes, supportedAxes)
|
||||
|
||||
function dumpSupportGraphs()
|
||||
for func in (supportGraphArgs, supportGraphTypes, supportGraphStyles,
|
||||
@@ -473,16 +488,18 @@ end
|
||||
|
||||
# Some conversion functions
|
||||
# note: I borrowed these conversion constants from Compose.jl's Measure
|
||||
const PX_PER_INCH = 100
|
||||
const DPI = PX_PER_INCH
|
||||
const MM_PER_INCH = 25.4
|
||||
const MM_PER_PX = MM_PER_INCH / PX_PER_INCH
|
||||
inch2px(inches::Real) = float(inches * PX_PER_INCH)
|
||||
px2inch(px::Real) = float(px / PX_PER_INCH)
|
||||
inch2mm(inches::Real) = float(inches * MM_PER_INCH)
|
||||
mm2inch(mm::Real) = float(mm / MM_PER_INCH)
|
||||
px2mm(px::Real) = float(px * MM_PER_PX)
|
||||
mm2px(mm::Real) = float(px / MM_PER_PX)
|
||||
|
||||
const PX_PER_INCH = 100
|
||||
const DPI = PX_PER_INCH
|
||||
const MM_PER_INCH = 25.4
|
||||
const MM_PER_PX = MM_PER_INCH / PX_PER_INCH
|
||||
|
||||
inch2px(inches::Real) = float(inches * PX_PER_INCH)
|
||||
px2inch(px::Real) = float(px / PX_PER_INCH)
|
||||
inch2mm(inches::Real) = float(inches * MM_PER_INCH)
|
||||
mm2inch(mm::Real) = float(mm / MM_PER_INCH)
|
||||
px2mm(px::Real) = float(px * MM_PER_PX)
|
||||
mm2px(mm::Real) = float(px / MM_PER_PX)
|
||||
|
||||
|
||||
"Smallest x in plot"
|
||||
@@ -491,4 +508,4 @@ xmin(plt::Plot) = minimum([minimum(d[:x]) for d in plt.seriesargs])
|
||||
xmax(plt::Plot) = maximum([maximum(d[:x]) for d in plt.seriesargs])
|
||||
|
||||
"Extrema of x-values in plot"
|
||||
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
|
||||
|
||||
@@ -4,9 +4,12 @@ Colors
|
||||
Reexport
|
||||
Requires
|
||||
FactCheck
|
||||
Cairo
|
||||
Gadfly
|
||||
Images
|
||||
ImageMagick
|
||||
PyPlot
|
||||
@osx QuartzImageIO
|
||||
GR
|
||||
DataFrames
|
||||
RDatasets
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using VisualRegressionTests
|
||||
using ExamplePlots
|
||||
|
||||
import DataFrames, RDatasets
|
||||
|
||||
# don't let pyplot use a gui... it'll crash
|
||||
# note: Agg will set gui -> :none in PyPlot
|
||||
ENV["MPLBACKEND"] = "Agg"
|
||||
@@ -16,12 +18,12 @@ using Plots, FactCheck
|
||||
default(size=(500,300))
|
||||
|
||||
|
||||
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
|
||||
# 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, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
|
||||
# first
|
||||
|
||||
# first
|
||||
Plots._debugMode.on = debug
|
||||
example = ExamplePlots._examples[idx]
|
||||
info("Testing plot: $pkg:$idx:$(example.header)")
|
||||
|
||||
@@ -8,10 +8,10 @@ default(show=false)
|
||||
img_eps = 5e-2
|
||||
|
||||
facts("Gadfly") do
|
||||
@fact gadfly() --> Plots.GadflyPackage()
|
||||
@fact backend() --> Plots.GadflyPackage()
|
||||
@fact gadfly() --> Plots.GadflyBackend()
|
||||
@fact backend() --> Plots.GadflyBackend()
|
||||
|
||||
@fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyPackage}
|
||||
@fact typeof(plot(1:10)) --> Plots.Plot{Plots.GadflyBackend}
|
||||
@fact plot(Int[1,2,3], rand(3)) --> not(nothing)
|
||||
@fact plot(sort(rand(10)), rand(Int, 10, 3)) --> not(nothing)
|
||||
@fact plot!(rand(10,3), rand(10,3)) --> not(nothing)
|
||||
@@ -20,15 +20,15 @@ facts("Gadfly") do
|
||||
end
|
||||
|
||||
facts("PyPlot") do
|
||||
@fact pyplot() --> Plots.PyPlotPackage()
|
||||
@fact backend() --> Plots.PyPlotPackage()
|
||||
@fact pyplot() --> Plots.PyPlotBackend()
|
||||
@fact backend() --> Plots.PyPlotBackend()
|
||||
|
||||
image_comparison_facts(:pyplot, skip=[4,10,13,19,21,23], eps=img_eps)
|
||||
end
|
||||
|
||||
facts("GR") do
|
||||
@fact gr() --> Plots.GRPackage()
|
||||
@fact backend() --> Plots.GRPackage()
|
||||
@fact gr() --> Plots.GRBackend()
|
||||
@fact backend() --> Plots.GRBackend()
|
||||
|
||||
# image_comparison_facts(:gr, only=[1], eps=img_eps)
|
||||
end
|
||||
|
||||