recipes overhaul; is_installed and dataframes logic; removed requires

This commit is contained in:
Thomas Breloff 2016-05-11 22:12:51 -04:00
parent 88be655dca
commit 5005d32afd
7 changed files with 198 additions and 98 deletions

View File

@ -4,5 +4,4 @@ RecipesBase
Colors Colors
Reexport Reexport
Compat Compat
Requires
FixedSizeArrays FixedSizeArrays

View File

@ -6,7 +6,7 @@ module Plots
using Compat using Compat
using Reexport using Reexport
@reexport using Colors @reexport using Colors
using Requires # using Requires
using FixedSizeArrays using FixedSizeArrays
@reexport using RecipesBase @reexport using RecipesBase
@ -171,7 +171,8 @@ include("backends.jl")
include("args.jl") include("args.jl")
include("themes.jl") include("themes.jl")
include("plot.jl") include("plot.jl")
include("series_args.jl") # include("series_args.jl")
include("series_new.jl")
include("subplot.jl") include("subplot.jl")
include("layouts.jl") include("layouts.jl")
include("recipes.jl") include("recipes.jl")
@ -279,10 +280,11 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
const CURRENT_BACKEND = CurrentBackend(:none) const CURRENT_BACKEND = CurrentBackend(:none)
setup_dataframes()
function __init__() function __init__()
setup_ijulia() setup_ijulia()
setup_dataframes() # setup_dataframes()
setup_atom() setup_atom()
end end

View File

@ -45,16 +45,13 @@ When you pass in matrices, it splits by columns. See the documentation for more
function plot(args...; kw...) function plot(args...; kw...)
pkg = backend() pkg = backend()
d = KW(kw) d = KW(kw)
userargs = preprocessArgs!(d) preprocessArgs!(d)
dumpdict(d, "After plot preprocessing")
plotargs = merge(d, getPlotArgs(pkg, d, 1)) plotargs = merge(d, getPlotArgs(pkg, d, 1))
dumpdict(plotargs, "Plot args")
plt = _create_plot(pkg, plotargs) # create a new, blank plot plt = _create_plot(pkg, plotargs) # create a new, blank plot
# now update the plot # now update the plot
_plot!(plt, d, userargs, args...) _plot!(plt, d, args...)
# plot!(plt, args...; kw...) # add to it
end end
@ -73,15 +70,15 @@ end
# this adds to a specific plot... most plot commands will flow through here # this adds to a specific plot... most plot commands will flow through here
function plot!(plt::Plot, args...; kw...) function plot!(plt::Plot, args...; kw...)
d = KW(kw) d = KW(kw)
userargs = preprocessArgs!(d) preprocessArgs!(d)
_plot!(plt, d, userargs, args...) _plot!(plt, d, args...)
end end
# this is the core plotting function. recursively apply recipes to build # this is the core plotting function. recursively apply recipes to build
# a list of series KW dicts. # a list of series KW dicts.
# note: at entry, we only have those preprocessed args which were passed in... no default values yet # note: at entry, we only have those preprocessed args which were passed in... no default values yet
function _plot!(plt::Plot, d::KW, userargs::KW, args...) function _plot!(plt::Plot, d::KW, args...)
# just in case the backend needs to set up the plot (make it current or something) # just in case the backend needs to set up the plot (make it current or something)
_before_add_series(plt) _before_add_series(plt)
@ -93,7 +90,24 @@ function _plot!(plt::Plot, d::KW, userargs::KW, args...)
end end
# for plotting recipes, swap out the args and update the parameter dictionary # for plotting recipes, swap out the args and update the parameter dictionary
args = RecipesBase.apply_recipe(d, userargs, args...) # we are keeping a queue of series that still need to be processed.
# each pass through the loop, we pop one off and apply the recipe.
# the recipe will return a list a Series objects... the ones that are
# finished (no more args) get added to the kw_list, and the rest go into the queue
# for processing.
kw_list = KW[]
still_to_process = [RecipesBase.Series(copy(d), args)]
while !isempty(still_to_process)
next_series = pop!(still_to_process)
series_list = RecipesBase.apply_recipe(next_series.d, next_series.args...)
for series in series_list
if isempty(series.args)
push!(kw_list, series.d)
else
push!(still_to_process, series)
end
end
end
# dumpdict(d, "After plot! preprocessing") # dumpdict(d, "After plot! preprocessing")
@ -110,32 +124,63 @@ function _plot!(plt::Plot, d::KW, userargs::KW, args...)
# nothing # nothing
# end # end
# TODO: why do i need to check for the subplot key?
# merge plot args # merge plot args
if !haskey(d, :subplot) if !haskey(d, :subplot)
# merge the plot args from the recipes, then update the plot colors
for k in keys(_plotDefaults) for k in keys(_plotDefaults)
if haskey(d, k) for kw in kw_list
plt.plotargs[k] = d[k] if haskey(kw, k)
plt.plotargs[k] = kw[k]
end
end end
end end
# merge!(plt.plotargs, d) # merge!(plt.plotargs, d)
handlePlotColors(plt.backend, plt.plotargs) handlePlotColors(plt.backend, plt.plotargs)
end end
_add_series(plt, d, args...) # _add_series(plt, d, args...)
_add_annotations(plt, d)
# this is it folks!
for kw in kw_list
plt.n += 1
# TODO: can this be handled as a recipe??
# if !stringsSupported() && di[:linetype] != :pie
# setTicksFromStringVector(plt, d, di, "x")
# setTicksFromStringVector(plt, d, di, "y")
# setTicksFromStringVector(plt, d, di, "z")
# end
# TODO: unnecessary??
# # remove plot args
# for k in keys(_plotDefaults)
# delete!(di, k)
# end
# TODO: why??
# # merge in plotarg_overrides
# plotarg_overrides = pop!(di, :plotarg_overrides, nothing)
# if plotarg_overrides != nothing
# merge!(plt.plotargs, plotarg_overrides)
# end
_replace_linewidth(kw)
_add_series(plt.backend, plt, kw)
end
# _add_annotations(plt, d) # TODO
# add title, axis labels, ticks, etc # add title, axis labels, ticks, etc
if !haskey(d, :subplot) if !haskey(d, :subplot)
merge!(plt.plotargs, d) # merge!(plt.plotargs, d) # this shouldn't be needed since we merged the keys earlier
# handlePlotColors(plt.backend, plt.plotargs)
dumpdict(plt.plotargs, "Updating plot items")
_update_plot(plt, plt.plotargs) _update_plot(plt, plt.plotargs)
end end
_update_plot_pos_size(plt, d) # _update_plot_pos_size(plt, d) # this is only used for Qwt... can we remove?
current(plt) current(plt)
# note: lets ignore the show param and effectively use the semicolon at the end of the REPL statement # note: lets ignore the show param and effectively use the semicolon at the end of the REPL statement

