3
$\begingroup$

I have a Manipulate that has dynamic variables that I want to use in the displayed expression and use in the parameters for the manipulate controls. I only calculate these dynamic variables when one of the TrackedSymbols changes using Refresh. It all works. However, these variables are in scope outside of the Manipulate. I would like them not to be as they are only needed inside of it.

The variables whose scope I want to restrict are lower and upper. After I execute this they are available in the notebook to query and alter. How do I restrict their scope? The two function definitions are included below as well.

Manipulate[

 Refresh[
  lower = distPlotRange[distribution, -1, 4];
  upper = distPlotRange[distribution, 1, 4];
  fillRange = {Max[#[[1]]], Min[#[[2]]]} &[Transpose[{fillRange, {lower, upper}}]];
  ,
  TrackedSymbols :> {distribution}
  ];

 plotPdfInterval[distribution, Interval[fillRange],
  PlotRange -> {{lower, upper}, {0, Full}},
  PlotStyle -> Orange,
  Filling -> Axis, FillingStyle -> Blue,
  AxesOrigin -> {lower, 0}]
 ,
 {fillRange, Dynamic@lower, Dynamic@upper, IntervalSlider, Method -> "Push", MinIntervalSize -> 0.01},
 {{distribution, NormalDistribution[]}, 
   {NormalDistribution[], StudentTDistribution[15], LogNormalDistribution[5, 1]}, 
   PopupMenu},
 Initialization :> (fillRange = {-1, 1};)]

First some utility functions:

plotPdfInterval[dist_?DistributionParameterQ, interval_, opts : OptionsPattern[Plot]] :=
 Module[{distPdf = PDF[dist, #] &},
   Plot[distPdf[x], {x, Min[interval], Max[interval]}, opts]
  ]

distPlotRange[dist_?DistributionParameterQ, boundary_?(MemberQ[{-1, 1}, #] &), stdDevs_?NumberQ] :=
 With[{qt = Quantile[dist, If[boundary == -1, 0, 1]]},
  If[NumberQ@qt, qt, 
   Mean@dist + boundary stdDevs StandardDeviation@dist]]
$\endgroup$
2

2 Answers 2

2
$\begingroup$

One can localize the scope of variables to Manipulate by adding them as arguments to Manipulate with ControlType None. For your case

Manipulate[Refresh[lower = distPlotRange[distribution, -1, 4];
  upper = distPlotRange[distribution, 1, 4];
  fillRange = {Max[#[[1]]], Min[#[[2]]]} &[
    Transpose[{fillRange, {lower, upper}}]];, 
  TrackedSymbols :> {distribution}];
 plotPdfInterval[distribution, Interval[fillRange], 
  PlotRange -> {{lower, upper}, {0, Full}}, PlotStyle -> Orange, 
  Filling -> Axis, FillingStyle -> Blue, 
  AxesOrigin -> {lower, 0}], {fillRange, Dynamic@lower, Dynamic@upper,
   IntervalSlider, Method -> "Push", 
  MinIntervalSize -> 0.01}, {{distribution, 
   NormalDistribution[]}, {NormalDistribution[], 
   StudentTDistribution[15], LogNormalDistribution[5, 1]}, 
  PopupMenu}, {lower, None}, {upper, None},
 Initialization :> (fillRange = {-1, 1};)]
$\endgroup$
3
$\begingroup$

You can insert your Manipulate[...] in a DynamicModule[{lower,upper},...]:

DynamicModule[{lower, upper},
 Manipulate[
  Refresh[
   lower = distPlotRange[distribution, -1, 4];
   upper = distPlotRange[distribution, 1, 4];
   fillRange = {Max[#[[1]]], Min[#[[2]]]} &[
     Transpose[{fillRange, {lower, upper}}]];,
   TrackedSymbols :> {distribution}
   ];
  plotPdfInterval[distribution, Interval[fillRange], 
   PlotRange -> {{lower, upper}, {0, Full}}, PlotStyle -> Orange, 
   Filling -> Axis, FillingStyle -> Blue, 
   AxesOrigin -> {lower, 0}], {fillRange, Dynamic@lower, 
   Dynamic@upper, IntervalSlider, Method -> "Push", 
   MinIntervalSize -> 0.01}, {{distribution, 
    NormalDistribution[]}, {NormalDistribution[], 
    StudentTDistribution[15], LogNormalDistribution[5, 1]}, 
   PopupMenu}, Initialization :> (fillRange = {-1, 1};)]
 ]

DynamicModule[{lower,upper},...] saves the variables lower and upper when the notebook is closed. You don't need that. I don't think that is a problem, but if it is, add the option UnsavedVariables -> {lower,upper}.

$\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.