2
$\begingroup$

I want to allow users to enter some parametrized plots, using the variable t. I want the variable t to be localized to a DynamicModule so that it can't be interfered with by other things running in Mathematica. I've wrote what I was hoping would work. However when I initialize my px and py use the variable FE`t$$618 instead of t. Then when I switch between Plots the values brought up for px and py also show this FE`t$$618 to the user. How can I get around this?

DynamicModule[{names, plots, Pn, Po, t, tplot},
 {{names = {"s1", "s2", "s3"},
    plots = {{-2  Sin[t], 2 + 2  Cos[t]}, {Sin[t], Cos[t]}, {3 Sin[t],
        4 Cos[t]}}
    },
   Manipulate[{{
       Pn = plot,
       If[Pn == Po,
        {(*no change in plot selected, update parameter values*)
         With[{
           
           pn = ReleaseHold[{px, py} /. 
              HoldPattern[t_ /; MatchQ[t, Symbol["t"]]] :> tplot]
           }, {
           plots[[plot]] = pn
           }
          ]
         },
        {(*change in plot selected, update manipulators*)
         {px, py} = plots[[plot]]/.tplot->t(*this is the problem line of code. I want to replace tplot with the symbol t, but it ends up as t$$SomeNumbers*)
         }],
       Po = plot
       },
      Grid[{{plots}}]
      }[[2]],
    
    {{plot, 1}, 
     Dynamic[Array[# -> ToString[names[[#]]] &, Length[plots]]], 
     ControlType -> PopupMenu},
    {{px, -2  Sin[t], 
      "\!\(\*SubscriptBox[\(S\), \(x\)]\)(t)"},InputField[#, Hold[Expression]] &},
    {{py, 2 + 2  Cos[t], 
      "\!\(\*SubscriptBox[\(S\), \(y\)]\)(t)"},InputField[#, Hold[Expression]] &}
    ]
   }[[2]]]
$\endgroup$
6
  • $\begingroup$ I'm struggling to reverse engineer your code, but just going off of your comments, I suspect that you don't need to worry about doing your own localization. Manipulate will manage the localization on its own. $\endgroup$ Commented Nov 29, 2024 at 21:01
  • $\begingroup$ It doesn't, "t" needs to be localized by DynamicModule. If I don't and a user begins entering the functions that parametrize x and y, and t is defined somewhere else in Mathematica, it will replace t with that value. $\endgroup$ Commented Nov 29, 2024 at 21:03
  • $\begingroup$ I added a comment in the code showing which line exactly I am having a problem with. $\endgroup$ Commented Nov 29, 2024 at 21:15
  • $\begingroup$ When t is localized by DynamicModule[], it is localized when the DynamicModule is instantiated by the Front End. Every time an instance of the module is created, a new localization is created. Mathematica localizes the symbol-name variable by adding $$ and a serial number; it is created in the FE` context and not the Global` one. What you're seeing is the symbol used to localize the nominal variable t. $\endgroup$ Commented Nov 29, 2024 at 21:16
  • $\begingroup$ I think you're using List ({}) instead of CompoundExpression[] (;) in some places. Like DynamicModule[{..}, init1; init2;...; Manipulate[...]]. It's not the problem though. $\endgroup$ Commented Nov 29, 2024 at 21:26

4 Answers 4

2
$\begingroup$

Points:

  • Refactored/streamlined code more from the OP's and from my other answer.
  • The use of contexts to control display
  • // MakeBoxes[#, StandardForm] & // DisplayForm must come after the output to be displayed but inside Block[{$ContextPath =....
  • Use whatever name for the context you wish to localize t in the context; I would start with a lower case, such as foo`t, tmp`t or my`t, so that you won't interfere with a built-in context.
  • TrackingFunction used to manage update of a single variable (plot), instead of the cumbersome use of flags, which trigger extra updates of Manipulate[] when they are changed.
  • All expressions with the global symbol t must be held at all times. Release the hold after Global`t is replaced by foo`t.
  • The InputField is formatted outside the blocked context path; t there refers to Global`t, and thus it must be held.
  • Maybe there's an easy way to unify the InputField[] and the Manipulate[] displays. For instance, Initialization and Deinitialization in Manipulate could change $ContextPath. However, this would probably make t entered outside Manipulate[] be foo`t instead of Global`t, in effect,un-localizing t. It defeats our purpose.

Code:

t = 5; (* test localization *)
Manipulate[
 Block[{$ContextPath =(* is "Global`" needed? not here *)
    {"foo`", "System`", "Global`"}},
  (* manage variables *)
  plots[[plot]] = {px, py};
  (* set up for display *)
  With[{dplots = plots /.
         HoldPattern[Global`t] :> foo`t // ReleaseHold},
   With[{dpx = dplots[[plot, 1]], dpy = dplots[[plot, 2]]},
    {dpx, dpy} -> Grid[dplots] //
      MakeBoxes[#, StandardForm] & // DisplayForm
    ]]
  ],
 {{plot, 1}, 
  Dynamic[Array[# -> ToString[names[[#]]] &, Length[plots]]],
  ControlType -> PopupMenu,
  TrackingFunction -> ((plot = #; {px, py} = plots[[plot]]) &)},
 {{px, Hold[-2 Sin[t]], "\!\(\*SubscriptBox[\(S\), \(x\)]\)(t)"},
  InputField[#, Hold[Expression]] &},
 {{py, Hold[2 + 2 Cos[t]], "\!\(\*SubscriptBox[\(S\), \(y\)]\)(t)"},
  InputField[#, Hold[Expression]] &},
 {{names, {"s1", "s2", "s3"}}, None},
 {{plots, Map[Hold,
     Hold@{
       {-2 Sin[t], 2 + 2 Cos[t]},
       {Sin[t], Cos[t]},
       {3 Sin[t], 4 Cos[t]}
       }, {3}] // ReleaseHold}, None}
 ]

enter image description here

$\endgroup$
2
  • $\begingroup$ Ah! I was just coming back here to ask if there was a more efficient way to deal with tracked symbols. This method is cumbersome and seemed unnecessary, thanks! $\endgroup$ Commented Dec 1, 2024 at 20:14
  • $\begingroup$ @Daniel Thanks for the accept. I would point out for anyone trying to solve a similar problem that replacing Hold -> HoldForm (see my comment to lericr's answer is a less cumbersome way to handle the display of t than HoldPattern[t] -> foo`t and $ContextPath. However, if you need a variable in your code, then t has to be replaced by something or it might evaluate to its global value. $\endgroup$ Commented Dec 2, 2024 at 12:13
2
$\begingroup$

How about something like this?

DynamicModule[
  {allplots = {{Hold[t], Hold[t^2]}, {Hold[Sin[t]], Hold[Cos[t]]}}, 
   initplotidx = 1, previousplotidx = 1},
  Manipulate[
    If[currentplotidx == previousplotidx, 
      allplots[[currentplotidx]] = {px, py}, 
      {px, py} = allplots[[previousplotidx = currentplotidx]]];
    ParametricPlot[ReleaseHold[allplots[[currentplotidx]]], {t, 0, 5}],
    {{currentplotidx, initplotidx}, {1, 2}, ControlType -> PopupMenu},
    {{px, allplots[[initplotidx, 1]], "X"}, InputField[#, Hold[Expression]] &},
    {{py, allplots[[initplotidx, 2]], "Y"}, InputField[#, Hold[Expression]] &}]]
$\endgroup$
2
  • $\begingroup$ Looks good, You might want to add something like PlotLabel -> ({px, py} /. Hold -> HoldForm) to Plot to show how to manage the display of t in the content area. $\endgroup$ Commented Dec 1, 2024 at 19:32
  • $\begingroup$ I would also point out the once-documented plot option, Evaluated -> True, which uses the evaluated form of the function argument. It is different from using Evaluate in that the function is evaluated after t is blocked. Using the evaluated form can save time and let the plot function parse the input, neither of which are an issue in the test code you provided. But they could be issues in other cases. $\endgroup$ Commented Dec 1, 2024 at 19:58
1
$\begingroup$

I continued playing with the code trying different things, and eventually ended up with this that fixes my problem.

DynamicModule[{names, plots, Pn, Po, t, tplot},
 names = {"s1", "s2"};
 plots = {{t, t^2}, {Sin[t], Cos[t]}};
 plottable = plots /. t -> tplot;
 Manipulate[
  Pn = plot;
  If[Pn == Po, {(*no change in plot selected,update parameter values*)
    With[
     {(*pn=ReleaseHold[{px,py}/. HoldPattern[t_/;MatchQ[t,Symbol[
      "t"]]]:>tplot]*)
      pn = {px, py}
      },
     (*Do not release hold here, release later*)
     {plots[[plot]] = pn,
      plottable[[plot]] = 
       ReleaseHold[
        pn /. HoldPattern[t_ /; MatchQ[t, Symbol["t"]]] :> tplot]
      }]},
   {
    {px, py} = plots[[plot]]
    }];
  Po = plot;
  Grid[{{plots}, {ParametricPlot[
      plottable[[plot]], {tplot, 0, 5}]}}],
  {{plot, 1}, 
   Dynamic[Array[# -> ToString[names[[#]]] &, Length[plots]]], 
   ControlType -> PopupMenu},
  {{px, Null, "\!\(\*SubscriptBox[\(S\), \(x\)]\)(t)"}, 
   InputField[#, Hold[Expression]] &},
  {{py, t^2, "\!\(\*SubscriptBox[\(S\), \(y\)]\)(t)"}, 
   InputField[#, Hold[Expression]] &}]]
$\endgroup$
1
$\begingroup$

It's hard to figure exactly what's wanted. Here's my take:

t = 5;
Manipulate[
 Pn = plot; 
 If[Pn == Po,(*no change in plot selected,update parameter values*)
  With[{pn = ReleaseHold[{px, py} /. HoldPattern[t] :> tplot]},
   plots[[plot]] = pn
   ],
  (*change in plot selected,update manipulators*)
  {px, py} = plots[[plot]](*/.tplot->t*)
  ];
 Po = plot;
 {px, py} -> Grid[plots],
 {{plot, 1}, 
  Dynamic[Array[# -> ToString[names[[#]]] &, Length[plots]]], 
  ControlType -> PopupMenu}, {{px, Hold[-2 Sin[tplot]], 
   "\!\(\*SubscriptBox[\(S\), \(x\)]\)(t)"}, 
  InputField[#, Hold[Expression]] &}, {{py, Hold[2 + 2 Cos[tplot]], 
   "\!\(\*SubscriptBox[\(S\), \(y\)]\)(t)"}, 
  InputField[#, Hold[Expression]] &},
 {{names, names = {"s1", "s2", "s3"}}, None}, {{plots, plots}, 
  None}, {Pn, None}, {Po, None}, {{tplot, tplot}, None},
 Initialization :> (
   MakeBoxes[tplot, form_] := "t";
   plots = {{-2 Sin[tplot], 2 + 2 Cos[tplot]},
     {Sin[tplot], Cos[tplot]}, {3 Sin[tplot], 4 Cos[tplot]}};
   ),
 Deinitialization :> (MakeBoxes[tplot, form_] =.)
 ]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.