diff --git a/src/Plots.jl b/src/Plots.jl index ce643933..1e4858e7 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -36,6 +36,10 @@ export ohlc, ohlc!, + title!, + xlabel!, + ylabel!, + savepng, backends, @@ -86,12 +90,35 @@ 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) + +title!(plt::Plot, s::AbstractString) = plot!(plt; title = s) +xlabel!(plt::Plot, s::AbstractString) = plot!(plt; xlabel = s) +ylabel!(plt::Plot, s::AbstractString) = plot!(plt; ylabel = s) + + # --------------------------------------------------------- savepng(args...; kw...) = savepng(currentPlot(), args...; kw...) -savepng(plt::PlottingObject, args...; kw...) = savepng(plt.plotter, plt, args...; kw...) -savepng(::PlottingPackage, plt::PlottingObject, fn::AbstractString, args...) = error("unsupported") # fallback so multiple dispatch doesn't get confused if it's missing +savepng(plt::PlottingObject, fn::AbstractString; kw...) = (io = open(fn); writemime(io, MIME"image/png", plt); close(io)) +# savepng(plt::PlottingObject, args...; kw...) = savepng(plt.plotter, plt, args...; kw...) +# savepng(::PlottingPackage, plt::PlottingObject, fn::AbstractString, args...) = error("unsupported") # fallback so multiple dispatch doesn't get confused if it's missing + +# function Base.writemime(io::IO, ::MIME"image/png", plt::Plot) + + +# function Base.writemime(io::IO, ::MIME"text/html", plt::Plot) +# # print(io, "

