From 9e34ed0383177b9ea48f45444849c2ac05b37d03 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Thu, 5 May 2022 15:15:56 +0200 Subject: [PATCH] add permute, deprecate orientation (#4164) * add series_permutation * works for dates and categorical input, not vector of strings * Update src/pipeline.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/pipeline.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * add test * correct test * make bar workign * add deprecation * rename series_permutation -> permute * add Documentation * fix uneccessary deprecation * permute h/vlines * Auto-format Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * 1.29.0 * Update Project.toml [skip ci] Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- Project.toml | 2 +- src/arg_desc.jl | 3 ++- src/args.jl | 16 ++++++++++++---- src/axes.jl | 9 +++++++++ src/backends.jl | 2 ++ src/consts.jl | 1 + src/pipeline.jl | 24 ++++++++++++++++++++++++ src/recipes.jl | 2 +- test/test_args.jl | 9 +++++++++ 9 files changed, 61 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index e15d141a..f78c9280 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Plots" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" author = ["Tom Breloff (@tbreloff)"] -version = "1.28.2" +version = "1.29.0" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/src/arg_desc.jl b/src/arg_desc.jl index 8d5b8adb..a6752a14 100644 --- a/src/arg_desc.jl +++ b/src/arg_desc.jl @@ -32,7 +32,8 @@ const _arg_desc = KW( :line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).", :fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.", :levels => "Integer (number of contours) or AbstractVector (contour values). Determines contour levels for a contour type.", - :orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", + :permute => "Tuple{Symbol,Symbol}. Permutes data and axis properties of the axes given in the tuple. E.g. (:x, :y).", + :orientation => "Symbol. (deprecated) Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", :bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)", :bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).", :bar_edges => "Bool. Align bars to edges (true), or centers (the default)?", diff --git a/src/args.jl b/src/args.jl index 2afec51f..c5fc4724 100644 --- a/src/args.jl +++ b/src/args.jl @@ -400,6 +400,7 @@ const _series_defaults = KW( :stride => (1, 1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. :connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh :z_order => :front, # one of :front, :back or integer in 1:length(sp.series_list) + :permute => :none, # tuple of two symbols to be permuted :extra_kwargs => Dict(), ) @@ -1611,7 +1612,7 @@ function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes) already_warned = get!(_already_warned, bend, Set{Symbol}()) extra_kwargs = Dict{Symbol,Any}() for k in keys(plotattributes) - is_attr_supported(pkg, k) && continue + is_attr_supported(pkg, k) && !(k in keys(_deprecated_attributes)) && continue k in _suppress_warnings && continue default_value = default(k) if ismissing(default_value) @@ -1625,9 +1626,16 @@ function warn_on_unsupported_args(pkg::AbstractBackend, plotattributes) get(plotattributes, :warn_on_unsupported, should_warn_on_unsupported(pkg)) for k in sort(collect(_to_warn)) push!(already_warned, k) - @warn( - "Keyword argument $k not supported with $pkg. Choose from: $(join(supported_attrs(pkg), ", "))" - ) + if k in keys(_deprecated_attributes) + @warn(""" + Keyword argument `$k` is deprecated. + Please use `$(_deprecated_attributes[k])` instead. + """) + else + @warn( + "Keyword argument $k not supported with $pkg. Choose from: $(join(supported_attrs(pkg), ", "))" + ) + end end end return extra_kwargs diff --git a/src/axes.jl b/src/axes.jl index 974f34b8..b7b03842 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -675,6 +675,15 @@ end # these methods track the discrete (categorical) values which correspond to axis continuous values (cv) # whenever we have discrete values, we automatically set the ticks to match. # we return (continuous_value, discrete_index) +function discrete_value!(plotattributes, letter::Symbol, dv) + l = if plotattributes[:permute] !== :none + only(filter(!=(letter), plotattributes[:permute])) + else + letter + end + discrete_value!(plotattributes[:subplot][get_attr_symbol(l, :axis)], dv) +end + function discrete_value!(axis::Axis, dv) cv_idx = get(axis[:discrete_map], dv, -1) if cv_idx == -1 diff --git a/src/backends.jl b/src/backends.jl index d09f4d6a..535a95fe 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -241,6 +241,7 @@ const _base_supported_args = [ :projection, :show_empty_bins, :z_order, + :permute, ] function merge_with_base_supported(v::AVec) @@ -949,6 +950,7 @@ const _unicodeplots_seriestype = [ :heatmap, :contour, # :contour3d, + :permute, :spy, :surface, :wireframe, diff --git a/src/consts.jl b/src/consts.jl index 3f2a8653..6f4b22d2 100644 --- a/src/consts.jl +++ b/src/consts.jl @@ -1,4 +1,5 @@ +const _deprecated_attributes = Dict{Symbol,Symbol}(:orientation => :permute) const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults] const _initial_defaults = deepcopy(_all_defaults) diff --git a/src/pipeline.jl b/src/pipeline.jl index 786d8523..3bd3f1eb 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -68,6 +68,17 @@ end function _preprocess_userrecipe(kw::AKW) _add_markershape(kw) + if get(kw, :permute, default(:permute)) != :none + l1, l2 = kw[:permute] + for k in _axis_args + k1 = _attrsymbolcache[l1][k] + k2 = _attrsymbolcache[l2][k] + kwk = keys(kw) + if k1 in kwk || k2 in kwk + kw[k1], kw[k2] = get(kw, k2, default(k2)), get(kw, k1, default(k1)) + end + end + end # map marker_z if it's a Function if isa(get(kw, :marker_z, default(:marker_z)), Function) # TODO: should this take y and/or z as arguments? @@ -338,6 +349,19 @@ RecipesPipeline.is_seriestype_supported(plt::Plot, st) = is_seriestype_supported function RecipesPipeline.add_series!(plt::Plot, plotattributes) sp = _prepare_subplot(plt, plotattributes) + if plotattributes[:permute] != :none + letter1, letter2 = plotattributes[:permute] + if plotattributes[:markershape] == :hline && + (plotattributes[:permute] == (:x, :y) || plotattributes[:permute] == (:y, :x)) + plotattributes[:markershape] = :vline + elseif plotattributes[:markershape] == :vline && ( + plotattributes[:permute] == (:x, :y) || plotattributes[:permute] == (:y, :x) + ) + plotattributes[:markershape] = :hline + end + plotattributes[letter1], plotattributes[letter2] = + plotattributes[letter2], plotattributes[letter1] + end _expand_subplot_extrema(sp, plotattributes, plotattributes[:seriestype]) _update_series_attributes!(plotattributes, plt, sp) _add_the_series(plt, sp, plotattributes) diff --git a/src/recipes.jl b/src/recipes.jl index ff073534..8221d0c3 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -438,7 +438,7 @@ end procx, procy, xscale, yscale, baseline = _preprocess_barlike(plotattributes, x, y) nx, ny = length(procx), length(procy) axis = plotattributes[:subplot][isvertical(plotattributes) ? :xaxis : :yaxis] - cv = [discrete_value!(axis, xi)[1] for xi in procx] + cv = [discrete_value!(plotattributes, :x, xi)[1] for xi in procx] procx = if nx == ny cv elseif nx == ny + 1 diff --git a/test/test_args.jl b/test/test_args.jl index f49c0e21..e0f1373f 100644 --- a/test/test_args.jl +++ b/test/test_args.jl @@ -16,3 +16,12 @@ end @test pl[1][axis][:tickfontfamily] == "Times" end end + +@testset "Permute recipes" begin + pl = bar(["a", "b", "c"], [1, 2, 3]) + ppl = bar(["a", "b", "c"], [1, 2, 3], permute = (:x, :y)) + @test xticks(ppl) == yticks(pl) + @test yticks(ppl) == xticks(pl) + @test filter(isfinite, pl[1][1][:x]) == filter(isfinite, ppl[1][1][:y]) + @test filter(isfinite, pl[1][1][:y]) == filter(isfinite, ppl[1][1][:x]) +end