# What's wrong in my use of Manipulate

GROUPS:
 This code contains control system functions, but I'm posting it under Dynamics because I suspect that's where my problem lies.The code below defines a simple plant, and then a generic PID controller. I extract the poles of the closed loop transfer function and try to plot them while using manipulate to adjust the model parameters. When I manipulate only the list of points to be plotted, it works fine. But when I enclose the list in ListPlot, ListPlot does not plot them?If someone can point out the flaw in my code I would appreciaate it greatly!The code below has output deleted, but will execute: (* TF for plant *) plantTf = TransferFunctionModel[k/s, s]  (* TF for PID controller *) pidTf = TransferFunctionModel[kp (1 + 1/(\[Tau]i s) + \[Tau]d s), s]  (* TF for closed loop system *) closedLoopTf = SystemsModelFeedbackConnect[plantTf, pidTf] (* poles of the closed loop system in symbolic form *)closedLoopPoles = TransferFunctionPoles[closedLoopTf][[1, 1]](* convret complex number to a vector *)complexPair[z_] := {Re[z], Im[z]}(* Manipulate can create a list of the poles *)Manipulate[ complexPair /@ closedLoopPoles // Evaluate, {k, 1, 10}, {kp, 1, 10}, {\[Tau]i, 1, 10}, {\[Tau]d, 1, 10}]This works fine. The image below is from one setting of parameters:(* but when ListPlot plots them, they don't plot *)Manipulate[ ListPlot[complexPair /@ closedLoopPoles // Evaluate], {k, 1, 10}, {kp, 1, 10}, {\[Tau]i, 1, 10}, {\[Tau]d, 1, 10}]But that did not work. No points get plotted:
3 years ago
9 Replies
 Nasser M. Abbasi 2 Votes Manipulate does not see the dependency, since you have all the dependent variables out of its scope. One way is to put the function inside Manipulate Manipulate[ {kp, \[Tau]i, \[Tau]d, k}; ListPlot[complexPair /@ closedLoopPoles], {k, 1, 10}, {kp, 1,10}, {\[Tau]i, 1, 10}, {\[Tau]d, 1, 10}, Initialization :>   (    plantTf = TransferFunctionModel[k/s, s];    pidTf = TransferFunctionModel[kp (1 + 1/(\[Tau]i s) + \[Tau]d s), s];    closedLoopTf = SystemsModelFeedbackConnect[plantTf, pidTf];    closedLoopPoles = TransferFunctionPoles[closedLoopTf][[1, 1]];   complexPair[z_] := {Re[z], Im[z]}   )]Another option is to use LocalizedVariables->FalseManipulate[{kp, \[Tau]i, \[Tau]d, k};ListPlot[complexPair /@ closedLoopPoles // Evaluate], {k, 1,10}, {kp, 1, 10}, {\[Tau]i, 1, 10}, {\[Tau]d, 1, 10},LocalizeVariables -> False]
3 years ago
 Thank you very much, Nasser. That worked great.It does leave me a bit confused. I do not see how my implemention differs from the example:Manipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}]Which of course works fine. Could you perhaps point out the difference for me?Best regards,David
3 years ago
 Nasser M. Abbasi 3 Votes David; in the example you showManipulate[Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2}]The manipulate expression is anything between the start of Manipulate the first ",", i..e thisManipulate[  expression,   controlVariables, Initialization :> ()]In your case, it is:Plot[Sin[x (1 + a x)], {x, 0, 6}]Hence, the dependent variable, which is "a"  is visible to Manipulate. i.e. Manipulate "sees" that there is a dependent variable (symbol) in its expression which needs to be tracked by the change in the slider.If you change this example to foo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}]Manipulate[Evaluate@foo[], {a, 0, 2}]Which is basically what you had, now Manipulate looks at its expression and does not "see" the "a" in there any more. So, it has nothing to track. It is important that symbols to be tracked to appear literally in the expression of Manipulate, or somewhere in the body of Manipulate. Otherwise, you have to tell Manipulate to track all symbols all over the place. This is what "LocalizeVariables -> False" does. However, this is not a good solution. It is better to put all code and data used by Manipulate inside Manipulate and not in the global context as you had.Here is a summary of all the cases:Case 1move "foo[]" in the above example to inside Manipulate, in the initialization section, add literal symbol "a" so Manipulate will track itManipulate[ a; foo[], {a, 0, 2}, Initialization :>  (   foo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}];   ) ]Notice the trick above. "a;" was added so that it appears in the Manipulate expression. Otherwise, it will not be tracked. You'll get an initial plot, but nothing will happen when moving the sliderCase 2move "foo[]" to global context, but have to tell Manipulate that LocalizeVariable is falsefoo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}];Manipulate[  a;  foo[],  {a, 0, 2},  LocalizeVariables -> False]But notice, we still need to put "a" somewhere in the expression for it to tracked.  Not enough just to say LocalizeVariables -> FalseCase 3It is not enough to use "TrackedSymbols :>a", if the symbol itself do not show up in the expression. Hence this does not workfoo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}];Manipulate[foo[],{a, 0, 2},LocalizeVariables -> False,TrackedSymbols :> a]Notice there is no "a" in the expression. Manipulate will not track "a" even though we told it to !case 4Same as case 3, even if we put the function inside the Initialization section, it will still not track "a" . One will get an initial plot, but that is all. Manipulate[ foo[], {a, 0, 2}, TrackedSymbols :> a, Initialization :>   (    foo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}];    ) ]Case 5Putting the function definition of foo[] itself inside Manipulate expression, now Manipulate sees "a" there and will automatically track it. No need to do anything more:Manipulate[Module[{},  foo[] := Plot[Sin[x (1 + a x)], {x, 0, 6}];  foo[]  ],{a, 0, 2}]Or simplyManipulate[ Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2} ]Case 6This is the method I use myself. Put all the functions inside the initialization section, but pass the dependent variables by argument call. Manipulate[foo[a],{a, 0, 2},Initialization :>  (   foo[a_] := Module[{x}, Plot[Sin[x (1 + a x)], {x, 0, 6}]]   )]I like this, becuase it achieves both the goal of having all the slider symbols inside the Manipulate expression, hence Manipulate will track them, and at the same time, it avoid the function be in global context, and it is the modular way, since one can see which parameter each function depends on by looking at the signature of the function.Case 7Similar to case 6, but the function itself is now in the global context. This is a fine solution as well, if this function needs to be called from somewhere else as well other than from the Manipulate. Otherwise, it is best not to have in the global context and use case 6.foo[a_] := Module[{x}, Plot[Sin[x (1 + a x)], {x, 0, 6}]];Manipulate[foo[a],{a, 0, 2}]
