New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add compatibility to a general table type and remove DataFrames dependency #82
Changes from 10 commits
fca39ac
a6201ae
a6fdd7c
64c4a9e
dd23d74
7a02029
f11fd2f
b81027a
51732b9
f5500d8
07518ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,5 @@ Distributions | |
DataFrames | ||
KernelDensity | ||
Loess | ||
IterableTables 0.5.0 | ||
TableTraitsUtils 0.1.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,18 +9,33 @@ If you want to avoid replacing the symbol, escape it with `^`. | |
for strings and symbols respectively. | ||
""" | ||
macro df(d, x) | ||
esc(_df(d,x)) | ||
syms = Any[] | ||
vars = Symbol[] | ||
plot_call = _df(d, x, syms, vars) | ||
compute_vars = Expr(:(=), Expr(:tuple, vars...), Expr(:call, :(StatPlots.compute_all), d, syms...)) | ||
esc(Expr(:block, compute_vars, plot_call)) | ||
end | ||
|
||
_df(d, x) = x | ||
_df(d, x, syms, vars) = x | ||
|
||
function _df(d, x::Expr) | ||
(x.head == :quote) && return :(StatPlots.select_column($d, $x)) | ||
function _df(d, x::Expr, syms, vars) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could the names also be more informative? compute_all seems very broad (should it perhaps be extract_columns_from_table?) and _df a little sparse (parse_table_call or something like that)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good choice of names, I'll just replace |
||
if x.head == :quote | ||
new_var = gensym(x.args[1]) | ||
push!(syms, x) | ||
push!(vars, new_var) | ||
return new_var | ||
end | ||
if x.head == :call | ||
x.args[1] == :^ && length(x.args) == 2 && return x.args[2] | ||
x.args[1] == :cols && return :(hcat((StatPlots.convert_column($d[i]) for i in $(x.args[2]))...)) | ||
if x.args[1] == :cols | ||
range = eval(x.args[2]) | ||
new_vars = gensym.(string.(range)) | ||
append!(syms, range) | ||
append!(vars, new_vars) | ||
return Expr(:hcat, new_vars...) | ||
end | ||
end | ||
return Expr(x.head, _df.(d, x.args)...) | ||
return Expr(x.head, (_df(d, arg, syms, vars) for arg in x.args)...) | ||
end | ||
|
||
function _argnames(d, x::Expr) | ||
|
@@ -33,7 +48,7 @@ not_kw(x::Expr) = !(x.head in [:kw, :parameters]) | |
_arg2string(d, x) = stringify(x) | ||
function _arg2string(d, x::Expr) | ||
if x.head == :call && x.args[1] == :cols | ||
return :(reshape([(DataFrames.names($d)[i]) for i in $(x.args[2])], 1, :)) | ||
return :(reshape([StatPlots.compute_name($d, i) for i in $(x.args[2])], 1, :)) | ||
elseif x.head == :call && x.args[1] == :hcat | ||
return hcat(stringify.(x.args[2:end])...) | ||
elseif x.head == :hcat | ||
|
@@ -45,18 +60,20 @@ end | |
|
||
stringify(x) = filter(t -> t != ':', string(x)) | ||
|
||
select_column(df, s) = haskey(df, s) ? convert_column(df[s]) : s | ||
|
||
convert_column(col) = col | ||
compute_name(df, i) = column_names(getiterator(df))[i] | ||
|
||
function convert_column(col::AbstractDataArray{T}) where T | ||
try | ||
convert(Array, col) | ||
catch | ||
error("Missing data of type $T is not supported") | ||
end | ||
function compute_all(df, syms...) | ||
isiterabletable(df) || error("Only iterable tables are supported") | ||
iter = getiterator(df) | ||
name2index = Dict(zip(column_names(iter), 1:length(column_names(iter)))) | ||
col_index = [isa(s, Integer) ? s : get(name2index, s, 0) for s in syms] | ||
cols = convert(Array{Any}, collect(syms)) | ||
cols[col_index .!= 0] = create_columns_from_iterabletable(df, filter(t -> t != 0, col_index))[1] | ||
return Tuple(convert_missing.(t) for t in cols) | ||
end | ||
|
||
convert_column(col::AbstractDataArray{<:AbstractString}) = convert(Array, col, "") | ||
convert_column(col::AbstractDataArray{Symbol}) = convert(Array, col, Symbol()) | ||
convert_column(col::AbstractDataArray{<:Real}) = convert(Array, convert(DataArray{Float64}, col), NaN) | ||
convert_missing(el) = el | ||
convert_missing(el::DataValue{T}) where {T} = get(el, error("Missing data of type $T is not supported")) | ||
convert_missing(el::DataValue{<:AbstractString}) = get(el, "") | ||
convert_missing(el::DataValue{Symbol}) = get(el, Symbol()) | ||
convert_missing(el::DataValue{<:Real}) = get(convert(DataValue{Float64}, el), NaN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could also import these from IterableTables - wouldn't that be cleaner?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gotta say your macro-fu is pretty on point :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I'd leave it like it is, see my other comments.