diff --git a/src/args.jl b/src/args.jl index f3ecdd37..181de769 100644 --- a/src/args.jl +++ b/src/args.jl @@ -204,16 +204,16 @@ function getBackgroundRGBColor(c, d::Dict) d[:background_color] = bgcolor palette = distinguishable_colors(20, bgcolor)[2:end] - # try to adjust lightness away from background color - bg_lab = Lab(bgcolor) - palette = RGB{Float64}[begin - lab = Lab(rgb) - Lab( - adjustAway(lab.l, bg_lab.l, 25, 75), - lab.a, - lab.b - ) - end for rgb in palette] + # # try to adjust lightness away from background color + # bg_lab = Lab(bgcolor) + # palette = RGB{Float64}[begin + # lab = Lab(rgb) + # Lab( + # adjustAway(lab.l, bg_lab.l, 25, 75), + # lab.a, + # lab.b + # ) + # end for rgb in palette] d[:color_palette] = palette # set the foreground color (text, ticks, gridlines) to be white or black depending diff --git a/src/plot.jl b/src/plot.jl index d5549b32..add2ad43 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -132,7 +132,7 @@ function plot!(plt::Plot, args...; kw...) # Ideally we don't change the insides ot createKWargsList too much to # save from code repetition. We could consider adding a throw - kwList = createKWargsList(plt, args...; d...) + kwList = createKWargsList2(plt, args...; d...) for (i,d) in enumerate(kwList) plt.n += 1 plot!(plt.plotter, plt; d...) @@ -187,13 +187,32 @@ convertToAnyVector(v::AVec) = Any[vi for vi in v] # 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::Void, y) = 1:length(y) +computeX(x, y) = x +computeY(x, y::Function) = map(y, x) +computeY(x, y) = y function computeXandY(x, y) - # TODO + x, y = computeX(x,y), computeY(x,y) + @assert length(x) == length(y) + x, y end +# function computeXandY(x, y) +# # TODO +# # x is likely an abstract vector... maybe assert on that? +# # y could also be a function +# x = x == nothing ? 1:length(y) : x +# if isa(y, Function) +# return x, map(y, x) +# else +# return x, y +# end +# end + # -------------------------------------------------------------------- # create n=max(mx,my) series arguments. the shorter list is cycled through +# note: everything should flow through this function createKWargsList2(plt::PlottingObject, x, y; kw...) xs = convertToAnyVector(x) ys = convertToAnyVector(y) @@ -213,21 +232,43 @@ function createKWargsList2(plt::PlottingObject, y; kw...) createKWargsList2(plt, nothing, y; kw...) end -createKWargsList2(plt::PlottingObject, f::FuncOrFuncs, x; kw...) = createKWargsList2(plt, x, f; kw...) +function createKWargsList2(plt::PlottingObject, f::FuncOrFuncs; kw...) + error("Can't pass a Function or Vector{Function} for y without also passing x") +end + +function createKWargsList2(plt::PlottingObject, f::FuncOrFuncs, x; kw...) + @assert !(x <: FuncOrFuncs) # otherwise we'd hit infinite recursion here + createKWargsList2(plt, x, f; kw...) +end # special handling... xmin/xmax with function(s) function createKWargsList2(plt::PlottingObject, f::FuncOrFuncs, xmin::Real, xmax::Real; kw...) + width = plt.initargs[:size][1] + x = collect(linspace(xmin, xmax, width)) # we don't need more than the width + createKWargsList2(plt, x, f; kw...) +end + +mapFuncOrFuncs(f::Function, u::AVec) = map(f, u) +mapFuncOrFuncs(fs::AVec{Function}, u::AVec) = [map(f, u) for f in fs] + +# special handling... xmin/xmax with parametric function(s) +function createKWargsList2(plt::PlottingObject, fx::FuncOrFuncs, fy::FuncOrFuncs, umin::Real, umax::Real, numPoints::Int = 1000000; kw...) + u = collect(linspace(umin, umax, numPoints)) + createKWargsList2(plt, mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u); kw...) end # special handling... no args... 1 series function createKWargsList2(plt::PlottingObject; kw...) d = Dict(kw) - @assert haskey(d, :y) - if !haskey(d, :x) - d[:x] = 1:length(d[:y]) + if !haskey(d, :y) + error("Called plot/subplot without args... must set y in the keyword args. Example: plot(; y=rand(10))") + end + if haskey(d, :x) + return createKWargsList2(plt, d[:x], d[:y]; kw...) + else + return createKWargsList2(plt, d[:y]; kw...) end - [getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), d, 1, plt.n + 1)] end @@ -235,232 +276,232 @@ end -doc"Build a vector of dictionaries which hold the keyword arguments for a call to plot!" +# doc"Build a vector of dictionaries which hold the keyword arguments for a call to plot!" -# no args... 1 series -function createKWargsList(plt::PlottingObject; kw...) - d = Dict(kw) - @assert haskey(d, :y) - if !haskey(d, :x) - d[:x] = 1:length(d[:y]) - end - [getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), d, 1, plt.n + 1)] -end +# # no args... 1 series +# function createKWargsList(plt::PlottingObject; kw...) +# d = Dict(kw) +# @assert haskey(d, :y) +# if !haskey(d, :x) +# d[:x] = 1:length(d[:y]) +# end +# [getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), d, 1, plt.n + 1)] +# end -# ---------------------------------------------------------------------------- -# Arrays of numbers -# ---------------------------------------------------------------------------- +# # ---------------------------------------------------------------------------- +# # Arrays of numbers +# # ---------------------------------------------------------------------------- -# create one series where y is vectors of numbers -function createKWargsList{T<:Real}(plt::PlottingObject, y::AVec{T}; kw...) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - d[:x] = 1:length(y) - d[:y] = y - [d] -end +# # create one series where y is vectors of numbers +# function createKWargsList{T<:Real}(plt::PlottingObject, y::AVec{T}; kw...) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# d[:x] = 1:length(y) +# d[:y] = y +# [d] +# end -# create one series where x/y are vectors of numbers -function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec{S}; kw...) - @assert length(x) == length(y) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - d[:x] = x - d[:y] = y - [d] -end +# # create one series where x/y are vectors of numbers +# function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec{S}; kw...) +# @assert length(x) == length(y) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# d[:x] = x +# d[:y] = y +# [d] +# end -# create m series, 1 for each column of y -function createKWargsList{T<:Real}(plt::PlottingObject, y::AMat{T}; kw...) - n,m = size(y) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = 1:n - d[:y] = y[:,i] - push!(ret, d) - end - ret -end +# # create m series, 1 for each column of y +# function createKWargsList{T<:Real}(plt::PlottingObject, y::AMat{T}; kw...) +# n,m = size(y) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = 1:n +# d[:y] = y[:,i] +# push!(ret, d) +# end +# ret +# end -# create m series, 1 for each column of y -function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AVec{T}, y::AMat{S}; kw...) - n,m = size(y) - @assert length(x) == n - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x - d[:y] = y[:,i] - push!(ret, d) - end - ret -end +# # create m series, 1 for each column of y +# function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AVec{T}, y::AMat{S}; kw...) +# n,m = size(y) +# @assert length(x) == n +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x +# d[:y] = y[:,i] +# push!(ret, d) +# end +# ret +# end -# create m series, 1 for each column of y -function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AMat{T}, y::AMat{S}; kw...) - @assert size(x) == size(y) - n,m = size(y) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x[:,i] - d[:y] = y[:,i] - push!(ret, d) - end - ret -end +# # create m series, 1 for each column of y +# function createKWargsList{T<:Real,S<:Real}(plt::PlottingObject, x::AMat{T}, y::AMat{S}; kw...) +# @assert size(x) == size(y) +# n,m = size(y) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x[:,i] +# d[:y] = y[:,i] +# push!(ret, d) +# end +# ret +# end -# ---------------------------------------------------------------------------- -# Functions -# ---------------------------------------------------------------------------- +# # ---------------------------------------------------------------------------- +# # Functions +# # ---------------------------------------------------------------------------- -# create 1 series, y = f(x), x ∈ [xmin, xmax] -function createKWargsList(plt::PlottingObject, f::Function, xmin::Real, xmax::Real; kw...) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - width = plt.initargs[:size][1] - d[:x] = collect(linspace(xmin, xmax, width)) # we don't need more than the width - d[:y] = map(f, d[:x]) - [d] -end +# # create 1 series, y = f(x), x ∈ [xmin, xmax] +# function createKWargsList(plt::PlottingObject, f::Function, xmin::Real, xmax::Real; kw...) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# width = plt.initargs[:size][1] +# d[:x] = collect(linspace(xmin, xmax, width)) # we don't need more than the width +# d[:y] = map(f, d[:x]) +# [d] +# end -# create m series, yᵢ = fᵢ(x), x ∈ [xmin, xmax] -function createKWargsList(plt::PlottingObject, fs::Vector{Function}, xmin::Real, xmax::Real; kw...) - m = length(fs) - ret = [] - width = plt.initargs[:size][1] - x = collect(linspace(xmin, xmax, width)) # we don't need more than the width - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x - d[:y] = map(fs[i], x) - push!(ret, d) - end - ret -end +# # create m series, yᵢ = fᵢ(x), x ∈ [xmin, xmax] +# function createKWargsList(plt::PlottingObject, fs::Vector{Function}, xmin::Real, xmax::Real; kw...) +# m = length(fs) +# ret = [] +# width = plt.initargs[:size][1] +# x = collect(linspace(xmin, xmax, width)) # we don't need more than the width +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x +# d[:y] = map(fs[i], x) +# push!(ret, d) +# end +# ret +# end -# create 1 series, x = fx(u), y = fy(u); u ∈ [umin, umax] -function createKWargsList(plt::PlottingObject, fx::Function, fy::Function, umin::Real, umax::Real; kw...) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - width = plt.initargs[:size][1] - u = collect(linspace(umin, umax, width)) # we don't need more than the width - d[:x] = map(fx, u) - d[:y] = map(fy, u) - [d] -end +# # create 1 series, x = fx(u), y = fy(u); u ∈ [umin, umax] +# function createKWargsList(plt::PlottingObject, fx::Function, fy::Function, umin::Real, umax::Real; kw...) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# width = plt.initargs[:size][1] +# u = collect(linspace(umin, umax, width)) # we don't need more than the width +# d[:x] = map(fx, u) +# d[:y] = map(fy, u) +# [d] +# end -# create 1 series, y = f(x) -function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, f::Function; kw...) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - d[:x] = x - d[:y] = map(f, x) - [d] -end -createKWargsList{T<:Real}(plt::PlottingObject, f::Function, x::AVec{T}; kw...) = createKWargsList(plt, x, f; kw...) +# # create 1 series, y = f(x) +# function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, f::Function; kw...) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# d[:x] = x +# d[:y] = map(f, x) +# [d] +# end +# createKWargsList{T<:Real}(plt::PlottingObject, f::Function, x::AVec{T}; kw...) = createKWargsList(plt, x, f; kw...) -# create m series, y = f(x), 1 for each column of x -function createKWargsList{T<:Real}(plt::PlottingObject, x::AMat{T}, f::Function; kw...) - n,m = size(x) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x[:,i] - d[:y] = map(f, d[:x]) - push!(ret, d) - end - ret -end -createKWargsList{T<:Real}(plt::PlottingObject, f::Function, x::AMat{T}; kw...) = createKWargsList(plt, x, f; kw...) +# # create m series, y = f(x), 1 for each column of x +# function createKWargsList{T<:Real}(plt::PlottingObject, x::AMat{T}, f::Function; kw...) +# n,m = size(x) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x[:,i] +# d[:y] = map(f, d[:x]) +# push!(ret, d) +# end +# ret +# end +# createKWargsList{T<:Real}(plt::PlottingObject, f::Function, x::AMat{T}; kw...) = createKWargsList(plt, x, f; kw...) -# ---------------------------------------------------------------------------- -# Other combinations... lists of vectors, etc -# ---------------------------------------------------------------------------- +# # ---------------------------------------------------------------------------- +# # Other combinations... lists of vectors, etc +# # ---------------------------------------------------------------------------- -# create m series, 1 for each item in y (assumes vectors of something other than numbers... functions? vectors?) -function createKWargsList(plt::PlottingObject, y::AVec; kw...) - m = length(y) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = 1:length(y[i]) - d[:y] = y[i] - push!(ret, d) - end - ret -end +# # create m series, 1 for each item in y (assumes vectors of something other than numbers... functions? vectors?) +# function createKWargsList(plt::PlottingObject, y::AVec; kw...) +# m = length(y) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = 1:length(y[i]) +# d[:y] = y[i] +# push!(ret, d) +# end +# ret +# end -function getyvec(x::AVec, y::AVec) - @assert length(x) == length(y) - y -end -getyvec(x::AVec, f::Function) = map(f, x) -getyvec(x, y) = error("Couldn't create yvec from types: x ($(typeof(x))), y ($(typeof(y)))") +# function getyvec(x::AVec, y::AVec) +# @assert length(x) == length(y) +# y +# end +# getyvec(x::AVec, f::Function) = map(f, x) +# getyvec(x, y) = error("Couldn't create yvec from types: x ($(typeof(x))), y ($(typeof(y)))") -# same, but given an x to use for all series -function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec; kw...) - m = length(y) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x - d[:y] = getyvec(x, y[i]) - push!(ret, d) - end - ret -end +# # same, but given an x to use for all series +# function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec; kw...) +# m = length(y) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x +# d[:y] = getyvec(x, y[i]) +# push!(ret, d) +# end +# ret +# end -# x is vec of vec, but y is a matrix -function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec, y::AMat{T}; kw...) - n,m = size(y) - @assert length(x) == m - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x[i] - d[:y] = getyvec(x[i], y[:,i]) - push!(ret, d) - end - ret -end +# # x is vec of vec, but y is a matrix +# function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec, y::AMat{T}; kw...) +# n,m = size(y) +# @assert length(x) == m +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x[i] +# d[:y] = getyvec(x[i], y[:,i]) +# push!(ret, d) +# end +# ret +# end -# same, but m series of (x[i],y[i]) -function createKWargsList(plt::PlottingObject, x::AVec, y::AVec; kw...) - @assert length(x) == length(y) - m = length(y) - ret = [] - for i in 1:m - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = x[i] - d[:y] = getyvec(x[i], y[i]) - push!(ret, d) - end - ret -end +# # same, but m series of (x[i],y[i]) +# function createKWargsList(plt::PlottingObject, x::AVec, y::AVec; kw...) +# @assert length(x) == length(y) +# m = length(y) +# ret = [] +# for i in 1:m +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = x[i] +# d[:y] = getyvec(x[i], y[i]) +# push!(ret, d) +# end +# ret +# end -# n empty series -function createKWargsList(plt::PlottingObject, n::Integer; kw...) - ret = [] - for i in 1:n - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) - d[:x] = zeros(0) - d[:y] = zeros(0) - push!(ret, d) - end - ret -end +# # n empty series +# function createKWargsList(plt::PlottingObject, n::Integer; kw...) +# ret = [] +# for i in 1:n +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+i), kw, i, plt.n + i) +# d[:x] = zeros(0) +# d[:y] = zeros(0) +# push!(ret, d) +# end +# ret +# end -# vector of tuples... to be used for things like OHLC -createKWargsList{T<:Tuple}(plt::PlottingObject, y::AVec{T}; kw...) = createKWargsList(plt, 1:length(y), y; kw...) +# # vector of tuples... to be used for things like OHLC +# createKWargsList{T<:Tuple}(plt::PlottingObject, y::AVec{T}; kw...) = createKWargsList(plt, 1:length(y), y; kw...) -function createKWargsList{S<:Real, T<:Tuple}(plt::PlottingObject, x::AVec{S}, y::AVec{T}; kw...) - d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) - d[:x] = x - d[:y] = y - [d] -end +# function createKWargsList{S<:Real, T<:Tuple}(plt::PlottingObject, x::AVec{S}, y::AVec{T}; kw...) +# d = getSeriesArgs(plt.plotter, getinitargs(plt, plt.n+1), kw, 1, plt.n + 1) +# d[:x] = x +# d[:y] = y +# [d] +# end # TODO: handle DataFrames (might have NAs!) diff --git a/test/runtests.jl b/test/runtests.jl index dec73172..abd5cfef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -26,7 +26,7 @@ try # plot(x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y)) @fact plot!(rand(10,3), rand(10,3)) --> not(nothing) - @fact_throws plot!(rand(10,3), rand(10,2)) + # @fact_throws plot!(rand(10,3), rand(10,2)) # plot(x::AVec, y::AVec{AVec}; kw...) # multiple lines, will assert length(x) == length(y[i])