2
$\begingroup$

Short Version

Consider the following code:

test = "I";
label = "I";
paramlist = {a, b};
ToExpression[StringReplace[test, {label -> "(v2@@paramlist)[t]"}]]

(* v2[a,b][t] *)

When I try this inside a DynamicModule, it fails:

DynamicModule[
  {dispVar2 = "I", 
   varyingparamlist, 
   fitExpression = "I", 
   fitfn}, 
  varyingparamlist = {a, b}; 
  fitfn = ToExpression[
            StringReplace[fitExpression, 
              {dispVar2 -> "(v2@@varyingparamlist)[t]"}]]; 
  Dynamic@Panel[fitfn]]

(* {a,b}[t] *)

What is going on here, and how can I get the correct expression inside a DynamicModule?

Context

I have a system where I want non-Mathematica-savy users to be able to enter an expression in a (limited) natural notation for them as part of a dynamic interface. They can specify labels for variables and a system of differential equations which are then fit against experimental data using a combination of ParametricNDSolve and NonlinearModelFit. So if they specify

a S I

where S and I are the first and second time-dependent quantities in the system, this gets translated to

a v1[t] v2[t]

After solving the system of equations, I have parametric models that I need to access via something like:

((v1/.solution)@@varParams)[t]

The problem comes in when the fitting variable isn't a single value, like S or I. If I need S+I, I need to do something like:

ToExpression[StringReplace["S+I",
     {"S"->"(v1@@varParams)[t]",
      "I"->"(v2@@varParams)[t]"}]]/.solution
$\endgroup$
5
$\begingroup$

1.

DynamicModule[{dispVar2 = "I", varyingparamlist, fitExpression = "I", 
  fitfn}, varyingparamlist = {a, b};
 fitfn = ToExpression[
   StringReplace[fitExpression, {dispVar2 -> "(v2@@varyingparamlist)[t]"}], 
   StandardForm, Dynamic];
 Panel[fitfn]]

enter image description here

2.

DynamicModule[{dispVar2 = "I", varyingparamlist, fitExpression = "I", 
  fitfn}, varyingparamlist = {a, b};
 fitfn = ToExpression[
   StringReplace[fitExpression, {dispVar2 -> "(v2@@varyingparamlist)[t]"}], 
   StandardForm, Hold];
 Dynamic @ ReleaseHold @ Panel[fitfn]]

enter image description here

3.

DynamicModule[{dispVar2 = "I", varyingparamlist = {a, b}, 
  fitExpression = "I", fitfn},
 fitfn = MakeExpression[
   StringReplace[fitExpression, {dispVar2 -> "(v2@@varyingparamlist)[t]"}]];
 Dynamic @ ReleaseHold @ Panel[fitfn]]

enter image description here

Notes:

DynamicModule[{dispVar2 = "I", varyingparamlist = {a, b}, 
  fitExpression = "I", fitfn},
 fitfn = ToExpression[
   StringReplace[fitExpression, {dispVar2 -> "(v2@@varyingparamlist)[t]"}]];
 Panel[fitfn]]

enter image description here

What happened to v2?:

 foo @@ x
 x

Now, wrapping this with Dynamic updates varyingparamlist$$ and injects {a, b} for it:

DynamicModule[{dispVar2 = "I", varyingparamlist = {a, b}, 
  fitExpression = "I", fitfn},
 fitfn = ToExpression[
   StringReplace[fitExpression, {dispVar2 -> "(v2@@varyingparamlist)[t]"}]];
 Dynamic @ Panel[fitfn]]

enter image description here

That is, ToExpression (without the third argument) evaluates the string "(v2@@varyingparamlist)[t]" before varyingparamlist is updated so that v2@@varyingparamlist evaluates to varyingparamlist$$ and the result is varyingparamlist$$[t]. Using the Hold as the third argument of ToExpression or using MakeExpression (which "returns the result wrapped in HoldComplete") prevents this untimely evaluation.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Works beautifully! Can you share some insights into why it works? Regardless, thank you! $\endgroup$ – Kevin Ausman Apr 16 at 17:41
  • 1
    $\begingroup$ @Kevin, added a few comments re "why it works". Hope it helps. $\endgroup$ – kglr Apr 16 at 19:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.