Skip to content

Manipulate

Status: Stable

documented, exercised by the test suite and/or worked examples, with no known limitations recorded.

Description

Manipulate[expr, {u, umin, umax}, ...]

Opens an interactive window with one control per variable and re-evaluates expr with each variable bound to its current value whenever a control changes. Returns Null once the window is closed. expr is typically a Graphics[...] or Plot[...] call that depends on the control variables. Unlike Animate, every control is independently user-driven from the first frame -- there is no animation phase or playback transport. Control specs (any number, one row each): {u, umin, umax} continuous slider, default = umin {u, umin, umax, du} continuous slider with step du {{u, u0}, umin, umax} continuous slider, explicit default u0 {{u, u0}, umin, umax, du} continuous slider, default + step {u, {v1, v2, ...}} discrete button set, default = v1 {{u, u0}, {v1, v2, ...}} discrete button set, explicit default u0 Click-drag a slider handle or click a discrete button to change its value; click Reset to restore every control to its default. Esc closes the window.

Examples (9)

Every input below was run against the current Mathilda build and its output recorded.

Basic examples (4)

In[1]:= Manipulate[Plot[Sin[n x], {x, 0, 2 Pi}], {n, 1, 5}]
Out[1]= Manipulate[Plot[Sin[n x], {x, 0, 2 Pi}], {n, 1, 5}]

In[2]:= Manipulate[Plot[f, {x, -5, 5}], {f, {Sin[x], Cos[x], x^2}}]
Out[2]= Manipulate[Plot[f, {x, -5, 5}], {f, {Sin[x], Cos[x], x^2}}]

In[3]:= Manipulate[Plot[a Sin[x] + b, {x, 0, 2 Pi}], {a, 0, 3}, {b, {-1, 0, 1}}]
Out[3]= Manipulate[Plot[a Sin[x] + b, {x, 0, 2 Pi}], {a, 0, 3}, {b, {-1, 0, 1}}]

In[4]:= Manipulate[Plot3D[Sin[x + n] Cos[y], {x, -3, 3}, {y, -3, 3}], {n, 0, 3}]
Out[4]= Manipulate[Plot3D[Sin[x + n] Cos[y], {x, -3, 3}, {y, -3, 3}], {n, 0, 3}]

Options (1)

In[5]:= Manipulate[ Graphics[Disk[{0, 0}, r], PlotRange -> {{-5, 5}, {-5, 5}}], {{r, 2}, 0.5, 5, 0.25}]
Out[5]= Manipulate[-Graphics-, {{r, 2}, 0.5, 5, 0.25}]

Applications (4)

In[6]:= Attributes[Manipulate]
Out[6]= {HoldAll, Protected}

In[7]:= Manipulate[Plot[Sin[n x], {x, 0, 2 Pi}], {n, 1, 5}]
Out[7]= Manipulate[Plot[Sin[n x], {x, 0, 2 Pi}], {n, 1, 5}]

In[8]:= Manipulate[Plot[f, {x, -5, 5}], {f, {Sin[x], Cos[x], x^2}}]
Out[8]= Manipulate[Plot[f, {x, -5, 5}], {f, {Sin[x], Cos[x], x^2}}]

In[9]:= Manipulate[Graphics[Disk[{0, 0}, r], PlotRange -> {{-5, 5}, {-5, 5}}], {{r, 2}, 0.5, 5, 0.25}]
Out[9]= Manipulate[-Graphics-, {{r, 2}, 0.5, 5, 0.25}]

Algorithm

manipulate.c — Manipulate[expr, {u, umin, umax}, ...]

Opens a Raylib window (when USE_GRAPHICS is compiled in) with one control row per variable, stacked above a thin footer:

  ┌─────────────────────────────────────────────────────────────┐
  │                                                               │
  │                        (rendered content)                    │
  │                                                               │
  ├─────────────────────────────────────────────────────────────┤
  │ u  │ 0 ─────────────●────────── 10              │  3.42     │
  │ f  │ [Sin[x]] [Cos[x]] [Tan[x]]                              │
  ├─────────────────────────────────────────────────────────────┤
  │ [Reset]  Esc: close                                          │
  └─────────────────────────────────────────────────────────────┘

Each control is independently user-driven from the first frame — there is no animation phase or playback transport (see Animate for that). A control is either:

  - a continuous drag slider:  {u, umin, umax}, {u, umin, umax, du},
    {{u, u0}, umin, umax}, {{u, u0}, umin, umax, du}
  - a discrete button set:     {u, {v1, v2, ...}}, {{u, u0}, {v1, ...}}

Implementation notes

Algorithm. builtin_manipulate is HoldAll and Protected. Like Animate it returns C NULL (leaving Manipulate[...] symbolic, body unevaluated) when MATHILDA_NO_WINDOW is set, so doc-generation never opens a window. Otherwise each control spec (args 1+, each evaluated first) is parsed by parse_control_spec into one of up to MAX_CTRLS = 8 controls: parse_var_part reads a bare symbol u or a {u, u0} default pair; a single remaining nonempty List makes a discrete button set (MCTRL_DISCRETE, a packed/visible NDArray value list is first materialised with ndarray_to_nested_list, capped at MAX_DISCRETE_VALUES = 32), while two or three further numeric args make a continuous range (MCTRL_RANGE, numericised through N[], with an optional step du that enables snapping). It then calls graphics_manipulate and returns Null. Per frame the binding is cleaner than Animate's: for each control it iter_spec_shadows any prior value, installs an OwnValue (expr_new_real(value) for a range, a copy of the selected value for a discrete set), evaluates expr_copy(body), then restores in reverse order. One control row is drawn per variable (drag sliders for ranges, clickable button sets for discrete controls); a footer Reset button restores every control's default and the 3-D camera. 2-D/3-D dispatch is identical to Animate (graphics_render_in_region / graphics3d_render_in_region with an orbit cam3d). There is no playback transport. The Raylib loop blocks the REPL until Esc closes it.

Data structures. ManipCtrl (a MCTRL_RANGE/MCTRL_DISCRETE kind, the var Expr*, range fields vmin/vmax/step/value/default_value, discrete fields values/n_values/selected_idx/default_idx); loop state drag_ctrl, Expr* frame_expr, Graphics3DEmbedState* cam3d. Window is 800×500, MAX_CTRLS = 8, MAX_DISCRETE_VALUES = 32.

Complexity / limits. One full body evaluation every frame (SetTargetFPS(60)), unconditionally — the "whenever a control changes" wording in the docstring is looser than the code. Headless/no-Raylib behaviour matches Animate (a one-line message, still returns Null). At most 8 controls and 32 discrete values.

Attributes: HoldAll, Protected.

References

See also: HoldAll, Animate, Show

Notes & additional examples

Notes

Manipulate is HoldAll and Protected: one control row is drawn per variable and the body is re-evaluated with each variable bound to its current value as a control changes. Control specs cover continuous sliders ({u, min, max}, with an optional step du, or a {{u, u0}, ...} explicit default) and discrete button sets ({u, {v1, v2, ...}}). A footer Reset button restores every control's default. Unlike Animate there is no playback transport — every control is user-driven.

The window blocks the REPL until closed, then returns Null; a Graphics3D/Plot3D body gets its own orbit camera. Under the headless MATHILDA_NO_WINDOW environment (used by documentation generation) Manipulate returns unevaluated, which is why the examples above display as the held Manipulate[...] form rather than opening a window.