3 years ago
 Vitaliy Kaurov 3 Votes Nasser did a very nice explanation. I just wanted to add something short. Look at this example:x = 5; y = cat;Manipulate[Sin[y x], {x, 0, 1}]While y is global and leaks inside Manipulate, which is basically a DynamicModule, global x=5 is not the same as as dynamic local x inside manipulate. You can see it by selecting Manipulate cell and going Top menu >> Cell >> Show expression. It is x which is a different variable.
3 years ago
 Thanks to both of you. It was very helpful, and I think I mostly understand.Consider the following code: f[x] := x^a  (* case 1 *) Manipulate[Plot[f[x], {x, 0, 3}], {a, 0, 3}]  (* case 2 *) Manipulate[Plot[f[x] /. a -> pa, {x, 0, 3}], {pa, 0, 3}]  (*case 3 *)Manipulate[Plot[f[x] /. a -> pa // Evaluate, {x, 0, 3}], {pa, 0, 3}](* case 4 *)Manipulate[Plot[f[x] // Evaluate, {x, 0, 3}], {a, 0, 3}]In[53]:= f[x] // EvaluateOut[53]= x^aThe first case does not work, for the reasons given, Manipulate can't see the a. The second puts pa in scope, but Manipulate doesn't see it as part of f  until the expression is evaluated. And the third case works, because once evaluated, pa is seen.But the last case confuses me. If f is evaluated inside Plot to become x^a, then why wouldn't Manipulate see it, as in the third case.The reason this is of interest to me is that in many cases I want the functions to have global scope,because looking at their output with Manipulate is just one step in their development, and they will be of further use in the notebook.Best regards,David
3 years ago
 Nasser M. Abbasi 1 Vote btw, you missed the underscore in your function. It should be "f[x_] := x^a" not "f := x^af[x_] := x^aManipulate[Plot[f[x] // Evaluate, {x, 0, 3}], {a, 0, 3}]But that is why it does not work. Again, the slider symbol (the symbols that the expression depends on) has to appear literally in the expression (i.e. during the initial parsing phase of the Manipulate body). It does not matter if it when evaluates then "a" will appear, becuase the expression will not evaluate in the first place since Manipulate has no reason to evaluate it, since there is nothing to track and update in the first place ! You can, if you want, get that external input from inside Manipulate. There is no reason to have shared global variables all over the place. makes maintenance of code hard. In the above your "a" is global. The function "f[x_]" is not a true function either. A true function is one that takes all its input via parameters.  In your case, "f[x_]" get one of its input, the "x" via parameter, but the other variable "a" is somewhere else.A function should be all self contained. It should take all its input via argument calls, and return its result by its evaluated value.  That is the right way to do things. You can still have your itself function be global, but simply pass it all its input like this:f[x_, a_] := x^aManipulate[ Plot[f[x, a], {x, 0, 3}], {a, 0, 3} ]Now the function is all self contained. The function itself is global, but it takes all its input via arguments. So it is modular and reusable in other places as well.btw, This is the same pattern as putting the function in the Initialization section, which is case 6 I showed before. In this case, the function itself is global (no problem as long as its input is via parameters) while in case 6, the function itself was not global, but only known inside Manipulate. I added case 7 in my last reply to cover this case as well. Thank you for reminding me about it. I am sure one can come up with more variations, but I think these 7 cases now cover all the main ones.