View File

@ -28,6 +28,53 @@ function RecipesBase.apply_recipe(d::KW, kw::KW, args...; issubplot=false)
args args
end end
if is_installed("DataFrames")
@eval begin
import DataFrames
DFS = Union{Symbol, AbstractArray{Symbol}}
function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, dfs::DFS)
if isa(dfs, Symbol)
get!(d, symbol(letter * "label"), string(dfs))
collect(df[dfs])
else
get!(d, :label, reshape(dfs, 1, length(dfs)))
Any[collect(df[s]) for s in dfs]
end
end
function handle_group(df::DataFrames.AbstractDataFrame, d::KW)
if haskey(d, :group)
g = d[:group]
if isa(g, Symbol)
d[:group] = collect(df[g])
end
end
end
@recipe function f(df::DataFrames.AbstractDataFrame, sy::DFS)
handle_group(df, d)
handle_dfs(df, d, "y", sy)
end
@recipe function f(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS)
handle_group(df, d)
x = handle_dfs(df, d, "x", sx)
y = handle_dfs(df, d, "y", sy)
x, y
end
@recipe function f(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS, sz::DFS)
handle_group(df, d)
x = handle_dfs(df, d, "x", sx)
y = handle_dfs(df, d, "y", sy)
z = handle_dfs(df, d, "z", sz)
x, y, z
end
end
end
# macro kw(k, v) # macro kw(k, v)
# esc(:(get!(d, $k, $v))) # esc(:(get!(d, $k, $v)))
# end # end

View File

