24

Background: My Manipulate programs are becoming (too) long. I want to split them up in to independent modules, if at all possible. Take this program as a prototype:

Manipulate[
   {i, 2 i, 3 i},
   {{i, i, "i="}, -11, 11, 1},
   Initialization -> {i = 0}
]

Suppose this is in fact a custom control with parameters {label, begin, end, step}

   {{i, i, "i="}, -11, 11, 1},

Ideally I would be able to code something like

Manipulate[
    {i, 2 i, 3 i},
    = = = = CustomSlider[i, " i= " , -11, 11, 1 ]  = = = =
    Initialization -> {i = 0}
]

Question: So the question is about how to get a function to work as a control in a Manipulate, if that is at all possible? Any Ideas or other suggestions to handle my need of refactoring my Manipulate code?

rm -rf
  • 88,781
  • 21
  • 293
  • 472
nilo de roock
  • 9,657
  • 3
  • 35
  • 77

3 Answers3

26

Not sure if this helps, but you can define a control in Manipulate as

Manipulate[
  some code,
  {{var, init, label}, func}, 
  ...
]

where func is a function defining a custom control. The first argument given to func is then Dynamic[var].

As an example, suppose that instead of an ordinary slider you want a red dot which you can move along a scale. You could define your customSlider as

customSlider[Dynamic[i_], str_, b_, e_, st_] :=
 LocatorPane[Dynamic[{i, 0}, (i = Round[#[[1]], st]) &],
   Dynamic[
    Graphics[{Red, Disk[{i, 0}, Abs[e - b]/40]},
     PlotRange -> {{b, e}, All},
     ImagePadding -> 10,
     PlotLabel -> Row[{str,i}], Axes -> {True, False}]], Appearance -> None]

You can then use this control in Manipulate as

Manipulate[{i, 2 i, 3 i},
 {{i, 0}, (customSlider[#1, " i= ", -11, 11, 1] &)}, 
 SaveDefinitions -> True]

Mathematica graphics

Heike
  • 35,858
  • 3
  • 108
  • 157
8

How about this?

Manipulate[
     {i, 2 i, 3 i},
     {{i, 0, ""}, ControlType -> None},
     CustomSlider[i, " i= " , -11, 11, 1 ],
     SaveDefinitions -> True
    ]

SaveDefinitions to retain the defintion of your CustomSlider. The dummy control (ControlType -> None) essentially introduces the variable into the resulting DynamicModule with the initial value assigned, but without creating a control for it.

Yu-Sung Chang
  • 7,061
  • 1
  • 39
  • 31
8

Here's one I have used that adds sliders:

Options[Line1DControls] = {"Button" -> Options[Button], 
   "Slider" -> Options[Manipulator]};

Line1DControls[Dynamic[partition_], {min_, col_}, OptionsPattern[]] :=
   DynamicModule[{incr = Sign[col - min], buttonOpts, sliderOpts, tmp,
     n = Length[partition]},

   buttonOpts = OptionValue["Button"];
   sliderOpts = OptionValue["Slider"];

   Dynamic@Column[
     Join[
      {Button["Add Slider", AppendTo[partition, 0]; n++, 
        buttonOpts]},
      Table[
       With[{i = i}, 
        Manipulator[Dynamic[partition[[i]]], {min, col, incr}, 
         sliderOpts, Appearance -> "Open", 
         AppearanceElements -> {"InputField", "StepLeftButton", 
           "StepRightButton", "HideControlsButton"}, 
         ImageSize -> Tiny]], {i, n}],
      If[n > 
        1, {Button["Remove Slider", n = Max[1, n - 1]; 
         partition = partition[[Range[n]]], buttonOpts]}, {}]
      ],
     Alignment -> Center
     ]
   ];

Toy usage example:

Manipulate[

 Column[{
   Dynamic@{partition, col, row},
   Line1D[partition, {col, row}, 
    "Graphics" -> {Frame -> True, PlotRange -> {{0, col}, {0, row}}}]
   }],

 {{col, 4}, 1, 8, 1},
 {{row, 4}, 1, 8, 1},

 {{partition, {1}, "hello"}, 
  Line1DControls[#, {0, col}, 
    "Button" -> {BaseStyle -> Directive[FontFamily -> "Arial", 10], 
      ImageSize -> 100}, "Slider" -> {ImageSize -> Small}] &},
 SaveDefinitions -> True
 ]

enter image description here

see also in the help documentation: tutorial/AdvancedManipulateFunctionality and the section "Custom Control Appearances"

Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158