6
votes

I've been fighting with Mathematica's Manipulate function for the last few days for a project.

I'm working on tweaking assumptions and boundary conditions that go into a physical model. For this, I want to be able to plot different equations and adjust the parameters and have the graphs update on the fly. Manipulate seems to be the perfect tool for the job -- except that I can't get it to work. The plots won't update when the parameters are changed.

Basic example:

a =.;
b =.;
c =.;
func1[x_] := a*x;
func2[x_] := a*x^2 + b*x + c;
funcNamesList := {"Linear", "Quadratic"};
funcList := {func1[x], func2[x]}
Manipulate[
   Plot[function, {x, -5, 5}], {function,MapThread[Function[#1 -> #2],
    {funcList, funcNamesList}]}, {a, -5, 5}, {b, -5, 5}, {c, -5, 5},
    LocalizeVariables -> False
]

I can get, for example, func1 to refresh by clicking func1, adjusting a, and then clickingfunc1 again, but I'm hoping to have it update when I adjust a because the real functions I'm using are rather temperamental with respect to their parameters.

-Because I'll be dealing with long functions that have different parameters, using a list of functions is useful.

EDIT:

In case it produces any ideas for anyone, here are some working examples of the individual components of what I want to do (from the Wolfram documentation):

Plot graphs and have them update when parameters are changed:

Manipulate[
    Plot[Sin[a x + b], {x, 0, 6}], {{a, 2, "Multiplier"}, 1, 4},
    {{b, 0, "Phase Parameter"}, 0, 10}
]

Note: This breaks when the function is taken outside:

func[x] := Sin[a x + b];
Manipulate[
  Plot[func[x], {x, 0, 6}], {{a, 2, "Multiplier"}, 1, 4},
  {{b, 0, "Phase Parameter"}, 0, 10}, LocalizeVariables -> False
]

Example of changing the function being plotted:

Manipulate[
   Plot[f[x], {x, 0, 2 Pi}], {f, {Sin -> "sine", Cos -> "cosine", Tan -> "tangent"}}
]

Edit 2 Changed func2 from a*x^2 to a*x^2 + b*x + c to reflect the fact that the functions may have different parameters.

Edit 3 Added the tidbit I use to get nice names on the function buttons.

2
what do you mean "that have different parameters"? do they have different signatures? - acl
Generally, you have to make sure that the Manipulate control variables appear explicitly in Manipulate's body. So, its best to use the parameters in the function definition, so that they're visible to Manipulate. - Sjoerd C. de Vries
If I execute your code the buttons are labeled a x and a x^2 not func1 and func2 as you state in the text. Have you really posted your latest code? - Sjoerd C. de Vries
@Sjoerd or 1.32x and 1.32x^2 etc if you re-execute the Manipulate... Global state can be confusing! - acl
So how would you like this to work? For instance, to have sliders for a, b and c, and simply ignore the b and c values when you are plotting the linear function? Or some other behaviour? - acl

2 Answers

7
votes

There are two problems that prevent your Manipulate statement from working.

First, while the Manipulate variable a is global due to the LocalizeVariables -> False setting, the Plot variable x is not. x is local to the Plot expression.

The second problem is that Manipulate, by default, assumes TrackedSymbols -> Full. This means that only symbols that explicitly appear in the manipulated expression are tracked. Note that a does not appear in the expression, so it is not tracked.

We can correct both problems thus:

a =.;
function =.;
func1[x_] := a*x;
func2[x_] := a*x^2;
funcList := {func1, func2}
Manipulate[
 Plot[function[x], {x, -5, 5}], {function, funcList}, {a, -5, 5}, 
 LocalizeVariables -> False, TrackedSymbols :> {a, function}
 ]

The changes are:

  1. funcList was changed to {func1, func2}
  2. The Plot expression was changed to function[x], thereby referencing the local x variable.
  3. The Manipulate option TrackedSymbols :> {a, function} was added.
  4. function is initially unset.
2
votes

I'd do this in a slightly different way:

func1[x_, a_] := a*x;
func2[x_, a_] := a*x^2;
funcList = {func1, func2};
Manipulate[
    Plot[Evaluate[function[x, b]],
        {x, -5, 5},
        PlotLabel \[Rule] funcList
    ],
    {function, funcList},
    {b, -5, 5}
 ]

but this may be unsuitable for what you want. Do your functions have different signatures?

EDIT: I've renamed the parameter to b to make it clearer that is it just a parameter being passed, as opposed to a global variable as you were using it.