25
$\begingroup$

Not all functions seem to work with SetOptions. e.g.

SetOptions[Grid, BaseStyle -> Directive[Red]];
Grid[{{"hello", "world"}}]

hello world

the font is not red.

SetOptions[Row, BaseStyle -> Directive[Red]];
Row[{"hello", "world"}]

hello world

...and the font is red.

enter image description here

SetOptions[InputField, FieldSize -> 5];
InputField[Dynamic[x]]

the input field size is much larger than 5. But on the other hand

InputField[Dynamic[x], Sequence @@ Options[InputField]]

yields an input field with field size 5.

enter image description here

...and so on.

What is the easiest way to work out (i.e. make a list of ...) which functions can't be used with SetOptions?

$\endgroup$
2
  • 1
    $\begingroup$ It'd also be interesting to know which objects work with it, e.g. it works with Graph, $FrontEndSession, etc. but all these are somewhat special $\endgroup$
    – Szabolcs
    Commented Jan 20, 2012 at 9:16
  • 1
    $\begingroup$ Really good question! +1 $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 9:20

5 Answers 5

10
$\begingroup$

I don't know the direct answer to the specific question on SetOptions, but if we look at the purpose of (re)setting options globally, I have some alternative suggestion. A need to set options globally means that you need some persistent configuration of options which you'd like to be applied many times, without extra effort on your side. This can be achieved by creating such option(s) configuration and then always passing options locally (explicitly). It is possible to create helper functions / macros, which would automate this process for you and make it look and feel (almost) as if you have set your options globally.

I have implemented a simplistic options configuration manager, and a lexically scoped construct withOptionConfiguration, which can be wrapped around your code containing a function call of interest. One can also implement dynamically-scoped environments, for which the option-passing will happen also for all code called from the code within a construct. To my mind, this will save a lot of hassle even if / when you get the exhaustive answer to your direct question, since with the approach I suggest, you don't have at all to remember which functions work with SetOptions and which don't.

$\endgroup$
12
  • $\begingroup$ In a rare turn of events I shall not vote for your answer as I don't believe it addresses the question asked. (but I'll go find another answer of yours I haven't seen yet and vote for that to compensate) $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 17:01
  • 2
    $\begingroup$ @Mr.Wizard I wanted to make this a comment, but it was too large for that. I actually strongly dislike resetting options globally (SetOptions), particularly for system functions, but also generally. I think this practice should be officially discouraged, since it changes the global state of the system. As soon as their will be many interdependent third-party applications / packages in widespread use, (and I hope this will happen, for the sake of Mathematica community), the use of SetOptions will create nothing but problems. My personal view, of course. $\endgroup$ Commented Jan 20, 2012 at 17:07
  • $\begingroup$ @Mr.Wizard You are right that this does not address the direct question, but I clearly stated so, and also I think it addresses the reason for this question. If I get lots of negative feedback on this from others, I may delete this answer and just incorporate this in the book. $\endgroup$ Commented Jan 20, 2012 at 17:09
  • $\begingroup$ Please do not delete it; again I know (or at least presume) that you cannot see my votes, but I still feel the need to explain why I don't vote for an otherwise thoughtful answer. I do not share your blanket distaste for global options, because Mathematica is often an individually used and individualized software. I would however be concerned by packages that changed my options without notice! $\endgroup$
    – Mr.Wizard
    Commented Jan 20, 2012 at 17:17
  • $\begingroup$ @LeonidShifrin No, please don't delete. An answer is always useful if it adds anything of substance to solving/understanding the question. Sometimes (generally, not specific to this), such answers can also be helpful in figuring out the underlying problem or if it's a conceptual misunderstanding on the OP's part. Deleting should be reserved for answers that talk of football when the question is on tennis. I can understand people not wanting to vote, but that doesn't diminish the usefulness. $\endgroup$
    – rm -rf
    Commented Jan 20, 2012 at 17:20
9
$\begingroup$

As noted in the question, when you set an option to a function which appears not to work with SetOptions the options do get set, e.g. from the question:

InputField[Dynamic[x], Sequence @@ Options[InputField]]

but for whatever reason the global setting does not get used locally by default.

Another interesting case is this:

SetOptions[Grid, Background -> RGBColor[1, 0, 0]]

which returns a list of Grid options with the new Background, yet when you do the same with GridBox

SetOptions[GridBox, Background -> RGBColor[1, 0, 0]]
SetOptions::nspt: "SetOptions of GridBox is not supported"

So testing the actual "box form" seems to highlight the problem. In this case GridBox is not supported for SetOptions even though Grid did not return an error. So the following solution is a variation of what was provided to me by tech support. Check can be used to return something in the case of a SetOptions error:

Check[SetOptions[GridBox, "a" -> "b"], err, SetOptions::nspt]

SetOptions::nspt: "SetOptions of GridBox is not supported."
err

