Cross-posted: https://community.wolfram.com/groups/-/m/t/1625808
Answer posted on Wolfram Community
I'm creating an interactive UI which allows the user to import data from a spreadsheet, perform calculation and plot the results. The issue I'm having is with MapThread
, which is evaluated at the same time as the DynamicModule
, giving an error message that dimensions of objects are incompatible. I noticed that outputs of dynamically displayed objects such as buttons in this case are retained in the memory and used as initial values every time DynamicModule
is re-evaluated (specifying initial values didn't help), and because dimensions of these objects are different at the point of DynamicModule
re-evaluation further output of ListPlot
is suppressed before any action is taken. I'm struggling to get around this problem. Any help will be greatly appreciated.
DynamicModule[{userSystemWindow = {}},
Dynamic @ Column[{
Row[(*Load Data Button*)
{Button[
"Load Geometry",
userSystemWindow = SystemDialogInput["FileOpen"];
importedData =
If[ToString[userSystemWindow] != "$Canceled",
Flatten[Import[userSystemWindow, "XLSX"], 1] // Rest, {}],
Method -> "Queued"] }],
Spacer[1], Style[
Dynamic@Grid[{(*Calculate Button*)
{Button[
"Calculate",
calculatedList1 = Table[1, {N[Length[importedData] - 1]}];
For[l = 2, l <= Length[importedData], l++,
calculatedList1[[l - 1]] =
Sqrt[(importedData[[l, 1]] -
importedData[[l - 1, 1]])^2 + (importedData[[l, 2]] -
importedData[[l - 1, 2]])^2]];
PrependTo[calculatedList1, 0];
calculatedList2 = Table[1, Length[importedData]];
For[t = 2; calculatedList2[[1]] = 170,
t <= Length[importedData], t++,
calculatedList2[[t]] =
10 + (calculatedList2[[t - 1]] - 10)*
Exp[-N[Pi]*0.345*5*calculatedList1[[t]]/(10*2000)]],
Method -> "Queued", ImageSize -> {75, 27},
ContentPadding -> True,
Enabled -> (If[
ToString[userSystemWindow] === "$Canceled" \[Or]
ToString[userSystemWindow] === "{}", False, True])],
(*Clear Results Button*)
Button[
"Clear Plot", calculatedList2 = {0}]}}]],
Spacer[1],
Dynamic@Grid[{
{"Temperature Units",
PopupMenu[Dynamic[temperatureUnits], {
celsius -> "C",
fahrenheit -> "F"}]}}],
Spacer[1],
(*Graph Plot*)
ListPlot[
If[Dimensions[importedData[[All, 1]]] ===
Dimensions[calculatedList2], temperatureUnits, {}],
Frame -> True, FrameLabel -> {"Distance [m]",
Switch[temperatureUnits,
celsius, "Temperature [C]",
fahrenheit, "Temperature [F]"]},
ImageSize -> 500, Joined -> True]
}, Alignment -> Left],
Initialization :> (
celsius =
MapThread[List, {importedData[[All, 1]], calculatedList2}];
fahrenheit =
MapThread[
List, {importedData[[All, 1]],
QuantityMagnitude@
UnitConvert[QuantityArray[calculatedList2, "DegreesCelsius"],
"DegreesFahrenheit"]}];
),
SynchronousInitialization -> False
]
Edit:
This a description of what the UI should calculate.
At first the UI should display:
- 3 buttons: "Load Data", "Calculate Data" and "Clear Plot" (the last 2 should initially be disabled);
- popup menu which is linked to the graph allowing the user to change the temperature unit of plotted data;
- graph which initially should be blank just showing frames and labels
Button "Load Data" upon mouse-click should open system dialog window, allowing the user to select the excel file with data which upon file selection are imported in the form {{x1, y1}, {x2, y2}, ...}
. In case the user clicks on button "Load Data" but decides to cancel the selection and close the system dialog window the button “Calculate” should remain disabled with a graph being blank.
Button “Calculate” should become enable as soon as data is imported, which upon mouse-click should solve couple of equations using imported data and inputs from InputField
’s (removed from the code posted here) returning result of final equation in the form {z1, z2, …}
.
When the data is ready to be plotted ListPlot
should automatically plot data in the form {{x1, z1}, {x2, z2}, …}
with temperature unit DegreesCelsius
. This is why I need to use MapTherad
to combine the first column from imported data with the calculated data set of z
’s. Then every time the user decides to change the input data or import new data and press the button “Calculate” ListPlot
should update accordingly and plot new set of data by adding the new curve to the old one i.e. {list1, list2, ….} where each list corresponds to mouse-click, so the user can compare different results.
Button “Clear Plot” is there to bring the plot to the blank state. I hope all that makes sense.