@ -463,78 +463,78 @@ end
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them. # For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
# -------------------------------------------------------------------- # --------------------------------------------------------------------
function setup_dataframes() # function setup_dataframes()
@require DataFrames begin # @require DataFrames begin
# @eval begin # # @eval begin
# import DataFrames # # import DataFrames
#
DFS = Union{Symbol, AbstractArray{Symbol}} # DFS = Union{Symbol, AbstractArray{Symbol}}
#
function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, dfs::DFS) # function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, dfs::DFS)
if isa(dfs, Symbol) # if isa(dfs, Symbol)
get!(d, symbol(letter * "label"), string(dfs)) # get!(d, symbol(letter * "label"), string(dfs))
collect(df[dfs]) # collect(df[dfs])
else # else
get!(d, :label, reshape(dfs, 1, length(dfs))) # get!(d, :label, reshape(dfs, 1, length(dfs)))
Any[collect(df[s]) for s in dfs] # Any[collect(df[s]) for s in dfs]
end # end
end # end
#
function handle_group(df::DataFrames.AbstractDataFrame, d::KW) # function handle_group(df::DataFrames.AbstractDataFrame, d::KW)
if haskey(d, :group) # if haskey(d, :group)
g = d[:group] # g = d[:group]
if isa(g, Symbol) # if isa(g, Symbol)
d[:group] = collect(df[g]) # d[:group] = collect(df[g])
end # end
end # end
end # end
#
@recipe function plot(df::DataFrames.AbstractDataFrame, sy::DFS) # @recipe function plot(df::DataFrames.AbstractDataFrame, sy::DFS)
handle_group(df, d) # handle_group(df, d)
handle_dfs(df, d, "y", sy) # handle_dfs(df, d, "y", sy)
end # end
#
@recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS) # @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS)
handle_group(df, d) # handle_group(df, d)
x = handle_dfs(df, d, "x", sx) # x = handle_dfs(df, d, "x", sx)
y = handle_dfs(df, d, "y", sy) # y = handle_dfs(df, d, "y", sy)
x, y # x, y
end # end
#
@recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS, sz::DFS) # @recipe function plot(df::DataFrames.AbstractDataFrame, sx::DFS, sy::DFS, sz::DFS)
handle_group(df, d) # handle_group(df, d)
x = handle_dfs(df, d, "x", sx) # x = handle_dfs(df, d, "x", sx)
y = handle_dfs(df, d, "y", sy) # y = handle_dfs(df, d, "y", sy)
z = handle_dfs(df, d, "z", sz) # z = handle_dfs(df, d, "z", sz)
x, y, z # x, y, z
end # end
#
# get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg] # # get_data(df::DataFrames.AbstractDataFrame, arg::Symbol) = df[arg]
# get_data(df::DataFrames.AbstractDataFrame, arg) = arg # # get_data(df::DataFrames.AbstractDataFrame, arg) = arg
# # #
# function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...) # # function process_inputs(plt::AbstractPlot, d::KW, df::DataFrames.AbstractDataFrame, args...)
# # d[:dataframe] = df # # # d[:dataframe] = df
# process_inputs(plt, d, map(arg -> get_data(df, arg), args)...) # # process_inputs(plt, d, map(arg -> get_data(df, arg), args)...)
# end # # end
# # #
# # expecting the column name of a dataframe that was passed in... anything else should error # # # expecting the column name of a dataframe that was passed in... anything else should error
# function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...) # # function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
# if haskey(df, s) # # if haskey(df, s)
# return extractGroupArgs(df[s]) # # return extractGroupArgs(df[s])
# else # # else
# error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d") # # error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
# end # # end
# end # # end
#
# function getDataFrameFromKW(d::KW) # # function getDataFrameFromKW(d::KW)
# get(d, :dataframe) do # # get(d, :dataframe) do
# error("Missing dataframe argument!") # # error("Missing dataframe argument!")
# end # # end
# end # # end
#
# # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes # # # the conversion functions for when we pass symbols or vectors of symbols to reference dataframes
# convertToAnyVector(s::Symbol, d::KW) = Any[getDataFrameFromKW(d)[s]], s # # convertToAnyVector(s::Symbol, d::KW) = Any[getDataFrameFromKW(d)[s]], s
# convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v # # convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
#
end # end
end # end

View File

@ -237,6 +237,14 @@ end
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected() isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
function is_installed(pkgstr::AbstractString)
try
Pkg.installed(pkgstr) === nothing ? false: true
catch
false
end
end
istuple(::Tuple) = true istuple(::Tuple) = true
istuple(::Any) = false istuple(::Any) = false
isvector(::AVec) = true isvector(::AVec) = true

View File

@ -3,7 +3,6 @@ julia 0.4
RecipesBase RecipesBase
Colors Colors
Reexport Reexport
Requires
FactCheck FactCheck
Cairo Cairo
Gadfly Gadfly