diff --git a/Project.toml b/Project.toml index 3d6f97485..e2e9b2680 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.13.2" +version = "1.13.3" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/src/args.jl b/src/args.jl index 12e75cdde..fa2a038dd 100644 --- a/src/args.jl +++ b/src/args.jl @@ -320,6 +320,7 @@ const _series_defaults = KW( :contour_labels => false, :subplot => :auto, # which subplot(s) does this series belong to? :series_annotations => nothing, # a list of annotations which apply to the coordinates of this series + :series_annotationfont => nothing, :primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow # one logical series to be broken up (path and markers, for example) :hover => nothing, # text to display when hovering over the data points @@ -331,17 +332,12 @@ const _series_defaults = KW( const _plot_defaults = KW( :plot_title => "", - :plot_titlefontsize => 16, + :plot_titlefont => (; pointsize=16), :plot_title_location => :center, # also :left or :right - :plot_titlefontfamily => :match, - :plot_titlefonthalign => :hcenter, - :plot_titlefontvalign => :vcenter, - :plot_titlefontrotation => 0.0, - :plot_titlefontcolor => :match, :background_color => colorant"white", # default for all backgrounds, :background_color_outside => :match, # background outside grid, :foreground_color => :auto, # default for all foregrounds, and title color, - :fontfamily => "sans-serif", + :font => (; pointsize=11), :size => (600,400), :pos => (0,0), :window_title => "Plots.jl", @@ -365,13 +361,8 @@ const _plot_defaults = KW( const _subplot_defaults = KW( :title => "", :titlelocation => :center, # also :left or :right - :fontfamily_subplot => :match, - :titlefontfamily => :match, - :titlefontsize => 14, - :titlefonthalign => :hcenter, - :titlefontvalign => :vcenter, - :titlefontrotation => 0.0, - :titlefontcolor => :match, + :subplotfont => nothing, + :titlefont => (; pointsize=14), :background_color_subplot => :match, # default for other bg colors... match takes plot default :background_color_legend => :match, # background of legend :background_color_inside => :match, # background inside grid @@ -383,31 +374,16 @@ const _subplot_defaults = KW( :legendtitle => nothing, :colorbar => :legend, :clims => :auto, - :colorbar_fontfamily => :match, + :colorbar_tickfont => (; pointsize=8), :colorbar_ticks => :auto, - :colorbar_tickfontfamily => :match, - :colorbar_tickfontsize => 8, - :colorbar_tickfonthalign => :hcenter, - :colorbar_tickfontvalign => :vcenter, - :colorbar_tickfontrotation => 0.0, - :colorbar_tickfontcolor => :match, :colorbar_scale => :identity, :colorbar_formatter => :auto, :colorbar_discrete_values => [], :colorbar_continuous_values => zeros(0), - :legendfontfamily => :match, - :legendfontsize => 8, - :legendfonthalign => :hcenter, - :legendfontvalign => :vcenter, - :legendfontrotation => 0.0, - :legendfontcolor => :match, - :legendtitlefontfamily => :match, - :legendtitlefontsize => 11, - :legendtitlefonthalign => :hcenter, - :legendtitlefontvalign => :vcenter, - :legendtitlefontrotation => 0.0, - :legendtitlefontcolor => :match, + :legendfont => (; pointsize=8), + :legendtitlefont => (; pointsize=11), :annotations => [], # annotation tuples... list of (x,y,annotation) + :annotationfont => (; pointsize=14), :projection => :none, # can also be :polar or :3d :aspect_ratio => :auto, # choose from :none or :equal :margin => 1mm, @@ -417,16 +393,11 @@ const _subplot_defaults = KW( :bottom_margin => :match, :subplot_index => -1, :colorbar_title => "", - :colorbar_titlefontsize => 10, + :colorbar_titlefont => (; pointsize=10), :colorbar_title_location => :center, # also :left or :right - :colorbar_titlefontfamily => :match, - :colorbar_titlefonthalign => :hcenter, - :colorbar_titlefontvalign => :vcenter, - :colorbar_titlefontrotation => 0.0, - :colorbar_titlefontcolor => :match, :framestyle => :axes, :camera => (30,30), - :extra_kwargs => Dict() + :extra_kwargs => Dict(), ) const _axis_defaults = KW( @@ -438,18 +409,8 @@ const _axis_defaults = KW( :rotation => 0, :flip => false, :link => [], - :tickfontfamily => :match, - :tickfontsize => 8, - :tickfonthalign => :hcenter, - :tickfontvalign => :vcenter, - :tickfontrotation => 0.0, - :tickfontcolor => :match, - :guidefontfamily => :match, - :guidefontsize => 11, - :guidefonthalign => :hcenter, - :guidefontvalign => :vcenter, - :guidefontrotation => 0.0, - :guidefontcolor => :match, + :tickfont => (; pointsize=8), + :guidefont => (; pointsize=11), :foreground_color_axis => :match, # axis border/tick colors, :foreground_color_border => :match, # plot area border/spines, :foreground_color_text => :match, # tick text color, @@ -516,11 +477,13 @@ const _initial_defaults = deepcopy(_all_defaults) const _initial_axis_defaults = deepcopy(_axis_defaults) # to be able to reset font sizes to initial values +#= const _initial_fontsizes = Dict(:titlefontsize => _subplot_defaults[:titlefontsize], :legendfontsize => _subplot_defaults[:legendfontsize], :legendtitlefontsize => _subplot_defaults[:legendtitlefontsize], :tickfontsize => _axis_defaults[:tickfontsize], :guidefontsize => _axis_defaults[:guidefontsize]) + =# const _internal_args = [:plot_object, :series_plotindex, :markershape_to_add, :letter, :idxfilter] @@ -652,7 +615,7 @@ add_aliases(:zguide, :zlabel, :zlab, :zl) add_aliases(:zlims, :zlim, :zlimit, :zlimits) add_aliases(:zticks, :ztick) add_aliases(:zrotation, :zrot, :zr) -add_aliases(:guidefontsize, :labelfontsize) +add_aliases(:guidefont, :labelfont) add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor, :surfcolour) add_aliases(:legend, :leg, :key) add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title) @@ -967,39 +930,6 @@ function processMinorGridArg!(plotattributes::AKW, arg, letter) end end -function processFontArg!(plotattributes::AKW, fontname::Symbol, arg) - T = typeof(arg) - if T <: Font - plotattributes[Symbol(fontname, :family)] = arg.family - plotattributes[Symbol(fontname, :size)] = arg.pointsize - plotattributes[Symbol(fontname, :halign)] = arg.halign - plotattributes[Symbol(fontname, :valign)] = arg.valign - plotattributes[Symbol(fontname, :rotation)] = arg.rotation - plotattributes[Symbol(fontname, :color)] = arg.color - elseif arg == :center - plotattributes[Symbol(fontname, :halign)] = :hcenter - plotattributes[Symbol(fontname, :valign)] = :vcenter - elseif arg in (:hcenter, :left, :right) - plotattributes[Symbol(fontname, :halign)] = arg - elseif arg in (:vcenter, :top, :bottom) - plotattributes[Symbol(fontname, :valign)] = arg - elseif T <: Colorant - plotattributes[Symbol(fontname, :color)] = arg - elseif T <: Symbol || T <: AbstractString - try - plotattributes[Symbol(fontname, :color)] = parse(Colorant, string(arg)) - catch - plotattributes[Symbol(fontname, :family)] = string(arg) - end - elseif typeof(arg) <: Integer - plotattributes[Symbol(fontname, :size)] = arg - elseif typeof(arg) <: Real - plotattributes[Symbol(fontname, :rotation)] = convert(Float64, arg) - else - @warn("Skipped font arg: $arg ($(typeof(arg)))") - end -end - _replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape) _replace_markershape(shapes::AVec) = map(_replace_markershape, shapes) _replace_markershape(shape) = shape @@ -1013,6 +943,27 @@ function _add_markershape(plotattributes::AKW) end end +""" +```julia +@fontdependency a b c +``` +is equivalent to +```julia +fontattributes[:c] = font( + plotattributes[:a], + plotattributes[:b], + plotattributes[:c] + ) +``` +""" +macro fontdependency(dependencies...) +esc( + quote + fontattributes[$(QuoteNode(last(dependencies)))] = font(get.(Ref(plotattributes), $dependencies, nothing)) + end + ) +end + "Handle all preprocessing of args... break out colors/sizes/etc and replace aliases." function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) replaceAliases!(plotattributes, _keyAliases) @@ -1075,24 +1026,30 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) processMinorGridArg!(plotattributes, arg, letter) end end - # handle font args common to all axes - for fontname in (:tickfont, :guidefont) - args = RecipesPipeline.pop_kw!(plotattributes, fontname, ()) - for arg in wraptuple(args) - for letter in (:x, :y, :z) - processFontArg!(plotattributes, 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), ()) - for arg in wraptuple(args) - processFontArg!(plotattributes, Symbol(letter, fontname), arg) - end - end - end + + fontattributes = Dict{Symbol, Font}() + + + @fontdependency font + @fontdependency font plot_titlefont + @fontdependency font subplotfont + @fontdependency font subplotfont series_annotationfont + @fontdependency font subplotfont titlefont + @fontdependency font subplotfont legendfont + @fontdependency font subplotfont legendfont legendtitlefont + @fontdependency font subplotfont annotationfont + @fontdependency font subplotfont tickfont + @fontdependency font subplotfont guidefont + @fontdependency font subplotfont tickfont colorbar_tickfont + @fontdependency font subplotfont guidefont colorbar_titlefont + @fontdependency font subplotfont tickfont xtickfont + @fontdependency font suibplotfont guidefont xguidefont + @fontdependency font subplotfont tickfont ytickfont + @fontdependency font suibplotfont guidefont yguidefont + @fontdependency font subplotfont tickfont ztickfont + @fontdependency font suibplotfont guidefont zguidefont + merge!(plotattributes, fontattributes) + # handle axes args for k in _axis_args if haskey(plotattributes, k) && k !== :link @@ -1106,14 +1063,6 @@ function RecipesPipeline.preprocess_attributes!(plotattributes::AKW) end end - # fonts - for fontname in (:titlefont, :legendfont, :legendtitlefont, :plot_titlefont, :colorbar_titlefont) - args = RecipesPipeline.pop_kw!(plotattributes, fontname, ()) - for arg in wraptuple(args) - processFontArg!(plotattributes, fontname, arg) - end - end - # handle line args for arg in wraptuple(RecipesPipeline.pop_kw!(plotattributes, :line, ())) processLineArg(plotattributes, arg) @@ -1344,21 +1293,6 @@ const _match_map = KW( :top_margin => :margin, :right_margin => :margin, :bottom_margin => :margin, - :titlefontfamily => :fontfamily_subplot, - :titlefontcolor => :foreground_color_subplot, - :legendfontfamily => :fontfamily_subplot, - :legendfontcolor => :foreground_color_subplot, - :legendtitlefontfamily => :fontfamily_subplot, - :legendtitlefontcolor => :foreground_color_subplot, - :colorbar_fontfamily => :fontfamily_subplot, - :colorbar_titlefontfamily => :fontfamily_subplot, - :colorbar_titlefontcolor => :foreground_color_subplot, - :colorbar_tickfontfamily => :fontfamily_subplot, - :colorbar_tickfontcolor => :foreground_color_subplot, - :plot_titlefontfamily => :fontfamily, - :plot_titlefontcolor => :foreground_color, - :tickfontcolor => :foreground_color_text, - :guidefontcolor => :foreground_color_guide, ) # these can match values from the parent container (axis --> subplot --> plot) @@ -1371,9 +1305,6 @@ const _match_map2 = KW( :foreground_color_minor_grid=> :foreground_color_subplot, :foreground_color_guide => :foreground_color_subplot, :foreground_color_text => :foreground_color_subplot, - :fontfamily_subplot => :fontfamily, - :tickfontfamily => :fontfamily_subplot, - :guidefontfamily => :fontfamily_subplot, ) # properly retrieve from plt.attr, passing `:match` to the correct key diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 161ac190b..ff6d21698 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -663,8 +663,6 @@ function gr_set_tickfont(sp, letter) sp, halign = halign, valign = valign, - rotation = axis[:rotation], - color = axis[:tickfontcolor], ) end @@ -1010,7 +1008,7 @@ function gr_add_legend(sp, leg, viewport_plotarea) should_add_to_legend(series) || continue st = series[:seriestype] lc = get_linecolor(series, clims) - gr_set_line(sp[:legendfontsize] / 8, get_linestyle(series), lc, sp) + gr_set_line(sp[:legendfont].pointsize / 8, get_linestyle(series), lc, sp) if (st == :shape || series[:fillrange] !== nothing) && series[:ribbon] === nothing fc = get_fillcolor(series, clims) @@ -1046,16 +1044,16 @@ function gr_add_legend(sp, leg, viewport_plotarea) ms = first(series[:markersize]) msw = first(series[:markerstrokewidth]) s, sw = if ms > 0 - 0.8 * sp[:legendfontsize], 0.8 * sp[:legendfontsize] * msw / ms + 0.8 * sp[:legendfont].pointsize, 0.8 * sp[:legendfont].pointsize * msw / ms else - 0, 0.8 * sp[:legendfontsize] * msw / 8 + 0, 0.8 * sp[:legendfont].pointsize * msw / 8 end gr_draw_markers(series, xpos - leg.width_factor * 2, ypos, clims, s, sw) end lab = series[:label] GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) - gr_set_textcolor(plot_color(sp[:legendfontcolor])) + gr_set_textcolor(plot_color(sp[:legendfont].color)) gr_text(xpos, ypos, string(lab)) ypos -= leg.dy end @@ -1192,7 +1190,7 @@ function gr_get_legend_geometry(viewport_plotarea, sp) x_legend_offset = (viewport_plotarea[2] - viewport_plotarea[1]) / 30 y_legend_offset = (viewport_plotarea[4] - viewport_plotarea[3]) / 30 - dy = gr_point_mult(sp) * sp[:legendfontsize] * 1.75 + dy = gr_point_mult(sp) * sp[:legendfont].pointsize * 1.75 legendh = dy * legendn return ( @@ -1672,7 +1670,7 @@ function gr_add_series(sp, series) if sp[:legend] == :inline && should_add_to_legend(series) gr_set_font(legendfont(sp), sp) - gr_set_textcolor(plot_color(sp[:legendfontcolor])) + gr_set_textcolor(plot_color(sp[:legendfont].color)) if sp[:yaxis][:mirror] (_,i) = sp[:xaxis][:flip] ? findmax(x) : findmin(x) GR.settextalign(GR.TEXT_HALIGN_RIGHT, GR.TEXT_VALIGN_HALF) diff --git a/src/components.jl b/src/components.jl index d7a6c98bf..3dea12baf 100644 --- a/src/components.jl +++ b/src/components.jl @@ -243,76 +243,75 @@ julia> font(family="serif",halign=:center,rotation=45.0) ``` """ function font(args...;kw...) - - # defaults - family = "sans-serif" - pointsize = 14 - halign = :hcenter - valign = :vcenter - rotation = 0.0 - color = colorant"black" + f = Font( + "sans-serif", + 14, + :hcenter, + :vcenter, + 0.0, + colorant"black", + ) for arg in args - T = typeof(arg) - - if T == Font - family = arg.family - pointsize = arg.pointsize - halign = arg.halign - valign = arg.valign - rotation = arg.rotation - color = arg.color - elseif arg == :center - halign = :hcenter - valign = :vcenter - elseif arg in (:hcenter, :left, :right) - halign = arg - elseif arg in (:vcenter, :top, :bottom) - valign = arg - elseif T <: Colorant - color = arg - elseif T <: Symbol || T <: AbstractString - try - color = parse(Colorant, string(arg)) - catch - family = string(arg) - end - elseif typeof(arg) <: Integer - pointsize = arg - elseif typeof(arg) <: Real - rotation = convert(Float64, arg) - else - @warn("Unused font arg: $arg ($(typeof(arg)))") - end + prop = process_font_arg(arg) + isnothing(prop) && continue + setproperty!.(Ref(f), prop...) end - for symbol in keys(kw) - if symbol == :family - family = kw[:family] - elseif symbol == :pointsize - pointsize = kw[:pointsize] - elseif symbol == :halign - halign = kw[:halign] - if halign == :center - halign = :hcenter - end - @assert halign in (:hcenter, :left, :right) - elseif symbol == :valign - valign = kw[:valign] - if valign == :center - valign = :vcenter + for (k, v) in kw + if k === :halign && v === :center + v = :hcenter + elseif k === :valign && v === :center + v = :vcenter + elseif k === :color + v = parse(Colorant, v) end - @assert valign in (:vcenter, :top, :bottom) - elseif symbol == :rotation - rotation = kw[:rotation] - elseif symbol == :color - color = parse(Colorant, kw[:color]) - else - @warn("Unused font kwarg: $symbol") - end + setproperty!(f, k, v) end - - Font(family, pointsize, halign, valign, rotation, color) + return f +end + +process_font_arg(arg::T) where T = @warn("Unused font arg: $arg") +process_font_arg(::Nothing) = nothing +process_font_arg(::Tuple{Vararg{Nothing}}) = nothing + +process_font_arg(arg::Pair) = (arg...,) +function process_font_arg(arg::Font) + pn = propertynames(arg) + vals = getproperty.(Ref(arg), pn) + return (pn, vals) +end +process_font_arg(arg::Colorant) = (:color, arg) +process_font_arg(arg::Integer) = (:pointsize, arg) +process_font_arg(arg::Real) = (:rotation, arg) +function process_font_arg(arg::T) where {T<:Union{Symbol, AbstractString}} + arg === :center && return ([:halign, :valign], [:hcenter, :vcenter]) + arg in (:hcenter, :left, :right) && return (:halign, arg) + arg in (:vcenter, :top, :bottom) && return (:valign, arg) + try + return (:color, parse(Colorant, string(arg))) + catch + return (:family, string(arg)) + end +end +function process_font_arg(arg::Tuple) + k = Symbol[] + v = Any[] + for a in arg + prop = process_font_arg(a) + isnothing(prop) && continue + if prop[1] isa Symbol + push!(k, prop[1]) + push!(v, prop[2]) + else + append!(k, prop[1]) + append!(v, prop[2]) + end + end + return (k, v) +end +function process_font_arg(arg::NamedTuple) + return (keys(arg), values(arg)) end function scalefontsize(k::Symbol, factor::Number) diff --git a/src/recipes.jl b/src/recipes.jl index 952bf0aac..c12867c17 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -472,15 +472,6 @@ end fillto = map(x -> _is_positive(x) ? typeof(baseline)(x) : baseline, fillto) end - if !isnothing(plotattributes[:series_annotations]) - if isvertical(plotattributes) - annotations := (x,y,plotattributes[:series_annotations].strs,:bottom) - else - annotations := (y,x,plotattributes[:series_annotations].strs,:left) - end - series_annotations := nothing - end - # create the bar shapes by adding x/y segments xseg, yseg = Segments(), Segments() for i = 1:ny @@ -507,15 +498,29 @@ end # switch back if !isvertical(plotattributes) xseg, yseg = yseg, xseg + x, y = y, x end - # reset orientation orientation := default(:orientation) - x := xseg.pts - y := yseg.pts - seriestype := :shape + # draw the bar shapes + @series begin + seriestype := :shape + series_annotations := nothing + primary := true + x := xseg.pts + y := yseg.pts + () + end + + # add empty series for series annotations (and hover in plotly) + primary := false + seriestype := :scatter + markersize := 0 + markeralpha := 0 + x := x + y := y () end @deps bar shape diff --git a/src/utils.jl b/src/utils.jl index 0bfd61ff0..9b4fdaf35 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -57,7 +57,7 @@ struct SeriesSegment # indexes of this segement in series data vectors range::UnitRange # index into vector-valued attributes corresponding to this segment - attr_index::Int + attr_index::Int end # ----------------------------------------------------- @@ -88,11 +88,11 @@ function series_segments(series::Series, seriestype::Symbol = :path) (SeriesSegment(i:i, i) for i in r) else (SeriesSegment(i:i+1, i) for i in first(r):last(r)-1) - end + end end) else (SeriesSegment(r, 1) for r in nan_segments) - end + end seg_range = UnitRange(minimum(first(seg.range) for seg in result), maximum(last(seg.range) for seg in result)) @@ -103,7 +103,7 @@ function series_segments(series::Series, seriestype::Symbol = :path) if any(v -> !isnothing(v) && any(isnan, v), (x,y,z)) @info """Data contains NaNs or missing values, and indices of `$attr` vector do not match data indices. If you intend elements of `$attr` to apply to individual NaN-separated segements in the data, - pass each segment in a separate vector instead, and use a row vector for `$attr`. Legend entries + pass each segment in a separate vector instead, and use a row vector for `$attr`. Legend entries may be suppressed by passing an empty label. For example, plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], $attr=[1 2]) @@ -266,7 +266,7 @@ function heatmap_edges(x::AVec, xscale::Symbol, y::AVec, yscale::Symbol, z_size: or `size(z) == (length(y)+1, length(x)+1))` (x & y define edges).""") end x, y = heatmap_edges(x, xscale, isedges), - heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots + heatmap_edges(y, yscale, isedges, ispolar) # special handle for `r` in polar plots return x, y end @@ -935,68 +935,14 @@ ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt)) # --------------------------------------------------------------- # get fonts from objects: -plottitlefont(p::Plot) = font( - p[:plot_titlefontfamily], - p[:plot_titlefontsize], - p[:plot_titlefontvalign], - p[:plot_titlefonthalign], - p[:plot_titlefontrotation], - p[:plot_titlefontcolor], -) - -colorbartitlefont(sp::Subplot) = font( - sp[:colorbar_titlefontfamily], - sp[:colorbar_titlefontsize], - sp[:colorbar_titlefontvalign], - sp[:colorbar_titlefonthalign], - sp[:colorbar_titlefontrotation], - sp[:colorbar_titlefontcolor], -) - -titlefont(sp::Subplot) = font( - sp[:titlefontfamily], - sp[:titlefontsize], - sp[:titlefontvalign], - sp[:titlefonthalign], - sp[:titlefontrotation], - sp[:titlefontcolor], -) - -legendfont(sp::Subplot) = font( - sp[:legendfontfamily], - sp[:legendfontsize], - sp[:legendfontvalign], - sp[:legendfonthalign], - sp[:legendfontrotation], - sp[:legendfontcolor], -) - -legendtitlefont(sp::Subplot) = font( - sp[:legendtitlefontfamily], - sp[:legendtitlefontsize], - sp[:legendtitlefontvalign], - sp[:legendtitlefonthalign], - sp[:legendtitlefontrotation], - sp[:legendtitlefontcolor], -) - -tickfont(ax::Axis) = font( - ax[:tickfontfamily], - ax[:tickfontsize], - ax[:tickfontvalign], - ax[:tickfonthalign], - ax[:tickfontrotation], - ax[:tickfontcolor], -) - -guidefont(ax::Axis) = font( - ax[:guidefontfamily], - ax[:guidefontsize], - ax[:guidefontvalign], - ax[:guidefonthalign], - ax[:guidefontrotation], - ax[:guidefontcolor], -) +plottitlefont(p::Plot) = p[:plottiltefont] +colorbartitlefont(sp::Subplot) = sp[:colorbar_titlefont] +titlefont(sp::Subplot) = sp[:titlefont] +legendfont(sp::Subplot) = sp[:legendfont] +legendtitlefont(sp::Subplot) = sp[:legendtitlefont] +annotationfont(sp::Subplot) = sp[:annotationfont] +tickfont(ax::Axis) = ax[:tickfont] +guidefont(ax::Axis) = ax[:guidefont] # --------------------------------------------------------------- # converts unicode scientific notation, as returned by Showoff,