Let us assume that you are designing a function which can take its own unique options, but also shares option names with Plot
. What is the best way to implement such a function myPlot
? Below I will try to give a complete guide on how to do this.
There are two common approaches:
The default values for Plot
-specific options will be taken directly from Plot
. Changing Plot
options with SetOptions
also affects myPlot
. It is not possible to use SetOptions
on myPlot
with Plot
-specific options. This is only possible with options unique to myPlot
.
myPlot
has its own copy of Plot
's options. Changing Plot
's options does not affect myPlot
. Any of these options can be changed directly on myPlot
using SetOptions
.
Most builtin functions use approach (2).
For the following, it is good to be aware that when an option is specified multiple times, Mathematica always takes the first value.
Inheriting defaults from Plot
Here's how to implement approach (1). We start by setting the defaults of myPlot
's unique options:
Options[myPlot] = { Top -> 10 };
myPlot[f_, opt : OptionsPattern[{myPlot, Plot}]] :=
Plot[f[x], {x, 0, OptionValue[Top]},
Evaluate@FilterRules[{opt}, Options[Plot]]
]
Here, the purpose of specifying Plot
within OptionsPattern
was to avoid error messages when using options that are present in Options[Plot]
but not in Options[myPlot]
.
An additional effect is that now you can use OptionValue
with Plot
-specific options. We do not need this in this specific implementation. However, specifying Plot
within OptionsPattern
is still necessary to avoid errors.
Using Evaluate
before FilterRule
was necessary because Plot
is HoldAll
.
If you put this function in a package, at some point you may want to add syntax information to it. Like this:
SyntaxInformation[myPlot] = {"ArgumentsPattern" -> {_, OptionsPattern[]}}
But now we run into a problem. Plot
-specific options work, but they are coloured in red, as if they were incorrect.
The workaround is using an undocumented entry in SyntaxInformation
, "OptionNames"
:
SyntaxInformation[
myPlot] = {"ArgumentsPattern" -> {_, OptionsPattern[]},
"OptionNames" -> Union[First /@ Options[myPlot], First /@ Options[Plot]]};
Separate defaults for myPlot
and Plot
This is the more common approach, and this is what builtins use.
We start by setting myPlot
's unique options, as well as copying over Plot
's options. Here, we do not change Plot
's defaults.
Options[myPlot] = Join[
{Top -> 10}
Options[Plot]
];
Now we are ready to change some Plot
-specific options from their default values:
SetOptions[myPlot, {PlotRange -> All, PlotStyle -> Red}];
Now we can define myPlot
:
myPlot[f_, opt : OptionsPattern[]] :=
Plot[f[x], {x, 0, OptionValue[Top]},
Evaluate@FilterRules[Join[{opt}, Options[myPlot]], Options[Plot]]
]
We no longer need to list function names in OptionsPattern[]
. But now we need to pass down all options, as set either in opt
or in Options[myPlot]
to the Plot
function. We can simply Join
all of them together, relying on the fact that when duplicates are present, the value will be taken from the first occurrence.
Now the SyntaxInformation can be simpler:
SyntaxInformation[myPlot] = {"ArgumentsPattern" -> {_, OptionsPattern[]}}
The allowed option names will be taken from Options[myPlot]
.
Finally, you can also mix these two approaches. You can have only a subset of Plot
's options present in Options[myPlot]
. I do not recommend that you do this because it can be confusing to users. Either put all of them in there (the more common approach), or none of them at all.
myPlot[function_, opts : OptionsPattern[]] := Plot[function[x], {x, 1, 5}, Evaluate @ FilterRules[{opts} ~Join~ Options[myPlot], Options[Plot]]]
? $\endgroup$PlotRange
, not"PlotRange"
. Generally, string and symbol versions should be interchangeable when used in option handling functions. But if you (or the author or some other function) accidentally uses some other functions to manipulate options (like @MB1965 did withDeleteDuplicatesBy
, see my comment), then there may be a mixup. $\endgroup$FilterOptions[]
instead of the modernFilterRules[]
. $\endgroup$