2
$\begingroup$

Attempting to implement @Nasser's answer for How to avoid an expensive subset of a Manipulate computation when dependent variables have not changed?, using a Manipulate that includes a TabView, I wrote the following

Manipulate[tick;
 TabView[{
    "not continuous slider: b" -> Grid[{
      {"b",
       Manipulator[
        Dynamic[b, {activeTab = 1 ; b = #; f = preCalculateStuff[b];
           tick = Not[tick]} &], {0, 1, 0.01},
        ContinuousAction -> False], Dynamic[b]}}]
   , "Plot; continous slider: t" -> Grid[{
      {"t",
       Manipulator[
        Dynamic[t, {activeTab = 2 ; t = #; tick = Not[tick]} &], {0,
         1, 0.01}], Dynamic[t]},
      {Row[{"f=", f, " b=", b, " t=", t}]},
      {Plot[(f t) Sin[t + r], {r, 0, 2 Pi}, ImagePadding -> 30,
        ImageSize -> 400, Frame -> True]}
      }, Spacings -> {.5, .5}]
   }, activeTab, Alignment -> Center]
 , {{tick, False}, None}
 , {{b, .4}, None}
 , {{t, .7}, None}
 , {{f, .5*.4}, None}
 , {{activeTab, 1}, None}
 , TrackedSymbols :> {tick}
 , Initialization :> (preCalculateStuff[b_] :=
    Module[{},(*heavy computation goes here*)0.5 b])]

This displays fine:

tab B

tab T

I had an issue with TabView resetting to the first Tab after any Manipulator change, but solved that by adding the activeTab variable.

Without a TabView (i.e. just a Grid) this works fine, but when I use the TabView:

  • the slider that does not include ContinuousAction -> False will only slide by a small amount at a time.
  • either slider automatically goes into "Pause" state if the Play arrow of the control is used.

Nasser's sample that uses Grid handles Play without this pausing issue, so I'm thinking that the trouble is with something like a temporary change of Tab focus happening somewhere under the covers.

EDIT: Note that one of my end goals was to have a fairly large set of control variables all in one tab (ones associated with preCalculateStuff), without cluttering up the rest. This is attempt to conform to the size restrictions imposed on wolfram demonstrations submissions.

Here's an example of a TabView with the Manipulates distributed between them. This works fine, but doesn't use the Tick method that allows the change of the variables to act as callbacks as in Nasser's code:

Manipulate[
 pts1 = p;
 pltrng = {{-1, 1}, {-1, 1}};

 pnts = LocatorPane[ Dynamic[p, {(pts1 = p; p = #) &, (p = #) &}],
   Dynamic@Graphics[Point[p], PlotRange -> pltrng], LocatorAutoCreate -> True ];

 slider = Grid[{ { "q", Manipulator[ Dynamic[q, {q = #} &] , {0, 1, 0.01} ], Dynamic[q] },
    { "r", Manipulator[ Dynamic[r, {r = #} &] , {0, 1, 0.01} , ContinuousAction -> False ], Dynamic[r] } }] ;

 tbl = Dynamic[ Grid[ { { (Table[
         With[{i = i}, {i, Dynamic[pts1[[i]]]}], {i, Length@pts1}] // TableForm) , Dynamic[q] } } ]];

 ln = Dynamic@Graphics[{Red, Thick, Line[pts1]}, PlotRange -> pltrng];

 TabView[{ "table" -> tbl , "locators" -> pnts , "line" -> ln , "slider" -> slider }, Alignment -> Center]
 , {{p, {{-.5, -0.5}, {-.25, .5}, {.6, 0.6}}}, None}
 , {{q, 0.5}, None}
 , {{r, 0.5}, None}
 ]

(This is based on: https://mathematica.stackexchange.com/a/5515/10)

$\endgroup$
5
  • 1
    $\begingroup$ Note that one of my end goals was to have a fairly large set of control variables all in one tab (ones associated with preCalculateStuff), without cluttering up the rest. you can definitely do that. Here is demo with multiple tabs, each tab has in it many more controls that show up when selected. This is allow more controls to be put on the same screen area. demonstrations.wolfram.com/… This has three layers to have even more controls demonstrations.wolfram.com/… $\endgroup$
    – Nasser
    Jan 16, 2014 at 16:04
  • $\begingroup$ Thanks for the references. I am seriously humbled even looking at the code of those demos! $\endgroup$ Jan 16, 2014 at 19:06
  • $\begingroup$ Are you able to distill the technique that you are using down to a simple example? I'm not having much luck decoding what you've done in those (rather large) demos. $\endgroup$ Jan 17, 2014 at 2:44
  • $\begingroup$ I've added a small example as separate answer. This is the basic idea used in those demos. Those demos are more complicated, only because there are more tabs and controls, and use the Macro method by Leonid to help in the layout of the controls. See stackoverflow.com/questions/7551647/… for more information on the macro method. But for simple demos, you can just code the controls inline right there, and not use macros, as shown in the example. $\endgroup$
    – Nasser
    Jan 17, 2014 at 4:09
  • $\begingroup$ Awesome, great example. Thanks Nasser. $\endgroup$ Jan 17, 2014 at 4:57

3 Answers 3

5
$\begingroup$

Here is the general layout to use Tabbed view with dynamic controls inside them, to allow one to add more controls, so as to save on the display area.

enter image description here

Manipulate[
 tick;
 Plot[Sin[a x], {x, -3 Pi, 3 Pi}, PlotStyle -> color, ImageSize -> 300, 
    ImagePadding -> 30, Frame -> True],

 Grid[{
   {

    TabView[{

      "frequency" -> 
       Row[{Manipulator[Dynamic[a, {a = #; tick = Not[tick]} &], {1, 20, 1}, 
        ImageSize -> Tiny, ContinuousAction -> True], Dynamic[NumberForm[a, 5]]}],

      "style" -> PopupMenu[Dynamic[color, {color = #; tick = Not[tick]} &],
        {
         Red -> "Red",
         Blue -> "Blue",
         Dashed -> "Dashed"
         }, ImageSize -> All]
      }]

    }}],

 {{tick, False}, None},
 {{a, 1}, None},
 {{color, Red}, None},
 TrackedSymbols :> {tick},
 ControlPlacement -> Left
 ]
$\endgroup$
2
  • $\begingroup$ What was the function of the Grid that surrounded the TabView here? $\endgroup$ Feb 18, 2014 at 3:25
  • $\begingroup$ @PeeterJoot As it stands, Grid does nothing. I must had some text or something else I wanted to add and left the Grid there. I use Grid always as the base for setting up/laying out everything. In this case it can be removed with no effect. $\endgroup$
    – Nasser
    Feb 18, 2014 at 7:24
1
$\begingroup$

You are putting the control dynamics inside the Manipulate expression itself. I do not think this will work.

The controls variables, should be separated from the expression itself. The layout is like this:

Manipulate[ expression_contains_dynamic_symbols, controls_that_changes_dyanmics ]

You put inside the TabView the controls. Simply use the standard layout. Remember that each time you tickle the tick, the whole Manipulate expression will evaluate. Hence, if you put a slider inside the expression, and tickle the expression at the same time, then Manipulate will just keep evaluating itself right away, and the slider will not get a chance to move. This is not how the tick is meant to be used.

enter image description here

Manipulate[tick;

 Grid[{
   {TabView[{
      "not continuous slider: b" -> b,
      "Plot; continous slider: t" ->
       Plot[(f t) Sin[t + r], {r, 0, 2 Pi}, ImagePadding -> 30, ImageSize -> 400, 
       Frame -> True]
      }, activeTab, Alignment -> Center
     ]
    }}],


 Grid[{
   {"b", Manipulator[Dynamic[b, {activeTab = 1; b = #; f = preCalculateStuff[b]; 
     tick = Not[tick]} &], {0, 1, 0.01}, ContinuousAction -> False], Dynamic[b]},

   {"t", Manipulator[Dynamic[t, {activeTab = 2; t = #; tick = Not[tick]} &], 
     {0, 1, 0.01}, ContinuousAction -> True], Dynamic[t]}}
 ],

 {{tick, False}, None},
 {{b, .4}, None},
 {{t, .7}, None}, 
 {{f, .5*.4}, None}, 
 {{activeTab, 1}, None}, 
 TrackedSymbols :> {tick}, 
 Initialization :> (preCalculateStuff[b_] := Module[{},0.5 b]
   )
 ]
$\endgroup$
1
  • $\begingroup$ I've added an EDIT to my question with my motivation. I suppose that I could do it manually with Slider's, and have those sliders constrained to the tabs. $\endgroup$ Jan 16, 2014 at 15:54
1
$\begingroup$

I wasn't sure what the main question is, but below is an alternative answer to this concern:

Note that one of my end goals was to have a fairly large set of control variables all in one tab (ones associated with preCalculateStuff), without cluttering up the rest.

I give a made-up example showing this sort of separation of controls in a TabView. The Dynamic around various expressions prevents the whole TabView from being reevaluated. If were reevaluated, it would be recreated, which would set the view to the first tab every time a variable was changed. As it is, the variables in the "setup" tab may be manipulated without causing an update; the plot will not be reevaluated until the "view" tab is selected. Since preCalculateStuff beeps, it's easy to monitor when it's evaluated.

Manipulate[
 TabView[{

   "view" -> Dynamic[Column[
      tab; preCalculateStuff[b];
      {
       Labeled[Control[{color, Blue}], Style["color", "Label"], Left],
       Dynamic @ Plot3D[Sin[a x] + Cos[b y + c], {x, -x0, x0}, {y, -y0, y0},
         PlotStyle -> color]
       }],
     TrackedSymbols :> {tab}],

   "setup" -> Grid[
     {Style[#1, "Label"], Manipulator[##2]} & @@@ {
       {"a", Dynamic[a], {0, 5}},
       {"b", Dynamic[b], {0, 5}},
       {"c", Dynamic[c], {-5, 5}},
       {"x0", Dynamic[x0], {0.1, 8}},
       {"y0", Dynamic[y0], {0.1, 8}}
       }
     ]

   }, Dynamic@tab],

 {{color, Blue}, None},
 {{a, 1}, None}, {{b, 1}, None}, {{c, 0}, None},
 {{x0, 1}, None}, {{y0, 1}, None},
 {{tab, 1}, None},
 Initialization :> (preCalculateStuff[b_] := Beep[])
 ]

enter image description here enter image description here


Another alternative

Manipulate seems to localize variables appropriately here. Let me know if there's a problem.

Here the variable show switches between what code is displayed.

Manipulate[
 show,

 {{color, Blue}, None},
 {{a, 1}, None}, {{b, 1}, None}, {{c, 0}, None},
 {{x0, 1}, None}, {{y0, 1}, None},

 Evaluate[{{show, #[[1, 1]]}, #, Setter} & @@ Hold[{
     Dynamic @ Column[
        preCalculateStuff[b];
        {
         Labeled[Control[{color, Blue}], Style["color", "Label"], 
          Left],
         Dynamic @
          Plot3D[Sin[a x] + Cos[b y + c], {x, -x0, x0}, {y, -y0, y0},
           PlotStyle -> color]
         }] -> "view",
     Dynamic @ Grid[
        {Style[#1, "Label"], Manipulator[##2]} & @@@ {
          {"a", Dynamic[a], {0, 5}},
          {"b", Dynamic[b], {0, 5}},
          {"c", Dynamic[c], {-5, 5}},
          {"x0", Dynamic[x0], {0.1, 8}},
          {"y0", Dynamic[y0], {0.1, 8}}
          }
        ] -> "setup"}]],

 Initialization :> (preCalculateStuff[b_] := Beep[])
 ]
$\endgroup$
1
  • $\begingroup$ This is a useful example in a number of ways. I'd used semicolon lists of statements in Module, but see in your first example you use: Column[ tab; preCalculateStuff[b]; {...} ], that this is really a more general construct. You've used this to run your Beep code, but still provide the list that Column[] expects. $\endgroup$ Jan 17, 2014 at 16:04

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.