44

I have a function that operates on a list of parameters of variable-length $n$. I would like to create a Manipulate[] that has $n$ sliders, one for each list element, each considered a separate parameter. The syntax Manipulate[expr,{u,...},{v,...},...]] does not lend itself to this, as it is geared toward a fixed number of parameters known in advance, and referenced by separate variable names.

I have started exploring preparing a list of arguments to Manipulate[] and then using Apply[], but this seems tricky and complicated.

Anyone come upon this conundrum before?

VividD
  • 3,660
  • 4
  • 26
  • 42
Joseph O'Rourke
  • 4,731
  • 25
  • 42

3 Answers3

38

The Advanced Dynamic Functionality in Mathematica documentation has the following example that looks like what you need.

DynamicModule[{n = 5, data = Table[RandomReal[], {20}]},
Column[{
Slider[Dynamic[n], {1, 20, 1}],
Dynamic[Grid[Table[With[{i = i},
   {Slider[Dynamic[data[[i]]]], Dynamic[data[[i]]]}], {i, n}]
 ]]}]]

nested sliders

It builds a list of controllers (Slider-s in this particular case) by using the fact that you can assign values to not just symbols but also to members of a list by doing data[[1]] = value. Which is exactly the thing that happens inside Dynamic[data[[i]]], as it is equivalent to:

Dynamic[data[[i]], (data[[i]] = #)&]

telling Mathematica to whenever the actual value of data[[i]] is changed, use the new value (#) to update the expression data[[i]].

Also from the Documentation Center, the last example in Manipulate: Neat Examples may be useful:

Manipulate[
ArrayPlot[
Take[data, h, w]], {{data, RandomInteger[{0, 1}, {10, 20}]}, 
ControlType -> None}, {{h, 5}, 1, 10, 1}, {{w, 5}, 1, 20, 1}, 
Dynamic[Panel[
 Grid[Outer[Checkbox[Dynamic[data[[#1, #2]]], {0, 1}] &, Range[h], 
 Range[w]]]]]]

which gives

enter image description here

István Zachar
  • 47,032
  • 20
  • 143
  • 291
kglr
  • 394,356
  • 18
  • 477
  • 896
10

Here is a followup to my question, code based on the example provided by kguler. Note there is no longer any need for Manipulate[]— it is all handled by Dynamic[].

data = Table[RandomReal[], {5}];

DynamicModule[ {n = Length[data]},

 Column[{

   Dynamic[
    Grid[
     Table[
      With[{i = i},
       {i,
        Slider[Dynamic[data[[i]]]],
        Dynamic[data[[i]]]
        }
       ],
      {i, n}
      ](*Table*)
     ]],(*Dynamic*)

   Dynamic[ListPlot[data, Joined -> True]]

   }, Center](*Column*)
 ]


     enter image description here

Joseph O'Rourke
  • 4,731
  • 25
  • 42
9

This is similar to kguler's solution, but it assumes that there is a more complex updating going on during slider-interaction (namely, both list and total are updated), to illustrate more realistic cases where a single Dynamic object might affect more than one variables. Also it shows how to use Map with a variable number of Slider-s. For localization and elegance, the whole code should be wrapped into DynamicModule, but since this is not the point here, I omitted.

update[n_] := (list = Table[0, {n}]; total = Total@list); (* function called when n is changed *)

n = 5;
update[n]; (* initialize list and total *)

Slider[Dynamic[n, (n = #; update[#]) &], {1, 10, 1}]

Dynamic[total]

Dynamic[Grid[
  {
   #,
   Slider[Dynamic[list[[#]], 
       Function[{x}, list[[#]] = x; total = Total@list]], {0, 1}], 
   Dynamic[list[[#]]]
  } & /@ Range[n]
  ], TrackedSymbols :> {n}]

Mathematica graphics

István Zachar
  • 47,032
  • 20
  • 143
  • 291