Skip to content

Commit

Permalink
Merge pull request JuliaPlots#82 from piever/iter
Browse files Browse the repository at this point in the history
WIP: add compatibility to a general table type and remove DataFrames dependency
  • Loading branch information
Pietro Vertechi authored Sep 5, 2017
2 parents 071ca96 + 07518ee commit 0d10166
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 19 deletions.
2 changes: 2 additions & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Distributions
DataFrames
KernelDensity
Loess
IterableTables 0.5.0
TableTraitsUtils 0.1.0
4 changes: 4 additions & 0 deletions src/StatPlots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import Plots: _cycle
using StatsBase
using Distributions
using DataFrames
import IterableTables
import DataValues: DataValue
import TableTraits: column_types, column_names, getiterator, isiterabletable
import TableTraitsUtils: create_columns_from_iterabletable

import KernelDensity
import Loess
Expand Down
56 changes: 37 additions & 19 deletions src/df.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,34 @@ 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 = parse_iterabletable_call!(d, x, syms, vars)
compute_vars = Expr(:(=), Expr(:tuple, vars...),
Expr(:call, :(StatPlots.extract_columns_from_iterabletable), d, syms...))
esc(Expr(:block, compute_vars, plot_call))
end

_df(d, x) = x
parse_iterabletable_call!(d, x, syms, vars) = x

function _df(d, x::Expr)
(x.head == :quote) && return :(StatPlots.select_column($d, $x))
function parse_iterabletable_call!(d, x::Expr, syms, vars)
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, (parse_iterabletable_call!(d, arg, syms, vars) for arg in x.args)...)
end

function _argnames(d, x::Expr)
Expand All @@ -33,7 +49,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
Expand All @@ -45,18 +61,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 extract_columns_from_iterabletable(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)

0 comments on commit 0d10166

Please sign in to comment.