From 82d2cc943d6cd0ff9f2593de8cb5b55f5c40355d Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 11 Apr 2016 18:19:06 -0400 Subject: [PATCH] working on get/set xy/xyz indexing overhaul --- src/backends/bokeh.jl | 20 +-- src/backends/gadfly.jl | 4 +- src/backends/glvisualize.jl | 4 +- src/backends/gr.jl | 4 +- src/backends/immerse.jl | 4 +- src/backends/pgfplots.jl | 20 +-- src/backends/plotly.jl | 20 +-- src/backends/plotlyjs.jl | 10 +- src/backends/pyplot.jl | 58 +++++---- src/backends/qwt.jl | 4 +- src/backends/template.jl | 16 +-- src/series_args.jl | 5 +- src/utils.jl | 238 +++++++++++++++++++++++------------- 13 files changed, 249 insertions(+), 158 deletions(-) diff --git a/src/backends/bokeh.jl b/src/backends/bokeh.jl index db309f6a..672f24e9 100644 --- a/src/backends/bokeh.jl +++ b/src/backends/bokeh.jl @@ -124,16 +124,16 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{BokehBackend}, i::Int) - series = plt.o.datacolumns[i].data - series[:x], series[:y] -end - -function Base.setindex!(plt::Plot{BokehBackend}, xy::Tuple, i::Integer) - series = plt.o.datacolumns[i].data - series[:x], series[:y] = xy - plt -end +# function getxy(plt::Plot{BokehBackend}, i::Int) +# series = plt.o.datacolumns[i].data +# series[:x], series[:y] +# end +# +# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer) +# series = plt.o.datacolumns[i].data +# series[:x], series[:y] = xy +# plt +# end # ---------------------------------------------------------------- diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 01490e14..df023750 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -560,12 +560,12 @@ function getGadflyMappings(plt::Plot, i::Integer) mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]] end -function Base.getindex(plt::Plot{GadflyBackend}, i::Integer) +function getxy(plt::Plot{GadflyBackend}, i::Integer) mapping = getGadflyMappings(plt, i)[1] mapping[:x], mapping[:y] end -function Base.setindex!(plt::Plot{GadflyBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) for mapping in getGadflyMappings(plt, i) mapping[:x], mapping[:y] = xy end diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl index 61202590..e40ecf59 100644 --- a/src/backends/glvisualize.jl +++ b/src/backends/glvisualize.jl @@ -59,14 +59,14 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{GLVisualizeBackend}, i::Int) +function getxy(plt::Plot{GLVisualizeBackend}, i::Int) # TODO: # series = plt.o.lines[i] # series.x, series.y nothing, nothing end -function Base.setindex!(plt::Plot{GLVisualizeBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{GLVisualizeBackend}, xy::Tuple{X,Y}, i::Integer) # TODO: # series = plt.o.lines[i] # series.x, series.y = xy diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 6fb6101a..9f073864 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -736,12 +736,12 @@ end # ---------------------------------------------------------------- -function Base.getindex(plt::Plot{GRBackend}, i::Int) +function getxy(plt::Plot{GRBackend}, i::Int) d = plt.seriesargs[i] d[:x], d[:y] end -function Base.setindex!(plt::Plot{GRBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{GRBackend}, xy::Tuple{X,Y}, i::Integer) d = plt.seriesargs[i] d[:x], d[:y] = xy plt diff --git a/src/backends/immerse.jl b/src/backends/immerse.jl index da72ebbb..0352534b 100644 --- a/src/backends/immerse.jl +++ b/src/backends/immerse.jl @@ -58,12 +58,12 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{ImmerseBackend}, i::Integer) +function getxy(plt::Plot{ImmerseBackend}, i::Integer) mapping = getGadflyMappings(plt, i)[1] mapping[:x], mapping[:y] end -function Base.setindex!(plt::Plot{ImmerseBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) for mapping in getGadflyMappings(plt, i) mapping[:x], mapping[:y] = xy end diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index 94a12642..b9ddcd03 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -52,16 +52,16 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{PGFPlotsBackend}, i::Int) - d = plt.seriesargs[i] - d[:x], d[:y] -end - -function Base.setindex!(plt::Plot{PGFPlotsBackend}, xy::Tuple, i::Integer) - d = plt.seriesargs[i] - d[:x], d[:y] = xy - plt -end +# function getxy(plt::Plot{PGFPlotsBackend}, i::Int) +# d = plt.seriesargs[i] +# d[:x], d[:y] +# end +# +# function setxy!{X,Y}(plt::Plot{PGFPlotsBackend}, xy::Tuple{X,Y}, i::Integer) +# d = plt.seriesargs[i] +# d[:x], d[:y] = xy +# plt +# end # ---------------------------------------------------------------- diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 0efa2a50..ba38ee77 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -77,16 +77,16 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{PlotlyBackend}, i::Int) - d = plt.seriesargs[i] - d[:x], d[:y] -end - -function Base.setindex!(plt::Plot{PlotlyBackend}, xy::Tuple, i::Integer) - d = plt.seriesargs[i] - d[:x], d[:y] = xy - plt -end +# function getxy(plt::Plot{PlotlyBackend}, i::Int) +# d = plt.seriesargs[i] +# d[:x], d[:y] +# end +# +# function setxy!{X,Y}(plt::Plot{PlotlyBackend}, xy::Tuple{X,Y}, i::Integer) +# d = plt.seriesargs[i] +# d[:x], d[:y] = xy +# plt +# end # ---------------------------------------------------------------- diff --git a/src/backends/plotlyjs.jl b/src/backends/plotlyjs.jl index cf7719c4..4291aa20 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -85,12 +85,12 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{PlotlyJSBackend}, i::Int) - d = plt.seriesargs[i] - d[:x], d[:y] -end +# function getxy(plt::Plot{PlotlyJSBackend}, i::Int) +# d = plt.seriesargs[i] +# d[:x], d[:y] +# end -function Base.setindex!(plt::Plot{PlotlyJSBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{PlotlyJSBackend}, xy::Tuple{X,Y}, 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 diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 2c1793b8..c8ccccbb 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -459,7 +459,7 @@ function _add_series(pkg::PyPlotBackend, plt::Plot; kw...) plotfunc(x, y, z; extra_kwargs...) elseif lt in _3dTypes - plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...) + plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...)[1] elseif lt in (:scatter, :hist2d, :hexbin) plotfunc(d[:x], d[:y]; extra_kwargs...) @@ -507,15 +507,6 @@ end # ----------------------------------------------------------------- -function Base.getindex(plt::Plot{PyPlotBackend}, i::Integer) - series = plt.seriesargs[i][:serieshandle] - try - return series[:get_data]() - catch - xy = series[:get_offsets]() - return vec(xy[:,1]), vec(xy[:,2]) - end -end function minmaxseries(ds, vec, axis) lo, hi = Inf, -Inf @@ -552,23 +543,46 @@ function set_lims!(plt::Plot{PyPlotBackend}, axis::Symbol) end end -function Base.setindex!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer) - d = plt.seriesargs[i] - series = d[:serieshandle] - x, y = xy - d[:x], d[:y] = x, y - try - series[:set_data](x, y) - catch - series[:set_offsets](hcat(x, y)) - end +# -------------------------------------------------------------------------- +# function getxy(plt::Plot{PyPlotBackend}, i::Integer) +# series = plt.seriesargs[i][:serieshandle] +# try +# return series[:get_data]() +# catch +# xy = series[:get_offsets]() +# return vec(xy[:,1]), vec(xy[:,2]) +# end +# end + +function setxy!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer) + d = plt.seriesargs[i] + d[:x], d[:y] = xy + series = d[:serieshandle] + try + series[:set_data](d[:x], d[:y]) + catch + series[:set_offsets](hcat(d[:x], d[:y])) + end set_lims!(plt, d[:axis]) plt end -function Base.setindex!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer) - warn("setindex not implemented for xyz") + +function setxyz!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer) + d = plt.seriesargs[i] + # @show typeof(d), typeof(xyz) + d[:x], d[:y], d[:z] = xyz + series = d[:serieshandle] + # @show keys(series) + # try + series[:set_data](d[:x], d[:y]) + series[:set_3d_properties](d[:z]) + # catch + # series[:set_offsets](hcat(d[:x], d[:y], d[:z])) + # end + set_lims!(plt, d[:axis]) + # dumpdict(d, "H",true) plt end diff --git a/src/backends/qwt.jl b/src/backends/qwt.jl index bbd6a9ba..cc7da44a 100644 --- a/src/backends/qwt.jl +++ b/src/backends/qwt.jl @@ -199,12 +199,12 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{QwtBackend}, i::Int) +function getxy(plt::Plot{QwtBackend}, i::Int) series = plt.o.lines[i] series.x, series.y end -function Base.setindex!(plt::Plot{QwtBackend}, xy::Tuple, i::Integer) +function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) series = plt.o.lines[i] series.x, series.y = xy plt diff --git a/src/backends/template.jl b/src/backends/template.jl index 21c225ca..90870fde 100644 --- a/src/backends/template.jl +++ b/src/backends/template.jl @@ -51,14 +51,14 @@ end # accessors for x/y data -function Base.getindex(plt::Plot{[PkgName]AbstractBackend}, i::Int) - # TODO: return a tuple of (x, y) vectors -end - -function Base.setindex!(plt::Plot{[PkgName]AbstractBackend}, xy::Tuple, i::Integer) - # TODO: set the plot data from the (x,y) tuple - plt -end +# function getxy(plt::Plot{[PkgName]AbstractBackend}, i::Int) +# # TODO: return a tuple of (x, y) vectors +# end +# +# function setxy!{X,Y}(plt::Plot{[PkgName]AbstractBackend}, xy::Tuple{X,Y}, i::Integer) +# # TODO: set the plot data from the (x,y) tuple +# plt +# end # ---------------------------------------------------------------- diff --git a/src/series_args.jl b/src/series_args.jl index 8a8b4098..4a7a1e70 100644 --- a/src/series_args.jl +++ b/src/series_args.jl @@ -279,7 +279,10 @@ 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) + lt = get(d, :linetype, :none) + if lt == :scatter + d[:linetype] = :scatter3d + elseif !(lt in _3dTypes) d[:linetype] = :path3d end d[:x], d[:y], d[:z] = x, y, zvec diff --git a/src/utils.jl b/src/utils.jl index c3aa2288..f5766635 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -114,6 +114,7 @@ function regressionXY(x, y) regx, regy end +# --------------------------------------------------------------- # ------------------------------------------------------------------------------------ @@ -261,6 +262,7 @@ allReals(arg) = trueOrAllTrue(a -> typeof(a) <: Real, arg) allFunctions(arg) = trueOrAllTrue(a -> isa(a, Function), arg) # --------------------------------------------------------------- +# --------------------------------------------------------------- """ @@ -348,6 +350,7 @@ function with(f::Function, args...; kw...) ret end +# --------------------------------------------------------------- # --------------------------------------------------------------- type DebugMode @@ -382,70 +385,7 @@ function dumpcallstack() end # --------------------------------------------------------------- - - -# push/append/clear/set the underlying plot data -# NOTE: backends should implement the getindex and setindex! methods to get/set the x/y data objects - - -# index versions -function Base.push!(plt::Plot, i::Integer, x::Real, y::Real) - xdata, ydata = plt[i] - plt[i] = (extendSeriesData(xdata, x), extendSeriesData(ydata, y)) - plt -end -function Base.push!(plt::Plot, i::Integer, y::Real) - xdata, ydata = plt[i] - # if !isa(xdata, UnitRange) - # error("Expected x is a UnitRange since you're trying to push a y value only. typeof(x) = $(typeof(xdata))") - # end - plt[i] = (extendSeriesByOne(xdata), extendSeriesData(ydata, y)) - plt -end - -Base.push!(plt::Plot, y::Real) = push!(plt, 1, y) - -# update all at once -function Base.push!(plt::Plot, x::AVec, y::AVec) - nx = length(x) - ny = length(y) - for i in 1:plt.n - push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)]) - end - plt -end - -function Base.push!(plt::Plot, x::Real, y::AVec) - push!(plt, [x], y) -end - -function Base.push!(plt::Plot, y::AVec) - ny = length(y) - for i in 1:plt.n - push!(plt, i, y[mod1(i,ny)]) - end - plt -end - - -# append to index -function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec) - @assert length(x) == length(y) - xdata, ydata = plt[i] - plt[i] = (extendSeriesData(xdata, x), extendSeriesData(ydata, y)) - plt -end - -function Base.append!(plt::Plot, i::Integer, y::AVec) - xdata, ydata = plt[i] - if !isa(xdata, UnitRange{Int}) - error("Expected x is a UnitRange since you're trying to push a y value only") - end - plt[i] = (extendSeriesByOne(xdata, length(y)), extendSeriesData(ydata, y)) - plt -end - - +# --------------------------------------------------------------- # used in updating an existing series extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n) @@ -456,24 +396,157 @@ 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) +# ------------------------------------------------------- +# NOTE: backends should implement the following methods to get/set the x/y/z data objects + +tovec(v::AbstractVector) = v +tovec(v::Void) = zeros(0) + +function getxy(plt::Plot, i::Integer) + d = plt.seriesargs[i] + tovec(d[:x]), tovec(d[:y]) +end +function getxyz(plt::Plot, i::Integer) + d = plt.seriesargs[i] + tovec(d[:x]), tovec(d[:y]), tovec(d[:z]) +end + +function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) + d = plt.seriesargs[i] + d[:x], d[:y] = xy +end +function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) + d = plt.seriesargs[i] + d[:x], d[:y], d[:z] = xyz +end + + +# ------------------------------------------------------- +# indexing notation + +Base.getindex(plt::Plot, i::Integer) = getxy(plt, i) +Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = setxy!(plt, xy, i) +Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = setxyz!(plt, xyz, i) + +# ------------------------------------------------------- +# push/append for one series + +# push value to first series +Base.push!(plt::Plot, y::Real) = push!(plt, 1, y) +Base.push!(plt::Plot, x::Real, y::Real) = push!(plt, 1, x, y) +Base.push!(plt::Plot, x::Real, y::Real, z::Real) = push!(plt, 1, x, y, z) + +# y only +function Base.push!(plt::Plot, i::Integer, y::Real) + xdata, ydata = getxy(plt, i) + setxy!(plt, (extendSeriesByOne(xdata), extendSeriesData(ydata, y)), i) + plt +end +function Base.append!(plt::Plot, i::Integer, y::AVec) + xdata, ydata = plt[i] + if !isa(xdata, UnitRange{Int}) + error("Expected x is a UnitRange since you're trying to push a y value only") + end + plt[i] = (extendSeriesByOne(xdata, length(y)), extendSeriesData(ydata, y)) + plt +end + +# x and y +function Base.push!(plt::Plot, i::Integer, x::Real, y::Real) + xdata, ydata = getxy(plt, i) + setxy!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y)), i) + plt +end +function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec) + @assert length(x) == length(y) + xdata, ydata = getxy(plt, i) + setxy!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y)), i) + plt +end + +# x, y, and z +function Base.push!(plt::Plot, i::Integer, x::Real, y::Real, z::Real) + # @show i, x, y, z + xdata, ydata, zdata = getxyz(plt, i) + # @show xdata, ydata, zdata + setxyz!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y), extendSeriesData(zdata, z)), i) + plt +end +function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec, z::AVec) + @assert length(x) == length(y) == length(z) + xdata, ydata, zdata = getxyz(plt, i) + setxyz!(plt, (extendSeriesData(xdata, x), extendSeriesData(ydata, y), extendSeriesData(zdata, z)), i) + plt +end + +# tuples +Base.push!{X,Y}(plt::Plot, xy::Tuple{X,Y}) = push!(plt, 1, xy...) +Base.push!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}) = push!(plt, 1, xyz...) +Base.push!{X,Y}(plt::Plot, i::Integer, xy::Tuple{X,Y}) = push!(plt, i, xy...) +Base.push!{X,Y,Z}(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) = push!(plt, i, xyz...) + +# ------------------------------------------------------- +# push/append for all series + +# push y[i] to the ith series +function Base.push!(plt::Plot, y::AVec) + ny = length(y) + for i in 1:plt.n + push!(plt, i, y[mod1(i,ny)]) + end + plt +end + +# push y[i] to the ith series +# same x for each series +function Base.push!(plt::Plot, x::Real, y::AVec) + push!(plt, [x], y) +end + +# push (x[i], y[i]) to the ith series +function Base.push!(plt::Plot, x::AVec, y::AVec) + nx = length(x) + ny = length(y) + for i in 1:plt.n + push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)]) + end + plt +end + +# push (x[i], y[i], z[i]) to the ith series +function Base.push!(plt::Plot, x::AVec, y::AVec, z::AVec) + nx = length(x) + ny = length(y) + nz = length(z) + for i in 1:plt.n + push!(plt, i, x[mod1(i,nx)], y[mod1(i,ny)], z[mod1(i,nz)]) + end + plt +end + + + + # --------------------------------------------------------------- +# --------------------------------------------------------------- +# graphs detailing the features that each backend supports function supportGraph(allvals, func) - vals = reverse(sort(allvals)) - bs = sort(backends()) - x = ASCIIString[] - y = ASCIIString[] - for val in vals - for b in bs - supported = func(Plots._backend_instance(b)) - if val in supported - push!(x, string(b)) - push!(y, string(val)) + vals = reverse(sort(allvals)) + bs = sort(backends()) + x = ASCIIString[] + y = ASCIIString[] + for val in vals + for b in bs + supported = func(Plots._backend_instance(b)) + if val in supported + push!(x, string(b)) + push!(y, string(val)) + end end - end - end - n = length(vals) - scatter(x, y, m=:rect, ms=10, size=(300,100+18*n), leg=false) + end + n = length(vals) + scatter(x, y, m=:rect, ms=10, size=(300,100+18*n), leg=false) end supportGraphArgs() = supportGraph(_allArgs, supportedArgs) @@ -484,14 +557,15 @@ supportGraphScales() = supportGraph(_allScales, supportedScales) supportGraphAxes() = supportGraph(_allAxes, supportedAxes) function dumpSupportGraphs() - for func in (supportGraphArgs, supportGraphTypes, supportGraphStyles, + for func in (supportGraphArgs, supportGraphTypes, supportGraphStyles, supportGraphMarkers, supportGraphScales, supportGraphAxes) - plt = func() - png(joinpath(Pkg.dir("ExamplePlots"), "docs", "examples", "img", "supported", "$(string(func))")) - end + plt = func() + png(joinpath(Pkg.dir("ExamplePlots"), "docs", "examples", "img", "supported", "$(string(func))")) + end end # --------------------------------------------------------------- +# --------------------------------------------------------------- # Some conversion functions