I am in the middle of making a CDF for a calculation of many random variables. I've gone with `DynamicModule` and have read the documentation plus these posts: [32294][1] and [30079][2]. I've obviously missed a few things as it is not working as expected.
I have constructed the module as such (working snippet at the end of post):
DynamicModule[
{dynamic variables},
constant variables;
Dynamic@Refresh[
expensive calcs;
plots and tables;
, TrackedSymbols->{update}]
Column[{controls for dynamic variables, plots, tables}],
Initialization :> (functions for calcs, plots, and controls),
UnsavedVariables :> {update},
SaveDefinitions -> True
]
I am having 3 issues.
1. The controls created by the `variableRow` function for the dynamic variables do not display on first execution but everything else does. The plots and charts are linked to the update variable and refresh when the button is clicked. A second evaluation of the cell will show the controls made by `variableRow`.
2. The `Dynamic@Refresh` keeps kicking out a `Null`. If I end it with a `;` then none of the plots and tables update when the *Run Simulation* button is pressed. This seems odd. How do I get rid of this *Null*
3. When previewed as *CDF Player* I get a ton of errors from the `FE'` context when I click the *Run Simulation* button. I have `SaveDefinitions -> True` on the module so am not certain why this is happening.
**Added a smaller example of issue**
This has the same three problems described above.
DynamicModule[
{numPoints = 100, interpolation = None, update = 1},
plotColour = Pink;
Dynamic@Refresh[
data = RandomReal[{100, 1000}, numPoints];
plot = plotPoints[data, plotColour, interpolation];
,
TrackedSymbols -> {update}]
Column[{
Grid[{
{"Control from function call",
makeControl[Dynamic@numPoints, {10, 1000, 10}, "Num Points"]},
{"Direct created control",
PopupMenu[Dynamic@interpolation, Range[5], "Select ..."]}
}],
Button["Run Simulation", update = update + 1, ImageSize -> Large],
Dynamic@plot
}]
,
Initialization :>
(
plotPoints[points_, colour_, interpOrder_] :=
ListLinePlot[points, PlotStyle -> colour,
InterpolationOrder -> interpOrder, ImageSize -> 400];
makeControl[variable_, range_, name_] :=
Column[{name,
Slider[variable, range, Appearance -> Tiny, ImageSize -> Tiny]
}];
),
UnsavedVariables :> {update}, SaveDefinitions -> True]
--------------------------------------
**Orignal code snippet (too large and busy)**
It is a big module so I've taken a lot of things out while preserving my issue. The functions definitions have been reduced as well so please don't focus on the calculations.
DynamicModule[
(* Parameters *)
{numberOfRuns = 10000,
investmentCaptial = 15000000,
(* Many more dynamic parameters in this section *)
\[Mu]OverheadExpenses = 600000, \[Sigma]OverheadExpenses = 40000,
\[Mu]ReturnOnInvest = 0.05, \[Sigma]SpliceLower =
0.03, \[Sigma]SpliceUpper = 0.02,
update = 1},
rtnPeriods = {50, 100, 250, 500, 1000};
variableNames = {(*
more names for the omitted dynamic variables above *)
"OverheadExpenses", "ReturnOnInvestLogN", "ReturnOnInvestSpliceN"};
(* A few other constant parameters in this section *)
Dynamic@Refresh[
(* Many distributions defined in this section to the dynamic parameters omitted above *)
overheadExpensesDist =
NormalDistribution[\[Mu]OverheadExpenses, \[Sigma]OverheadExpenses];
returnOnInvestLogNDist =
LogNormalDistribution[1 + \[Mu]ReturnOnInvest,
Sqrt[\[Sigma]SpliceLower^2 + \[Sigma]SpliceUpper^2]];
returnOnInvestSpliceNDist =
SplicedDistribution[{\[Sigma]SpliceLower/\[Sigma]SpliceUpper,
1}, {-\[Infinity], \[Mu]ReturnOnInvest, \[Infinity]}, {
NormalDistribution[\[Mu]ReturnOnInvest, \[Sigma]SpliceLower],
NormalDistribution[\[Mu]ReturnOnInvest, \[Sigma]SpliceUpper]}];
(* Single step simulation *)
sampleRuns =
Transpose[
RandomVariate[#, numberOfRuns] & /@ {(*
More distributions here o the dynamic parameters omitted above *)
overheadExpensesDist, returnOnInvestLogNDist,
returnOnInvestSpliceNDist}];
runsAssoc = AssociationThread[variableNames, #] & /@ sampleRuns;
(* Calculations begin *)
{netIncomeInvestLogN, netIncomeInvestSpliceN} =
Transpose[(Function[{rtnOnInvest},
netIncome[(*
More dynamic parameter names here *)#OverheadExpenses,
Switch[rtnOnInvest, "ReturnOnInvestLogN",
Log[#[rtnOnInvest]] - 1,
"ReturnOnInvestSpliceN", #[rtnOnInvest]],
investmentCaptial]] /@ {"ReturnOnInvestLogN",
"ReturnOnInvestSpliceN"}) & /@ runsAssoc];
{netIncomeDistPlotLogN,
netIncomeDistPlotSpliceN} = {distributionPlot[
netIncomeInvestLogN,
PlotLabel ->
"Investment Return \[Distributed] " <>
ToString@Head[returnOnInvestLogNDist], ImageSize -> 400],
distributionPlot[netIncomeInvestSpliceN,
PlotLabel ->
"Investment Return \[Distributed] " <>
ToString@Head[returnOnInvestSpliceNDist], ImageSize -> 400]};
{netIncomeInvestLogNHdt, netIncomeInvestSpliceNHdt} =
DistributionFitTest[#, NormalDistribution[x, y],
"HypothesisTestData"] & /@ {netIncomeInvestLogN,
netIncomeInvestSpliceN};
{netIncomeInvestLogNReturnPeriod,
netIncomeInvestSpliceNReturnPeriod} =
returnPeriodTables[{netIncomeInvestLogNHdt,
netIncomeInvestSpliceNHdt}, "Net Income"];
(* More calcuations, tables, and plots on simulation *)
,
TrackedSymbols -> {update}
]
Column[{
Grid[{
{, "Distribution", "Mean", "Std. Deviation"},
(* More variable rows here *)
Evaluate@
variableRow["Overhead Expense", "Normal",
Dynamic@\[Mu]OverheadExpenses, {500000, 4000000, 25000},
Dynamic@\[Sigma]OverheadExpenses, {30000, 100000, 5000}],
{Item["Return On Investment", Alignment -> Center], "Log Normal",
Item[
Column[{Dynamic@\[Mu]ReturnOnInvest,
Slider[Dynamic@\[Mu]ReturnOnInvest, {.01, .08, .005},
Appearance -> Tiny, ImageSize -> Tiny]},
Alignment -> {Center, Center}],
Alignment -> Center],
Item[
Dynamic@Sqrt[\[Sigma]SpliceLower^2 + \[Sigma]SpliceUpper^2],
Alignment -> {Center, Bottom}]},
{SpanFromAbove, "Splice Normal", SpanFromAbove,
Row[{
Column[{Dynamic@\[Sigma]SpliceLower,
Slider[Dynamic@\[Sigma]SpliceLower, {.001, .1, .001},
Appearance -> Tiny, ImageSize -> Tiny]},
Alignment -> {Center, Center}],
Column[{Dynamic@\[Sigma]SpliceUpper,
Slider[Dynamic@\[Sigma]SpliceUpper, {.001, .1, .001},
Appearance -> Tiny, ImageSize -> Tiny]},
Alignment -> {Center, Center}]
}, Spacer[2]]},
{, "Number of Runs",
PopupMenu[Dynamic[numberOfRuns], Range[25000, 100000, 25000],
"Select ..."]}
}],
Button["Run Simulation", update = update + 1, ImageSize -> Large],
Dynamic@netIncomeDistPlotLogN,
Dynamic@netIncomeInvestLogNReturnPeriod
}, Dividers -> {None, {-3 -> True}}]
,
(* Initialise functions *)
Initialization :>
(
netIncome[(* parameters removed for example *)overheadExpenses_,
returnOnInvestment_, investmentCapital_] :=
returnOnInvestment*investmentCapital - overheadExpenses;
distributionPlot[data_List,
opts : OptionsPattern[{Histogram, SmoothHistogram}]] :=
With[{\[Mu] = Mean@data, \[Sigma] = StandardDeviation@data},
Show[
Histogram[data, 30, "PDF",
Sequence @@ FilterRules[{opts}, Options[Histogram]],
Frame -> {{False, False}, {True, False}}],
SmoothHistogram[data,
Sequence @@ FilterRules[{opts}, Options[SmoothHistogram]]]
]];
returnPeriodTables[hypoTestData_List, valueHeading_String] :=
TableForm[
Transpose@{Function[{rp},
AccountingForm[InverseCDF[#["FittedDistribution"], 1/rp](*,
DigitBlock\[Rule]{3,2}*)]] /@ rtnPeriods, rtnPeriods},
TableHeadings -> {None, {valueHeading, "Return Period"}}] & /@
hypoTestData;
variableRow[name_String,
distributionName_String, \[Mu]Variable_, \[Mu]VariableRange_, \[Sigma]Variable_, \[Sigma]VariableRange_] :=
{name, distributionName,
Column[{\[Mu]Variable,
Slider[\[Mu]Variable, \[Mu]VariableRange, Appearance -> Tiny,
ImageSize -> Tiny]}, Alignment -> {Center, Center}],
Column[{\[Sigma]Variable,
Slider[\[Sigma]Variable, \[Sigma]VariableRange,
Appearance -> Tiny, ImageSize -> Tiny]},
Alignment -> {Center, Center}]};
),
UnsavedVariables :> {update},
SaveDefinitions -> True
]
[1]: http://mathematica.stackexchange.com/questions/32294/using-refresh-to-skip-expensive-computations
[2]: http://mathematica.stackexchange.com/questions/30079/what-is-the-right-way-to-construct-dynamicmodule