diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index e9b3023b..364498d1 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -226,20 +226,36 @@ end function pyplot_figure(plotargs::Dict) w,h = map(px2inch, plotargs[:size]) bgcolor = getPyPlotColor(plotargs[:background_color]) + + # reuse the current figure? fig = if plotargs[:overwrite_figure] PyPlot.gcf() else PyPlot.figure() end + + # update the specs fig[:set_size_inches](w,h,true) fig[:set_facecolor](bgcolor) fig[:set_dpi](DPI) fig[:set_tight_layout](true) + + # clear the figure PyPlot.clf() + + # resize the window PyPlot.plt[:get_current_fig_manager]()[:resize](plotargs[:size]...) fig end +function pyplot_3d_setup!(wrap, d) + # 3D? + # if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper) + if trueOrAllTrue(lt -> lt in _3dTypes, get(d, :linetype, :none)) + push!(wrap.kwargs, (:projection, "3d")) + end +end + # TODO: # fillto # might have to use barHack/histogramHack?? @@ -260,9 +276,10 @@ function _create_plot(pkg::PyPlotPackage; kw...) wrap = PyPlotAxisWrapper(nothing, nothing, pyplot_figure(d), []) # wrap = PyPlotAxisWrapper(nothing, nothing, PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true), []) - if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper) - push!(wrap.kwargs, (:projection, "3d")) - end + # if haskey(d, :linetype) && first(d[:linetype]) in _3dTypes # && isa(plt.o, PyPlotFigWrapper) + # push!(wrap.kwargs, (:projection, "3d")) + # end + pyplot_3d_setup!(wrap, d) end plt = Plot(wrap, pkg, 0, d, Dict[]) @@ -683,7 +700,8 @@ function _create_subplot(subplt::Subplot{PyPlotPackage}, isbefore::Bool) # w,h = map(px2inch, getplotargs(subplt,1)[:size]) # bgcolor = getPyPlotColor(getplotargs(subplt,1)[:background_color]) # fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true) - fig = pyplot_figure(getplotargs(subplt, 1)) + plotargs = getplotargs(subplt, 1) + fig = pyplot_figure(plotargs) nr = nrows(l) for (i,(r,c)) in enumerate(l) @@ -694,10 +712,12 @@ function _create_subplot(subplt::Subplot{PyPlotPackage}, isbefore::Bool) ax = fig[:add_subplot](nr, nc, fakeidx) subplt.plts[i].o = PyPlotAxisWrapper(ax, nothing, fig, []) + pyplot_3d_setup!(subplt.plts[i].o, plotargs) end # subplt.o = PyPlotFigWrapper(fig, []) subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, []) + pyplot_3d_setup!(subplt.o, plotargs) true end diff --git a/src/components.jl b/src/components.jl index 3cc2e7a9..1a24822d 100644 --- a/src/components.jl +++ b/src/components.jl @@ -234,6 +234,11 @@ Surface(f::Function, x, y) = Surface(Float64[f(xi,yi) for xi in x, yi in y]) Base.Array(surf::Surface) = surf.surf +for f in (:length, :size) + @eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...) +end +Base.copy(surf::Surface) = Surface(copy(surf.surf)) + # ----------------------------------------------------------------------- type OHLC{T<:Real} diff --git a/src/plot.jl b/src/plot.jl index 845c54f0..9458444b 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -228,41 +228,49 @@ end typealias FuncOrFuncs @compat(Union{Function, AVec{Function}}) +all3D(d::Dict) = trueOrAllTrue(lt -> lt in (:contour, :surface, :wireframe, :image), get(d, :linetype, :none)) + # missing -convertToAnyVector(v::@compat(Void); kw...) = Any[nothing], nothing +convertToAnyVector(v::@compat(Void), d::Dict) = Any[nothing], nothing # fixed number of blank series -convertToAnyVector(n::Integer; kw...) = Any[zeros(0) for i in 1:n], nothing +convertToAnyVector(n::Integer, d::Dict) = Any[zeros(0) for i in 1:n], nothing # numeric vector -convertToAnyVector{T<:Real}(v::AVec{T}; kw...) = Any[v], nothing +convertToAnyVector{T<:Real}(v::AVec{T}, d::Dict) = Any[v], nothing # string vector -convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}; kw...) = Any[v], nothing +convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::Dict) = Any[v], nothing # numeric matrix -convertToAnyVector{T<:Real}(v::AMat{T}; kw...) = Any[v[:,i] for i in 1:size(v,2)], nothing +function convertToAnyVector{T<:Real}(v::AMat{T}, d::Dict) + if all3D(d) + Any[Surface(v)] + else + Any[v[:,i] for i in 1:size(v,2)] + end, nothing +end # function -convertToAnyVector(f::Function; kw...) = Any[f], nothing +convertToAnyVector(f::Function, d::Dict) = Any[f], nothing # surface -convertToAnyVector(s::Surface; kw...) = Any[s], nothing +convertToAnyVector(s::Surface, d::Dict) = Any[s], nothing # vector of OHLC -convertToAnyVector(v::AVec{OHLC}; kw...) = Any[v], nothing +convertToAnyVector(v::AVec{OHLC}, d::Dict) = Any[v], nothing # dates -convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}; kw...) = Any[dts], nothing +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; kw...) +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)[1] for vi in v]...), nothing + vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing # Any[vi for vi in v], nothing end end @@ -272,7 +280,7 @@ end # in computeXandY, we take in any of the possible items, convert into proper x/y vectors, then return. # this is also where all the "set x to 1:length(y)" happens, and also where we assert on lengths. -computeX(x::@compat(Void), y) = 1:length(y) +computeX(x::@compat(Void), y) = 1:size(y,1) computeX(x, y) = copy(x) computeY(x, y::Function) = map(y, x) computeY(x, y) = copy(y) @@ -291,8 +299,9 @@ end # create n=max(mx,my) series arguments. the shorter list is cycled through # note: everything should flow through this function createKWargsList(plt::PlottingObject, x, y; kw...) - xs, xmeta = convertToAnyVector(x; kw...) - ys, ymeta = convertToAnyVector(y; kw...) + kwdict = Dict(kw) + xs, xmeta = convertToAnyVector(x, kwdict) + ys, ymeta = convertToAnyVector(y, kwdict) mx = length(xs) my = length(ys) @@ -300,7 +309,7 @@ function createKWargsList(plt::PlottingObject, x, y; kw...) for i in 1:max(mx, my) # try to set labels using ymeta - d = Dict(kw) + d = copy(kwdict) if !haskey(d, :label) && ymeta != nothing if isa(ymeta, Symbol) d[:label] = string(ymeta) @@ -317,13 +326,22 @@ function createKWargsList(plt::PlottingObject, x, y; kw...) dumpdict(d, "after getSeriesArgs") d[:x], d[:y] = computeXandY(xs[mod1(i,mx)], ys[mod1(i,my)]) + lt = d[:linetype] + if isa(d[:y], Surface) + if lt in (:contour, :surface, :wireframe, :image) + z = d[:y] + d[:y] = 1:size(z,2) + d[lt == :image ? :zcolor : :z] = z + end + end + if haskey(d, :idxfilter) d[:x] = d[:x][d[:idxfilter]] d[:y] = d[:y][d[:idxfilter]] end # for linetype `line`, need to sort by x values - if d[:linetype] == :line + if lt == :line # order by x indices = sortperm(d[:x]) d[:x] = d[:x][indices] @@ -379,6 +397,16 @@ function createKWargsList(plt::PlottingObject, x::AVec, y::AVec, zvec::AVec; kw. 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 @@ -518,18 +546,22 @@ end end end - function getDataFrameFromKW(; kw...) - for (k,v) in kw - if k == :dataframe - return v - end + function getDataFrameFromKW(d::Dict) + # for (k,v) in kw + # if k == :dataframe + # return v + # end + # end + get(d, :dataframe) do + error("Missing dataframe argument!") end - error("Missing dataframe argument in arguments!") end # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes - 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; 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