Mathematica Asked by Mike Honeychurch on July 29, 2021
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.
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.
…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
?
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
.
Correct answer by Mike Honeychurch on July 29, 2021
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.
Answered by Leonid Shifrin on July 29, 2021
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 *)
SetOptions[DateListPlot, BaseStyle -> Directive[Red]];
XYZLineGraph[test]
(* still not red, because I set the relevant defaults separately *)
DateListPlot[test] (* is red *)
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
.
Answered by Verbeia on July 29, 2021
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
But it's not the case in v5:
BTW, you may think you can reproduce the old behavior with
<<Version5`Graphics`
but unfortunately it's buggy in this case:
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.
Answered by xzczd on July 29, 2021
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:
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];
Answered by Sean on July 29, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP