diff --git a/src/Plots.jl b/src/Plots.jl index e62f513e..4da481e2 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -171,7 +171,7 @@ include("backends.jl") include("args.jl") include("themes.jl") include("plot.jl") -# include("series_args.jl") +include("series_args.jl") include("series_new.jl") include("subplot.jl") include("layouts.jl") diff --git a/src/series_args.jl b/src/series_args.jl index b96ffc53..e24a230a 100644 --- a/src/series_args.jl +++ b/src/series_args.jl @@ -97,367 +97,367 @@ compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!") # -------------------------------------------------------------------- -# create n=max(mx,my) series arguments. the shorter list is cycled through -# note: everything should flow through this -function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter) - x, y, z = map(sym -> pop!(kw, sym, nothing), (:x, :y, :z)) - if nothing == x == y == z - return [], nothing, nothing - end - - xs, xmeta = convertToAnyVector(x, kw) - ys, ymeta = convertToAnyVector(y, kw) - zs, zmeta = convertToAnyVector(z, kw) - - fr = pop!(kw, :fillrange, nothing) - fillranges, _ = if typeof(fr) <: Number - ([fr],nothing) - else - convertToAnyVector(fr, kw) - end - - mx = length(xs) - my = length(ys) - mz = length(zs) - ret = Any[] - for i in 1:max(mx, my, mz) - - # try to set labels using ymeta - d = copy(kw) - if !haskey(d, :label) && ymeta != nothing - if isa(ymeta, Symbol) - d[:label] = string(ymeta) - elseif isa(ymeta, AVec{Symbol}) - d[:label] = string(ymeta[mod1(i,length(ymeta))]) - end - end - - # build the series arg dict - numUncounted = pop!(d, :numUncounted, 0) - commandIndex = i + numUncounted - n = plt.n + i - - dumpdict(d, "before getSeriesArgs") - d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n) - dumpdict(d, "after getSeriesArgs") - - d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]) - lt = d[:linetype] - - # for linetype `line`, need to sort by x values - if lt == :line - # order by x - indices = sortperm(d[:x]) - d[:x] = d[:x][indices] - d[:y] = d[:y][indices] - d[:linetype] = :path - end - - # special handling for missing x in box plot... all the same category - if lt == :box && xs[mod1(i,mx)] == nothing - d[:x] = ones(Int, length(d[:y])) - end - - # map functions to vectors - if isa(d[:marker_z], Function) - d[:marker_z] = map(d[:marker_z], d[:x]) - end - - # @show fillranges - d[:fillrange] = fillranges[mod1(i,length(fillranges))] - if isa(d[:fillrange], Function) - d[:fillrange] = map(d[:fillrange], d[:x]) - end - - # handle error bars - for esym in (:xerror, :yerror) - if get(d, esym, nothing) != nothing - # we make a copy of the KW and apply an errorbar recipe - append!(ret, apply_series_recipe(copy(d), Val{esym})) - end - end - - # handle ribbons - if get(d, :ribbon, nothing) != nothing - rib = d[:ribbon] - d[:fillrange] = (d[:y] - rib, d[:y] + rib) - end - - # handle quiver plots - # either a series of velocity vectors are passed in (`:quiver` keyword), - # or we just add arrows to the path - - # if lt == :quiver - # d[:linetype] = lt = :path - # d[:linewidth] = 0 - # end - if get(d, :quiver, nothing) != nothing - append!(ret, apply_series_recipe(copy(d), Val{:quiver})) - elseif lt == :quiver - d[:linetype] = lt = :path - d[:arrow] = arrow() - end - - # now that we've processed a given series... optionally split into - # multiple dicts through a recipe (for example, a box plot is split into component - # parts... polygons, lines, and scatters) - # note: we pass in a Val type (i.e. Val{:box}) so that we can dispatch on the linetype - kwlist = apply_series_recipe(d, Val{lt}) - append!(ret, kwlist) - - # # add it to our series list - # push!(ret, d) - end - - ret, xmeta, ymeta -end - - -# -------------------------------------------------------------------- -# process_inputs -# -------------------------------------------------------------------- - -# These methods take a plot and the keyword arguments, and processes the input -# arguments (x/y/z, group, etc), populating the KW dict with appropriate values. - -# -------------------------------------------------------------------- -# 0 arguments -# -------------------------------------------------------------------- - -# don't do anything -function process_inputs(plt::AbstractPlot, d::KW) -end - -# -------------------------------------------------------------------- -# 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 - -# no special handling... assume x and z are nothing -function process_inputs(plt::AbstractPlot, d::KW, y) - d[:y] = y -end - -# 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 - -# 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 - -# 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 - - -# plotting arbitrary shapes/polygons -function process_inputs(plt::AbstractPlot, d::KW, shape::Shape) - d[:x], d[:y] = shape_coords(shape) - d[:linetype] = :shape -end -function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape}) - d[:x], d[:y] = shape_coords(shapes) - d[:linetype] = :shape -end -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 - - -# 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 - -# -------------------------------------------------------------------- -# 2 arguments -# -------------------------------------------------------------------- - -function process_inputs(plt::AbstractPlot, d::KW, x, y) - d[:x], d[:y] = x, y -end - -# 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 - -# -------------------------------------------------------------------- -# 3 arguments -# -------------------------------------------------------------------- - -# no special handling... just pass them through -function process_inputs(plt::AbstractPlot, d::KW, x, y, z) - d[:x], d[:y], d[:z] = x, y, z -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 - 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 - -# 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 - -# 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 - -# 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 - - -# -------------------------------------------------------------------- -# 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 - -# 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)) - -# 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)) - - -# -------------------------------------------------------------------- -# 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 - -# (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 -function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2}) - process_inputs(plt, d, [xy[1]], [xy[2]]) -end - -# (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 - -# 2D FixedSizeArrays -function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}}) - process_inputs(plt, d, unzip(xy)...) -end -function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T}) - process_inputs(plt, d, [xy[1]], [xy[2]]) -end - -# 3D FixedSizeArrays -function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}}) - process_inputs(plt, d, unzip(xyz)...) -end -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 - -# -------------------------------------------------------------------- -# 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) -# # TODO: don't automatically overwrite labels -# 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) +# # create n=max(mx,my) series arguments. the shorter list is cycled through +# # note: everything should flow through this +# function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter) +# x, y, z = map(sym -> pop!(kw, sym, nothing), (:x, :y, :z)) +# if nothing == x == y == z +# return [], nothing, nothing # end -# ret, nothing, nothing # TODO: handle passing meta through +# +# xs, xmeta = convertToAnyVector(x, kw) +# ys, ymeta = convertToAnyVector(y, kw) +# zs, zmeta = convertToAnyVector(z, kw) +# +# fr = pop!(kw, :fillrange, nothing) +# fillranges, _ = if typeof(fr) <: Number +# ([fr],nothing) +# else +# convertToAnyVector(fr, kw) +# end +# +# mx = length(xs) +# my = length(ys) +# mz = length(zs) +# ret = Any[] +# for i in 1:max(mx, my, mz) +# +# # try to set labels using ymeta +# d = copy(kw) +# if !haskey(d, :label) && ymeta != nothing +# if isa(ymeta, Symbol) +# d[:label] = string(ymeta) +# elseif isa(ymeta, AVec{Symbol}) +# d[:label] = string(ymeta[mod1(i,length(ymeta))]) +# end +# end +# +# # build the series arg dict +# numUncounted = pop!(d, :numUncounted, 0) +# commandIndex = i + numUncounted +# n = plt.n + i +# +# dumpdict(d, "before getSeriesArgs") +# d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n) +# dumpdict(d, "after getSeriesArgs") +# +# d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]) +# lt = d[:linetype] +# +# # for linetype `line`, need to sort by x values +# if lt == :line +# # order by x +# indices = sortperm(d[:x]) +# d[:x] = d[:x][indices] +# d[:y] = d[:y][indices] +# d[:linetype] = :path +# end +# +# # special handling for missing x in box plot... all the same category +# if lt == :box && xs[mod1(i,mx)] == nothing +# d[:x] = ones(Int, length(d[:y])) +# end +# +# # map functions to vectors +# if isa(d[:marker_z], Function) +# d[:marker_z] = map(d[:marker_z], d[:x]) +# end +# +# # @show fillranges +# d[:fillrange] = fillranges[mod1(i,length(fillranges))] +# if isa(d[:fillrange], Function) +# d[:fillrange] = map(d[:fillrange], d[:x]) +# end +# +# # handle error bars +# for esym in (:xerror, :yerror) +# if get(d, esym, nothing) != nothing +# # we make a copy of the KW and apply an errorbar recipe +# append!(ret, apply_series_recipe(copy(d), Val{esym})) +# end +# end +# +# # handle ribbons +# if get(d, :ribbon, nothing) != nothing +# rib = d[:ribbon] +# d[:fillrange] = (d[:y] - rib, d[:y] + rib) +# end +# +# # handle quiver plots +# # either a series of velocity vectors are passed in (`:quiver` keyword), +# # or we just add arrows to the path +# +# # if lt == :quiver +# # d[:linetype] = lt = :path +# # d[:linewidth] = 0 +# # end +# if get(d, :quiver, nothing) != nothing +# append!(ret, apply_series_recipe(copy(d), Val{:quiver})) +# elseif lt == :quiver +# d[:linetype] = lt = :path +# d[:arrow] = arrow() +# end +# +# # now that we've processed a given series... optionally split into +# # multiple dicts through a recipe (for example, a box plot is split into component +# # parts... polygons, lines, and scatters) +# # note: we pass in a Val type (i.e. Val{:box}) so that we can dispatch on the linetype +# kwlist = apply_series_recipe(d, Val{lt}) +# append!(ret, kwlist) +# +# # # add it to our series list +# # push!(ret, d) +# end +# +# ret, xmeta, ymeta # end +# +# +# # -------------------------------------------------------------------- +# # process_inputs +# # -------------------------------------------------------------------- +# +# # These methods take a plot and the keyword arguments, and processes the input +# # arguments (x/y/z, group, etc), populating the KW dict with appropriate values. +# +# # -------------------------------------------------------------------- +# # 0 arguments +# # -------------------------------------------------------------------- +# +# # don't do anything +# function process_inputs(plt::AbstractPlot, d::KW) +# end +# +# # -------------------------------------------------------------------- +# # 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 +# +# # no special handling... assume x and z are nothing +# function process_inputs(plt::AbstractPlot, d::KW, y) +# d[:y] = y +# end +# +# # 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 +# +# # 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 +# +# # 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 +# +# +# # plotting arbitrary shapes/polygons +# function process_inputs(plt::AbstractPlot, d::KW, shape::Shape) +# d[:x], d[:y] = shape_coords(shape) +# d[:linetype] = :shape +# end +# function process_inputs(plt::AbstractPlot, d::KW, shapes::AVec{Shape}) +# d[:x], d[:y] = shape_coords(shapes) +# d[:linetype] = :shape +# end +# 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 +# +# +# # 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 +# +# # -------------------------------------------------------------------- +# # 2 arguments +# # -------------------------------------------------------------------- +# +# function process_inputs(plt::AbstractPlot, d::KW, x, y) +# d[:x], d[:y] = x, y +# end +# +# # 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 +# +# # -------------------------------------------------------------------- +# # 3 arguments +# # -------------------------------------------------------------------- +# +# # no special handling... just pass them through +# function process_inputs(plt::AbstractPlot, d::KW, x, y, z) +# d[:x], d[:y], d[:z] = x, y, z +# 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 +# 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 +# +# # 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 +# +# # 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 +# +# # 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 +# +# +# # -------------------------------------------------------------------- +# # 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 +# +# # 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)) +# +# # 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)) +# +# +# # -------------------------------------------------------------------- +# # 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 +# +# # (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 +# function process_inputs{R1<:Number,R2<:Number}(plt::AbstractPlot, d::KW, xy::Tuple{R1,R2}) +# process_inputs(plt, d, [xy[1]], [xy[2]]) +# end +# +# # (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 +# +# # 2D FixedSizeArrays +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::AVec{FixedSizeArrays.Vec{2,T}}) +# process_inputs(plt, d, unzip(xy)...) +# end +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xy::FixedSizeArrays.Vec{2,T}) +# process_inputs(plt, d, [xy[1]], [xy[2]]) +# end +# +# # 3D FixedSizeArrays +# function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, xyz::AVec{FixedSizeArrays.Vec{3,T}}) +# process_inputs(plt, d, unzip(xyz)...) +# end +# 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 +# +# # -------------------------------------------------------------------- +# # 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) +# # # TODO: don't automatically overwrite labels +# # 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 # TODO: handle passing meta through +# # end # -------------------------------------------------------------------- # For DataFrame support. Imports DataFrames and defines the necessary methods which support them. diff --git a/src/series_new.jl b/src/series_new.jl index 09de7649..2aeb0f0e 100644 --- a/src/series_new.jl +++ b/src/series_new.jl @@ -87,17 +87,47 @@ end # instead of process_inputs: +# the catch-all recipes +@recipe function f(x, y, z) + @show "HERE", typeof((x,y,z)) + xs, _ = convertToAnyVector(x, d) + ys, _ = convertToAnyVector(y, d) + zs, _ = convertToAnyVector(z, d) -@recipe function f{Y<:Number}(y::AVec{Y}) - x --> 1:length(y) - y --> y - dumpdict(d,"y",true) - () + fr = pop!(d, :fillrange, nothing) + fillranges, _ = if typeof(fr) <: Number + ([fr],nothing) + else + convertToAnyVector(fr, d) + end + + mx = length(xs) + my = length(ys) + mz = length(zs) + # ret = Any[] + for i in 1:max(mx, my, mz) + # 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)]) + @show i, di[:x], di[:y], di[:z] + push!(series_list, RecipeData(di, ())) + end + nothing # don't add a series for the main block end -@recipe function f{X<:Number,Y<:Number}(x::AVec{X}, y::AVec{Y}) - x --> x - y --> y - dumpdict(d,"xy",true) - () -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) +# () +# end +# +# @recipe function f{X<:Number,Y<:Number}(x::AVec{X}, y::AVec{Y}) +# x --> x +# y --> y +# dumpdict(d,"xy",true) +# () +# end