From 60ce3c5b5f5090a49b92a4f2f089cdfcf6eca475 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 11 Sep 2015 12:16:25 -0400 Subject: [PATCH] working on plot/args reorg --- src/Plots.jl | 5 +- src/args.jl | 13 +-- src/plot.jl | 232 +++++++++++++++++++++++++++++++++---------------- src/subplot.jl | 27 ++++++ 4 files changed, 193 insertions(+), 84 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index 17a42758..dc9aea9a 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -31,6 +31,7 @@ export typealias AVec AbstractVector typealias AMat AbstractMatrix +abstract PlottingObject abstract PlottingPackage const IMG_DIR = Pkg.dir("Plots") * "/img/" @@ -38,7 +39,7 @@ const IMG_DIR = Pkg.dir("Plots") * "/img/" # --------------------------------------------------------- -type Plot +type Plot <: PlottingObject o # the underlying object plotter::PlottingPackage n::Int # number of series @@ -48,6 +49,7 @@ Base.string(plt::Plot) = "Plot{$(plt.plotter) n=$(plt.n)}" Base.print(io::IO, plt::Plot) = print(io, string(plt)) Base.show(io::IO, plt::Plot) = print(io, string(plt)) +getplot(plt::Plot, args...) = plt # --------------------------------------------------------- @@ -77,6 +79,7 @@ include("plotter.jl") include("utils.jl") include("args.jl") include("plot.jl") +include("subplot.jl") # const LINE_TYPES = (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hist, :bar) diff --git a/src/args.jl b/src/args.jl index 06592a51..41f1a39d 100644 --- a/src/args.jl +++ b/src/args.jl @@ -82,14 +82,15 @@ function getRGBColor(c, n::Int = 0) end -function getPlotKeywordArgs(kw, i::Int, plt = nothing) +# note: i is the index of this series within this call, n is the index of the series from all calls to plot/subplot +function getPlotKeywordArgs(kw, i::Int, n::Int) d = Dict(kw) outd = Dict() # default to a white background, but only on the initial call (so we don't change the background automatically) if haskey(d, :background_color) outd[:background_color] = getRGBColor(d[:background_color]) - elseif plt == nothing + elseif n == 0 d[:background_color] = colorant"white" end @@ -106,18 +107,18 @@ function getPlotKeywordArgs(kw, i::Int, plt = nothing) end # once the plot is created, we can get line/marker colors - if plt != nothing + if n > 0 # update color - outd[:color] = getRGBColor(outd[:color], plt.n) + outd[:color] = getRGBColor(outd[:color], n) # update markercolor mc = outd[:markercolor] - mc = (mc == :match ? outd[:color] : getRGBColor(mc, plt.n)) + mc = (mc == :match ? outd[:color] : getRGBColor(mc, n)) outd[:markercolor] = mc # set label label = outd[:label] - outd[:label] = string(label == "AUTO" ? "y_$i" : label, outd[:axis] == :left ? "" : " (R)") + outd[:label] = string(label == "AUTO" ? "y_$n" : label, outd[:axis] == :left ? "" : " (R)") end outd diff --git a/src/plot.jl b/src/plot.jl index 4eb1cc96..dd066939 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -63,7 +63,7 @@ When plotting multiple lines, you can give every line the same trait by using th # this creates a new plot with args/kw and sets it to be the current plot function plot(args...; kw...) - plt = plot(plotter(); getPlotKeywordArgs(kw, 1)...) # create a new, blank plot + plt = plot(plotter(); getPlotKeywordArgs(kw, 1, 0)...) # create a new, blank plot plot!(plt, args...; kw...) # add to it end @@ -99,107 +99,185 @@ end # ------------------------- -# These methods are various ways to add to an existing plot -function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, y::AVec{T}; kw...) - plt.n += 1 - plot!(pkg, plt; x = 1:length(y), y = y, getPlotKeywordArgs(kw, 1, plt)...) + +doc"Build a vector of dictionaries which hold the keyword arguments for a call to plot!" + +# create one series where y is vectors of numbers +function createKWargsList{T<:Real}(plt::PlottingObject, y::AVec{T}; kw...) + d = getPlotKeywordArgs(kw, 1, plt.n + 1) + d[:x] = 1:length(y) + d[:y] = y + [d] end -function plot!{T<:Real,S<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec{S}; kw...) # one line (will assert length(x) == length(y)) +# 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) - plt.n += 1 - plot!(pkg, plt; x=x, y=y, getPlotKeywordArgs(kw, 1, plt)...) + d = getPlotKeywordArgs(kw, 1, plt.n + 1) + d[:x] = x + d[:y] = y + [d] end -function plot!(pkg::PlottingPackage, plt::Plot, y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1) +# create m series, 1 for each column of y +function createKWargsList(plt::PlottingObject, y::AMat; kw...) n,m = size(y) + ret = [] for i in 1:m + d = getPlotKeywordArgs(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(plt::PlottingObject, x::AVec, y::AMat; kw...) +end + +# create m series, 1 for each column of y +function createKWargsList(plt::PlottingObject, x::AMat, y::AMat; kw...) +end + +# create 1 series, y = f(x) +function createKWargsList(plt::PlottingObject, x::AVec, f::Function; kw...) +end + +# create m series, y = f(x), 1 for each column of x +function createKWargsList(plt::PlottingObject, x::AMat, f::Function; kw...) +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...) +end + +# same, but given an x to use for all series +function createKWargsList{T<:Real}(plt::PlottingObject, x::AVec{T}, y::AVec; kw...) +end + +# same, but m series of (x[i],y[i]) +function createKWargsList(plt::PlottingObject, x::AVec, y::AVec; kw...) +end + +# n empty series +function createKWargsList(plt::PlottingObject, n::Integer; kw...) +end + + +function plot!(pkg::PlottingPackage, plt::Plot, args...; kw...) + kwList = createKWargsList(plt, args...; kw...) + for (i,d) in enumerate(kwList) plt.n += 1 - plot!(pkg, plt; x = 1:n, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) + plot!(pkg, plt; d...) end plt end -function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1)) - n,m = size(y) - for i in 1:m - @assert length(x) == n - plt.n += 1 - plot!(pkg, plt; x = x, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) - end - plt -end +# ------------------------- -function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y)) - @assert size(x) == size(y) - for i in 1:size(x,2) - plt.n += 1 - plot!(pkg, plt; x = x[:,i], y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) - end - plt -end +# # These methods are various ways to add to an existing plot -function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, f::Function; kw...) # one line, y = f(x) - plt.n += 1 - plot!(pkg, plt; x = x, y = map(f,x), getPlotKeywordArgs(kw, 1, plt)...) -end +# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, y::AVec{T}; kw...) +# plt.n += 1 +# # plot!(pkg, plt; x = 1:length(y), y = y, getPlotKeywordArgs(kw, 1, plt)...) +# end -function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ) - for i in 1:size(x,2) - xi = x[:,i] - plt.n += 1 - plot!(pkg, plt; x = xi, y = map(f, xi), getPlotKeywordArgs(kw, i, plt)...) - end - plt -end +# function plot!{T<:Real,S<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec{S}; kw...) # one line (will assert length(x) == length(y)) +# @assert length(x) == length(y) +# plt.n += 1 +# plot!(pkg, plt; x=x, y=y, getPlotKeywordArgs(kw, 1, plt)...) +# end -# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ) -# for i in 1:length(fs) +# function plot!(pkg::PlottingPackage, plt::Plot, y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1) +# n,m = size(y) +# for i in 1:m # plt.n += 1 -# plot!(pkg, plt; x = x, y = map(fs[i], x), getPlotKeywordArgs(kw, i, plt)...) +# plot!(pkg, plt; x = 1:n, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) # end # plt # end -function plot!(pkg::PlottingPackage, plt::Plot, y::AVec; kw...) # multiple lines, each with x = 1:length(y[i]) - for i in 1:length(y) - plt.n += 1 - plot!(pkg, plt; x = 1:length(y[i]), y = y[i], getPlotKeywordArgs(kw, i, plt)...) - end - plt -end +# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1)) +# n,m = size(y) +# for i in 1:m +# @assert length(x) == n +# plt.n += 1 +# plot!(pkg, plt; x = x, y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) +# end +# plt +# end -function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec; kw...) # multiple lines, will assert length(x) == length(y[i]) - for i in 1:length(y) - if typeof(y[i]) <: AbstractVector - @assert length(x) == length(y[i]) - plt.n += 1 - plot!(pkg, plt; x = x, y = y[i], getPlotKeywordArgs(kw, i, plt)...) - elseif typeof(y[i]) == Function - plt.n += 1 - plot!(pkg, plt; x = x, y = map(y[i], x), getPlotKeywordArgs(kw, 1, plt)...) - end - end - plt -end +# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y)) +# @assert size(x) == size(y) +# for i in 1:size(x,2) +# plt.n += 1 +# plot!(pkg, plt; x = x[:,i], y = y[:,i], getPlotKeywordArgs(kw, i, plt)...) +# end +# plt +# end -function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec; kw...) # multiple lines, will assert length(x[i]) == length(y[i]) - @assert length(x) == length(y) - for i in 1:length(x) - @assert length(x[i]) == length(y[i]) - plt.n += 1 - plot!(pkg, plt; x = x[i], y = y[i], getPlotKeywordArgs(kw, i, plt)...) - end - plt -end +# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, f::Function; kw...) # one line, y = f(x) +# plt.n += 1 +# plot!(pkg, plt; x = x, y = map(f,x), getPlotKeywordArgs(kw, 1, plt)...) +# end -function plot!(pkg::PlottingPackage, plt::Plot, n::Integer; kw...) # n lines, all empty (for updating plots) - for i in 1:n - plt.n += 1 - plot(pkg, plt, x = zeros(0), y = zeros(0), getPlotKeywordArgs(kw, i, plt)...) - end -end +# function plot!(pkg::PlottingPackage, plt::Plot, x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ) +# for i in 1:size(x,2) +# xi = x[:,i] +# plt.n += 1 +# plot!(pkg, plt; x = xi, y = map(f, xi), getPlotKeywordArgs(kw, i, plt)...) +# end +# plt +# end + +# # function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ) +# # for i in 1:length(fs) +# # plt.n += 1 +# # plot!(pkg, plt; x = x, y = map(fs[i], x), getPlotKeywordArgs(kw, i, plt)...) +# # end +# # plt +# # end + +# function plot!(pkg::PlottingPackage, plt::Plot, y::AVec; kw...) # multiple lines, each with x = 1:length(y[i]) +# for i in 1:length(y) +# plt.n += 1 +# plot!(pkg, plt; x = 1:length(y[i]), y = y[i], getPlotKeywordArgs(kw, i, plt)...) +# end +# plt +# end + +# function plot!{T<:Real}(pkg::PlottingPackage, plt::Plot, x::AVec{T}, y::AVec; kw...) # multiple lines, will assert length(x) == length(y[i]) +# for i in 1:length(y) +# if typeof(y[i]) <: AbstractVector +# @assert length(x) == length(y[i]) +# plt.n += 1 +# plot!(pkg, plt; x = x, y = y[i], getPlotKeywordArgs(kw, i, plt)...) +# elseif typeof(y[i]) == Function +# plt.n += 1 +# plot!(pkg, plt; x = x, y = map(y[i], x), getPlotKeywordArgs(kw, 1, plt)...) +# end +# end +# plt +# end + +# function plot!(pkg::PlottingPackage, plt::Plot, x::AVec, y::AVec; kw...) # multiple lines, will assert length(x[i]) == length(y[i]) +# @assert length(x) == length(y) +# for i in 1:length(x) +# @assert length(x[i]) == length(y[i]) +# plt.n += 1 +# plot!(pkg, plt; x = x[i], y = y[i], getPlotKeywordArgs(kw, i, plt)...) +# end +# plt +# end + +# function plot!(pkg::PlottingPackage, plt::Plot, n::Integer; kw...) # n lines, all empty (for updating plots) +# for i in 1:n +# plt.n += 1 +# plot(pkg, plt, x = zeros(0), y = zeros(0), getPlotKeywordArgs(kw, i, plt)...) +# end +# end # ------------------------- diff --git a/src/subplot.jl b/src/subplot.jl index e69de29b..d7040849 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -0,0 +1,27 @@ + +doc""" +y = rand(100,3) +subplot(y; layout=(2,2), kw...) # creates 3 lines going into 3 separate plots, laid out on a 2x2 grid (last row is filled with plot #3) +subplot(y; layout=(1,3), kw...) # again 3 plots, all in the same row +subplot(y; layout=[1,[2,3]]) # pass a nested Array to fully specify the layout. here the first plot will take up the first row, + # and the others will share the second row +""" +type SubPlot <: PlottingObject + plts::Vector{Plot} # the underlying object + plotter::PlottingPackage + p::Int # number of plots + n::Int # number of series +end + +Base.string(subplt::SubPlot) = "SubPlot{$(subplt.plotter) p=$(subplt.p) n=$(subplt.n)}" +Base.print(io::IO, subplt::SubPlot) = print(io, string(subplt)) +Base.show(io::IO, subplt::SubPlot) = print(io, string(subplt)) + +getplot(subplt::SubPlot, i::Int) = subplt.plts[mod1(i, subplt.p)] + +# ------------------------------------------------------------ + + +function subplot(args...; ) +end +