4
$\begingroup$

I'm trying to use Dynamic and If inside Manipulate to alternate controls depending on a check box control. For example,

Manipulate[a,
 Control[{{a, 0}, {0, 1}}],
 Dynamic[If[a == 0, Control[{{abc, 0}, {0, 1}}], Control[{{abcdef, 0}, {0, 1}}]]],
 ControlPlacement -> Left]

Which gives

enter image description here

and

enter image description here

However, I would like both check boxes to automatic align whenever a is selected or not, as happens in the default case

Manipulate[a,
 Control[{{a, 0}, {0, 1}}],
 Control[{{abc, 0}, {0, 1}}],
 Control[{{abcdef, 0}, {0, 1}}],
 ControlPlacement -> Left]

Giving

enter image description here

The same thing happens if I use other control types, such as sliders. Any idea how to fix this?

Edit 1: In the check box case, the answer was already provided by user chuy, below. I am, however, also interested in the case where I have both sliders and boxes. Following the answer, I could write

Manipulate[a, 
 Column[{Control[{a, 0, 1, 0.1}], 
   Dynamic[If[a < 1, Control[{{abc, 0}, {0, 1}}], 
     Control[{{abcdef, 0}, {0, 1}}]]]}, Alignment -> Right], 
 ControlPlacement -> Left]

which gives

enter image description here

This is already pretty good, but I wonder if it's possible to get an alignment as in the following case

Manipulate[a, Control[{a, 0, 1, 0.1}], Control[{{abc, 0}, {0, 1}}], 
 ControlPlacement -> Left]

that is,

enter image description here

together, again, with Dynamic and If. In this case, the solution provided doesn't seem to work, even with Alignment set to Center or Right. I can probably play around with Spacer and Row to get what I want, but is there any shorter solution?

Edit 2: Regarding spacing, as discussed in the comment section of m_goldberg's answer, I have, for example and considering an extra slider after the check box,

Manipulate[a, 
 Dynamic@Grid[{{"a", Control[{{a, 0, ""}, 0, 1, 0.1}]}, 
    If[a < 1, {"abc", Control[{{abc, 0, ""}, {0, 1}}]}, {"", 
      SpanFromLeft}], {"b", Control[{{b, 0, ""}, 0, 1, 0.1}]}}, 
   Alignment -> {{Right, Left}, Automatic}], ControlPlacement -> Left]

that is,

enter image description here

When a=1, we get

enter image description here

There is clearly some spacing between the sliders due to {"", SpanFromLeft}, which I want to avoid. My goal is to get the natural spacing, as seen in

Manipulate[a, 
 Dynamic@Grid[{{"a", Control[{{a, 1, ""}, 0, 1, 0.1}]}, {"b", 
     Control[{{b, 0, ""}, 0, 1, 0.1}]}}, 
   Alignment -> {{Right, Left}, Automatic}], ControlPlacement -> Left]

that is,

enter image description here

Any ideas?

Note: I recognise I might be deviating a bit from the original question (which was already answered with different approaches), so I will stop editing it after I solve this last problem. Either way, thanks for all the answers!

$\endgroup$
2
$\begingroup$

You could use Grid. Like so:

Manipulate[a,
  Dynamic @
    Grid[
      {{"a", Control[{{a, 0, ""}, 0, 1, 0.1}]},
       If[a < 1,
         {"abc", Control[{{abc, 0, ""}, {0, 1}}]}, 
         {"abcde", Control[{{abcdef, 0, ""}, {0, 1}}]}]},
       Alignment -> {{Right, Left}, Automatic}],
  ControlPlacement -> Left]

manip_1

manip_2

Update

The following is added to address concerns raised by the OP in a comment to this answer.

Maybe this will work for you.

Manipulate[a,
  Dynamic @
  Grid[
    {{"a", Control[{{a, 0, ""}, 0, 1, 0.1}]},
     If[a < 1,
       {"abc", Control[{{abc, 0, ""}, {0, 1}}]},
       {"", SpanFromLeft}]},
     Alignment -> {{Right, Left}, Automatic}],
  ControlPlacement -> Left]

manip_3