First get a list of names:

names = Names["System`*"]

test the names for the SetOptions error

list = Quiet[Map[Check[SetOptions[ToExpression[#], "a" -> "b"]; Null, #, 
      SetOptions::nspt] &, names]];

delete the Null elements

DeleteCases[list, Null]

{ActionMenuBox,AnimatorBox,CheckboxBox,ColorSetterBox,CounterBox,DynamicBox,
DynamicModuleBox,DynamicWrapperBox,GridBox,InputFieldBox,ItemBox,Line3DBox,LineBox,
LocatorBox,LocatorPaneBox,OpenerBox,OptionValueBox,OverlayBox,PaneBox,PanelBox,
PaneSelectorBox,Point3DBox,PointBox,PopupMenuBox,ProgressIndicatorBox,RadioButtonBox,
RectangleBox,RotationBox,SetterBox,Slider2DBox,SliderBox,TabViewBox,TemplateBox,
TogglerBox,TooltipBox,ValueBox}

So we have a list of 36 types of boxes that cannot be used with SetOptions.

$\endgroup$
5
  • $\begingroup$ Despite new answers bumping questions to the top I missed this until now. +1 (Also, consider accepting your own answer.) $\endgroup$
    – Mr.Wizard
    Commented Feb 16, 2012 at 12:49
  • $\begingroup$ 95% of this answer came from tech support. Nevertheless it does seem to be the best way of finding this information so I am accepting "my own" answer. $\endgroup$ Commented Feb 16, 2012 at 23:51
  • 2
    $\begingroup$ re "is accepting your own answer good etiquette?" if you want the consensus opinion of this specific community I suggest a question in Meta; mine is that is that it is perfectly fine if it is a proper answer and not simply something of the form: "I ended up using Joe's answer with this small tweak:" which I am sure you have seen before. In the case of an answer like this one could argue that it is bad etiquette to not accept your answer as then it doesn't show the problem as solved. $\endgroup$
    – Mr.Wizard
    Commented Feb 17, 2012 at 3:04
  • 2
    $\begingroup$ @Mr.Wizard and Mike Honeychurch: I've checked that this method miss Style(StyleBox) and Text(InterpretationBox). What lead me to the doubts if this is the core of the problem. For example: SetOptions[Style, FontColor -> Red]; Style["test"] will not work while you can SetOptions on StyleBox. It is getting weirder, try to set SetOptions[StyleBox, FontColor -> Red] (set it to Automatic to undo) and later SetOptions[StyleBox, FontSize -> 25] <- it seems that color was changed on all types of cells while size only for "InlineText", but basic "InlineText" cell have no StyleBox... $\endgroup$
    – Kuba
    Commented Jul 18, 2013 at 7:07
  • $\begingroup$ @Kuba Also, function calling GridBox internally isn't necessarily influenced, for example: SetOptions[MatrixForm, TableSpacing -> {5, 2}]; {#, # // ToBoxes} &@MatrixForm[{{1, 2}, {1, 2}}]. $\endgroup$
    – xzczd
    Commented Jun 3, 2018 at 8:36
2
$\begingroup$

I think the reason for this is that many functions pass their options to other functions that they call during evaluation. See for example this answer to a related question on StackOverflow. So you can't set the option for the function you use, only the function that the option is passed to.

So for example, in one of my packages (you can guess which one, I have of course changed the initials of my employer to "XYZ") I have a function that starts with the definition:

XYZLineGraph[data:{{__?NumericQ} ..}, 
dates_List, opts:OptionsPattern[{XYZLineGraph, 
 DateListPlot, XYZDateTicks, XYZTickGrid, GraphNotesGrid}]] := (* more here *)

I cannot set the defaults for XYZLineGraph that are actually defaults of DateListPlot using SetOptions[XYZLineGraph].

An example:

test = FinancialData["AAPL", {2008}];
SetOptions[XYZLineGraph, BaseStyle -> Directive[Red]];
XYZLineGraph[test]  (* not red *)

enter image description here

SetOptions[DateListPlot, BaseStyle -> Directive[Red]];
XYZLineGraph[test]  

(* still not red, because I set the relevant defaults separately *)

DateListPlot[test]  (* is red *)

enter image description here

As for identifying which functions can have SetOptions work this way, I suspect the only way you could do this for built-in functions would be a laborious use of Trace.

$\endgroup$
4
  • $\begingroup$ hmmm, I might email you about that @Verbeia. $\endgroup$ Commented Jan 20, 2012 at 23:32
  • $\begingroup$ Don't tell me this question is about your implementation of the same functionality? That is funny. $\endgroup$
    – Verbeia
    Commented Jan 21, 2012 at 0:00
  • $\begingroup$ No completely unrelated actually but given your answer I thought I would chat to you about it. I am the only person that uses my computer and I like to set certain configurations for functions I use regularly. $\endgroup$ Commented Jan 21, 2012 at 0:07
  • 1
    $\begingroup$ As you've shown, the issue is that BaseStyle is not an option of XYZLineGraph. However, you can make it one by including Options[DateListPlot] in the options for XYZLineGraph, using FilterRules to strip out any changes to the defaults you make. Then, using FilterRules, you pass the DateListPlot options to it from within XYZLineGraph. $\endgroup$
    – rcollyer
    Commented Jan 31, 2012 at 4:21
1
$\begingroup$

I expanded upon Mike Honeychurch's excellent solution by generalizing his solution into a general-purpose "Option Dictionary" creator. It includes his use of Check to indicate whether you are allowed to use a SetOptions on a given symbol, but it also includes a formatted list of all the available options, not cluttered with the current default values.

The net output is formatted in a Grid-friendly manner, but need not be used with a Grid. For example, you can use the raw List output with no arguments to generate an option dictionary for all of Mathematica, then do things like use Cases or Position to search for some particular "child option" that exists in any symbol in Mathematica.

Here is the code:

(* HoldComplete needed -- TemplateSequence options "DefaultValue" and "Delimiters" contain Sequence[] *)

FreeRulesQ = 
  Function[expr, FreeQ[Unevaluated@expr, _Rule | _RuleDelayed], 
   HoldAllComplete];

RulesToOptionList[rules_List] := Replace[
  Replace[
   ReplaceAll[
    rules,
    {Rule[opt_, val_?(FreeRulesQ)] :> opt, 
     RuleDelayed[opt_, val_?(FreeRulesQ)] :> opt}
    ],
   {Rule[opt_, val_] | RuleDelayed[opt_, val_] :> {opt, val}},
   {1, Infinity}
   ],
  opt : Except[_List] :> {opt, {}},
  {1}
  ]

SetOptionsQ = 
  Function[symbol, 
   Quiet@Check[SetOptions[ReleaseHold@symbol, {}]; True, False], 
   Listable];

With[{symbolListDefault = MakeExpression@Names["System`*"]},
 OptionsDictionary[HoldPattern[optionList_ : Sequence[]], 
   symbolList_List : symbolListDefault] :=
  
  With[{optionsForSymbols = 
     Quiet@ReleaseHold@
       Thread@Hold[Options][symbolList, Hold@optionList]},
   Transpose@
      {symbolList[[#]] /. HoldComplete -> HoldForm, 
       RulesToOptionList@optionsForSymbols[[#]], 
       SetOptionsQ@symbolList[[#]]} &@
    Flatten@Position[optionsForSymbols, {__}, {1}]
   ]
 ]

Usage:

OptionsDictionary[{ContentPadding, ImageSize}] // Grid
OptionsDictionary[GeneratedCellStyles] // Grid

Output:

enter image description here

enter image description here

As a bonus (off-topic a bit), here are a couple helper utilities that I found useful in visualizing the data structure while I was developing this:

LevelFormatted = Function[{expr, level, patternTest}, {
    level,
    Row@Map[
       Framed[patternTest@First@#, 
         Background -> If[level == 0, None, Last@#]] &]@
      MapIndexed[{#1, GrayLevel[.3, 0.2 - 0.1*Mod[First@#2, 2]]} &]@
       Level[expr, {level}]
    },
   Listable
   ];

LevelGrid = Function[{expr, patternTest},
   Grid[#, Frame -> All, Background -> {
        {1 -> LightYellow},
        {{{LightBlue, None}}, Depth[expr] + 3 -> LightYellow}
        }] &@
    Prepend[{Style[ToString@Unevaluated@expr, Bold], SpanFromLeft}]@
     LevelFormatted[Unevaluated@expr, 
      Range[-Depth[expr] - 1, Depth[expr]], patternTest],
   HoldAllComplete
   ];

RuleLevels = 
  Function[expr, 
   LevelGrid[expr, Row@{Framed@#, Framed@FreeQ[_Rule]@#} &], HoldAll];
$\endgroup$
0
$\begingroup$

I believe this is another problem caused by the significant change of graphics functionality between versions 5 and 6. (As to other problems, check post about AbsoluteOptions and post about FullGraphics.)

A key evidence is Text. As mentioned by Kuba, this is a function that doesn't call those functions mentioned in Mike's answer, yet SetOptions still fails on it, for example:

$Version

SetOptions[Text, Background -> RGBColor[1, 0, 0]];
Text["A", {0, 0}] // Graphics

enter image description here

But it's not the case in v5:

enter image description here

BTW, you may think you can reproduce the old behavior with

<<Version5`Graphics`

but unfortunately it's buggy in this case:

enter image description here

So, functions related to graphics added or modified in or after v6 are likely to be influenced, but I can't think out a systematic way to test my guess at the moment.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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