Unwanted re-evaluation of a variable inside Manipulate
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 :> {τ}]
Notes
GetDiff
is not needed.- 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 fordata
andtdta
. - Calling
MakePoints
as an initializer in the specification ofdta
fixes you problem of unwanted re-evaluation. - Only
τ
need be tracked, which reduces the load on the front-end. - Introducing
Column
andRow
much simplifies the formatting of the output. - Adding the
Appearance -> "Labeled"
option to the specification ofτ
eliminates the need to write code to showτ
in the output, - This approach does not require calling
Dynamic
explicitly anywhere in theManipulate
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:
- There is a wired-in dependence on having 15 data points and plotting over a domain of 0 – 15.
- The list plot is given only range values and so used the default domain of 1 – 15; it should adjusted to start at zero.
- Changing the code to support a user-specified number of data points also requires permitting a user-specified range for the plot.
- 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.
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. ]
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]
}
]