$\endgroup$
  • $\begingroup$ Thanks! That looks great. Just one question, what if instead of getting the box "abcde" when a=1, I wanted to get nothing, so that there's no space occupied? I tried to include an empty list or {Null, Null} (as the 'else' option), but still these seem to occupy some space. $\endgroup$ – sam wolfe Dec 7 '19 at 2:21
  • $\begingroup$ Essentially, I guess, my question is how do I suppress a row in the grid with the Dynamic If. $\endgroup$ – sam wolfe Dec 7 '19 at 2:23
  • 1
    $\begingroup$ @samwolfe. I have updated my answer to address the concern you raise in the above comments $\endgroup$ – m_goldberg Dec 7 '19 at 3:18
  • $\begingroup$ It doesn't seem to work if you have another slider after the box. The spacing is somewhat different (empty lists occupy space?). Check my updated question. $\endgroup$ – sam wolfe Dec 7 '19 at 4:04
  • $\begingroup$ In the meantime, I think I've found a solution. Just use Unevaluated[Sequence[]]. $\endgroup$ – sam wolfe Dec 7 '19 at 21:47
6
$\begingroup$

You can use the Method suboption "ControlAreaDisplayFunction" to modify the control labels to have the same size:

Manipulate[a, 
 Control[{a, 0, 1, 0.1}], 
 Dynamic[If[a < 1, Control[{{abc, 0}, {0, 1}}], 
   Control[{{abcdef, 0}, {0, 1}}]]], ControlPlacement -> Left, 
 ContentSize -> {100, 100}, Alignment -> Center, 
 Method -> {"ControlAreaDisplayFunction" -> 
   (Replace[#, RawBoxes[s_] :> Item[s, ItemSize -> {5, 2}], All] &)}]

enter image description here

Alternatively, you can use

Method -> {"ControlAreaDisplayFunction" -> (Replace[#, 
      RawBoxes[s_] :> Pane[s, Alignment -> Right, 
        ImageSize -> Rasterize["abcdef", "RasterSize"]], All] &)}

enter image description here

Note: As far as I know the option Method and its suboptions are not documented. I came across $ManipulateMethodOptions during a spelunking expedition using ??*`*Manipulat*. Clicking on one of the results gave:

Manipulate`Dump`$ManipulateMethodOptions
{"BookmarkAnimationClipping" -> True, 
 "BookmarkDurationMultiplier" -> 1.5`, 
 "ContentAreaBackground" -> Automatic, 
 "ControlAreaDisplayFunction" -> (#1 &), "ExtraVariables" :> {}, 
 "DynamicCore" -> True, "HeuristicControllerBindings" -> True, 
 "InlineCell" -> False, "SingleEvaluation" -> True, 
 "ShowControls" -> True, "TemplateExpand" -> False}

Update: An alternative approach is to wrap control labels with Pane and use the rastersize of the longest label as the ImageSize:

is = Rasterize["abcdef", "RasterSize"];
pane = Pane[#, ImageSize -> is, Alignment -> Right] &;

Manipulate[a, 
 Control[{{a, 0, pane@"a"}, 0, 1, 0.1}], 
 Dynamic[If[a < 1, Control[{{abc, 0, pane@"abc"}, {0, 1}}], 
   Control[{{abcdef, 0, pane@"abcdef"}, {0, 1}}]]], 
 ControlPlacement -> Left, ContentSize -> {100, 100}, Alignment -> Center]

enter image description here

Update 2: To make a control invisible without adding vertical space between its neighbors:

Manipulate[a, 
 Dynamic @ Grid[{{pane @ "a", Control[{{a, 0, ""}, 0, 1, 0.1}]}, 
    If[a < 1, {pane @ "abcdef", Control[{{abcdef, 0, ""}, {0, 1}}]}, ## &[]], 
   {pane@"b", Control[{{b, 0, ""}, 0, 1, 0.1}]}}, 
    Alignment -> {{Right, Left}, Automatic}], ControlPlacement -> Left]

enter image description here

$\endgroup$
  • $\begingroup$ Please share the guide/tutorial/documentation link where "ControlAreaDisplayFunction" is documented. $\endgroup$ – Edmund Dec 7 '19 at 3:06
  • 1
    $\begingroup$ @Edmund, afaik it is not documented. I added a note re how i bumped into it. $\endgroup$ – kglr Dec 7 '19 at 4:52
5
$\begingroup$

You can put your Controls in a Column to lay out your controls in a arbitrary way. From here, you can use the Alignment option for Column.

Manipulate[a, 
 Column[{Control[{{a, 0}, {0, 1}}], 
   Dynamic[If[a == 0, Control[{{abc, 0}, {0, 1}}], 
     Control[{{abcdef, 0}, {0, 1}}]]]}, Alignment -> Right], 
 ControlPlacement -> Left]

Mathematica graphics

$\endgroup$
  • $\begingroup$ Thanks! That pretty much solves the case for the check boxes, but I'm still having problems with the mixed problem (sliders and boxes). Could you please check the edited question? $\endgroup$ – sam wolfe Dec 6 '19 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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