3
$\begingroup$

It seems this should be easy, by I just can not figure out how. I'm making many very similar style plots, so I want to make a function with all the default options specified. Sometimes I need to tweak a plot though, like changing a color or adding a legend, so I want to be able to pass options to it if I want. If a want to tweak the plot the following function works

fplot[f_, range_, opt_] := 
  Plot[f, range, PlotLabel -> "A plot", Frame -> True, Axes -> False, opt];

fplot[Sin[x], {x, 0, 2 \[Pi]}, {PlotStyle -> Orange,    
  FrameLabel -> {{"y[x]", ""}, {"x", ""}}}]

But I also want my function to be able to handle me not giving it options, so I want the following to work as well

fplot[Sin[x], {x, 0, 2 \[Pi]}]

which now just gives me back the output:fplot[Sin[x], {x, 0, 2 [Pi]}]

I have loot at similar questions of passing optional options to a function, but I can't get either method to work, and they seem the require that I predefine the Options that I might later want to tweak. I would like to be able to tweak any of the options in Plot without having to predefine them. Passing list of options to Plot

Pass list of options to Plot3D

Any help is much apprechiated!

$\endgroup$
3
  • $\begingroup$ I have marked this question as a duplicate as the solution you Accepted is already addressed therein. However I encourage you to read through (353) as I feel the approach you have chosen is not as efficient as it might be. $\endgroup$
    – Mr.Wizard
    Feb 12, 2016 at 23:20
  • 1
    $\begingroup$ @Mr.Wizard I have editede it now. The If stuff was my attempt to create something, but it was a lot more complicated than what JasonB suggested further down in his post. That was the part of his answer that I ended up using. Is it still a duplicate? $\endgroup$
    – Espen Brun
    Feb 13, 2016 at 6:22
  • $\begingroup$ In my opinion, yes, but a duplicate of (353) instead. I'll change the redirect accordingly. $\endgroup$
    – Mr.Wizard
    Feb 13, 2016 at 7:48

2 Answers 2

6
$\begingroup$

When you evaluate the statement opt=="def" it evaluates to True if opt really is "def", but it doesn't give False for any other object.

Read the answer here to see why you need to use SameQ (===) instead of Equal (==),

f[a_, opt_] := Module[{defOpt, opt2},
  defOpt = {PlotLabel -> "Label"};
  If[opt === "def", opt2 = defOpt, opt2 = Join[defOpt, opt]];
  Plot[Sin[a x], {x, 0, 2 π}, Evaluate@opt2]]

enter image description here

For the record, the easiest way to define the function you have there is

f[a_, opt : OptionsPattern[Plot]] :=
  Plot[Sin[a x], {x, 0, 2 π}, opt, PlotLabel -> "Label"]

and then

f[2]
f[2, Background -> LightBlue, PlotStyle -> Orange]

would give the exact same output as above

$\endgroup$
3
  • $\begingroup$ how it helps with the second statement that gives false? $\endgroup$
    – garej
    Feb 8, 2016 at 7:59
  • 1
    $\begingroup$ @garej, the way the OP's function was originally defined, it evaluates opt to see if it is "def". If that is True then it defines opt2 in a certain way. If it were False then it defines it a different way. But the way he had it written, it was not evaluating to False $\endgroup$
    – Jason B.
    Feb 8, 2016 at 8:02
  • $\begingroup$ @JasonB, Thanks, that was what I was looking for! $\endgroup$
    – Espen Brun
    Feb 8, 2016 at 9:04
4
$\begingroup$

To define a function with options, give it a set of defaults and use OptionsPattern in the definition. To use the value of a particular option in the function defintion, use OptionValue:

Options[f] = {"ThisIsAnOption" -> False, SoIsThis -> 1};

f[a_, opt : OptionsPattern[]] :=
 (If[OptionValue["ThisIsAnOption"], Print[{opt}]]; a + OptionValue[SoIsThis])

If f is used without specifying any options, OptionValue will use the default values:

f[2]

(* 3 *)

If you specify an option where OptionsPattern[] is used in the definition, you can override the default values:

f[2, "ThisIsAnOption" -> True]

(* {"ThisIsAnOption"->True} *)
(* 3 *)

You can just add more options as you like and the order of the option arguments doesn't matter, so long as they all occur in sequence where OptionsPattern[] was specified:

f[2, SoIsThis -> 2, "ThisIsAnOption" -> True]

(* {SoIsThis->2, "ThisIsAnOption"->True} *)
(* 4 *)

This will trigger a message because "NotValidOption was never given for Options[f]:

f[2, "NotValidOption" -> "hello"]

(* OptionValue::nodef: Unknown option NotValidOption for f. *)
(* 3 *)

For your specific example, you can set the options of f to have the same options as Plot and override the default for PlotLabel with SetOptions. Then it's just a matter of passing the options argument to Plot. Here I used Join because it will take the first option value it finds if there are any duplicates:

Options[f] = Options[Plot];
SetOptions[f, PlotLabel -> "Label"];

f[a_, opts : OptionsPattern[]] := 
    Plot[Sin[a x], {x, 0, 2 Pi}, Evaluate[Join[{opts}, Options[f]]]];
$\endgroup$
1
  • $\begingroup$ Thanks for taking the time to answer :) $\endgroup$
    – Espen Brun
    Feb 8, 2016 at 9:35

Not the answer you're looking for? Browse other questions tagged or ask your own question.