Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Suppose you want to create a function which has optional arguments.

Maeder's book "Programming in Mathematica" covers the topic extensively up to version 3, but some things have changed/evolved since then.

So now what is the standard code to use for a function func[x, ...] which takes optional arguments?

share|improve this question

4 Answers 4

up vote 55 down vote accepted

The main change since that time seems to be that the modern way of using options is associated with OptionsPattern[] - OptionValue commands. A typical way of defining a function would be:

Options[f] = {
    FirstOption -> 1,
    SecondOption ->2
}
f[x_,y_,opts:OptionsPattern[]]:=
    Print[{x,y,OptionValue[FirstOption],OptionValue[SecondOption]}]

The OptionsPattern[] is a pattern which is similar to ___?OptionQ in its purpose, but has subtle differences, some of which are discussed in this question. In the same question, it is discussed what are the major differences and advantages / disadvantages of old and new approaches. You can still use the old way though. The OptionValue command is a rather magical function, which knows which function you are in, so that you often don't have to supply the function name explicitly. However, you can always do so, since OptionValue has forms with more arguments. What you can not do is to mix the two approaches: if you declare options as ___?OptionQ, then OptionValue won't work.

The second difference is that there is new built-in functions FilterRules, which can be used to filter options. Previously, there was a package by Maeder called FilterOptions, which provided similar functionality, but was not in the widespread use, just because not everyone knew about it. The typical options filtering call looks like

g[x_,y_,opts:OptionsPattern[]]:=
    f[x,y,Sequence@@FilterRules[{opts},Options[f]]]

Filtering options is a good practice, so this addition is quite useful.

If you wanted to pass options that belong to other functions (e.g. functions that are called inside your function g) you would do something like this, and it would work even if useQ was actually an option of the function p:

g[x_,y_,opts:OptionsPattern[{g,f,p,q}] ]:=
  Module[{s=If[OptionValue[useQ],q[y,FilterRules[q] ], p[x,FilterRules[p] ]},
   f[x,s,Sequence@@FilterRules[{opts},Options[f]] ] ]
share|improve this answer
    
Never seen FilterRules before. That is a useful tool! –  Eli Lansey Jan 20 '12 at 14:44
    
Thank you Leonid, i was waiting for your answer :-) –  magma Jan 20 '12 at 14:46
    
@Eli: it definitely should be a function that everybody who deals with options should know. –  J. M. Jan 20 '12 at 14:52
1  
@Eli Lansey Sometimes you need to do somthing with options, for example, pass them to some function you call: f[x,y,opts:OptionsPattern]:=g[x,y,OptionValue[FirstOption],opts], or, better, f[x,y,opts:OptionsPattern]:=g[x,y,OptionValue[FirstOption],Sequence@@FilterRule‌​s[{opts},Options[g]]]. There can be other cases when you'd like to have an explicit handle on the options passed to your function. –  Leonid Shifrin Jan 20 '12 at 15:43
1  
@Eli see my answer for a working example of opts:OptionsPattern[] –  Mr.Wizard Jan 20 '12 at 16:54

Here is a practical example from a StackOverflow question. I hope that it gives a good overview of the basic methods.

Question


  • What would be the best way to make a function out of the below code ?

  • It would take a dataList as well as some graphical options (such as colors) as arguments and return a customized tabular representation as shown below.

    overviewtheData=Text@Grid[{Map[Rotate[Text[#],
    90Degree]&,data[[1]]]}~Join~data[[2;;]],
    Background->{{{{White,Pink}},{1->White}}},
    Dividers->{All,{1->True,2->True,0->True}},
    ItemSize->{1->5,Automatic},
    Alignment->Top,
    Frame->True,
    FrameStyle->Thickness[2],
    ItemStyle->{Automatic,Automatic,{{1,1},
    {1,Length@data[[1]]}}->Directive[FontSize->15,Black,Bold]}]
    

enter image description here


Goals

  1. Since the main function used is Grid it makes sense to allow passing options to it.

  2. You have a series of options that define your table. I want to be able to conveniently change these.

  3. I want the possibility of custom options not understood by Grid.


Implementation

I will use this sample data in all examples below:

data = Prepend[
         RandomInteger[99, {5, 12}], 
         DateString[{1, #}, "MonthName"] & /@ Range@12
       ];

Goal #1

An argument pattern opts:OptionsPattern[] is added, which matches any sequence of Option -> Setting arguments, and names it opts. (See: OptionsPattern for more.) Then, opts is inserted into the basic function before the other options for Grid. This allows any explicitly given options to override the defaults, or new ones to be given.

customTabular[data_, opts : OptionsPattern[]] :=
  Grid[MapAt[Rotate[#, 90 Degree] & /@ # &, data, 1],
   opts,
   Background -> {{{White, Pink}}},
   Dividers -> {All, {2 -> True}},
   ItemSize -> {1 -> 5},
   Alignment -> {Center, {1 -> Top}},
   Frame -> True,
   FrameStyle -> Thickness[2],
   ItemStyle -> Directive[FontSize -> 15, Black, Bold]
  ] // Text

Examples:

customTabular[data]

enter image description here

customTabular[data, Background -> LightBlue]

enter image description here

Goal #2

The options that define your tabular format can be separated from the function body. This will allow them to be conveniently changed or referenced. I start by clearing the previous definition with ClearAll. Then I set default Options for customTabular:

ClearAll[customTabular]

Options[customTabular] =
  {Background -> {{{White, Pink}}},
   Dividers -> {All, {2 -> True}},
   ItemSize -> {1 -> 5},
   Alignment -> {Center, {1 -> Top}},
   Frame -> True,
   FrameStyle -> Thickness[2],
   ItemStyle -> Directive[FontSize -> 15, Black, Bold]};

Now the function proper. Here Options@customTabular gets the rules given above.

The opts pattern is changed to OptionsPattern[{customTabular, Grid}] to declare options for either function as valid options (that is all options in either Options[customTabular] or Options[Grid]).

customTabular[data_, opts : OptionsPattern[{customTabular, Grid}]] := 
 Grid[MapAt[Rotate[#, 90 Degree] & /@ # &, data, 1],
   opts, 
   Sequence @@ Options@customTabular
 ] // Text

Now you can easily change the defaults with SetOptions. Example:

SetOptions[customTabular, 
  Background -> {{{LightMagenta, LightOrange}}}
];

customTabular[data]

enter image description here

Goal #3

Now I want to add an option that is not passed to Grid. I choose "Rotation" to change the text rotation of the title row.

Again I clear the prior definition and the default options. Notice the inclusion of "Rotation" -> 90 Degree in the list.

ClearAll[customTabular]

Options[customTabular] =
  {Background -> {{{White, Pink}}},
   Dividers -> {All, {2 -> True}},
   ItemSize -> {1 -> 5},
   Alignment -> {Center, {1 -> Top}},
   Frame -> True,
   FrameStyle -> Thickness[2],
   ItemStyle -> Directive[FontSize -> 15, Black, Bold],
   "Rotation" -> 90 Degree};

Now I need a way to use this new option, and I need a way to keep this option from being sent to Grid:

  • I access the option with OptionValue which will give the default if none is explicitly given.

  • I pass only valid Grid options by using FilterRules.

I first join any explicit options to the front of the Options@customTabular list, again to override defaults.

customTabular[data_, opts : OptionsPattern[{customTabular, Grid}]] :=
 Grid[MapAt[Rotate[#, OptionValue["Rotation"]] & /@ # &, data, 1],
   Sequence @@ FilterRules[{opts} ~Join~ Options@customTabular, Options@Grid]
 ] // Text

Example:

SetOptions[customTabular, Background -> {{{LightBrown, LightYellow}}}];

customTabular[data,
  Dividers -> All,
  "Rotation" -> -90 Degree,
  FrameStyle -> {Darker@Red, Thick}
]

enter image description here

share|improve this answer
    
Oh man this answer helped me through hours of pain. Thanks! –  Gabriel Oct 7 '12 at 19:16
    
@Gabriel you're very welcome! :-) Let me know if you need help getting anything specific working, or just have questions about the framework I laid out here. –  Mr.Wizard Oct 7 '12 at 19:45

For additional reference, found within the file $InstallationDirectory/SystemFiles/Kernel/TextResources/English/Messages.m are all of the defined messages for the system, and there are 11 General messages for Options that do not conform. The list is

General::optlist = "Value of option `1` -> `2` should be a list."
General::optb = "Optional object `1` in `2` is not a single blank."
General::optrs = "Option specification `1` in `2` is not a rule for a symbol or string."
General::opttf = "Value of option `1` -> `2` should be True or False."
General::optpn = "The value of `1` -> `2` should be a positive machine-sized real number."
General::opttfa = "Value of option `1` -> `2` should be True, False, or Automatic."
General::opttfna = "Value of option `1` -> `2` should be True, False, None, or Automatic."
General::optv = "Value of option `1` in `2` is not valid."
General::optvg = "Value of option `1` -> `2` should be `3`."
General::optvp = "Invalid option value at position `1` in `2`. Allowed values are `3`."
General::optx = "Unknown option `1` in `2`."

As they are General messages, they can be used with any function as follows,

Message[f::opttfa, "SomeOpt", SomeOptValue]
share|improve this answer
1  
I was aware of some of those but I never bothered to find them all. Good reference. –  Mr.Wizard Apr 13 '12 at 16:52
3  
@Mr.Wizard grep General::opt Messages.m. :) –  rcollyer Apr 13 '12 at 16:59

Providing optional arguments to functions is rather straight forward. I'll show you three possibilities.

  1. Positional arguments

    This defines a function with a second optional argument. If the argument is omitted it is taken to have the default value.

    fx[list_, panel_: True] := fx0[list, panel]
    
  2. Named arguments

    This sets up a default value for a named optional argument.

    Options[fx] = {panel -> True}
    fx[list_, OptionsPattern[]] := fx0[list, OptionValue[panel]]
    

    If you explicitly provide a rule for the named argument it will override the default rules stored in Options[]

    fx[{1, 2, 3}, panel -> False]
    
  3. Filtering options

    If you want to provide a decorator function for a built in function and you want to pass options to the function that it calls.

    myplot3D[f_, {x_, x0_, x1_}, {y_, y0_, y1_}, 
       opts : OptionsPattern[]] := 
        Plot3D[f, {x, x0, x1}, {y, y0, y1}, 
       Evaluate[FilterRules[{opts}, Options[Plot3D]]]]
    

    calling that without options, the default options of Plot3D are used

    myplot3D[Im[ArcSin[(x + I y)^4]], {x, -2, 2}, {y, -2, 2}]
    

    enter image description here

    This changes the method used by Plot3D

    myplot3D[Im[ArcSin[(x + I y)^4]], {x, -2, 2}, {y, -2, 2}, Mesh -> None, 
        PlotStyle -> Directive[Yellow, Specularity[White, 20], Opacity[0.8]],
        ExclusionsStyle -> {None, Red}]
    

    enter image description here

Hope that helped.

share|improve this answer
    
Thanks @rm -rf that looks much better. –  Stefan Dec 19 '12 at 14:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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