From 70b635dbe166683dfa11c93565866af075a48634 Mon Sep 17 00:00:00 2001 From: Nicholas Bauer Date: Tue, 31 Aug 2021 15:36:58 -0400 Subject: [PATCH] Cache axis args in a dictionary (#3775) Co-authored-by: t-bltg Co-authored-by: Simon Christ --- Project.toml | 2 +- src/args.jl | 88 ++++++++++++++++------------- src/axes.jl | 54 +++++++++--------- src/backends.jl | 2 +- src/backends/deprecated/pgfplots.jl | 10 ++-- src/backends/gaston.jl | 2 +- src/backends/gr.jl | 26 ++++----- src/backends/pgfplotsx.jl | 2 +- src/backends/plotly.jl | 2 +- src/backends/pyplot.jl | 26 ++++++--- src/components.jl | 6 +- src/pipeline.jl | 4 +- src/utils.jl | 8 ++- 13 files changed, 128 insertions(+), 104 deletions(-) diff --git a/Project.toml b/Project.toml index 8d4d9142d..b9da09e3c 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "1.21.2" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Contour = "d38c429a-6771-53c6-b99e-75d170b6e991" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" @@ -31,7 +32,6 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" -Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" [compat] Contour = "0.5" diff --git a/src/args.jl b/src/args.jl index 461c07f1b..7b41a8c47 100644 --- a/src/args.jl +++ b/src/args.jl @@ -276,7 +276,7 @@ function hasgrid(arg::Symbol, letter) arg in (:all, :both, :on) || occursin(string(letter), string(arg)) else @warn( - "Unknown grid argument $arg; $(Symbol(letter, :grid)) was set to `true` instead." + "Unknown grid argument $arg; $(get_attr_symbol(letter, :grid)) was set to `true` instead." ) true end @@ -316,7 +316,7 @@ function showaxis(arg::Symbol, letter) arg in (:all, :both, :on, :yes) || occursin(string(letter), string(arg)) else @warn( - "Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead." + "Unknown showaxis argument $arg; $(get_attr_symbol(letter, :showaxis)) was set to `true` instead." ) true end @@ -571,11 +571,6 @@ function reset_axis_defaults_byletter!() end reset_axis_defaults_byletter!() -for letter in (:x, :y, :z), k in keys(_axis_defaults) - # allow the underscore version too: xguide or x_guide - add_aliases(Symbol(letter, k), Symbol(letter, "_", k)) -end - const _all_defaults = KW[_series_defaults, _plot_defaults, _subplot_defaults] const _initial_defaults = deepcopy(_all_defaults) @@ -620,6 +615,20 @@ const _all_subplot_args = sort(union([_subplot_args; _magic_subplot_args])) const _all_series_args = sort(union([_series_args; _magic_series_args])) const _all_plot_args = _plot_args +for letter in (:x, :y, :z) + _attrsymbolcache[letter] = Dict{Symbol, Symbol}() + for k in keys(_axis_defaults) + # populate attribute cache + lk = Symbol(letter, k) + _attrsymbolcache[letter][k] = lk + # allow the underscore version too: xguide or x_guide + add_aliases(lk, Symbol(letter, "_", k)) + end + for k in (_magic_axis_args..., :(_discrete_indices)) + _attrsymbolcache[letter][k] = Symbol(letter, k) + end +end + const _all_args = sort(union([_all_axis_args; _all_subplot_args; _all_series_args; _all_plot_args])) @@ -1216,69 +1225,69 @@ end function processGridArg!(plotattributes::AKW, arg, letter) if arg in _allGridArgs || isa(arg, Bool) - plotattributes[Symbol(letter, :grid)] = hasgrid(arg, letter) + plotattributes[get_attr_symbol(letter, :grid)] = hasgrid(arg, letter) elseif allStyles(arg) - plotattributes[Symbol(letter, :gridstyle)] = arg + plotattributes[get_attr_symbol(letter, :gridstyle)] = arg elseif typeof(arg) <: Stroke arg.width === nothing || - (plotattributes[Symbol(letter, :gridlinewidth)] = arg.width) + (plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg.width) arg.color === nothing || ( - plotattributes[Symbol(letter, :foreground_color_grid)] = + plotattributes[get_attr_symbol(letter, :foreground_color_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color) ) - arg.alpha === nothing || (plotattributes[Symbol(letter, :gridalpha)] = arg.alpha) - arg.style === nothing || (plotattributes[Symbol(letter, :gridstyle)] = arg.style) + arg.alpha === nothing || (plotattributes[get_attr_symbol(letter, :gridalpha)] = arg.alpha) + arg.style === nothing || (plotattributes[get_attr_symbol(letter, :gridstyle)] = arg.style) # linealpha elseif allAlphas(arg) - plotattributes[Symbol(letter, :gridalpha)] = arg + plotattributes[get_attr_symbol(letter, :gridalpha)] = arg # linewidth elseif allReals(arg) - plotattributes[Symbol(letter, :gridlinewidth)] = arg + plotattributes[get_attr_symbol(letter, :gridlinewidth)] = arg # color - elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_grid)) + elseif !handleColors!(plotattributes, arg, get_attr_symbol(letter, :foreground_color_grid)) @warn("Skipped grid arg $arg.") end end function processMinorGridArg!(plotattributes::AKW, arg, letter) if arg in _allGridArgs || isa(arg, Bool) - plotattributes[Symbol(letter, :minorgrid)] = hasgrid(arg, letter) + plotattributes[get_attr_symbol(letter, :minorgrid)] = hasgrid(arg, letter) elseif allStyles(arg) - plotattributes[Symbol(letter, :minorgridstyle)] = arg - plotattributes[Symbol(letter, :minorgrid)] = true + plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg + plotattributes[get_attr_symbol(letter, :minorgrid)] = true elseif typeof(arg) <: Stroke arg.width === nothing || - (plotattributes[Symbol(letter, :minorgridlinewidth)] = arg.width) + (plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg.width) arg.color === nothing || ( - plotattributes[Symbol(letter, :foreground_color_minor_grid)] = + plotattributes[get_attr_symbol(letter, :foreground_color_minor_grid)] = arg.color in (:auto, :match) ? :match : plot_color(arg.color) ) arg.alpha === nothing || - (plotattributes[Symbol(letter, :minorgridalpha)] = arg.alpha) + (plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg.alpha) arg.style === nothing || - (plotattributes[Symbol(letter, :minorgridstyle)] = arg.style) - plotattributes[Symbol(letter, :minorgrid)] = true + (plotattributes[get_attr_symbol(letter, :minorgridstyle)] = arg.style) + plotattributes[get_attr_symbol(letter, :minorgrid)] = true # linealpha elseif allAlphas(arg) - plotattributes[Symbol(letter, :minorgridalpha)] = arg - plotattributes[Symbol(letter, :minorgrid)] = true + plotattributes[get_attr_symbol(letter, :minorgridalpha)] = arg + plotattributes[get_attr_symbol(letter, :minorgrid)] = true # linewidth elseif allReals(arg) - plotattributes[Symbol(letter, :minorgridlinewidth)] = arg - plotattributes[Symbol(letter, :minorgrid)] = true + plotattributes[get_attr_symbol(letter, :minorgridlinewidth)] = arg + plotattributes[get_attr_symbol(letter, :minorgrid)] = true # color - elseif handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_minor_grid)) - plotattributes[Symbol(letter, :minorgrid)] = true + elseif handleColors!(plotattributes, arg, get_attr_symbol(letter, :foreground_color_minor_grid)) + plotattributes[get_attr_symbol(letter, :minorgrid)] = true else @warn("Skipped grid arg $arg.") end @@ -1344,7 +1353,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end # handle axis args for letter in (:x, :y, :z) - asym = Symbol(letter, :axis) + asym = get_attr_symbol(letter, :axis) args = RecipesPipeline.pop_kw!(plotattributes, asym, ()) if !(typeof(args) <: Axis) for arg in wraptuple(args) @@ -1371,7 +1380,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end # handle individual axes grid args for letter in (:x, :y, :z) - gridsym = Symbol(letter, :grid) + gridsym = get_attr_symbol(letter, :grid) args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ()) for arg in wraptuple(args) processGridArg!(plotattributes, arg, letter) @@ -1386,7 +1395,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end # handle individual axes grid args for letter in (:x, :y, :z) - gridsym = Symbol(letter, :minorgrid) + gridsym = get_attr_symbol(letter, :minorgrid) args = RecipesPipeline.pop_kw!(plotattributes, gridsym, ()) for arg in wraptuple(args) processMinorGridArg!(plotattributes, arg, letter) @@ -1397,16 +1406,16 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) args = RecipesPipeline.pop_kw!(plotattributes, fontname, ()) for arg in wraptuple(args) for letter in (:x, :y, :z) - processFontArg!(plotattributes, Symbol(letter, fontname), arg) + processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg) end end end # handle individual axes font args for letter in (:x, :y, :z) for fontname in (:tickfont, :guidefont) - args = RecipesPipeline.pop_kw!(plotattributes, Symbol(letter, fontname), ()) + args = RecipesPipeline.pop_kw!(plotattributes, get_attr_symbol(letter, fontname), ()) for arg in wraptuple(args) - processFontArg!(plotattributes, Symbol(letter, fontname), arg) + processFontArg!(plotattributes, get_attr_symbol(letter, fontname), arg) end end end @@ -1415,7 +1424,7 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) if haskey(plotattributes, k) && k !== :link v = plotattributes[k] for letter in (:x, :y, :z) - lk = Symbol(letter, k) + lk = get_attr_symbol(letter, k) if !is_explicit(plotattributes, lk) plotattributes[lk] = v end @@ -1922,7 +1931,8 @@ function _update_axis( end # then get those args that were passed with a leading letter: `xlabel = "X"` - lk = Symbol(letter, k) + lk = get_attr_symbol(letter, k) + if haskey(plotattributes_in, lk) kw[k] = slice_arg(plotattributes_in[lk], subplot_index) end @@ -1979,7 +1989,7 @@ function _update_subplot_args( lims_warned = false for letter in (:x, :y, :z) _update_axis(plt, sp, plotattributes_in, letter, subplot_index) - lk = Symbol(letter, :lims) + lk = get_attr_symbol(letter, :lims) # warn against using `Range` in x,y,z lims if !lims_warned && diff --git a/src/axes.jl b/src/axes.jl index 31c339ee4..86ec10e81 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -23,7 +23,7 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...) end function get_axis(sp::Subplot, letter::Symbol) - axissym = Symbol(letter, :axis) + axissym = get_attr_symbol(letter, :axis) if haskey(sp.attr, axissym) sp.attr[axissym] else @@ -35,40 +35,40 @@ function process_axis_arg!(plotattributes::AKW, arg, letter = "") T = typeof(arg) arg = get(_scaleAliases, arg, arg) if typeof(arg) <: Font - plotattributes[Symbol(letter, :tickfont)] = arg - plotattributes[Symbol(letter, :guidefont)] = arg + plotattributes[get_attr_symbol(letter, :tickfont)] = arg + plotattributes[get_attr_symbol(letter, :guidefont)] = arg elseif arg in _allScales - plotattributes[Symbol(letter, :scale)] = arg + plotattributes[get_attr_symbol(letter, :scale)] = arg elseif arg in (:flip, :invert, :inverted) - plotattributes[Symbol(letter, :flip)] = true + plotattributes[get_attr_symbol(letter, :flip)] = true elseif T <: AbstractString - plotattributes[Symbol(letter, :guide)] = arg + plotattributes[get_attr_symbol(letter, :guide)] = arg # xlims/ylims elseif (T <: Tuple || T <: AVec) && length(arg) == 2 sym = typeof(arg[1]) <: Number ? :lims : :ticks - plotattributes[Symbol(letter, sym)] = arg + plotattributes[get_attr_symbol(letter, sym)] = arg # xticks/yticks elseif T <: AVec - plotattributes[Symbol(letter, :ticks)] = arg + plotattributes[get_attr_symbol(letter, :ticks)] = arg elseif arg === nothing - plotattributes[Symbol(letter, :ticks)] = [] + plotattributes[get_attr_symbol(letter, :ticks)] = [] elseif T <: Bool || arg in _allShowaxisArgs - plotattributes[Symbol(letter, :showaxis)] = showaxis(arg, letter) + plotattributes[get_attr_symbol(letter, :showaxis)] = showaxis(arg, letter) elseif typeof(arg) <: Number - plotattributes[Symbol(letter, :rotation)] = arg + plotattributes[get_attr_symbol(letter, :rotation)] = arg elseif typeof(arg) <: Function - plotattributes[Symbol(letter, :formatter)] = arg + plotattributes[get_attr_symbol(letter, :formatter)] = arg - elseif !handleColors!(plotattributes, arg, Symbol(letter, :foreground_color_axis)) + elseif !handleColors!(plotattributes, arg, get_attr_symbol(letter, :foreground_color_axis)) @warn("Skipped $(letter)axis arg $arg") end end @@ -297,7 +297,7 @@ for l in (:x, :y, :z) end end # get_ticks from axis symbol :x, :y, or :z -get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[Symbol(s, :axis)]) +get_ticks(sp::Subplot, s::Symbol) = get_ticks(sp, sp[get_attr_symbol(s, :axis)]) get_ticks(p::Plot, s::Symbol) = [get_ticks(sp, s) for sp in p.subplots] function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where {T} @@ -393,7 +393,7 @@ end function reset_extrema!(sp::Subplot) for asym in (:x, :y, :z) - sp[Symbol(asym, :axis)][:extrema] = Extrema() + sp[get_attr_symbol(asym, :axis)][:extrema] = Extrema() end for series in sp.series_list expand_extrema!(sp, series.plotattributes) @@ -446,7 +446,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) ) data = [NaN] end - axis = sp[Symbol(letter, "axis")] + axis = sp[get_attr_symbol(letter, :axis)] if isa(data, Volume) expand_extrema!(sp[:xaxis], data.x_extents) @@ -463,7 +463,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) # TODO: need more here... gotta track the discrete reference value # as well as any coord offset (think of boxplot shape coords... they all # correspond to the same x-value) - plotattributes[letter], plotattributes[Symbol(letter, "_discrete_indices")] = + plotattributes[letter], plotattributes[get_attr_symbol(letter, :(_discrete_indices))] = discrete_value!(axis, data) expand_extrema!(axis, plotattributes[letter]) end @@ -502,7 +502,7 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) plotattributes[:bar_width] = _bar_width * ignorenan_minimum(filter(x -> x > 0, diff(sort(data)))) end - axis = sp.attr[Symbol(dsym, :axis)] + axis = sp.attr[get_attr_symbol(dsym, :axis)] expand_extrema!(axis, ignorenan_maximum(data) + 0.5maximum(bw)) expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw)) end @@ -511,8 +511,8 @@ function expand_extrema!(sp::Subplot, plotattributes::AKW) if plotattributes[:seriestype] == :heatmap for letter in (:x, :y) data = plotattributes[letter] - axis = sp[Symbol(letter, "axis")] - scale = get(plotattributes, Symbol(letter, "scale"), :identity) + axis = sp[get_attr_symbol(letter, :axis)] + scale = get(plotattributes, get_attr_symbol(letter, :scale), :identity) expand_extrema!(axis, heatmap_edges(data, scale)) end end @@ -586,10 +586,10 @@ end function axis_limits( sp, letter, - should_widen = default_should_widen(sp[Symbol(letter, :axis)]), + should_widen = default_should_widen(sp[get_attr_symbol(letter, :axis)]), consider_aspect = true, ) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] ex = axis[:extrema] amin, amax = ex.emin, ex.emax lims = axis[:lims] @@ -724,10 +724,10 @@ end # compute the line segments which should be drawn for this axis function axis_drawing_info(sp, letter) # find out which axis we are dealing with - asym = Symbol(letter, :axis) + asym = get_attr_symbol(letter, :axis) isy = letter === :y oletter = isy ? :x : :y - oasym = Symbol(oletter, :axis) + oasym = get_attr_symbol(oletter, :axis) # get axis objects, ticks and minor ticks ax, oax = sp[asym], sp[oasym] @@ -856,9 +856,9 @@ function axis_drawing_info_3d(sp, letter) near_letter = letter in (:x, :z) ? :y : :x far_letter = letter in (:x, :y) ? :z : :x - ax = sp[Symbol(letter, :axis)] - nax = sp[Symbol(near_letter, :axis)] - fax = sp[Symbol(far_letter, :axis)] + ax = sp[get_attr_symbol(letter, :axis)] + nax = sp[get_attr_symbol(near_letter, :axis)] + fax = sp[get_attr_symbol(far_letter, :axis)] amin, amax = axis_limits(sp, letter) namin, namax = axis_limits(sp, near_letter) diff --git a/src/backends.jl b/src/backends.jl index 4905e0d69..9eb7f8a04 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -247,7 +247,7 @@ function merge_with_base_supported(v::AVec) for vi in v if haskey(_axis_defaults, vi) for letter in (:x, :y, :z) - push!(v, Symbol(letter, vi)) + push!(v, get_attr_symbol(letter, vi)) end end end diff --git a/src/backends/deprecated/pgfplots.jl b/src/backends/deprecated/pgfplots.jl index 4c9f1ea37..471618e01 100644 --- a/src/backends/deprecated/pgfplots.jl +++ b/src/backends/deprecated/pgfplots.jl @@ -331,7 +331,7 @@ end # ---------------------------------------------------------------- function pgf_axis(sp::Subplot, letter) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] style = [] kw = KW() @@ -342,7 +342,7 @@ function pgf_axis(sp::Subplot, letter) framestyle = pgf_framestyle(sp[:framestyle]) # axis guide - kw[Symbol(letter, :label)] = axis[:guide] + kw[get_attr_symbol(letter, :label)] = axis[:guide] # axis label position labelpos = "" @@ -378,7 +378,7 @@ function pgf_axis(sp::Subplot, letter) # scale scale = axis[:scale] if scale in (:log2, :ln, :log10) - kw[Symbol(letter, :mode)] = "log" + kw[get_attr_symbol(letter, :mode)] = "log" scale == :ln || push!(style, "log basis $letter=$(scale == :log2 ? 2 : 10)") end @@ -400,8 +400,8 @@ function pgf_axis(sp::Subplot, letter) lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(sp, :x)) : axis_limits(sp, letter) - kw[Symbol(letter, :min)] = lims[1] - kw[Symbol(letter, :max)] = lims[2] + kw[get_attr_symbol(letter, :min)] = lims[1] + kw[get_attr_symbol(letter, :max)] = lims[2] end if !(axis[:ticks] in (nothing, false, :none, :native)) && framestyle != :none diff --git a/src/backends/gaston.jl b/src/backends/gaston.jl index 5a87351e8..0b2fd2408 100644 --- a/src/backends/gaston.jl +++ b/src/backends/gaston.jl @@ -372,7 +372,7 @@ function gaston_parse_axes_args( for letter in (:x, :y, :z) (letter == :z && dims == 2) && continue - axis = sp.attr[Symbol(letter, :axis)] + axis = sp.attr[get_attr_symbol(letter, :axis)] # label names push!( axesconf, diff --git a/src/backends/gr.jl b/src/backends/gr.jl index e9de86306..85f59efd8 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -670,7 +670,7 @@ function gr_display(plt::Plot, fmt = "") end function gr_set_tickfont(sp, letter) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] # invalidate alignment changes for small rotations (|θ| < 45°) trigger(rot) = abs(sind(rot)) < abs(cosd(rot)) ? 0 : sign(rot) @@ -1456,7 +1456,7 @@ end function gr_draw_axis(sp, letter, viewport_plotarea) ax = axis_drawing_info(sp, letter) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] # draw segments gr_draw_grid(sp, axis, ax.grid_segments) @@ -1472,7 +1472,7 @@ end function gr_draw_axis_3d(sp, letter, viewport_plotarea) ax = axis_drawing_info_3d(sp, letter) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] # draw segments gr_draw_grid(sp, axis, ax.grid_segments, gr_polyline3d) @@ -1553,10 +1553,10 @@ function gr_draw_ticks(sp, axis, segments, func = gr_polyline) end function gr_label_ticks(sp, letter, ticks) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] isy = letter === :y oletter = isy ? :x : :y - oaxis = sp[Symbol(oletter, :axis)] + oaxis = sp[get_attr_symbol(oletter, :axis)] oamin, oamax = axis_limits(sp, oletter) gr_set_tickfont(sp, letter) out_factor = ifelse(axis[:tick_direction] === :out, 1.5, 1) @@ -1577,9 +1577,9 @@ function gr_label_ticks_3d(sp, letter, ticks) near_letter = letter in (:x, :z) ? :y : :x far_letter = letter in (:x, :y) ? :z : :x - ax = sp[Symbol(letter, :axis)] - nax = sp[Symbol(near_letter, :axis)] - fax = sp[Symbol(far_letter, :axis)] + ax = sp[get_attr_symbol(letter, :axis)] + nax = sp[get_attr_symbol(near_letter, :axis)] + fax = sp[get_attr_symbol(far_letter, :axis)] amin, amax = axis_limits(sp, letter) namin, namax = axis_limits(sp, near_letter) @@ -1589,7 +1589,7 @@ function gr_label_ticks_3d(sp, letter, ticks) # find out which axes we are dealing with i = findfirst(==(letter), (:x, :y, :z)) letters = axes_shift((:x, :y, :z), 1 - i) - asyms = Symbol.(letters, :axis) + asyms = get_attr_symbol.(letters, :axis) # get axis objects, ticks and minor ticks # regardless of the `letter` we now use the convention that `x` in variable names refer to @@ -1626,7 +1626,7 @@ function gr_label_ticks_3d(sp, letter, ticks) end function gr_label_axis(sp, letter, viewport_plotarea) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] mirror = axis[:mirror] # guide if axis[:guide] != "" @@ -1670,13 +1670,13 @@ function gr_label_axis(sp, letter, viewport_plotarea) end function gr_label_axis_3d(sp, letter) - ax = sp[Symbol(letter, :axis)] + ax = sp[get_attr_symbol(letter, :axis)] if ax[:guide] != "" near_letter = letter in (:x, :z) ? :y : :x far_letter = letter in (:x, :y) ? :z : :x - nax = sp[Symbol(near_letter, :axis)] - fax = sp[Symbol(far_letter, :axis)] + nax = sp[get_attr_symbol(near_letter, :axis)] + fax = sp[get_attr_symbol(far_letter, :axis)] amin, amax = axis_limits(sp, letter) namin, namax = axis_limits(sp, near_letter) diff --git a/src/backends/pgfplotsx.jl b/src/backends/pgfplotsx.jl index 0696ff57f..dd9dd8d96 100644 --- a/src/backends/pgfplotsx.jl +++ b/src/backends/pgfplotsx.jl @@ -1200,7 +1200,7 @@ function pgfx_sanitize_plot!(plt) end # -------------------------------------------------------------------------------------- function pgfx_axis!(opt::PGFPlotsX.Options, sp::Subplot, letter) - axis = sp[Symbol(letter, :axis)] + axis = sp[get_attr_symbol(letter, :axis)] # turn off scaled ticks push!(opt, "scaled $(letter) ticks" => "false", string(letter, :label) => axis[:guide]) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index adc9baa51..ab09ee809 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -499,7 +499,7 @@ function plotly_close_shapes(x, y) end function plotly_data(series::Series, letter::Symbol, data) - axis = series[:subplot][Symbol(letter, :axis)] + axis = series[:subplot][get_attr_symbol(letter, :axis)] data = if axis[:ticks] == :native && data !== nothing plotly_native_data(axis, data) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 062a5231c..6370150e0 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -60,6 +60,14 @@ end # # anything else just gets a bluesred gradient # py_colormap(c, α=nothing) = py_colormap(default_gradient(), α) +for k in (:linthresh, :base, :label) + # add PyPlot specific symbols to cache + _attrsymbolcache[k] = Dict{Symbol, Symbol}() + for letter in (:x, :y, :z, Symbol("")) + _attrsymbolcache[k][letter] = Symbol(k, letter) + end +end + py_handle_surface(v) = v py_handle_surface(z::Surface) = z.surf @@ -827,11 +835,11 @@ end function py_set_ticks(sp, ax, ticks, letter, env) ticks == :auto && return - axis = getproperty(ax, Symbol(letter, "axis")) + axis = getproperty(ax, get_attr_symbol(letter, :axis)) if ticks == :none || ticks === nothing || ticks == false kw = KW() for dir in (:top, :bottom, :left, :right) - kw[dir] = kw[Symbol(:label, dir)] = false + kw[dir] = kw[get_attr_symbol(:label, dir)] = false end axis."set_tick_params"(; which = "both", kw...) return @@ -887,15 +895,15 @@ function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol) arg = if scale == :identity "linear" else - kw[Symbol(:base, pyletter)] = if scale == :ln + kw[get_attr_symbol(:base, pyletter)] = if scale == :ln ℯ elseif scale == :log2 2 elseif scale == :log10 10 end - axis = sp[Symbol(letter, :axis)] - kw[Symbol(:linthresh, pyletter)] = + axis = sp[get_attr_symbol(letter, :axis)] + kw[get_attr_symbol(:linthresh, pyletter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) "symlog" end @@ -922,7 +930,7 @@ end function py_set_axis_colors(sp, ax, a::Axis) py_set_spine_color(ax.spines, py_color(a[:foreground_color_border])) - axissym = Symbol(a[:letter], :axis) + axissym = get_attr_symbol(a[:letter], :axis) if PyPlot.PyCall.hasproperty(ax, axissym) tickcolor = sp[:framestyle] in (:zerolines, :grid) ? @@ -1193,7 +1201,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) # axis attributes for letter in (:x, :y, :z) - axissym = Symbol(letter, :axis) + axissym = get_attr_symbol(letter, :axis) PyPlot.PyCall.hasproperty(ax, axissym) || continue axis = sp[axissym] pyaxis = getproperty(ax, axissym) @@ -1327,7 +1335,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if !ispolar(sp) ax.spines[string(dir)].set_visible(false) end - kw[dir] = kw[Symbol(:label, dir)] = false + kw[dir] = kw[get_attr_symbol(:label, dir)] = false end ax."xaxis"."set_tick_params"(; which = "both", kw...) end @@ -1337,7 +1345,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend}) if !ispolar(sp) ax.spines[string(dir)].set_visible(false) end - kw[dir] = kw[Symbol(:label, dir)] = false + kw[dir] = kw[get_attr_symbol(:label, dir)] = false end ax."yaxis"."set_tick_params"(; which = "both", kw...) end diff --git a/src/components.jl b/src/components.jl index e8eadc721..6786b98e1 100644 --- a/src/components.jl +++ b/src/components.jl @@ -321,7 +321,7 @@ function scalefontsizes(factor::Number) for letter in (:x, :y, :z) for k in keys(_initial_ax_fontsizes) - scalefontsize(Symbol(letter, k), factor) + scalefontsize(get_attr_symbol(letter, k), factor) end end end @@ -343,9 +343,9 @@ function scalefontsizes() for letter in (:x, :y, :z) for k in keys(_initial_ax_fontsizes) if k in keys(_initial_fontsizes) - f = default(Symbol(letter, k)) + f = default(get_attr_symbol(letter, k)) factor = f / _initial_fontsizes[k] - scalefontsize(Symbol(letter, k), 1.0 / factor) + scalefontsize(get_attr_symbol(letter, k), 1.0 / factor) end end end diff --git a/src/pipeline.jl b/src/pipeline.jl index bb87a69e6..476b4256c 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -250,12 +250,12 @@ function _subplot_setup(plt::Plot, plotattributes::AKW, kw_list::Vector{KW}) v = v[series_idx(kw_list, kw)] end for letter in (:x, :y, :z) - attr[Symbol(letter, k)] = v + attr[get_attr_symbol(letter, k)] = v end end for k in (:scale,), letter in (:x, :y, :z) # Series recipes may need access to this information - lk = Symbol(letter, k) + lk = get_attr_symbol(letter, k) if haskey(attr, lk) kw[lk] = attr[lk] end diff --git a/src/utils.jl b/src/utils.jl index 0d69f3a57..337598fe7 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -816,7 +816,7 @@ end function extend_series_data!(series::Series, v, letter) copy_series!(series, letter) d = extend_by_data!(series[letter], v) - expand_extrema!(series[:subplot][Symbol(letter, :axis)], d) + expand_extrema!(series[:subplot][get_attr_symbol(letter, :axis)], d) return d end @@ -1214,3 +1214,9 @@ function mesh3d_triangles(x, y, z, cns) end return X, Y, Z end + +# cache joined symbols so they can be looked up instead of constructed each time +const _attrsymbolcache = Dict{Symbol, Dict{Symbol, Symbol}}() + +get_attr_symbol(letter::Symbol, keyword::String) = get_attr_symbol(letter, Symbol(keyword)) +get_attr_symbol(letter::Symbol, keyword::Symbol) = _attrsymbolcache[letter][keyword]