Group Abstract Group Abstract

Message Boards Message Boards

Manipulate Re-evaluation

GROUPS:
Hi Guys,

I'm new to Mathematica and I am having trouble understanding manipulate. I have some code which should explore the relationships between the number of trials, the sample space and the sample size. The code below runs with the initialsed values but doesn't re-evaluate if I move any of the sliders, Where am I going wrong?

Many thanks in advance,

Tim

 Manipulate[
  Module[{populationSize = 20, sampleSize = 6, data = {}, rawData,
    dataR, dataL, totalData, trials = 5},
  
   drawSample :=
    AppendTo[data, RandomSample[Range[populationSize], sampleSize]];
   Do[drawSample, {trials}];
  
   rawData = Flatten[data]; dataR = Sort[rawData, Greater];
  dataL = Sort[rawData]; totalData = Join[dataL, dataR];
  BarChart[Drop[totalData, {1, Length[totalData], 2}]]
  ], {populationSize, 1, 50, 1}, {{sampleSize, 6}, 1, populationSize,
  1}, {{trials, 5}, 1, 10}]
POSTED BY: Tim Fernandez-Hart
Answer
9 months ago
Hi Tim,

I think the problem is that you try to localize the Manipulate variables (populationSize, sampleSize, populationSize) again inside the Module. It works just fine if you simply omit these variables from the Module to avoid this conflict.

Note that I had to add the initial value of populationSize to the Manipulate control. Setting the TrackedSymbols option stops the Manipulate from evaluating multiple times (just try out what happens without it).

Bianca

 Manipulate[Module[{data = {}, rawData, dataR, dataL, totalData, drawSample},
 drawSample :=
 AppendTo[data, RandomSample[Range[populationSize], sampleSize]];
 Do[drawSample, {trials}];
 rawData = Flatten[data];
 dataR = Sort[rawData, Greater];
 dataL = Sort[rawData];
 totalData = Join[dataL, dataR];
 BarChart[Drop[totalData, {1, Length[totalData], 2}]]
],
{{populationSize, 20}, 1, 50, 1},
{{sampleSize, 6}, 1, populationSize, 1},
{{trials, 5}, 1, 10},
TrackedSymbols :> {populationSize, sampleSize, trials}]
POSTED BY: Bianca Eifert
Answer
9 months ago
fyi, the above gives an error
RandomSample::smplen: "RandomSample cannot generate a sample of length 15,
which is greater than the length of the sample set {1,2,3,4,5,6,7,8,9,10,11}.
If you want a choice of possibly repeated elements from the set, use RandomChoice"
when moving the populationSize slides less than 15.
POSTED BY: Nasser
Answer
9 months ago
Hi Tim,

Bianca is right and Nasser correctly points out an additional issue. One way to avoid the latter is to make sure that updates to populationSize also update sampleSize if necessary. Here's how you might do that:

 Manipulate[
 
  Module[{data = {}, rawData, dataR, dataL, totalData},
   drawSample :=
    AppendTo[data, RandomSample[Range[populationSize], sampleSize]];
   Do[drawSample, {trials}];
   rawData = Flatten[data];
   dataR = Sort[rawData, Greater];
   dataL = Sort[rawData];
  totalData = Join[dataL, dataR];
  BarChart[Drop[totalData, {1, Length[totalData], 2}]]],

{{populationSize, 20},
  Manipulator[
    Append[#,
     Function[{val, expr},
      expr = val;
      sampleSize = Min[val, sampleSize],
      {HoldRest}]],
    {1, 50, 1}] &},
{{sampleSize, 6}, 1, populationSize, 1},
{{trials, 5}, 1, 10}]

What we've done above is essentially reconstruct the default control, except that we added a customized update function for populationSize that also updates sampleSize if necessary. The details here are relatively intricate. I encourage you to study the Details subsection of ref/Manipulate carefully, and there's probably nothing better for getting acquainted with the nuances and power of Dynamic / Manipulate functionality than a certain set of four tutorials found in the Mathematica Documentation Center, under "Learning Resources" at the following Guide page: http://reference.wolfram.com/mathematica/guide/DynamicInteractivityLanguage.html

