28
$\begingroup$

Is there a way to SetOptions locally? For example, I have a Module and inside it I am doing a lot of Plots with similar options. If I do a SetOptions[Plot, ...] inside the Module, the change propagates outside. I don't like this because I have other Modules where I am doing other plots with different options.

Is there a way to do a SetOptions[Plot, ...] that only affects "local" plots (say inside a Module, but I am open to any scoping construct)? Here Plot is only an example. In general I want to set options locally for any symbol.

$\endgroup$
10
  • 3
    $\begingroup$ Internal`InheritedBlock[{Plot}, SetOptions[Plot, Frame -> True]; Plot[x, {x, 0, 1}] ] like this? $\endgroup$
    – Kuba
    Jan 23, 2017 at 14:51
  • 1
    $\begingroup$ Why not cache the list returned by Options[Plot], do your custom stuff, and use SetOptions[] again at the end? $\endgroup$ Jan 23, 2017 at 14:55
  • 2
    $\begingroup$ @Kuba, I guess Internal`WithLocalSettings[] is also a possibility. $\endgroup$ Jan 23, 2017 at 15:06
  • 3
    $\begingroup$ For the plotting problem in particular, one could define a plot theme. $\endgroup$
    – Michael E2
    Apr 13, 2017 at 15:36
  • 2
    $\begingroup$ @MichaelE2 Wolfram should support an easy way to create new themes. $\endgroup$
    – a06e
    Apr 13, 2017 at 15:47

4 Answers 4

26
$\begingroup$

Version 12.2

In version 12.2, use the new function WithCleanup[]:

With[{plotOptions = Options[Plot]}, 
     WithCleanup[SetOptions[Plot, PlotStyle -> Green], 
                 Plot[Sin[x], {x, -π, π}],
                 SetOptions[Plot, plotOptions]]]

which is a direct replacement of the older undocumented function described below.


Older versions

Usual caveats about using undocumented functions aside, here is how one might use Internal`WithLocalSettings[]:

With[{plotOptions = Options[Plot]}, 
     Internal`WithLocalSettings[SetOptions[Plot, PlotStyle -> Green], 
                                Plot[Sin[x], {x, -π, π}],
                                SetOptions[Plot, plotOptions]]]

but I do not think this to be any better than Nasser's proposal. As can be surmised from how it was used above, you can think of the three arguments of Internal`WithLocalSettings[] as three stages: setup, body, and clean-up. Carl notes in a comment below that the advantage of using this function is that any code in the first and third arguments are uninterruptible.

A more usual case for its use would be for localizing changes to system settings that are not easily accessible to SetOptions[]. Using the Wizard's code from here as an example:

With[{spopt = SystemOptions["SparseArrayOptions"]},
     Internal`WithLocalSettings[
              SetSystemOptions["SparseArrayOptions" -> {"TreatRepeatedEntries" -> 1}],
              ind = {{3, 1}, {3, 3}, {1, 3}, {2, 1}, {3, 2}, {3, 1},
                     {3, 2}, {3, 3}, {1, 3}, {3, 1}};
              val = {1, 1, 3, 0, 3, 4, 3, 1, 1, 1};
              SparseArray[ind -> val] // Normal,
              SetSystemOptions[spopt]]]
   {{0, 0, 4}, {0, 0, 0}, {6, 6, 2}}

(See also this SO thread and this example usage by Oleksandr.)

$\endgroup$
3
  • 9
    $\begingroup$ I would say using Internal`WithLocalSettings is better than using Module, because the first and third arguments of Internal`WithLocalSettings are not interruptible, and always happen. If you add a Pause[10] to Nasser's example and abort the computation, you will see that the PlotStyle remains Green. Also, it's convenient that the second argument is the output, so one doesn't need to store the result so that it can be returned as the output after the cleanup occurs. $\endgroup$
    – Carl Woll
    Jan 23, 2017 at 17:11
  • $\begingroup$ "Also, it's convenient that the second argument is the output, so one doesn't need to store the result so that it can be returned as the output after the cleanup occurs." - that was certainly a convenient feature for me, but I definitely didn't know about the non-interruptibility. Thanks @Carl! $\endgroup$ Jan 23, 2017 at 17:22
  • $\begingroup$ @CarlWoll Maybe for you but if it eventually break your app you can't even complain because you used undocumented function. (the point here is to push it to System`​ since everyone is using it anyway). $\endgroup$
    – Kuba
    Jan 24, 2017 at 6:32
17
$\begingroup$

I have used several methods, including the ones in the other answers. I have found that the simplest method is Internal`InheritedBlock as it allows for temporary changes to a symbol to be made, including changes to Options. For example,

Internal`InheritedBlock[{Plot},
  SetOptions[Plot, PlotStyle -> Red, Frame -> True];
  Plot[Sin[x], {x, 0, 2 Pi}]
]
Plot[Sin[x], {x, 0, 2 Pi}]

enter image description here

Obviously, this has the most utility when you are making multiple plots, but this illustrates the point.

$\endgroup$
3
  • 2
    $\begingroup$ Why don't you (not you personally ofc) document them then? Just add where it would not be a good idea to use it, if there are any problems. It is not like System`​ is perfect anyway. $\endgroup$
    – Kuba
    Jan 24, 2017 at 6:30
  • 1
    $\begingroup$ @Kuba not unreasonable, but not my department. $\endgroup$
    – rcollyer
    Jan 24, 2017 at 12:41
  • 1
    $\begingroup$ I have a particular project in which I want to change the options of a function locally in a ScheduledTaskObject without the options change altering subsequent calls in the FrontEnd. This solution seems to do the trick for me. $\endgroup$ Apr 13, 2017 at 14:07
12
$\begingroup$

Just define your options as sequence held in a local variable.

Module[{opts = Sequence[PlotStyle -> Red, Frame -> True]},
  Plot[Sin[2 π x], {x, 0, 1}, Evaluate @ opts]]

plot

$\endgroup$
4
  • 2
    $\begingroup$ Or use a List instead of a Sequence: opts = {PlotStyle -> Red, Frame -> True} $\endgroup$
    – Bob Hanlon
    Jan 23, 2017 at 15:18
  • $\begingroup$ @becko - it's shorter ... but flavor to taste. $\endgroup$
    – Bob Hanlon
    Jan 23, 2017 at 20:09
  • $\begingroup$ @becko - on my system (11.0.1 for Mac OS X x86 (64-bit)) the Evaluate is still needed. $\endgroup$
    – Bob Hanlon
    Jan 23, 2017 at 20:17
  • 2
    $\begingroup$ If you use With instead of Module, you can eliminate the Evaluate. $\endgroup$
    – rcollyer
    Jan 24, 2017 at 4:11
10
$\begingroup$

This is a simple solution. The idea is to save the Plot options on entry, and restore it on leaving the module to whatever it was

f := Module[{savedOpt = Options[Plot]},
  SetOptions[Plot, PlotStyle -> Green];
  Print@Plot[Sin[x], {x, -Pi, Pi}];
  SetOptions[Plot, savedOpt]
  ]

Now global Plot options are not changed. Test:

Mathematica graphics

$\endgroup$

Your Answer

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

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