22

I couldn't find a more descriptive title, but I guess an example will explain my problem.

I set up some customized Grid function including some additional functionalities which I control with custom Options. Additionally, I would like to change some of the standard Grid Options, e.g. always use Frame->All. Take the following working example:

Options[myGrid] = {Frame -> All, "Tooltip" -> False};
myGrid[content_, opts : OptionsPattern[]] :=
  Module[{con},
    If[OptionValue["Tooltip"],
      con = MapIndexed[Tooltip[#1, #2] &, content, {-1}],
      con = content
    ];
    Grid[con,
      Sequence @@ 
        FilterRules[{opts}~Join~Options[myGrid], Options[Grid]]
    ]
  ]

defining an example content:

mat = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

We can test the behavior:

myGrid[mat]

Mathematica graphics

The custom "Tooltip" flag works as intended. Now I want to pass an Option to Grid, that has not been explicitely set in the above Options[myGrid] declaration.This eventually makes it through to the Grid, but produces an error message.

myGrid[mat, Background -> Blue]

Mathematica graphics

Mathematica graphics

To get rid of the errors I embed the Options from Grid into my custom function:

Options[myGrid] = 
  Join[
    {Frame -> All, "Tooltip" -> False},
    Options[Grid]
  ];

Now, I can change the Grid Options without raising an error:

myGrid[mat, Background -> Green]

Mathematica graphics

but the custom setting Frame->All gets lost.

myGrid[mat, Frame -> All]

Mathematica graphics

Apparently, the default Frame->None setting for Grid overrules my custom setting. I banged my head against this problem for too long already, therefore my plea for your assistance.

xyz
  • 605
  • 4
  • 38
  • 117
Markus Roellig
  • 7,703
  • 2
  • 29
  • 53

2 Answers2

31

OptionsPattern:

Mathematica graphics

Therefore declare Options for both myGrid and Grid as valid:

Options[myGrid] = {Frame -> All, "Tooltip" -> False};

myGrid[content_, opts : OptionsPattern[{myGrid, Grid}]] := . . .

Then:

myGrid[mat, Background -> Blue]
Grid[mat, Background -> RGBColor[0, 0, 1], Frame -> All]

With no error message.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • 2
    This is pretty cool, +1. – Leonid Shifrin Mar 01 '13 at 17:36
  • @Leonid I had no idea this was esoteric. :-) – Mr.Wizard Mar 01 '13 at 17:39
  • This particular form is not documented (list of functions inside OptionsPattern[]). I wasn't aware of it. – Leonid Shifrin Mar 01 '13 at 17:49
  • @Leonid I put a copy of a line from the documentation at the top of my post. Does it not describe this use? – Mr.Wizard Mar 01 '13 at 18:10
  • This does indeed, but this is not what I see in the V9 documentation, where only list of rules is mentioned. I will try to remember to ask why there was such a change. – Leonid Shifrin Mar 01 '13 at 19:30
  • @Leonid It's right on that page, under Details -- I can see how that seems hidden. – Mr.Wizard Mar 01 '13 at 19:32
  • Ok, you are right. My fault, then. In some sense, the placement is right in the docs. – Leonid Shifrin Mar 01 '13 at 19:49
  • Hi Mr.Wizard and @Leonid, instead of a separate question I will write it as a comment, unless you consider it is better not to. I have been using the method of this answer succesfully with buil-tin functions. But now imagine that Grid in the above example is one functon I wrote in package A and myGrid is a function I wrote in package B. Then this method returns an error message, that an option is unknown. When I evaluate myGrid twice then it works. You have an idea why? – Santiago Mar 16 '15 at 14:20
  • @Santi Are you including package A in the BeginPackage expression in package B? – Mr.Wizard Mar 16 '15 at 14:30
  • @Wizard yes I am using this: BeginPackage["PackageB", {"PackageA"}] – Santiago Mar 16 '15 at 14:33
  • I can't format very well the output here, but yes, I am not forgetting any "`" or something – Santiago Mar 16 '15 at 14:34
  • I also declared the options for my custom "Grid" function in package A, using: option1::usage="..." before trhe Private context. That means that packageB can see the options of the function in package A. – Santiago Mar 16 '15 at 14:56
  • 1
    @Santi (1) To escape code that includes a back-tick you must wrap it in double back-ticks. (2) I suggest you post a new question with a minimal working example of both packages A and B. To debug the problem I would need to start by recreating these myself and it would be better that it come from you so that it is genuinely representative. – Mr.Wizard Mar 16 '15 at 23:04
  • Ok thanks! At the moment I don't have much time, but on the weekend I'll try to do the most suitable MWE that I can come up with. – Santiago Mar 17 '15 at 13:45
6

The problem in this particular case comes from the default setting of the Dividers option, which overrides the Frame option settings. This does not strike me as a right behavior, or at least these options are not as orthogonal as they should be. This appears to fix the problem:

Options[myGrid] = 
   Join[{Frame -> All, "Tooltip" -> False}, 
      DeleteCases[Options[Grid], Dividers -> _]];

On a general note, however, I would add all options you may ever want to pass to some functions inside your function, explicitly as valid options of your function. If you find this too bothersome, you can, for this particular function (myGrid), switch back to good old OptionQ pattern:

myGrid[content_, opts___?OptionQ] := ...

at the expense of the short "magical" version of OptionValue not working any more, so you will have to use OptionValue[myGrid,{opts},"Tooltip"]. I do this sometimes, in exactly this sort of situations.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • Any advantage of using OptionQ versus OptionsPattern[] if in any case you will end up using the longer versions of OptionValue? – Rojo Mar 01 '13 at 17:03
  • @Rojo with my method you do not need the longer version of OptionValue. – Mr.Wizard Mar 01 '13 at 17:18