From cf9b60660dcbcb1a7b1d50f013b442a1629c7302 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 12 May 2016 14:51:53 -0400 Subject: [PATCH] working on recipes overhaul --- src/args.jl | 2 +- src/backends/pyplot.jl | 1 + src/plot.jl | 4 +- src/series_new.jl | 314 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 309 insertions(+), 12 deletions(-) diff --git a/src/args.jl b/src/args.jl index 65ebe192..f13d4398 100644 --- a/src/args.jl +++ b/src/args.jl @@ -746,7 +746,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::KW, d_out::KW, k::Symbol, idx::Int, defaults::KW) - if haskey(d_in, k) && !(typeof(d_in[k]) <: Union{AbstractArray, Tuple} && isempty(d_in[k])) + if haskey(d_in, k) && !(typeof(d_in[k]) <: Union{AbstractMatrix, Tuple} && isempty(d_in[k])) d_out[k] = getArgValue(d_in[k], idx) else d_out[k] = defaults[k] diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 8e68e678..661f649a 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -338,6 +338,7 @@ end function fix_xy_lengths!(plt::Plot{PyPlotBackend}, d::KW) x, y = d[:x], d[:y] + @show x, y nx, ny = length(x), length(y) if !isa(get(d, :z, nothing), Surface) && nx != ny if nx < ny diff --git a/src/plot.jl b/src/plot.jl index a82d0f57..99dadf16 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -96,7 +96,7 @@ function _plot!(plt::Plot, d::KW, args...) # finished (no more args) get added to the kw_list, and the rest go into the queue # for processing. kw_list = KW[] - still_to_process = [RecipeData(copy(d), args)] + still_to_process = isempty(args) ? [] : [RecipeData(copy(d), args)] while !isempty(still_to_process) next_series = pop!(still_to_process) series_list = RecipesBase.apply_recipe(next_series.d, next_series.args...) @@ -167,7 +167,9 @@ function _plot!(plt::Plot, d::KW, args...) # merge!(plt.plotargs, plotarg_overrides) # end + dumpdict(kw, "before add defaults", true) _add_defaults!(kw, plt, i) + dumpdict(kw, "after add defaults", true) # getSeriesArgs(plt.backend, getplotargs(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n) _replace_linewidth(kw) diff --git a/src/series_new.jl b/src/series_new.jl index 2aeb0f0e..e4f44cf5 100644 --- a/src/series_new.jl +++ b/src/series_new.jl @@ -100,6 +100,7 @@ end else convertToAnyVector(fr, d) end + mf = length(fillranges) mx = length(xs) my = length(ys) @@ -109,6 +110,11 @@ end # add a new series di = copy(d) di[:x], di[:y], di[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]) + + # handle fillrange + fr = fillranges[mod1(i,mf)] + d[:fillrange] = isa(fr, Function) ? map(fr, di[:x]) : fr + @show i, di[:x], di[:y], di[:z] push!(series_list, RecipeData(di, ())) end @@ -118,16 +124,304 @@ end @recipe f(x, y) = x, y, nothing @recipe f(y) = nothing, y, nothing -# @recipe function f{Y<:Number}(y::AVec{Y}) -# x --> 1:length(y) -# y --> y -# dumpdict(d,"y",true) -# () + +# # -------------------------------------------------------------------- +# # 1 argument +# # -------------------------------------------------------------------- +# +# function process_inputs(plt::AbstractPlot, d::KW, n::Integer) +# # d[:x], d[:y], d[:z] = zeros(0), zeros(0), zeros(0) +# d[:x] = d[:y] = d[:z] = n +# end + +@recipe f(n::Integer) = n, n, n + +# +# # 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 + +# return a surface if this is a 3d plot, otherwise let it be sliced up +@recipe function f{T<:Number}(mat::AMat{T}) + if all3D(d) + n,m = size(mat) + 1:n, 1:m, Surface(mat) + else + nothing, nothing, mat + end +end + + +# +# # images - grays +# function process_inputs{T<:Gray}(plt::AbstractPlot, d::KW, mat::AMat{T}) +# d[:linetype] = :image +# n,m = size(mat) +# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat) +# # handle images... when not supported natively, do a hack to use heatmap machinery +# if !nativeImagesSupported() +# d[:linetype] = :heatmap +# d[:yflip] = true +# d[:z] = Surface(convert(Matrix{Float64}, mat.surf)) +# d[:fillcolor] = ColorGradient([:black, :white]) +# end +# end + +# TODO + +# +# # images - colors +# function process_inputs{T<:Colorant}(plt::AbstractPlot, d::KW, mat::AMat{T}) +# d[:linetype] = :image +# n,m = size(mat) +# d[:x], d[:y], d[:z] = 1:n, 1:m, Surface(mat) +# # handle images... when not supported natively, do a hack to use heatmap machinery +# if !nativeImagesSupported() +# d[:yflip] = true +# imageHack(d) +# end # end # -# @recipe function f{X<:Number,Y<:Number}(x::AVec{X}, y::AVec{Y}) -# x --> x -# y --> y -# dumpdict(d,"xy",true) -# () + +# TODO + +# +# # plotting arbitrary shapes/polygons +# function process_inputs(plt::AbstractPlot, d::KW, shape::Shape) +# d[:x], d[:y] = shape_coords(shape) +# d[:linetype] = :shape # end + +# TODO + +# function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape}) +# d[:x], d[:y] = shape_coords(shapes) +# d[:linetype] = :shape +# end + +# TODO + +# 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 + +# TODO + +# +# +# # 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 + +# TODO + +# +# # -------------------------------------------------------------------- +# # 2 arguments +# # -------------------------------------------------------------------- +# +# +# # 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 + +# TODO + +# +# # -------------------------------------------------------------------- +# # 3 arguments +# # -------------------------------------------------------------------- +# +# +# # 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 +# 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 +# end + +# TODO + +# +# # surface-like... function +# function process_inputs{TX,TY}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zf::Function) +# x = TX <: Number ? sort(x) : x +# y = TY <: Number ? sort(y) : y +# # 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 + +# TODO + +# +# # surface-like... matrix grid +# function process_inputs{TX,TY,TZ}(plt::AbstractPlot, d::KW, x::AVec{TX}, y::AVec{TY}, zmat::AMat{TZ}) +# # @assert size(zmat) == (length(x), length(y)) +# # if TX <: Number && !issorted(x) +# # idx = sortperm(x) +# # x, zmat = x[idx], zmat[idx, :] +# # end +# # if TY <: Number && !issorted(y) +# # idx = sortperm(y) +# # y, zmat = y[idx], zmat[:, idx] +# # end +# d[:x], d[:y], d[:z] = x, y, Surface{Matrix{TZ}}(zmat) +# if !like_surface(get(d, :linetype, :none)) +# d[:linetype] = :contour +# end +# end + +# TODO + +# +# # 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 + +# TODO: maybe change this logic... we should check is3d?? + +# +# +# # -------------------------------------------------------------------- +# # 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 + +# TODO + +# +# # 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)) + +# TODO + +# +# # 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)) + +# TODO + +# +# +# # -------------------------------------------------------------------- +# # 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 + +# TODO + +# +# # (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 + +# TODO + +# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2}) +# process_inputs(plt, d, [xy[1]], [xy[2]]) +# end + +# TODO + +# +# # (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 + +# TODO + +# +# # 2D FixedSizeArrays +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}}) +# process_inputs(plt, d, unzip(xy)...) +# end + +# TODO + +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T}) +# process_inputs(plt, d, [xy[1]], [xy[2]]) +# end + +# TODO + +# +# # 3D FixedSizeArrays +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}}) +# process_inputs(plt, d, unzip(xyz)...) +# end + +# TODO + +# 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 + +# TODO + +# +# # -------------------------------------------------------------------- +# # 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) +# # 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 +# # end + +# TODO