Proper way to handle free variables in manipulate/plot?

It took me a while today to figure out that Manipulate (used with Plot) requires that the variable I'm manipulating be an actual parameter of the thing that I'm manipulating.

That is, if I have something like:

foo = Exp[2 x+y]
Manipulate[Plot[foo, {x, 0, 10}], {y, 0, 10}]


It will not work as desired, but if I have:

ffoo[x_, y_] := Exp[2 x+y]
Manipulate[Plot[ffoo[x, y], {x, 0, 10}], {y, 0, 10}]


It will.

I can't help but wonder; what is the general correct approach here? To me it feels slightly "wrong" that I should need to declare all the free variables for my statements as arguments. But maybe this is just something I should get over. In my case, it means I need to change, say, an arbitrary amount of places where I might call these to get various things (like eigenvectors with free parameters) and do a bunch of work converting them into function calls? Just because I want to use them in plots?

My actual approach was to write little "plot functions" for the particular bits I wanted to plot, and I then I did a little probably-inappropriate trick of just sneaking them into functions:

foofunc[a_, b_, c_] := Evalulate[foo]


(Knowing that foo contains free variables named as "a", "b", etc...).

It seems, though, that there must be a better way of just asking Manipulate to consider implicit parameters (or whatever their formal name is; I tried a bit of searching and wasn't able to find anything about this; though I imagine it's fairly common).

Thanks for any advice.

-
I wonder why my comment with this link was deleted, I find it very relevant here and not linked to by other answers. Anyway, making another one. – Leonid Shifrin Sep 26 '12 at 13:42

3 Answers

In my opinion once you start passing objects as functions like this it makes sense to use the named argument form: ffoo[x_, y_] := Exp[2 x + y] Otherwise you risk conflicts with global assignments to x and y.

Nevertheless there are ways to do what you want more directly I believe, e.g.

foo = Exp[2 x + y];

With[{foo = foo},
Manipulate[Plot[foo, {x, 0, 10}], {y, 0, 10}]
]

-
Okay, thanks. (I understand the risk about global assignments; arguably that's actually the feature I want - the variables are sensibly named). My problem, really, was getting results back from other functions with these free variables in them (i.e. eigenvectors/values). And also, it seems slightly "semantically" confusing, because my function really only has one actual parameter, but the system itself has these free parameters. I still feel like I'm missing something. – Noon Silk Jul 23 '12 at 12:43
@NoonSilk I wonder if I'm missing something in your application. Would you consider adding another example to your question, perhaps with the eigenvectors usage that you mention? At a stretch, perhaps this method may be tangentially of interest to you. – Mr.Wizard Jul 23 '12 at 12:52
I'm new to Mathematica, so I'm likely wrong. I'm suggesting that, at some point I have a matrix, which has free variables in it (say x and y). So if I solve for Eigenvalues, I clearly get these free params in the result. So at some point I'll need to write something exactly like f[H_, x_] := ... Evaluate @ Eigensystem[H] ... to get the result appropriately back from Eigensystem for use further down the line? Then, I will need to "functionalise" all future things, say a density matrix which is formally a fn only of t, to be fn's of the somewhat arbitrary free variables from earlier? – Noon Silk Jul 23 '12 at 13:11
It seems weird to do so, to me, because I might at some point say "Okay, this variable is no longer free, it is now 10". I'd need to change a random number of function params to fully reflect this, or just now pass a constant around. I guess I'm differentiating "system" variables (by allowing them to be global) from function variables. And this Manipulate question has forced me to reconsider how I do that, because it doesn't play nicely with it, with my minimal knowledge. I actually think converting them to functions is probably correct, but only far latter; essentially as I'm doing. – Noon Silk Jul 23 '12 at 13:13
But the Evalulate in there to play the trick of using the same variable name as the function parameter seems like it will get me into trouble at some point. – Noon Silk Jul 23 '12 at 13:14

An alternative method to get the effect you want is to use a replacement rule:

Manipulate[Plot[foo /. {y -> b}, {x, 0, 10}], {b, 0, 10}]


The issue is that if you write:

Manipulate[Plot[foo, {x, 0, 10}], {y, 0, 10}]


then you have the y that is an expression within the expression foo, and the y that is a variable local to the Manipulate[] expression. They aren't the same thing.

Using the replacement rule ensures that you are inserting a variable that the Manipulate is actually manipulating, into the expression foo.

-
You're right; this seems to work in this trivial case. This is actually the very first thing I tried, and I actually had to stop using it because of the confusion it caused when I tried to plot a list of graphs {foo1, foo2} and replace them all at once: {foo1, foo2} /. {y -> b}. (It's no longer possible to colour them uniquely in this case). – Noon Silk Jul 23 '12 at 12:51
@NoonSilk actually, it is: add option Evaluated -> True to Plot. – Mr.Wizard Jul 23 '12 at 12:55
Ah! Thanks Mr. Wizard; you are right! This might be the simplest approach then (though I think the essential idea about reconsidering how I approach the general structure of my programs is a good one). – Noon Silk Jul 23 '12 at 12:59

Manipulate needs to see the parameters. This is mentioned in the 'Potential issues' part of its doc page. However, I think (but currently can't test this) that including a dummy statement using the parameters may work:

foo = Exp[2 x + y]
Manipulate[
{x, y};Plot[foo, {x, 0, 10}], {y, 0, 10},
LocalizeVariables -> False]

-
That doesn't work on my system. -1 Sorry. :-/ – Mr.Wizard Jul 23 '12 at 12:57
@mr.wizard perhaps an explicit assignment is necessary. Could you test this? – Sjoerd C. de Vries Jul 23 '12 at 13:00
What do you mean? – Mr.Wizard Jul 23 '12 at 13:00
@mr.wizard something like a={x,y} or perhaps a+={x,y}. – Sjoerd C. de Vries Jul 23 '12 at 13:05
I tried both without result, and frankly I cannot see why that would do anything. Isn't the scoping in Manipulate akin to With rather than Block? – Mr.Wizard Jul 23 '12 at 13:09