3
$\begingroup$

The below example works to initialize the Gauge, but it does not initialize sf until we interact with the gauge.

DynamicModule[{xa, x0 = 1, dx = 1, xb, xbScaled, fa, fb, fbScaled, 
  points, sf, sf2, scaledPoints, somePolys},
 somePolys = {1 + x, 0.5 - 0.1*x, 1 - 0.1*x^2, 
   1 - x - 0.2*x^2 + 0.05*x^3};
 xa = x0;
 xb = x0 + dx;
 xbScaled := x0 + dx*sf;
 fa = somePolys /. x -> xa;
 fb = somePolys /. x -> xb;
 fbScaled := fa + (fb - fa)/(xb - xa)*(sf - 1)*dx;
 points = MapThread[{{xa, #1}, {xb, #2}} &, {fa, fb}];
 scaledPoints := 
  MapThread[{{xa, #1}, {#3, #2}} &, {fa, fbScaled, xbScaled}];
 {
   sf2 = {0.1, 0.3, 0.5, 0.7};
   HorizontalGauge[Dynamic[sf2, (sf2 = #; sf = sf2;) &], 
    GaugeStyle -> 97],
   Dynamic[xbScaled],
   Dynamic[scaledPoints],
   Dynamic[Definition[xbScaled]]
   } // Column
 ]

The initial output before interacting with the Gauge at all looks like this, because sf has not been initialized yet.

Initial output before interaction with Gauge

After interacting with the gauge, sf is given a useable definition and xbScaled and fbScaled can be computed properly via their definitions.

Output after gauge interaction

The definition of the Gauge above is a workaround. I would really like to initialize sf and have the Gauge be defined like this:

HorizontalGauge[Dynamic[sf], GaugeStyle -> 97]

And then replace all instances of sf2 with sf. I would have expected this to work because the definition of xbScaled is SetDelayed, but when I do that, it seems like that definition is not created before sf is initialized:

(* I would expect this to always have sf in the definition since it is SetDelayed*)
xbScaled:=x0+dx*sf;
sf={0.1,0.2,0.3,0.5};
(*definition of xbScaled appears to contain the initialized values of sf,
 and not the symbol sf itself. Thus, it is not updated.*)
Dynamic[xbScaled] 

Even though xbScaled is set delayed, initializing sf (instead of sf2 in the workaround) gives the definition of xbScaled with the initialized values of sf, rather than containing the sf symbol.

So I maybe the ultimate question boils down to this: how can I use SetDelayed symbols that are meant to be Dynamic inside of a DynamicModule and properly initialize the variables they depend on without clobbering the definition of the delayed variables?

(Please edit the post if you believe the ultimate question should be different)

$\endgroup$
4
  • 1
    $\begingroup$ I can't commit to answer your specific case but I guess knowing this will save your time and will help to solve this: 121585 $\endgroup$
    – Kuba
    Nov 19 '21 at 5:49
  • $\begingroup$ Simply replace {sf2 {0.1, 0.3, 0.5, 0.7};` by {sf2 = sf = {0.1, 0.3, 0.5, 0.7}; $\endgroup$ Nov 19 '21 at 8:35
  • $\begingroup$ @DanielHuber Your "simple" suggestion does not solve the problem at all. Making your suggested change causes xbScaled to no longer be connected to the Gauge (or sf). That was the whole premise of the question. $\endgroup$ Nov 20 '21 at 5:43
  • $\begingroup$ @Kuba it took me some experimentation, but the answer you linked helped me to make this example work as intended. Thank you! I will post an answer. $\endgroup$ Nov 22 '21 at 14:53
1
$\begingroup$

The following post has some clues as to why the SetDelayed does not work (essentially, DynamicModule does not support SetDelayed) https://mathematica.stackexchange.com/a/121585/5478.

The following code does what I intended, but it is not obvious why this is needed. It feels like a hack. One needs to use square brackets [] in all the variable names that depend on the initialized variables (in this case everything that depends on sf), both the definition and usage, in order to maintain the unevaluated form in the definition. This allows one to maintain dynamicity when the variable is updated (sf in this example).

DynamicModule[{xa, x0 = 1, dx = 1, xb, xbScaled, fa, fb, fbScaled, 
  points, sf, sf2, scaledPoints, somePolys},
 somePolys = {1 + x, 0.5 - 0.1*x, 1 - 0.1*x^2, 
   1 - x - 0.2*x^2 + 0.05*x^3};
 xa = x0;
 xb = x0 + dx;
 xbScaled[] := x0 + dx*sf;
 fa = somePolys /. x -> xa;
 fb = somePolys /. x -> xb;
 fbScaled[] := fa + (fb - fa)/(xb - xa)*(sf - 1)*dx;
 points = MapThread[{{xa, #1}, {xb, #2}} &, {fa, fb}];
 scaledPoints[] := 
  MapThread[{{xa, #1}, {#3, #2}} &, {fa, fbScaled[], xbScaled[]}];
 {
   sf = {0.1, 0.3, 0.5, 0.7};
   HorizontalGauge[Dynamic[sf], GaugeStyle -> 97],
   Dynamic[xbScaled[]],
   Dynamic[scaledPoints[]],
   Dynamic[fbScaled[]],
   Dynamic[Definition[xbScaled[]]]
   } // Column
 ]

The output upon first execution before interacting with the gauge: enter image description here

And adjusting the Gauge updates the various Dynamic outputs.

$\endgroup$

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.