3
$\begingroup$

I use Grid to align controls in Manipulate. Here is a simple example

Grid[{
     {name1,Control2,value1},
     {name2,Control1,value2}
    }]

The 3 fields above come out aligned automatically, even when one field, such as name, is longer than another, and Spacing can be used to control field width for all controls at once.

A problem shows up when I need to use an If statement to build controls based on selection used in previous control:

Grid[{
     {name1,Control2,value1},

     (*now make a control based on above value*)

     {Dynamic[If[name1==1,
                 {name2,Control1,value2},
                 {name3,Control3,value3}
                ]
             ]
     }
    }]

This works well, and allows me to change the controls that appear on the UI based on a selection that was made in another control but the problem with the above is that it gives an extra set of {} coming out from inside the If needed grouping which ends up messing up the alignment.

I think I need to use Sequence or some other function to remove the inner {} but can't figure the syntax.

I made below a simple working code to illustrate

Manipulate[
 eq,

 Grid[{

   {"eq", SetterBar[Dynamic[eq], {1, 2}], Dynamic[eq]},

   {Dynamic[If[eq == 1,

      {"v1",
       Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}],
       Dynamic[v1]
       },

      {"v2",
       Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}],
       Dynamic[v2]
       }
      ]], SpanFromLeft
    }}
  ],

 {{eq, 1}, None},
 {{v1, 1}, None},
 {{v2, 1}, None}
 ]

which gives

enter image description here

You can see that the whole expression was treated as if I wrote

Grid[{
     {name1,Control2,value1},
     {{name2,Control1,value2}}
    }]

I tried using First, Sequence but can't get it to come out correct.

Again, I need to keep the 3 fields in each Row separate and in a List. I can't just use Row since it means each row will collapse to become one field, not three fields, and I lost the alignment I needed, i.e. I can't just write

Manipulate[
 eq,

 Grid[{

   {"eq", SetterBar[Dynamic[eq], {1, 2}], Dynamic[eq]},

   {
    Dynamic[If[eq == 1,

      Row[{"v1",
        Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}],
        Dynamic[v1]
        }],

      Row[{"v2",
        Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}],
        Dynamic[v2]
        }]
      ]], SpanFromLeft
    }
   }

  ],

 {{eq, 1}, None},
 {{v1, 1}, None},
 {{v2, 1}, None}
 ]

enter image description here

Any idea how to make the above work and remove those extra {}?

edit

Let me just clarify why using Row as a solution does not work.

Compare the following 2 examples

Manipulate[eq,

 Grid[{
   {"eq", SetterBar[Dynamic[eq], {1, 2}], Dynamic[eq]},

   {Dynamic[If[eq == 1,

     Row[{"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}],Dynamic[v1]}],

     Row[{"v2", Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}], Dynamic[v2]}]
    ]]
   }

   }],

 {{eq, 1}, None},
 {{v1, 1}, None},
 {{v2, 1}, None}
 ]

enter image description here

We can see that the whole Row was treated as one field. I want to the above to come out as if I have written this

Manipulate[eq,

 Grid[{
   {"eq", SetterBar[Dynamic[eq], {1, 2}], Dynamic[eq]},

   {"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}],Dynamic[v1]}

   }],

 {{eq, 1}, None},
 {{v1, 1}, None},
 {{v2, 1}, None}
 ]

enter image description here

You see the difference? This is the important part. thanks.

$\endgroup$
1

2 Answers 2

4
$\begingroup$

Does this work as you need?

  Manipulate[eq, Dynamic@Grid[{{"eq", SetterBar[Dynamic[eq], {1, 2}], 
  Dynamic[eq]}, {If[eq == 1,
    {"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}], Dynamic[v1]}, 
    {"v2", Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}], 
       Dynamic[v2]}], SpanFromLeft} /. 
      (lst : {x_String, _, _}) :>  Sequence @@ lst}], 
   {{eq, 1}, None}, {{v1, 1}, None}, {{v2, 1},  None}]

enter image description here

Alternatively, instead of post-processing, you can define a custom if that "holds" sequence arguments as follows:

 ifSeqHold = Function[{test, arg1, arg2}, 
    If[test, Sequence @@ arg1, Sequence @@ arg2], HoldAllComplete];

 Manipulate[eq,  Dynamic@Grid[{{"eq", SetterBar[Dynamic[eq], {1, 2}], 
 Dynamic[eq]}, {ifSeqHold[ eq == 1, 
   {"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}], Dynamic[v1]}, 
   {"v2", Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}], 
   Dynamic[v2]}], SpanFromLeft}}], 
   {{eq, 1}, None}, {{v1, 1}, None}, {{v2, 1}, None}]

which gives the same result.

Update: Hold[Sequence@@{...}] followed by ReleaseHold also works:

  Manipulate[eq, Dynamic@Grid[{{"eq", SetterBar[Dynamic[eq], {1, 2}], 
    Dynamic[eq]}, {If[eq == 1, 
     Hold[Sequence @@ {"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}], 
      Dynamic[v1]}], 
     Hold[Sequence @@ {"v2",  Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}], 
      Dynamic[v2]}]]// ReleaseHold, SpanFromLeft} }], 
   {{eq, 1},  None}, {{v1, 1}, None}, {{v2, 1}, None}]
$\endgroup$
0
3
$\begingroup$

Let's use a Column of Rows rather than a Grid.

Manipulate[eq,
 Column[{
   Row[{"eq", SetterBar[Dynamic[eq], {1, 2}], Dynamic[eq]},
    StringJoin@@Table[" ",{52}]],    
   Dynamic[If[eq == 1,
      Row[{"v1", Manipulator[Dynamic[v1, {v1 = #} &], {0, 2, .1}], 
        Dynamic[v1]}, "   "],
      Row[{"v2", Manipulator[Dynamic[v2, {v2 = #} &], {0, 2, .1}], 
        Dynamic[v2]}, "   "]
      ]
     ]   
   }],
 {{eq, 1}, None},
 {{v1, 1}, None},
 {{v2, 1}, None}
]

enter image description here

I do think that the use of spaces to format is a bit hacky; I'm not certain how it will look across platforms. There might be a better way to do it - perhaps use of Pane or Panel or Spacings or Margins or I don't know what. I think the basic idea is there, though.

$\endgroup$
0

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.