") +# png = MIME("image/png") +# print(io, "") +# end + + +# override the REPL display +Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::PlottingObject) = display(PlotsDisplay(), plt) function __init__() diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 46156778..8099597d 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -210,24 +210,52 @@ function plot!(::GadflyPackage, plt::Plot; kw...) plt end + +function findGuideAndSet(plt::Plot, t::DataType, s::AbstractString) + for guide in plt.o.guides + if isa(guide, t) + guide.label = s + end + end +end + +function updatePlotItems(::GadflyPackage, plt::Plot, d::Dict) + haskey(d, :title) && findGuideAndSet(plt, Gadfly.Guide.title, d[:title]) + haskey(d, :xlabel) && findGuideAndSet(plt, Gadfly.Guide.xlabel, d[:xlabel]) + haskey(d, :ylabel) && findGuideAndSet(plt, Gadfly.Guide.ylabel, d[:ylabel]) +end + function setGadflyDisplaySize(w,h) Compose.set_default_graphic_size(w * Compose.px, h * Compose.px) end -function Base.display(::GadflyPackage, plt::Plot) +# function Base.display(::GadflyPackage, plt::Plot) +# # function Base.writemime(io::IO, ::MIME") +# setGadflyDisplaySize(plt.initargs[:size]...) +# display(plt.o) +# end + +function Base.display(::PlotsDisplay, plt::Plot{GadflyPackage}) setGadflyDisplaySize(plt.initargs[:size]...) display(plt.o) end # ------------------------------- -function savepng(::GadflyPackage, plt::PlottingObject, fn::AbstractString; - w = plt.initargs[:size][1] * Gadfly.px, # 6 * Gadfly.inch, - h = plt.initargs[:size][2] * Gadfly.px) # 4 * Gadfly.inch) - o = getGadflyContext(plt.plotter, plt) - Gadfly.draw(Gadfly.PNG(fn, w, h), o) -end +# function savepng(::GadflyPackage, plt::PlottingObject, fn::AbstractString; +# w = plt.initargs[:size][1] * Gadfly.px, # 6 * Gadfly.inch, +# h = plt.initargs[:size][2] * Gadfly.px) # 4 * Gadfly.inch) +# o = getGadflyContext(plt.plotter, plt) +# Gadfly.draw(Gadfly.PNG(fn, w, h), o) +# end +function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{GadflyPackage}) + # w = plt.initargs[:size][1] * Gadfly.px, # 6 * Gadfly.inch, + # h = plt.initargs[:size][2] * Gadfly.px) # 4 * Gadfly.inch) + gplt = getGadflyContext(plt.plotter, plt) + setGadflyDisplaySize(plt.initargs[:size]...) + Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) +end # ------------------------------- @@ -246,12 +274,12 @@ function buildGadflySubplotContext(subplt::Subplot) end # create the underlying object (each backend will do this differently) -function buildSubplotObject!(::GadflyPackage, subplt::Subplot) +function buildSubplotObject!(subplt::Subplot{GadflyPackage}) subplt.o = nothing end -function Base.display(::GadflyPackage, subplt::Subplot) +function Base.display(::PlotsDisplay, subplt::Subplot{GadflyPackage}) setGadflyDisplaySize(plt.initargs[:size]...) display(buildGadflySubplotContext(subplt)) end diff --git a/src/backends/immerse.jl b/src/backends/immerse.jl index 7344a56b..1ff505d3 100644 --- a/src/backends/immerse.jl +++ b/src/backends/immerse.jl @@ -75,7 +75,7 @@ end # ------------------------------- -function buildSubplotObject!(::ImmersePackage, subplt::Subplot) +function buildSubplotObject!(subplt::Subplot{ImmersePackage}) # create the Gtk window with vertical box vsep d = subplt.initargs[1] @@ -120,12 +120,6 @@ function buildSubplotObject!(::ImmersePackage, subplt::Subplot) end -# # create the underlying object -# function buildSubplotObject!(::ImmersePackage, subplt::Subplot) -# subplt.o = (nothing, nothing) -# end - - function Base.display(::ImmersePackage, subplt::Subplot) # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 60e768d2..8121039d 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -94,8 +94,7 @@ function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol) # return linetype == :hist ? PyPlot.plt[:hist] : (linetype in (:sticks,:bar) ? PyPlot.bar : (linetype in (:heatmap,:hexbin) ? PyPlot.hexbin : PyPlot.plot)) end -function updateAxisColors(o, fgcolor) - ax = o[:axes][1] +function updateAxisColors(ax, fgcolor) for loc in ("bottom", "top", "left", "right") ax[:spines][loc][:set_color](fgcolor) end @@ -108,6 +107,8 @@ function updateAxisColors(o, fgcolor) ax[:title][:set_color](fgcolor) end +makePlotCurrent(plt::Plot) = PyPlot.figure(plt.o[1].o[:number]) + # ------------------------------------------------------------------ # TODO: @@ -125,13 +126,10 @@ function plot(pkg::PyPlotPackage; kw...) d = Dict(kw) w,h = map(px2inch, d[:size]) bgcolor = getPyPlotColor(d[:background_color]) - o = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96) + fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96) - PyPlot.title(d[:title]) - PyPlot.xlabel(d[:xlabel]) - PyPlot.ylabel(d[:ylabel]) - - plt = Plot(o, pkg, 0, d, Dict[]) + num = fig.o[:number] + plt = Plot((fig, num), pkg, 0, d, Dict[]) plt end @@ -139,6 +137,10 @@ end function plot!(pkg::PyPlotPackage, plt::Plot; kw...) d = Dict(kw) + fig, num = plt.o + # PyPlot.figure(num) # makes this current + makePlotCurrent(plt) + if !(d[:linetype] in supportedTypes(pkg)) error("linetype $(d[:linetype]) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))") end @@ -207,13 +209,21 @@ function plot!(pkg::PyPlotPackage, plt::Plot; kw...) d[:serieshandle] = plotfunc(d[:x], d[:y]; extraargs...)[1] end - # this sets the bg color inside the grid (plt.o.o == matplotlib.Figure) - plt.o.o[:axes][1][:set_axis_bgcolor](getPyPlotColor(plt.initargs[:background_color])) + # this sets the bg color inside the grid + fig.o[:axes][1][:set_axis_bgcolor](getPyPlotColor(plt.initargs[:background_color])) push!(plt.seriesargs, d) plt end + +function updatePlotItems(::PyPlotPackage, plt::Plot, d::Dict) + makePlotCurrent(plt) + haskey(d, :title) && PyPlot.title(d[:title]) + haskey(d, :xlabel) && PyPlot.xlabel(d[:xlabel]) + haskey(d, :ylabel) && PyPlot.ylabel(d[:ylabel]) +end + function addPyPlotLegend(plt::Plot) # add a legend? # try @@ -230,40 +240,34 @@ function addPyPlotLegend(plt::Plot) end function Base.display(::PyPlotPackage, plt::Plot) + fig, num = plt.o + # PyPlot.figure(num) # makes this current + makePlotCurrent(plt) addPyPlotLegend(plt) - updateAxisColors(plt.o.o, getPyPlotColor(plt.initargs[:foreground_color])) - display(plt.o) + ax = fig.o[:axes][1] + updateAxisColors(ax, getPyPlotColor(plt.initargs[:foreground_color])) + display(fig) end # ------------------------------- function savepng(::PyPlotPackage, plt::PlottingObject, fn::AbstractString, args...) + fig, num = plt.o addPyPlotLegend(plt) f = open(fn, "w") - writemime(f, "image/png", plt.o) + writemime(f, "image/png", fig) close(f) end # ------------------------------- # create the underlying object (each backend will do this differently) -function buildSubplotObject!(::PyPlotPackage, subplt::Subplot) - # i = 0 - # rows = [] - # for rowcnt in subplt.layout.rowcounts - # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...)) - # i += rowcnt - # end - # subplt.o = Qwt.vsplitter(rows...) +function buildSubplotObject!(subplt::Subplot{PyPlotPackage}) error("unsupported") end function Base.display(::PyPlotPackage, subplt::Subplot) - # for plt in subplt.plts - # Qwt.refresh(plt.o) - # end - # Qwt.showwidget(subplt.o) display(subplt.o) end diff --git a/src/backends/qwt.jl b/src/backends/qwt.jl index 1d51f7b9..a5f1649f 100644 --- a/src/backends/qwt.jl +++ b/src/backends/qwt.jl @@ -57,6 +57,12 @@ function plot!(::QwtPackage, plt::Plot; kw...) plt end +function updatePlotItems(::QwtPackage, plt::Plot, d::Dict) + haskey(d, :title) && Qwt.title(plt.o, d[:title]) + haskey(d, :xlabel) && Qwt.xlabel(plt.o, d[:xlabel]) + haskey(d, :ylabel) && Qwt.ylabel(plt.o, d[:ylabel]) +end + function Base.display(::QwtPackage, plt::Plot) Qwt.refresh(plt.o) Qwt.showwidget(plt.o) @@ -69,7 +75,7 @@ savepng(::QwtPackage, plt::PlottingObject, fn::AbstractString, args...) = Qwt.sa # ------------------------------- # create the underlying object (each backend will do this differently) -function buildSubplotObject!(::QwtPackage, subplt::Subplot) +function buildSubplotObject!(subplt::Subplot{QwtPackage}) i = 0 rows = [] for rowcnt in subplt.layout.rowcounts diff --git a/src/backends/template.jl b/src/backends/template.jl index 4f4d61fd..794ac94c 100644 --- a/src/backends/template.jl +++ b/src/backends/template.jl @@ -35,24 +35,42 @@ function plot!(::[PkgName]Package, plt::Plot; kw...) end -function Base.display(::[PkgName]Package, plt::Plot) +# TODO: override this to update plot items (title, xlabel, etc) after creation +function updatePlotItems(plt::Plot{[PkgName]Package}, d::Dict) +end + + +# function Base.display(::[PkgName]Package, plt::Plot) +# # TODO: display/show the plot +# end + +function Base.display(::PlotsDisplay, plt::Plot{[PkgName]Package}) # TODO: display/show the plot end + # ------------------------------- -function savepng(::[PkgName]Package, plt::PlottingObject, fn::AbstractString; kw...) - # TODO: save a PNG of the underlying plot/subplot object +# function savepng(::[PkgName]Package, plt::PlottingObject, fn::AbstractString; kw...) +# # TODO: save a PNG of the underlying plot/subplot object +# end + + +function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{[PkgName]Package}) + # TODO: write a png to io end - # ------------------------------- -function buildSubplotObject!(::[PkgName]Package, subplt::Subplot) +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 Base.display(::[PkgName]Package, subplt::Subplot) - # TODO: display/show the Subplot object +# function Base.display(::[PkgName]Package, subplt::Subplot) +# # TODO: display/show the Subplot object +# end + +function Base.display(::PlotsDisplay, plt::Subplot{[PkgName]Package}) + # TODO: display/show the subplot end diff --git a/src/plot.jl b/src/plot.jl index d3c4996f..07e7c6c2 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -93,6 +93,7 @@ function plot!(plt::Plot, args...; kw...) plot!(plt.plotter, plt; d...) end + updatePlotItems(plt.plotter, plt, d) currentPlot!(plt) # NOTE: lets ignore the show param and effectively use the semicolon at the end of the REPL statement @@ -104,10 +105,10 @@ function plot!(plt::Plot, args...; kw...) plt end -# show/update the plot -function Base.display(plt::PlottingObject) - display(plt.plotter, plt) -end +# # show/update the plot +# function Base.display(plt::PlottingObject) +# display(plt.plotter, plt) +# end # -------------------------------------------------------------------- diff --git a/src/plotter.jl b/src/plotter.jl index e86b2037..dcf97b7e 100644 --- a/src/plotter.jl +++ b/src/plotter.jl @@ -13,11 +13,12 @@ include("backends/winston.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") -Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented") +updatePlotItems(pkg::PlottingPackage, plt::Plot, d::Dict) = error("updatePlotItems($pkg, plt, d) is not implemented") +# Base.display(pkg::PlottingPackage, plt::Plot) = error("display($pkg, plt) is not implemented") 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") +# Base.display(pkg::PlottingPackage, subplt::Subplot) = error("display($pkg, subplt) is not implemented") # --------------------------------------------------------- diff --git a/src/subplot.jl b/src/subplot.jl index ca9591c8..8876a5fe 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -132,7 +132,7 @@ function subplot!(subplt::Subplot, args...; kw...) # create the underlying object (each backend will do this differently) if !subplt.initialized - buildSubplotObject!(subplt.plotter, subplt) + buildSubplotObject!(subplt) subplt.initialized = true end diff --git a/src/types.jl b/src/types.jl index ef085251..68002ab4 100644 --- a/src/types.jl +++ b/src/types.jl @@ -2,12 +2,14 @@ typealias AVec AbstractVector typealias AMat AbstractMatrix -abstract PlottingObject +immutable PlotsDisplay <: Display end + abstract PlottingPackage +abstract PlottingObject{T<:PlottingPackage} -type Plot <: PlottingObject +type Plot{T<:PlottingPackage} <: PlottingObject{T} o # the underlying object - plotter::PlottingPackage + plotter::T n::Int # number of series # store these just in case @@ -22,10 +24,10 @@ type SubplotLayout end -type Subplot <: PlottingObject +type Subplot{T<:PlottingPackage} <: PlottingObject{T} o # the underlying object plts::Vector{Plot} # the individual plots - plotter::PlottingPackage + plotter::T p::Int # number of plots n::Int # number of series layout::SubplotLayout