diff --git a/src/args.jl b/src/args.jl index b388c641..f32bfe42 100644 --- a/src/args.jl +++ b/src/args.jl @@ -460,6 +460,24 @@ is_axis_attr_noletter(k) = haskey(_axis_defaults, k) RecipesBase.is_key_supported(k::Symbol) = is_attr_supported(k) +const _internal_args = + [:plot_object, :series_plotindex, :markershape_to_add, :letter, :idxfilter] +const _magic_axis_args = [:axis, :tickfont, :guidefont] +const _magic_subplot_args = [:titlefont, :legendfont, :legendtitlefont, ] +const _magic_series_args = [:line, :marker, :fill] + +function is_default_attribute(k::Symbol) + k in _internal_args && return true + k in _all_args && return true + is_axis_attr(k) && return true + is_axis_attr_noletter(k) && return true + k in _magic_axis_args && return true + k in _magic_subplot_args && return true + k in _magic_series_args && return true + Symbol(chop(string(k); head = 1, tail = 0)) in _magic_axis_args && return true + return false +end + # ----------------------------------------------------------------------------- makeplural(s::Symbol) = Symbol(string(s,"s")) @@ -1017,6 +1035,16 @@ function preprocessArgs!(plotattributes::AKW, replace_aliases = true) end end end + # handle axes guides + if haskey(plotattributes, :guide) + guide = pop!(plotattributes, :guide) + for letter in (:x, :y, :z) + guide_sym = Symbol(letter, :guide) + if !is_explicit(plotattributes, guide_sym) + plotattributes[guide_sym] = guide + end + end + end # handle line args for arg in wraptuple(pop_kw!(plotattributes, :line, ())) diff --git a/src/pipeline.jl b/src/pipeline.jl index 383ac82a..5b4d9bf5 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -1,4 +1,26 @@ +# Error for aliases used in recipes +function warn_on_recipe_aliases!(plotattributes, recipe_type, args...) + for k in keys(plotattributes) + if !is_default_attribute(k) + dk = get(_keyAliases, k, k) + if k !== dk + @warn "Attribute alias `$k` detected in the $recipe_type recipe defined for the signature $(signature_string(Val{recipe_type}, args...)). To ensure expected behavior it is recommended to use the default attribute `$dk`." + end + plotattributes[dk] = pop_kw!(plotattributes, k) + end + end +end +warn_on_recipe_aliases!(v::AbstractVector, recipe_type, args) = + foreach(x -> warn_on_recipe_aliases!(x, recipe_type, args), v) +warn_on_recipe_aliases!(rd::RecipeData, recipe_type, args) = + warn_on_recipe_aliases!(rd.plotattributes, recipe_type, args) +function signature_string(::Type{Val{:user}}, args...) + return string("(::", join(string.(typeof.(args)), ", ::"), ")") +end +signature_string(::Type{Val{:type}}, T) = "(::Type{$T}, ::$T)" +signature_string(::Type{Val{:plot}}, st) = "(::Type{Val{:$st}}, ::AbstractPlot)" +signature_string(::Type{Val{:series}}, st) = "(::Type{Val{:$st}}, x, y, z)" # ------------------------------------------------------------------ # preprocessing @@ -82,7 +104,11 @@ function _process_userrecipes(plt::Plot, plotattributes::AKW, args) if isempty(next_series.args) _process_userrecipe(plt, kw_list, next_series) else - rd_list = RecipesBase.apply_recipe(next_series.plotattributes, next_series.args...) + rd_list = RecipesBase.apply_recipe( + next_series.plotattributes, + next_series.args... + ) + warn_on_recipe_aliases!(rd_list, :user, next_series.args) prepend!(still_to_process,rd_list) end end @@ -184,6 +210,7 @@ function _process_plotrecipe(plt::Plot, kw::AKW, kw_list::Vector{KW}, still_to_p st = kw[:seriestype] st = kw[:seriestype] = get(_typeAliases, st, st) datalist = RecipesBase.apply_recipe(kw, Val{st}, plt) + warn_on_recipe_aliases!(datalist, :plot, st) for data in datalist preprocessArgs!(data.plotattributes, false) if data.plotattributes[:seriestype] == st @@ -408,7 +435,9 @@ function _process_seriesrecipe(plt::Plot, plotattributes::AKW) else # get a sub list of series for this seriestype - datalist = RecipesBase.apply_recipe(plotattributes, Val{st}, plotattributes[:x], plotattributes[:y], plotattributes[:z]) + x, y, z = plotattributes[:x], plotattributes[:y], plotattributes[:z] + datalist = RecipesBase.apply_recipe(plotattributes, Val{st}, x, y, z) + warn_on_recipe_aliases!(datalist, :series, st) # assuming there was no error, recursively apply the series recipes for data in datalist diff --git a/src/recipes.jl b/src/recipes.jl index dc94c1a9..79b4176d 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -1261,8 +1261,8 @@ end yflip := true aspect_ratio := 1 rs, cs, zs = findnz(z.surf) - xlim := ignorenan_extrema(cs) - ylim := ignorenan_extrema(rs) + xlims := ignorenan_extrema(cs) + ylims := ignorenan_extrema(rs) if plotattributes[:markershape] == :none markershape := :circle end diff --git a/src/series.jl b/src/series.jl index 3e76d93a..5df68409 100644 --- a/src/series.jl +++ b/src/series.jl @@ -178,6 +178,7 @@ end function _apply_type_recipe(plotattributes, v, letter) _preprocess_axis_args!(plotattributes, letter) rdvec = RecipesBase.apply_recipe(plotattributes, typeof(v), v) + warn_on_recipe_aliases!(plotattributes, :type, typeof(v)) _postprocess_axis_args!(plotattributes, letter) return rdvec[1].args[1] end @@ -189,11 +190,13 @@ function _apply_type_recipe(plotattributes, v::AbstractArray, letter) _preprocess_axis_args!(plotattributes, letter) # First we try to apply an array type recipe. w = RecipesBase.apply_recipe(plotattributes, typeof(v), v)[1].args[1] + warn_on_recipe_aliases!(plotattributes, :type, typeof(v)) # If the type did not change try it element-wise if typeof(v) == typeof(w) isempty(skipmissing(v)) && return Float64[] x = first(skipmissing(v)) args = RecipesBase.apply_recipe(plotattributes, typeof(x), x)[1].args + warn_on_recipe_aliases!(plotattributes, :type, typeof(x)) _postprocess_axis_args!(plotattributes, letter) if length(args) == 2 && all(arg -> arg isa Function, args) numfunc, formatter = args