From 5f85ac01f72e6704e6216d5dc74ea3f5147cd7ae Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 3 Nov 2015 13:45:23 -0500 Subject: [PATCH] working on bokeh backend --- src/backends/bokeh.jl | 103 ++++++++++++++++++++++++++++++++++++++ src/backends/qwt.jl | 4 -- src/backends/supported.jl | 65 +++++++++++++++++++++++- src/backends/template.jl | 34 +++++++++++++ src/plotter.jl | 29 +++++++++-- src/utils.jl | 4 +- 6 files changed, 227 insertions(+), 12 deletions(-) create mode 100644 src/backends/bokeh.jl diff --git a/src/backends/bokeh.jl b/src/backends/bokeh.jl new file mode 100644 index 00000000..6a199eb4 --- /dev/null +++ b/src/backends/bokeh.jl @@ -0,0 +1,103 @@ + +# https://github.com/bokeh/Bokeh.jl + +# --------------------------------------------------------------------------- + +function plot(pkg::BokehPackage; kw...) + d = Dict(kw) + + dumpdict(d, "plot", true) + + # TODO: create the window/canvas/context that is the plot within the backend (call it `o`) + # TODO: initialize the plot... title, xlabel, bgcolor, etc + + datacolumns = Bokeh.BokehDataSet[] + tools = Bokeh.tools() + filename = tempname() * ".html" + title = d[:title] + w, h = d[:size] + xaxis_type = :auto + yaxis_type = :auto + # legend = d[:legend] ? xxxx : nothing + legend = nothing + bplt = Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) + + Plot(bplt, pkg, 0, d, Dict[]) +end + + +function plot!(::BokehPackage, plt::Plot; kw...) + d = Dict(kw) + + dumpdict(d, "plot!", true) + + # TODO: add one series to the underlying package + + + push!(plt.seriesargs, d) + plt +end + +# ---------------------------------------------------------------- + +# TODO: override this to update plot items (title, xlabel, etc) after creation +function updatePlotItems(plt::Plot{BokehPackage}, d::Dict) +end + +function updatePositionAndSize(plt::PlottingObject{BokehPackage}, d::Dict) +end + +# ---------------------------------------------------------------- + +# accessors for x/y data + +function Base.getindex(plt::Plot{BokehPackage}, i::Int) + # TODO + # series = plt.o.lines[i] + # series.x, series.y +end + +function Base.setindex!(plt::Plot{BokehPackage}, xy::Tuple, i::Integer) + # TODO + # series = plt.o.lines[i] + # series.x, series.y = xy + plt +end + + +# ---------------------------------------------------------------- + +function addAnnotations{X,Y,V}(plt::Plot{BokehPackage}, anns::AVec{@compat(Tuple{X,Y,V})}) + for ann in anns + # TODO: add the annotation to the plot + end +end + +# ---------------------------------------------------------------- + +function buildSubplotObject!(subplt::Subplot{BokehPackage}) + # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example +end + + +function expandLimits!(lims, plt::Plot{BokehPackage}, isx::Bool) + # TODO: call expand limits for each plot data +end + +function handleLinkInner(plt::Plot{BokehPackage}, isx::Bool) + # TODO: if plot is inner subplot, might need to remove ticks or axis labels +end + +# ---------------------------------------------------------------- + +function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{BokehPackage}) + # TODO: write a png to io +end + +function Base.display(::PlotsDisplay, plt::Plot{BokehPackage}) + # TODO: display/show the plot +end + +function Base.display(::PlotsDisplay, plt::Subplot{BokehPackage}) + # TODO: display/show the subplot +end diff --git a/src/backends/qwt.jl b/src/backends/qwt.jl index a5c230be..695c8aa3 100644 --- a/src/backends/qwt.jl +++ b/src/backends/qwt.jl @@ -233,10 +233,6 @@ function buildSubplotObject!(subplt::Subplot{QwtPackage}, isbefore::Bool) true end -function handleLinkInner(plt::Plot{QwtPackage}, isx::Bool) - warn("handleLinkInner isn't implemented for qwt") -end - function expandLimits!(lims, plt::Plot{QwtPackage}, isx::Bool) for series in plt.o.lines expandLimits!(lims, isx ? series.x : series.y) diff --git a/src/backends/supported.jl b/src/backends/supported.jl index a238c6a9..4706cdc0 100644 --- a/src/backends/supported.jl +++ b/src/backends/supported.jl @@ -310,4 +310,67 @@ supportedScales(::WinstonPackage) = [:identity, :log10] subplotSupported(::WinstonPackage) = false -# -------------------------------------------------------------------------------------- \ No newline at end of file +# -------------------------------------------------------------------------------------- + + + +supportedArgs(::BokehPackage) = [ + # :annotation, + # :axis, + # :background_color, + # :color, + # :color_palette, + # :fillrange, + # :fillcolor, + # :fillopacity, + # :foreground_color, + # :group, + # :label, + # :layout, + # :legend, + # :linestyle, + # :linetype, + # :linewidth, + # :lineopacity, + # :markershape, + # :markercolor, + # :markersize, + # :markeropacity, + # :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, + # :nlevels, + ] +supportedAxes(::BokehPackage) = [:auto, :left] +supportedTypes(::BokehPackage) = [:none] #, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour] +supportedStyles(::BokehPackage) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot] +supportedMarkers(::BokehPackage) = [:none, :auto] #vcat(_allMarkers, Shape) +supportedScales(::BokehPackage) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt] + + diff --git a/src/backends/template.jl b/src/backends/template.jl index fd044376..a735b5a2 100644 --- a/src/backends/template.jl +++ b/src/backends/template.jl @@ -83,12 +83,46 @@ end function updatePlotItems(plt::Plot{[PkgName]Package}, d::Dict) end +function updatePositionAndSize(plt::PlottingObject{[PkgName]Package}, d::Dict) +end + +# ---------------------------------------------------------------- + +# accessors for x/y data + +function Base.getindex(plt::Plot{[PkgName]Package}, i::Int) + series = plt.o.lines[i] + series.x, series.y +end + +function Base.setindex!(plt::Plot{[PkgName]Package}, xy::Tuple, i::Integer) + series = plt.o.lines[i] + series.x, series.y = xy + plt +end + +# ---------------------------------------------------------------- + +function addAnnotations{X,Y,V}(plt::Plot{[PkgName]Package}, anns::AVec{@compat(Tuple{X,Y,V})}) + for ann in anns + # TODO: add the annotation to the plot + end +end + # ---------------------------------------------------------------- function buildSubplotObject!(subplt::Subplot{[PkgName]Package}) # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example end +function expandLimits!(lims, plt::Plot{[PkgName]Package}, isx::Bool) + # TODO: call expand limits for each plot data +end + +function handleLinkInner(plt::Plot{[PkgName]Package}, isx::Bool) + # TODO: if plot is inner subplot, might need to remove ticks or axis labels +end + # ---------------------------------------------------------------- function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{[PkgName]Package}) diff --git a/src/plotter.jl b/src/plotter.jl index 9a5e9faf..6b7cc6ad 100644 --- a/src/plotter.jl +++ b/src/plotter.jl @@ -6,6 +6,7 @@ immutable PyPlotPackage <: PlottingPackage end immutable QwtPackage <: PlottingPackage end immutable UnicodePlotsPackage <: PlottingPackage end immutable WinstonPackage <: PlottingPackage end +immutable BokehPackage <: PlottingPackage end typealias GadflyOrImmerse @compat(Union{GadflyPackage, ImmersePackage}) @@ -14,7 +15,8 @@ export immerse, pyplot, qwt, - unicodeplots + unicodeplots, + bokeh # winston gadfly() = backend(:gadfly) @@ -22,6 +24,7 @@ immerse() = backend(:immerse) pyplot() = backend(:pyplot) qwt() = backend(:qwt) unicodeplots() = backend(:unicodeplots) +bokeh() = backend(:bokeh) # winston() = backend(:winston) backend_name(::GadflyPackage) = :gadfly @@ -29,6 +32,7 @@ backend_name(::ImmersePackage) = :immerse backend_name(::PyPlotPackage) = :pyplot backend_name(::UnicodePlotsPackage) = :unicodeplots backend_name(::QwtPackage) = :qwt +backend_name(::BokehPackage) = :bokeh include("backends/supported.jl") @@ -38,6 +42,7 @@ include("backends/unicodeplots.jl") include("backends/pyplot.jl") include("backends/immerse.jl") include("backends/winston.jl") +include("backends/bokeh.jl") # --------------------------------------------------------- @@ -57,7 +62,7 @@ subplot!(pkg::PlottingPackage, subplt::Subplot; kw...) = error("subplot!($pkg, s # --------------------------------------------------------- -const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse] +const BACKENDS = [:qwt, :gadfly, :unicodeplots, :pyplot, :immerse, :bokeh] const INITIALIZED_BACKENDS = Set{Symbol}() backends() = BACKENDS @@ -69,6 +74,7 @@ function backendInstance(sym::Symbol) sym == :pyplot && return PyPlotPackage() sym == :immerse && return ImmersePackage() sym == :winston && return WinstonPackage() + sym == :bokeh && return BokehPackage() error("Unsupported backend $sym") end @@ -107,6 +113,11 @@ function pickDefaultBackend() return CurrentBackend(:unicodeplots) end end + try + if Pkg.installed("Bokeh") != nothing + return CurrentBackend(:bokeh) + end + end try if Pkg.installed("Winston") != nothing return CurrentBackend(:winston) @@ -115,8 +126,6 @@ function pickDefaultBackend() warn("You don't have any of the supported backends installed! Chose from ", backends()) return CurrentBackend(:gadfly) end -# const CURRENT_BACKEND = pickDefaultBackend() -# println("[Plots.jl] Default backend: ", CURRENT_BACKEND.sym) # --------------------------------------------------------- @@ -125,7 +134,6 @@ end Returns the current plotting package name. Initializes package on first call. """ function backend() - # error() currentBackendSymbol = CURRENT_BACKEND.sym if !(currentBackendSymbol in INITIALIZED_BACKENDS) @@ -199,6 +207,15 @@ function backend() rethrow(err) end + elseif currentBackendSymbol == :bokeh + try + @eval import Bokeh + @eval export Bokeh + catch err + warn("Couldn't import Bokeh. Install it with: Pkg.add(\"Bokeh\").") + rethrow(err) + end + elseif currentBackendSymbol == :winston warn("Winston support is deprecated and broken. Try another backend: $BACKENDS") try @@ -243,6 +260,8 @@ function backend(modname) CURRENT_BACKEND.pkg = ImmersePackage() elseif modname == :winston CURRENT_BACKEND.pkg = WinstonPackage() + elseif modname == :bokeh + CURRENT_BACKEND.pkg = BokehPackage() else error("Unknown backend $modname. Choose from: $BACKENDS") end diff --git a/src/utils.jl b/src/utils.jl index 37a153d2..d13c0bec 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -283,8 +283,8 @@ end debugshow(x) = show(x) debugshow(x::AbstractArray) = print(summary(x)) -function dumpdict(d::Dict, prefix = "") - _debugMode.on || return +function dumpdict(d::Dict, prefix = "", alwaysshow = false) + _debugMode.on || alwaysshow || return println() if prefix != "" println(prefix, ":")