diff --git a/src/args.jl b/src/args.jl index 4fe276c1..091634e6 100644 --- a/src/args.jl +++ b/src/args.jl @@ -621,7 +621,17 @@ function preprocessArgs!(d::KW) delete!(d, :link) end - return + # pull out invalid keywords into their own KW dict... these are likely user-defined through recipes + kw = KW() + for k in keys(d) + try + default(k) + catch + # not a valid key... pop and add to user list + kw[k] = pop!(d, k) + end + end + kw end # ----------------------------------------------------------------------------- diff --git a/src/plot.jl b/src/plot.jl index 62bfd14c..d9ad1065 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -53,7 +53,7 @@ function plot(args...; kw...) plt = _create_plot(pkg, plotargs) # create a new, blank plot delete!(d, :background_color) - plot!(plt, args...; d...) # add to it + plot!(plt, args...; kw...) # add to it end @@ -72,10 +72,10 @@ end # this adds to a specific plot... most plot commands will flow through here function plot!(plt::Plot, args...; kw...) d = KW(kw) - preprocessArgs!(d) + userkw = preprocessArgs!(d) # for plotting recipes, swap out the args and update the parameter dictionary - args = _apply_recipe(d, args...; kw...) + args = _apply_recipe(d, userkw, args...) _add_markershape(d) dumpdict(d, "After plot! preprocessing") diff --git a/src/recipes.jl b/src/recipes.jl index 6b713941..9326bc32 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -17,10 +17,10 @@ plot!(plt::Plot, recipe::PlotRecipe, args...; kw...) = plot!(getRecipeXY(recipe) num_series(x::AMat) = size(x,2) num_series(x) = 1 -_apply_recipe(d::KW; kw...) = () +_apply_recipe(d::KW, kw::KW) = () # if it's not a recipe, just do nothing and return the args -function _apply_recipe(d::KW, args...; issubplot=false, kw...) +function _apply_recipe(d::KW, kw::KW, args...; issubplot=false) if issubplot && !haskey(d, :n) && !haskey(d, :layout) # put in a sensible default d[:n] = maximum(map(num_series, args)) @@ -105,7 +105,6 @@ macro recipe(funcexpr::Expr) if !(isa(lhs, Expr) && lhs.head == :call) error("Expected `lhs = ...` with lhs as a call Expr... got: $lhs") end - args = lhs.args[2:end] # for parametric definitions, take the "curly" expression and add the func front = lhs.args[1] @@ -115,12 +114,25 @@ macro recipe(funcexpr::Expr) func = front end + # get the arg list, stripping out any keyword parameters into a + # bunch of get!(kw, key, value) lines + args = lhs.args[2:end] + kw_body = Expr(:block) + if isa(args[1], Expr) && args[1].head == :parameters + for kwpair in args[1].args + k, v = kwpair.args + push!(kw_body.args, :(get!(kw, $(QuoteNode(k)), $v))) + end + args = args[2:end] + end + # replace all the key => value lines with argument setting logic replace_recipe_arrows!(body) # now build a function definition for _apply_recipe, wrapping the return value in a tuple if needed esc(quote - function $func(d::KW, $(args...); issubplot=false, kw...) + function $func(d::KW, kw::KW, $(args...); issubplot=false) + $kw_body ret = $body if typeof(ret) <: Tuple ret @@ -131,37 +143,6 @@ macro recipe(funcexpr::Expr) end) end -# macro plotrecipe(args, expr) -# if !isa(args, Expr) -# error("The first argument to `@plotrecipe` should be a valid argument list for dispatch.") -# end -# -# # wrap the args in a tuple -# if args.head != :tuple -# args = Expr(:tuple, args) -# end -# -# # # handle positional args -# # fixed_args = [] -# # positional_exprs = [] -# # for arg in args -# # if -# -# # replace all the key => value lines with argument setting logic -# replace_recipe_arrows!(expr) -# -# # now build a function definition for _apply_recipe, wrapping the return value in a tuple if needed -# esc(quote -# function Plots._apply_recipe(d::KW, $(args.args...); issubplot=false, kw...) -# ret = $expr -# if typeof(ret) <: Tuple -# ret -# else -# (ret,) -# end -# end -# end) -# end # --------------------------------------------------------------------------- diff --git a/src/subplot.jl b/src/subplot.jl index f03c7df3..421a9b27 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -43,7 +43,7 @@ function subplot(args...; kw...) preprocessArgs!(d) # for plotting recipes, swap out the args and update the parameter dictionary - args = _apply_recipe(d, args...; kw..., issubplot=true) + args = _apply_recipe(d, KW(kw), args...; issubplot=true) _add_markershape(d) # figure out the layout @@ -70,7 +70,7 @@ function subplot(args...; kw...) # create the object and do the plotting subplt = Subplot(nothing, plts, pkg, length(layout), 0, layout, d, false, false, false, (r,c) -> (nothing,nothing)) - subplot!(subplt, args...; d...) + subplot!(subplt, args...; kw...) subplt end @@ -117,10 +117,10 @@ end function _preprocess_subplot(subplt::Subplot, d::KW, args = ()) validateSubplotSupported() - preprocessArgs!(d) + userkw = preprocessArgs!(d) # for plotting recipes, swap out the args and update the parameter dictionary - args = _apply_recipe(d, args...; d..., issubplot=true) + args = _apply_recipe(d, userkw, args...; issubplot=true) _add_markershape(d) dumpdict(d, "After subplot! preprocessing")