Clarifying the behavior of `PLOTS_DEFAULTS` in Plots.jl

I’d like to set some default parameters for plotting using Plots.jl by defining the PLOTS_DEFAULTS variable in my “startup.jl” . I have questions regarding its behavior:

  1. It appears that setting PLOTS_DEFAULTS successfully applies my default parameters, and subsequent calls to the plot() function respect these settings. However, if I execute the default() function, all parameters revert to Plots.jl’s built-in defaults, and my custom PLOTS_DEFAULTS settings are lost. Is this the intended behavior? I expected that defining PLOTS_DEFAULTS would change the “defaults” themselves, but it seems that the default() function does not consider PLOTS_DEFAULTS.

  2. Given the behavior described above, how can I have my custom parameters defined in PLOTS_DEFAULTS re-effective after executing the default() function?

  3. I want to specify margins (such as top_margin) through PLOTS_DEFAULTS . Is it possible to set, for example, a 5mm top margin when mm is not available? I don’t want to load a package in my startup.jl just for this.

It’s not documented so I suppose it’s free to change, but the first line of the 0-positional argument method does suggest it resets the defaults if reset=true and there are no other keyword arguments for setting default values:

function default(; reset = true, kw...)
    (reset && isempty(kw)) && reset_defaults()
    kw = KW(kw)
    Plots.preprocess_attributes!(kw)
    for (k, v) in kw
        default(k, v) # 2-positional method sets 1 default value for 1 key
    end
end

Honestly not sure why it’s designed like that because:

  1. typical usage with keyword arguments would not reset, so I’d expect zero arguments to not reset either (a no-op overall)
  2. I might want to the one call to reset the defaults before I set new values.

Thank you @Benny

I usually do something like the following at the beginning of my code:

default()
default(thickness_scaling = 1.8, legend = false)
default(guidefontsize = 10, titlefontsize = 11, tickfontsize = 8)
default(markersize = 5, linewidth = 2)
default(left_margin = -5mm, bottom_margin = -3mm, right_margin = 0mm, top_margin = 0mm)

Here I call default() with empty argument first to reset to the defaults and then with custom parameters. Because I mostly always do this, I’d like to have these custom parameters in PLOTS_DEFAULTS variable so that I should be able to do just the following instead:

default()

to have the same effect. But unfortunately it does not reset to PLOTS_DEFAULTS but to the “default defaults”. So I wonder whether this is expected or not.

I quickly checked the code and found that neither default function nor reset_defaults function called from within default seems to check PLOTS_DEFAULTS at all. Maybe it seems it is designed so. Personally I think default() should respect PLOTS_DEFAULTS. If not the name PLOTS_DEFAULTS does not feel appropriate.

As for my question 3, using (5, :mm) instead of 5mm worked. I am not sure whether this is documented anywhere.

I’m not the last word on it, but when I checked the source code it seemed that way to me too. The defaults are actually split into several sections so I’m not positive, but it seems hard-coded instead of checking PLOTS_DEFAULTS. PLOTS_DEFAULTS only seems to be relevant to an __init__ step. I think it might have been intentional to have a reset go to the hard-coded values as a reference instead of PLOTS_DEFAULTS, but I’m just speculating there.

Could you get away with making a variant default function mydefault() that does all this instead of using PLOTS_DEFAULTS? If there isn’t a package for you to put it in, you could just include the one method into every plotting script and call it every time you need a personalized reset.

Thanks for the suggestion. I will define a function for applying custom paramters to a set of attributes. It’s easy and solves what I want to do for now. I think it will be useful if Plots.jl’s default provides more flexbile style switching.