Hope this helps!
POSTED BY: William Rummler
Answer
9 months ago
Hi Tim,
This is another way of skinning this particular cat. Variables are localized directly in the Manipulate, as controls.

 Manipulate[
  (* Computations pre output *)
  If[populationSize < sampleSize, populationSize = sampleSize];
  data = {};
  Do[
   AppendTo[data, RandomSample[Range[populationSize], sampleSize]], {trials}
  ];
  rawData = Flatten[data];
  dataR = Sort[rawData, Greater];
dataL = Sort[rawData];
totalData = Join[dataL, dataR];
(* The actual output *) 
BarChart[Drop[totalData, {1, Length[totalData], 2}]],
(* Controls *)
{{populationSize, 20}, 1, 50, 1, Appearance -> "Labeled"},
{{sampleSize, 6}, 1, populationSize, 1, Appearance -> "Labeled"},
{{trials, 5}, 1, 10, 1, Appearance -> "Labeled"},
(* Local variables as controls *)
{data, ControlType -> None},
{rawData, ControlType -> None},
{dataR, ControlType -> None},
{dataL, ControlType -> None},
{totalData, ControlType -> None},
(* Manipulate option *)
TrackedSymbols -> {populationSize, sampleSize, trials}
]
POSTED BY: Hans Milton
Answer
9 months ago
Hello William Rummler,
Your answer is really very useful! I will use this code:"...essentially reconstruct the default control, except that we added a customized update function ..." for all my problems with coupled controls that have inter related restrictions. This solves this problem definitely!
I worked hard to (almost) understand your code but I still have a question:
What is the real structure of the controls inside a Manipulate? What does the # inside the 'update function': Append[#,...]& refer to?
If I change the control and substitute Manipulator by Slider or Trigger etc.. it works fine. But it does not work for any of the gauges which presumably can also be used as controls? Where can we find more about customizing control?
POSTED BY: Erik Mahieu
Answer
9 months ago
Hi Erik,

Thanks for the kind words, I'm glad you find the idiom useful. I should give a fair warning that it may be a bit heavy-duty for some tasks. When you can get away with it, it's better to have simpler interdependencies such as the one sketched above by Hans, adapted here:

 Manipulate[
 
  Module[{data = {}, rawData, dataR, dataL, totalData},
   drawSample :=
    AppendTo[data, RandomSample[Range[populationSize], sampleSize]];
   Do[drawSample, {trials}];
   rawData = Flatten[data];
   dataR = Sort[rawData, Greater];
   dataL = Sort[rawData];
  totalData = Join[dataL, dataR];
  BarChart[Drop[totalData, {1, Length[totalData], 2}]]],

{{populationSize, 20}, sampleSize, 50, 1},
{{sampleSize, 6}, 1, populationSize, 1},
{{trials, 5}, 1, 10},
TrackedSymbols -> True]

Here, we've still prevented the bad interaction between populationSize and sampleSize by simply making them dynamic complementary bounds of each other. (As mentioned, Hans actually did this first in a slightly different way in his answer. Furthermore, these dependency semantics, though different, are probably more useful and certainly more elegant than what I chose to implement .)

Manipulate controls are most often Manipulator objects, but can be other types as described in the Details subsection of ref/Manipulate.

The # (or Slot symbol) inside the custom control specification I gave refers to the first (and only) argument given to the pure function I define. Note that I'm using the {u, func} control specification format described in the Details subsection of ref/Manipulate. The first argument given to func when this specification format is used is Dynamic. Since we want to slightly alter the dynamic update behavior of u, we Append a custom update function to it. The way a custom update function for a Dynamic object must be written is specified in the Details subsection of ref/Dynamic.

About the gauges... yes indeed, I noticed an odd thing, too. By some quick and shallow testing, it seems that the second argument given to the Dynamic update function by a gauge is an ordered pair, seemingly the coordinates of the gauge indicator in the gauge graphic, rather than the symbol to be updated as it is with all other controls I'm more familiar with. You can work around this easily enough by ignoring the second argument 'expr' and updating the relevant control variable directly:

 Manipulate[
 
  Module[{data = {}, rawData, dataR, dataL, totalData},
   drawSample :=
    AppendTo[data, RandomSample[Range[populationSize], sampleSize]];
   Do[drawSample, {trials}];
   rawData = Flatten[data];
   dataR = Sort[rawData, Greater];
   dataL = Sort[rawData];
  totalData = Join[dataL, dataR];
  BarChart[Drop[totalData, {1, Length[totalData], 2}]]],

{{populationSize, 20},
  AngularGauge[
    Append[#,
     Function[val,
      populationSize = Round@val;
      sampleSize = Min[populationSize, sampleSize],
      {HoldAll}]], {1, 50}] &},
{{sampleSize, 6}, 1, populationSize, 1},
{{trials, 5}, 1, 10}]

For more details and for the only good foundation you can have before setting off in more complicated directions, nothing beats browsing the dynamics tutorials mentioned in my previous post as well as the Details subsections of the reference pages of the many symbols involved in all this. Browse the examples at these pages and modify/re-evaluate/interact with them. Comfort comes with experience, and experience only comes with time invested.

Finally, here's another good, general "springboard" resource for things like this:
http://reference.wolfram.com/mathematica/guide/CustomInterfaceConstruction.html

--William
POSTED BY: William Rummler
Answer
9 months ago
Thanks, William. This solves my questions completely.
You,ve been a great help. Maybe one day in the future I will master this Dynamic completely emoticon
POSTED BY: Erik Mahieu
Answer
9 months ago