recipes overhaul; is_installed and dataframes logic; removed requires
This commit is contained in:
parent
88be655dca
commit
5005d32afd
@ -6,7 +6,7 @@ module Plots
|
||||
using Compat
|
||||
using Reexport
|
||||
@reexport using Colors
|
||||
using Requires
|
||||
# using Requires
|
||||
using FixedSizeArrays
|
||||
@reexport using RecipesBase
|
||||
|
||||
@ -171,7 +171,8 @@ include("backends.jl")
|
||||
include("args.jl")
|
||||
include("themes.jl")
|
||||
include("plot.jl")
|
||||
include("series_args.jl")
|
||||
# include("series_args.jl")
|
||||
include("series_new.jl")
|
||||
include("subplot.jl")
|
||||
include("layouts.jl")
|
||||
include("recipes.jl")
|
||||
@ -279,10 +280,11 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
setup_dataframes()
|
||||
|
||||
function __init__()
|
||||
setup_ijulia()
|
||||
setup_dataframes()
|
||||
# setup_dataframes()
|
||||
setup_atom()
|
||||
end
|
||||
|
||||
|
||||
81
src/plot.jl
81
src/plot.jl
@ -45,16 +45,13 @@ When you pass in matrices, it splits by columns. See the documentation for more
|
||||
function plot(args...; kw...)
|
||||
pkg = backend()
|
||||
d = KW(kw)
|
||||
userargs = preprocessArgs!(d)
|
||||
dumpdict(d, "After plot preprocessing")
|
||||
preprocessArgs!(d)
|
||||
|
||||
plotargs = merge(d, getPlotArgs(pkg, d, 1))
|
||||
dumpdict(plotargs, "Plot args")
|
||||
plt = _create_plot(pkg, plotargs) # create a new, blank plot
|
||||
|
||||
# now update the plot
|
||||
_plot!(plt, d, userargs, args...)
|
||||
# plot!(plt, args...; kw...) # add to it
|
||||
_plot!(plt, d, args...)
|
||||
end
|
||||
|
||||
|
||||
@ -73,15 +70,15 @@ end
|
||||
# this adds to a specific plot... most plot commands will flow through here
|
||||
function plot!(plt::Plot, args...; kw...)
|
||||
d = KW(kw)
|
||||
userargs = preprocessArgs!(d)
|
||||
_plot!(plt, d, userargs, args...)
|
||||
preprocessArgs!(d)
|
||||
_plot!(plt, d, args...)
|
||||
end
|
||||
|
||||
|
||||
# this is the core plotting function. recursively apply recipes to build
|
||||
# a list of series KW dicts.
|
||||
# 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)
|
||||
_before_add_series(plt)
|
||||
|
||||
@ -93,7 +90,24 @@ function _plot!(plt::Plot, d::KW, userargs::KW, args...)
|
||||
end
|
||||
|
||||
# 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")
|
||||
|
||||
@ -110,32 +124,63 @@ function _plot!(plt::Plot, d::KW, userargs::KW, args...)
|
||||
# nothing
|
||||
# end
|
||||
|
||||
# TODO: why do i need to check for the subplot key?
|
||||
|
||||
# merge plot args
|
||||
if !haskey(d, :subplot)
|
||||
# merge the plot args from the recipes, then update the plot colors
|
||||
for k in keys(_plotDefaults)
|
||||
if haskey(d, k)
|
||||
plt.plotargs[k] = d[k]
|
||||
for kw in kw_list
|
||||
if haskey(kw, k)
|
||||
plt.plotargs[k] = kw[k]
|
||||
end
|
||||
end
|
||||
end
|
||||
# merge!(plt.plotargs, d)
|
||||
handlePlotColors(plt.backend, plt.plotargs)
|
||||
end
|
||||
|
||||
_add_series(plt, d, args...)
|
||||
_add_annotations(plt, d)
|
||||
# _add_series(plt, d, args...)
|
||||
|
||||
# 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
|
||||
if !haskey(d, :subplot)
|
||||
merge!(plt.plotargs, d)
|
||||
# handlePlotColors(plt.backend, plt.plotargs)
|
||||
dumpdict(plt.plotargs, "Updating plot items")
|
||||
# merge!(plt.plotargs, d) # this shouldn't be needed since we merged the keys earlier
|
||||
_update_plot(plt, plt.plotargs)
|
||||
end
|
||||
|
||||
_update_plot_pos_size(plt, d)
|
||||
|
||||
# _update_plot_pos_size(plt, d) # this is only used for Qwt... can we remove?
|
||||
current(plt)
|
||||
|
||||
# note: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
|
||||
@ -28,6 +28,53 @@ function RecipesBase.apply_recipe(d::KW, kw::KW, args...; issubplot=false)
|
||||
args
|
||||
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)
|
||||
# esc(:(get!(d, $k, $v)))
|
||||
# end
|
||||
|
||||
@ -463,78 +463,78 @@ end
|
||||
# For DataFrame support. Imports DataFrames and defines the necessary methods which support them.
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
function setup_dataframes()
|
||||
@require DataFrames begin
|
||||
# @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 plot(df::DataFrames.AbstractDataFrame, sy::DFS)
|
||||
handle_group(df, d)
|
||||
handle_dfs(df, d, "y", sy)
|
||||
end
|
||||
|
||||
@recipe function plot(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 plot(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
|
||||
|
||||
# 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, map(arg -> get_data(df, arg), args)...)
|
||||
# end
|
||||
#
|
||||
# # expecting the column name of a dataframe that was passed in... anything else should error
|
||||
# function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
||||
# if haskey(df, s)
|
||||
# return extractGroupArgs(df[s])
|
||||
# else
|
||||
# error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
|
||||
# end
|
||||
# end
|
||||
|
||||
# function getDataFrameFromKW(d::KW)
|
||||
# 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::KW) = Any[getDataFrameFromKW(d)[s]], s
|
||||
# convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
|
||||
end
|
||||
end
|
||||
# function setup_dataframes()
|
||||
# @require DataFrames begin
|
||||
# # @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 plot(df::DataFrames.AbstractDataFrame, sy::DFS)
|
||||
# handle_group(df, d)
|
||||
# handle_dfs(df, d, "y", sy)
|
||||
# end
|
||||
#
|
||||
# @recipe function plot(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 plot(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
|
||||
#
|
||||
# # 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, map(arg -> get_data(df, arg), args)...)
|
||||
# # end
|
||||
# #
|
||||
# # # expecting the column name of a dataframe that was passed in... anything else should error
|
||||
# # function extractGroupArgs(s::Symbol, df::DataFrames.AbstractDataFrame, args...)
|
||||
# # if haskey(df, s)
|
||||
# # return extractGroupArgs(df[s])
|
||||
# # else
|
||||
# # error("Got a symbol, and expected that to be a key in d[:dataframe]. s=$s d=$d")
|
||||
# # end
|
||||
# # end
|
||||
#
|
||||
# # function getDataFrameFromKW(d::KW)
|
||||
# # 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::KW) = Any[getDataFrameFromKW(d)[s]], s
|
||||
# # convertToAnyVector(v::AVec{Symbol}, d::KW) = (df = getDataFrameFromKW(d); Any[df[s] for s in v]), v
|
||||
#
|
||||
# end
|
||||
# end
|
||||
|
||||
@ -237,6 +237,14 @@ end
|
||||
isijulia() = isdefined(Main, :IJulia) && Main.IJulia.inited
|
||||
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(::Any) = false
|
||||
isvector(::AVec) = true
|
||||
|
||||
@ -3,7 +3,6 @@ julia 0.4
|
||||
RecipesBase
|
||||
Colors
|
||||
Reexport
|
||||
Requires
|
||||
FactCheck
|
||||
Cairo
|
||||
Gadfly
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user