4
$\begingroup$

In the below Manipulate expression:

Discretize=Function[{f,steps,x1},Table[f[x],{x,0,x1,Floor[x1/steps]}]];
MakePoints=Function[var,Table[x^2+RandomReal[{-var,var}],{x,0,15,1}]];
Manipulate[
 GetDiff = Function[
   Total[dta] - Total[mdl]
   ];
 dta = MakePoints[15];
 mdl = Discretize[Function[x, τ*x^2], Length[dta] - 1, 
   Length[dta] - 1];
 ListLinePlot[{dta, mdl}, 
  PlotRange -> {{0, Length[dta] - 1}, {0, 250}}, 
  PlotLegends -> {"data", "model"}],
 {{τ, 1}, .01, 3, .01},
 Dynamic[
  diff = GetDiff[];
  "τ: " <> ToString[τ] <>
   "\nΣdata: " <> ToString[Total[dta]] <>
   "\nΣmodel: " <> ToString[Total[mdl]] <>
   "\nΣdata-Σmodel: " <> ToString[diff]
  ]
 ]

Why does varying the parameter seemingly reevaluate dta? I get a constantly changing dta line while I vary the parameter.

Manipulate plot

$\endgroup$

3 Answers 3

4
$\begingroup$

Your MakePoints[ ] function has a RandomReal[ ] function call in it, so it is randomizing each time you move the Manipulate slider. Just move it outside.

dta = MakePoints[15];

Manipulate[GetDiff = Function[Total[dta] - Total[mdl]];
 (*dta=MakePoints[15];*)
 ...Etc.]

or you can wrap the internal random call with a BlockRandom[ ]

Manipulate[GetDiff = Function[Total[dta] - Total[mdl]];
     dta = BlockRandom@MakePoints[15];
    .... Etc. ]
$\endgroup$
2
  • $\begingroup$ Can I ask if there is a way to not re-evaluate a variable that's independent from the parameter being manipulated? Thanks. $\endgroup$
    – user182917
    Jan 29, 2019 at 19:55
  • 1
    $\begingroup$ When you use Manipulate, the internals of the body of the command get evaluated no matter which parameter you are manipulating, so you have to use some tricks to suppress the random call. Somebody else smarter than I am may have a solution. $\endgroup$
    – MikeY
    Jan 29, 2019 at 20:04
6
$\begingroup$

Your code can be fixed and made much simpler and more efficient, all at the same time. Like so;

Discretize = Function[{f, steps, x1}, Table[f[x], {x, 0, x1, Floor[x1/steps]}]];

MakePoints = Function[var, Table[x^2 + RandomReal[{-var, var}], {x, 0, 15, 1}]];

SeedRandom[1];
Manipulate[
  mdl = Discretize[Function[x, τ x^2], Length[dta] - 1, Length[dta] - 1];
  tmdl = Total[mdl];
  Column[{
     ListLinePlot[{dta, mdl},
       PlotRange -> {{0, Length[dta] - 1}, {0, 250}}, 
       PlotLegends -> {"data", "model"},
       ImageSize -> Medium],
     Row[{"Σdata: ", tdta}],
     Row[{"Σmodel: ", tmdl}],
     Row[{"Σdata-Σmodel: ", tdta - tmdl}]}],
  {{dta, MakePoints[15]}, None},
  {{tdta, Total[dta]}, None},
  {mdl, None},
  {tmdl, None},
  {{τ, 1}, .01, 3, .01, Appearance -> "Labeled"},
  TrackedSymbols :> {τ}]

demo

Notes

  1. GetDiff is not needed.
  2. Introducing some local variables with specifications of the form {varspec, None}, which are automatically dynamic, makes for cleaner code and makes it easy to set static values for data and tdta.
  3. Calling MakePoints as an initializer in the specification of dta fixes you problem of unwanted re-evaluation.
  4. Only τ need be tracked, which reduces the load on the front-end.
  5. Introducing Column and Row much simplifies the formatting of the output.
  6. Adding the Appearance -> "Labeled" option to the specification of τ eliminates the need to write code to show τ in the output,
  7. This approach does not require calling Dynamic explicitly anywhere in the Manipulate expression.

Update

As usual I didn't stop thinking about this problem after I posted the above code. Eventually, I realized that there were some issues that needed to be addressed:

  1. There is a wired-in dependence on having 15 data points and plotting over a domain of 0 – 15.
  2. The list plot is given only range values and so used the default domain of 1 – 15; it should adjusted to start at zero.
  3. Changing the code to support a user-specified number of data points also requires permitting a user-specified range for the plot.
  4. There an error in way tmdl is initialized that needs fixing.

The 1st three issues are inherited from the OP's code; the last is my very own.

Here is the revised code. The modifications are not extensive, but I believe them to be worth posting

Discretize = Function[{f, xmax}, Table[f[x], {x, 0, xmax}]];
MakePoints = Function[xmax, Table[x^2 + RandomReal[{-xmax, xmax}], {x, 0, xmax}]];

SeedRandom[1];
With[{xmax = 20, ymax = 400},
  Manipulate[
    mdl = Discretize[Function[x, τ x^2], xmax];
    tmdl = Total[mdl];
    Column[
      {ListLinePlot[{dta, mdl},
         DataRange -> {0, xmax},
         PlotRange :> ymax,
         PlotLegends -> {"data", "model"},
         ImageSize -> Medium],
      Row[{"Σdata: ", tdta}],
      Row[{"Σmodel: ", tmdl}],
      Row[{"Σdata-Σmodel: ", tdta - tmdl}]}],
    {{dta, MakePoints[xmax]}, None},
    {tdta, None},
    {mdl, None},
    {tmdl, None},
    {{τ, 1}, .01, 3, .01, Appearance -> "Labeled"},
    Initialization :> (tdta = Total[dta]),
    TrackedSymbols :> {τ}]]

Here is how things look when dta consists of 20 points.

demo

$\endgroup$
4
$\begingroup$

Another option using DynamicModule which is the proper tool for interfaces that have local variables:

DynamicModule[
 {MakePoints, Discretize, dta, tdta, mdl, tmdl},
 Manipulate[
  mdl = Discretize[Function[x, τ x^2], Length[dta] - 1, 
    Length[dta] - 1];
  tmdl = Total[mdl];
  Grid[
   {
    {
     ListLinePlot[
      {dta, mdl},
      PlotRange -> {{0, Length[dta] - 1}, {All, 250}},
      PlotLegends -> {"data", "model"}, ImageSize -> Medium
      ],
     SpanFromLeft
     },
    {Subscript["Σ", "data"], ":", tdta},
    {Subscript["Σ", "model"], ":", tmdl},
    {
     Row@{Subscript["Σ", "data"], "-", 
       Subscript["Σ", "model"]}, ":",
     tdta - tmdl
     }
    },
   Alignment -> Left
   ],
  {{τ, 1}, .01, 3, .01, Appearance -> "Labeled"},
  TrackedSymbols :> {τ}
  ],
 Initialization :> {
   MakePoints = 
    Function[var, Range[0, 15]^2 + RandomReal[{-var, var}, 16]], 
   Discretize = 
    Function[{f, steps, x1}, Table[f[x], {x, 0, x1, Floor[x1/steps]}]],
   dta = MakePoints[15],
   tdta = Total[dta]
   }
 ]
$\endgroup$

Your Answer

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

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