1
$\begingroup$

I'm trying to create some code that plots a variable number of Gaussians, and allows me to control their parameters using Locators. One locator at the top controls $\mu$ and a vertical scaling factor, while another locator is fixed at half the max in the vertical, but can slide in the horizontal direction to control $\sigma$. As part of this, I thought it might be nice to use a Switch statement that updates the 2 locators for each Gaussian. I've got this working if I hard code each part, but trying to generate a variable number of conditions within the Switch is problematic.

I've come across other questions about Switch which suggest the use of Evaluate, (Switch[val, Evaluate[Sequence@@conditions]]) but that seems to result in all statements inside the Switch being evaluated. I think the trouble comes because conditions is not something that is pre-evaluated in my case. Here is a minimum working example:

Switch[1,
  Evaluate[Sequence @@ Flatten@Table[
    {
      i, 
      Print[ToString[2 i - 1]]; 
      Print[ToString[2 i]];, 
      i + 1, 
      Print[ToString[2 (i + 1) - 1]]; 
      Print[ToString[2 (i + 1)]];
    },
    {i, 1, 6, 2}]
  ]
]
(* Prints the numbers: 1 2 3 4 5 6 7 8 9 10 11 12 *)

This prints the numbers 1 through 12 rather than just 1 and 2. I think this is probably due to the function generating the conditions being inside of Evaluate, but I'm not sure how to achieve exactly what I'm after without it.

In my actual code, I'm trying to update my locator positions based upon CurrentValue["CurrentLocatorPaneThumb"], and I'm using Slots, so I don't think I can evaluate the conditions beforehand. Perhaps I can if I use some combination of Hold and ReleaseHold or something? I haven't been able to get that to work so far.

Here is a minimal version of my actual code. I'd like to replace the hard-coded Switch with something that changes based on the total number of Gaussians. The intended behaviour is that when the peak locator moves left or right, the whole Gaussian follows it. When the FWHM locator moves, it should only change the width of the Gaussian. Because all conditions seem to evaluate when I use a Table inside my Switch, I end up with only the peak locator moving while the FWHM locator stays still.

DynamicModule[
 {pts = {{1, 1}, {0, 0.5}, {2, 1}, {0, 0.5}}, dist = {1, 1}},
 LocatorPane[
  Dynamic[pts,
   Switch[CurrentValue["CurrentLocatorPaneThumb"],
     1,
     pts[[1]] = #[[1]];
     pts[[2]] = {#[[1, 1]] - dist[[1]], #[[1, 2]]/2},
     2,
     pts[[2]] = {#[[2, 1]], #[[1, 2]]/2};
     dist[[1]] = #[[1, 1]] - #[[2, 1]];,
     3,
     pts[[3]] = #[[3]];
     pts[[4]] = {#[[3, 1]] - dist[[2]], #[[3, 2]]/2},
     4,
     pts[[4]] = {#[[4, 1]], #[[3, 2]]/2};
     dist[[2]] = #[[3, 1]] - #[[4, 1]];
     ] &
   ],
  Dynamic@Plot[
    Evaluate[
     Table[
       Subscript[a, i]
         E^(-((x - Subscript[\[Mu], i])^2/(
         2 Subscript[\[Sigma], i]^2))),
       {i, 2}
       ] /. {Subscript[\[Sigma], 
         i_] :> (pts[[2 i - 1, 1]] - pts[[2 i, 1]])/Sqrt[2 Log[2]], 
       Subscript[\[Mu], i_] :> pts[[2 i - 1, 1]], 
       Subscript[a, i_] :> pts[[2 i - 1, 2]]}],
    {x, -5, 5},
    PlotRange -> Full
    ]
  ]
 ]

If I'm doing anything else in a back-asswards way, feel free to let me know!

$\endgroup$
2
$\begingroup$

An alternative way to specify the updating function that avoids using Switch:

DynamicModule[{pts = {{1, 1}, {0, 0.5}, {2, 1}, {0, 0.5}, {3, 1}, {0, 0.5}}, 
    dist = {1, 1, 1}}, 
 LocatorPane[Dynamic[pts, With[{i = CurrentValue["CurrentLocatorPaneThumb"]}, 
     If[EvenQ[i], pts[[i]] = {#[[i, 1]], #[[i - 1, 2]]/2};
      dist[[i/2]] = #[[i - 1, 1]] - #[[i, 1]], pts[[i]] = #[[i]];
      pts[[i + 1]] = {#[[i, 1]] - dist[[(i + 1)/2]], #[[i, 2]]/ 2}]] &], 
  Dynamic @ Plot[Evaluate[Table[Subscript[a, i] 
    E^(-((x - Subscript[μ, i])^2/(2 Subscript[σ, i]^2))), {i,  3}] /.
      {Subscript[σ, i_] :> (pts[[2 i - 1, 1]] - pts[[2 i, 1]])/Sqrt[2 Log[2]], 
       Subscript[μ, i_] :> pts[[2 i - 1, 1]], 
       Subscript[a, i_] :> pts[[2 i - 1, 2]]}], {x, -5, 5}, 
    PlotRange -> Full]]]

enter image description here

$\endgroup$
  • $\begingroup$ That works great, thanks! $\endgroup$ – MassDefect May 29 at 15:36

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.