groupby overhaul
This commit is contained in:
parent
2ab0dc20d7
commit
a0df6bfc12
155
src/plot.jl
155
src/plot.jl
@ -78,25 +78,140 @@ function plot!(plt::Plot, args...; kw...)
|
||||
args = _apply_recipe(d, args...; kw...)
|
||||
|
||||
dumpdict(d, "After plot! preprocessing")
|
||||
# @show groupargs map(typeof, args)
|
||||
|
||||
warnOnUnsupportedArgs(plt.backend, d)
|
||||
|
||||
# just in case the backend needs to set up the plot (make it current or something)
|
||||
_before_add_series(plt)
|
||||
|
||||
# grouping
|
||||
groupargs = get(d, :group, nothing) == nothing ? [nothing] : [extractGroupArgs(d[:group], args...)]
|
||||
# @show groupargs
|
||||
# # grouping
|
||||
# groupargs = get(d, :group, nothing) == nothing ? [nothing] : [extractGroupArgs(d[:group], args...)]
|
||||
# # @show groupargs
|
||||
|
||||
# TODO: get the GroupBy object (or nothing), and loop through the groups, doing the following section many times
|
||||
# dumpdict(d, "before", true)
|
||||
groupby = if haskey(d, :group)
|
||||
extractGroupArgs(d[:group], args...)
|
||||
else
|
||||
nothing
|
||||
end
|
||||
# dumpdict(d, "after", true)
|
||||
# @show groupby map(typeof, args)
|
||||
|
||||
_add_series(plt, d, groupby, args...)
|
||||
|
||||
#
|
||||
# # get the list of dictionaries, one per series
|
||||
# @show groupargs map(typeof, args)
|
||||
# dumpdict(d, "before process_inputs")
|
||||
# process_inputs(plt, d, groupargs..., args...)
|
||||
# dumpdict(d, "after process_inputs", true)
|
||||
# seriesArgList, xmeta, ymeta = build_series_args(plt, d)
|
||||
# # seriesArgList, xmeta, ymeta = build_series_args(plt, groupargs..., args...; d...)
|
||||
#
|
||||
# # if we were able to extract guide information from the series inputs, then update the plot
|
||||
# # @show xmeta, ymeta
|
||||
# updateDictWithMeta(d, plt.plotargs, xmeta, true)
|
||||
# updateDictWithMeta(d, plt.plotargs, ymeta, false)
|
||||
#
|
||||
# # now we can plot the series
|
||||
# for (i,di) in enumerate(seriesArgList)
|
||||
# plt.n += 1
|
||||
#
|
||||
# if !stringsSupported()
|
||||
# setTicksFromStringVector(d, di, :x, :xticks)
|
||||
# setTicksFromStringVector(d, di, :y, :yticks)
|
||||
# end
|
||||
#
|
||||
# # remove plot args
|
||||
# for k in keys(_plotDefaults)
|
||||
# delete!(di, k)
|
||||
# end
|
||||
#
|
||||
# dumpdict(di, "Series $i")
|
||||
#
|
||||
# _add_series(plt.backend, plt; di...)
|
||||
# end
|
||||
|
||||
_add_annotations(plt, d)
|
||||
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.plotargs, d)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
|
||||
_update_plot_pos_size(plt, d)
|
||||
|
||||
current(plt)
|
||||
|
||||
# NOTE: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
# # do we want to show it?
|
||||
if haskey(d, :show) && d[:show]
|
||||
gui()
|
||||
end
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
# handle the grouping
|
||||
function _add_series(plt::Plot, d::KW, groupby::GroupBy, args...)
|
||||
# error("ERRORRRRRRRR")
|
||||
|
||||
starting_n = plt.n
|
||||
for (i, glab) in enumerate(groupby.groupLabels)
|
||||
tmpd = copy(d)
|
||||
# d[:numUncounted] = i - 1
|
||||
tmpd[:numUncounted] = plt.n - starting_n
|
||||
_add_series(plt, tmpd, nothing, args...;
|
||||
idxfilter = groupby.groupIds[i],
|
||||
grouplabel = string(glab))
|
||||
end
|
||||
|
||||
# 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
|
||||
|
||||
filter_data(v::AVec, idxfilter::AVec{Int}) = v[idxfilter]
|
||||
filter_data(v, idxfilter) = v
|
||||
|
||||
# no grouping
|
||||
function _add_series(plt::Plot, d::KW, ::Void, args...;
|
||||
idxfilter = nothing,
|
||||
grouplabel = "")
|
||||
|
||||
# get the list of dictionaries, one per series
|
||||
@show groupargs map(typeof, args)
|
||||
dumpdict(d, "before process_inputs")
|
||||
process_inputs(plt, d, groupargs..., args...)
|
||||
dumpdict(d, "after process_inputs", true)
|
||||
seriesArgList, xmeta, ymeta = build_series_args(plt, d)
|
||||
process_inputs(plt, d, args...)
|
||||
dumpdict(d, "after process_inputs")
|
||||
|
||||
if idxfilter != nothing
|
||||
# add the group name as the label if there isn't one passed in
|
||||
get!(d, :label, grouplabel)
|
||||
|
||||
# filter the data
|
||||
for sym in (:x, :y, :z)
|
||||
# @show "before" sym, d[sym], idxfilter
|
||||
d[sym] = filter_data(get(d, sym, nothing), idxfilter)
|
||||
# @show "after" sym, d[sym], idxfilter
|
||||
end
|
||||
end
|
||||
|
||||
seriesArgList, xmeta, ymeta = build_series_args(plt, d) #, idxfilter)
|
||||
# seriesArgList, xmeta, ymeta = build_series_args(plt, groupargs..., args...; d...)
|
||||
|
||||
# if we were able to extract guide information from the series inputs, then update the plot
|
||||
@ -122,32 +237,6 @@ function plot!(plt::Plot, args...; kw...)
|
||||
|
||||
_add_series(plt.backend, plt; di...)
|
||||
end
|
||||
|
||||
# TODO: this is the end of the groupby loop
|
||||
|
||||
_add_annotations(plt, d)
|
||||
|
||||
warnOnUnsupportedScales(plt.backend, d)
|
||||
|
||||
|
||||
# add title, axis labels, ticks, etc
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.plotargs, d)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
|
||||
_update_plot_pos_size(plt, d)
|
||||
|
||||
current(plt)
|
||||
|
||||
# NOTE: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
# # do we want to show it?
|
||||
if haskey(d, :show) && d[:show]
|
||||
gui()
|
||||
end
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@ -91,7 +91,7 @@ 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)
|
||||
function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter)
|
||||
x, y, z = map(a -> pop!(kw, a, nothing), (:x, :y, :z))
|
||||
if nothing == x == y == z
|
||||
return [], nothing, nothing
|
||||
@ -101,6 +101,18 @@ function build_series_args(plt::AbstractPlot, kw::KW)
|
||||
ys, ymeta = convertToAnyVector(y, kw)
|
||||
zs, zmeta = convertToAnyVector(z, kw)
|
||||
|
||||
# if idxfilter != nothing
|
||||
# xs = filter_data(xs, idxfilter)
|
||||
# ys = filter_data(ys, idxfilter)
|
||||
# zs = filter_data(zs, idxfilter)
|
||||
# # # filter the data
|
||||
# # for sym in (:x, :y, :z)
|
||||
# # @show "before" sym, d[sym], idxfilter
|
||||
# # d[sym] = filter_data(get(d, sym, nothing), idxfilter)
|
||||
# # @show "after" sym, d[sym], idxfilter
|
||||
# # end
|
||||
# end
|
||||
|
||||
mx = length(xs)
|
||||
my = length(ys)
|
||||
mz = length(zs)
|
||||
@ -119,15 +131,17 @@ function build_series_args(plt::AbstractPlot, kw::KW)
|
||||
|
||||
# build the series arg dict
|
||||
numUncounted = pop!(d, :numUncounted, 0)
|
||||
n = plt.n + i + numUncounted
|
||||
commandIndex = i + numUncounted
|
||||
n = plt.n + i
|
||||
|
||||
dumpdict(d, "before getSeriesArgs")
|
||||
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, i + numUncounted, convertSeriesIndex(plt, n), n)
|
||||
# @show numUncounted i n commandIndex convertSeriesIndex(plt, n)
|
||||
d = getSeriesArgs(plt.backend, getplotargs(plt, n), d, commandIndex, convertSeriesIndex(plt, n), n)
|
||||
dumpdict(d, "after getSeriesArgs")
|
||||
|
||||
@show map(typeof, (xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]))
|
||||
# @show map(typeof, (xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)]))
|
||||
d[:x], d[:y], d[:z] = compute_xyz(xs[mod1(i,mx)], ys[mod1(i,my)], zs[mod1(i,mz)])
|
||||
@show map(typeof, (d[:x], d[:y], d[:z]))
|
||||
# @show map(typeof, (d[:x], d[:y], d[:z]))
|
||||
|
||||
|
||||
# # NOTE: this should be handled by the time it gets here
|
||||
@ -140,11 +154,11 @@ function build_series_args(plt::AbstractPlot, kw::KW)
|
||||
# end
|
||||
# end
|
||||
|
||||
if haskey(d, :idxfilter)
|
||||
idxfilter = pop!(d, :idxfilter)
|
||||
d[:x] = d[:x][idxfilter]
|
||||
d[:y] = d[:y][idxfilter]
|
||||
end
|
||||
# if haskey(d, :idxfilter)
|
||||
# idxfilter = pop!(d, :idxfilter)
|
||||
# d[:x] = d[:x][idxfilter]
|
||||
# d[:y] = d[:y][idxfilter]
|
||||
# end
|
||||
|
||||
# for linetype `line`, need to sort by x values
|
||||
if lt == :line
|
||||
@ -164,7 +178,7 @@ function build_series_args(plt::AbstractPlot, kw::KW)
|
||||
end
|
||||
|
||||
# cleanup those fields that were used only for generating kw args
|
||||
delete!(d, :dataframe)
|
||||
# delete!(d, :dataframe)
|
||||
# for k in (:idxfilter, :numUncounted, :dataframe)
|
||||
# delete!(d, k)
|
||||
# end
|
||||
@ -370,19 +384,19 @@ 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
|
||||
# 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.
|
||||
@ -391,9 +405,12 @@ end
|
||||
function setup_dataframes()
|
||||
@require DataFrames begin
|
||||
|
||||
get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg]
|
||||
get_data(df::DataFrames.AbstractDataFrame, arg) = arg
|
||||
|
||||
function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...)
|
||||
d[:dataframe] = df
|
||||
process_inputs(plt, d, args...)
|
||||
# d[:dataframe] = df
|
||||
process_inputs(plt, d, map(arg -> get_data(df, arg), args)...)
|
||||
end
|
||||
|
||||
# expecting the column name of a dataframe that was passed in... anything else should error
|
||||
@ -405,15 +422,15 @@ function setup_dataframes()
|
||||
end
|
||||
end
|
||||
|
||||
function getDataFrameFromKW(d::Dict)
|
||||
get(d, :dataframe) do
|
||||
error("Missing dataframe argument!")
|
||||
end
|
||||
end
|
||||
# function getDataFrameFromKW(d::Dict)
|
||||
# get(d, :dataframe) do
|
||||
# error("Missing dataframe argument!")
|
||||
# end
|
||||
# end
|
||||
|
||||
# the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
||||
convertToAnyVector(s::Symbol, d::Dict) = Any[getDataFrameFromKW(d)[s]], s
|
||||
convertToAnyVector(v::AVec{Symbol}, d::Dict) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
# # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
|
||||
# convertToAnyVector(s::Symbol, d::Dict) = Any[getDataFrameFromKW(d)[s]], s
|
||||
# convertToAnyVector(v::AVec{Symbol}, d::Dict) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user