This is a working example using the original post bullet #3 idea and the discussion in the comment section above (including custom theme and theme weighting):
First, we define a function that sets options using UpValues
and TagSetDelayed
and the other one that clears them:
ClearAll[robustSetOptions, robustClearOptions];
robustSetOptions[function_,
options_?(MatchQ[#, Rule[_, _]] || MatchQ[#, List[Rule[_, _] ...]] &)] :=
Module[{newTheme = "customTheme"},
System`PlotThemeDump`resolvePlotTheme[newTheme, ToString@function] :=
Themes`SetWeight[options, System`PlotThemeDump`$ComponentWeight];
Unprotect[PlotTheme];
If[UpValues[PlotTheme] =!= {},
PlotTheme /: Rule[PlotTheme, x_String] =.;
PlotTheme /: RuleDelayed[PlotTheme, x_String] =.
];
SetOptions[function, PlotTheme -> newTheme];
Unprotect[PlotTheme];
PlotTheme /: Rule[PlotTheme, x_String] :=
RuleDelayed[PlotTheme,
If[MemberQ[Stack[], function], {newTheme, x}, {x}]];
PlotTheme /: RuleDelayed[PlotTheme, x_String] :=
RuleDelayed[PlotTheme,
If[MemberQ[Stack[], function], {newTheme, x}, x]];
Protect[PlotTheme];
]
robustClearOptions[function_] := Module[{},
If[UpValues[PlotTheme] =!= {},
Unprotect[PlotTheme];
PlotTheme /: Rule[PlotTheme, x_String] =.;
PlotTheme /: RuleDelayed[PlotTheme, x_String] =.;
Protect[PlotTheme];
]
SetOptions[function, PlotTheme -> $PlotTheme];
]
Then we can call it to define custom options (applied as a custom theme). Multiple options are possible (in this example there is a custom legend from the OP and the AspectRatio
):
ClearAll[g1, g1t, g2, g2t, g1d, g2d, plot1, plot1t, plot2, plot2t];
(* define custom options *)
customLegend = LineLegend[97, {"base 2", "natural", "base 10"}, LegendLabel -> "Logarithms"];
plotTheme = "Detailed";
plot1 := ListPlot[{Log2, Log, Log10}[Range@40] // Through];
plot1t := ListPlot[{Log2, Log, Log10}[Range@40] // Through, PlotTheme -> plotTheme];
plot2 := ListLinePlot[{Log2, Log, Log10}[Range@40] // Through];
plot2t := ListLinePlot[{Log2, Log, Log10}[Range@40] // Through, PlotTheme -> plotTheme];
(* set custom options *)
robustSetOptions[ListPlot, {PlotLegends -> customLegend, AspectRatio -> 1}];
g1 = plot1; (* should see a legend *)
g1t = plot1t; (* should see a legend *)
g2 = plot2; (* should not see a legend *)
g2t = plot2t; (* should not see a legend *)
(* remove custom options *)
robustClearOptions[ListPlot];
g1d = plot1; (* should not see a legend *)
g2d = plot2; (* should not see a legend *)
Grid[{
{"", "robustSetOptions", SpanFromLeft, "default"},
{SpanFromAbove, "No PlotTheme", "With PlotTheme \"" <> plotTheme <> "\"", SpanFromAbove},
{"ListPlot", g1, g1t, g1d}, {"ListLinePlot", g2, g2t, g2d}},
Alignment -> {Left,
Automatic, {{1, 2} -> Center, {1, 4} -> {Center, Center}, {2, 2} ->
Center, {2, 3} -> Center, {2, 1} -> Center, {3, 1} -> Center}},
Dividers -> Center]
As expected, there is a legend and the graphs are squared when ListPlot
is called with or without the PlotTheme
option. Any other function (ilustrated with ListLinePlot
) is not affected by the options, as they are set only for a specific function (ListPlot
in this example). After the options are cleared, all functions are back to their default style.
As this is a working example, please comment, critique, improve or suggest better ways of implementing it.
PlotThemes
right. One could work to get many others to do the same. $\endgroup$SetOptions[ListPlot, PlotLegends -> Priority[customLegend]]
and have it supersede Themes. I'll code up something like that in a self-answer at some point I think. $\endgroup$PlotTheme
. It seems like the legends have to be used with everyListPlot
call. Checked on both Windows and Linux. $\endgroup$PlotTheme /: Rule[PlotTheme, x_String] := RuleDelayed[PlotTheme, If[MemberQ[Stack[], ListPlot], {"customLegendTheme", x}, x]]
? For complete solution, one would also need to define theTagSetDelayed
for theRuleDelayed
$\endgroup$