3
$\begingroup$

I am doing a number of calculations and I wish to add the results to a list. I would then like to select some of the results using check boxes and plot those results together. The length of the list of results will change as more results are added. I can't see how to link the Checkbox to showing the results. Here is a minimum working example.

The first module gives a name to the results. The second module assembles the results and adds a Checkbox. Here is where I can't think of a way of connecting the checkbox to show or not show the result. Finally there is a button to clear the list of results.

ClearAll[saveFittedResults];
saveFittedResults[] := DynamicModule[{name},
   Row[{"Output Name? ",
     InputField[
      Dynamic[name, (name = #; 
         AppendTo[allResults, {name, RandomReal[{0, 1}, 2]}]; 
         numOfResults = numOfResults + 1) &]],
     Dynamic[name]}]
   ];
ClearAll[assembleResults];
assembleResults[] := DynamicModule[{a},
   Column[{
     Dynamic@
      Column[Table[{Checkbox[Dynamic[]], allResults[[n, 1]]}, {n, 
         Length[allResults]}]],
     Dynamic@
      ListPlot[allResults[[All, 2]][[selectedResults]], 
       PlotRange -> {{0, 1}, {0, 1}}, Frame -> True, 
       PlotStyle -> {Red}]
     }]
   ];
ClearAll[delButton];
delButton[] := Row[{Button["Delete all results",
    ClearAll[allResults, numOfResults, selectedResults];
    allResults = {};
    selectedResults = {};
    numOfResults = 0],
   "   Number of results = ", Dynamic[numOfResults]}]

If the modules are executed then we get

delButton[]
saveFittedResults[]
assembleResults[]

Mathematica graphics

Here I have added 5 tests

Mathematica graphics

If I type

selectedResults = {1, 2, 4}

data appears in the plot so that part of the code is working. How do I do the really difficult bit of connecting each Checkbox to put a value in selectedResults? or is there a better way of doing this?

Thanks

$\endgroup$
5
$\begingroup$

The key point is to make the things you want to change dynamically, really Dynamic. I will give a small example that shows how to do this. Together with my example, I will show a different approach that tries to separate functionality as much as possible from the view. In computer science, this is often called Model View Controller pattern and we will use something similar.

Let's assume you have a small controller that handles your data and the functionality. I want something, that can run a small simulation by picking 3 numbers randomly. Each simulation is stored and the controller c lets us:

  • run a simulation by c["Simulate"]
  • get the number of simulations by c["GetCount"]
  • get the functions for each simulation by c["GetFuncs"] which is nothing more than putting the parameters into a small sinus sum

This can be written down by

createGUI[] := DynamicModule[{c, count = 0, params = {}},

   c["Simulate"] := (AppendTo[params, RandomReal[1, 3]]; ++count);
   c["GetCount"] := count;
   c["GetFuncs", selector_] := 
    Function[x, 
     Table[Sum[v[[i]]*Sin[i x], {i, Length[v]}], {v, 
       params[[selector]]}]];

   c["Simulate"];
   createView[c]
   ];

In the last two lines, we first run one simulation (to have at least one set of parameters) and then create a view for our controller. The good part is that we have used no code to display something at all. We just focused on the functionality. In return, this means that our view won't have to contain any functionality and we can focus on the display only.

This makes the following createView extremely easy to understand as it will send all the work of to the controller:

createView[c_] := DynamicModule[{count = c["GetCount"], chk = {1}},
  Panel[Column[{
     Button["Add Simulation", count = c["Simulate"]],
     Dynamic[CheckboxBar[Dynamic[chk], Range[count]]],
     Dynamic[Plot[Evaluate[c["GetFuncs", chk][x]], {x, 0, 2 Pi}]]
     }]
   ]
  ]

That's it. If you now start the GUI, you can run simulations and select which of them you want to display:

createGUI[]

Mathematica graphics

To answer your question explicitly: I used a CheckboxBar that itself is wrapped inside a Dynamic. Everytime our simulation count changes, it adds a checkbox.

$\endgroup$
2
$\begingroup$

Here is a solution with my versatile Checkbox named "myCheckbox" :

First define it :

 (* myCheckbox add or remove "elt" to/from the list "choice" *)
    SetAttributes[myCheckbox, HoldFirst];
    myCheckbox[choice_, elt_] := 
     Checkbox[Dynamic[MemberQ[choice, elt], 
       If[#, AppendTo[choice, elt], choice = DeleteCases[choice, elt]] &]]

Then simply replace in your code Checkbox[Dynamic[]] by myCheckbox[selectedResults,n]

ClearAll[saveFittedResults];
saveFittedResults[] := DynamicModule[{name},
   Row[{"Output Name? ",
     InputField[
      Dynamic[name, (name = #; 
         AppendTo[allResults, {name, RandomReal[{0, 1}, 2]}]; 
         numOfResults = numOfResults + 1) &]],
     Dynamic[name]}]
   ];
ClearAll[assembleResults];
assembleResults[] := DynamicModule[{a},
   Column[{
     Dynamic@
      Column[Table[{myCheckbox[selectedResults,n], allResults[[n, 1]]}, {n, 
         Length[allResults]}]],
     Dynamic@
      ListPlot[allResults[[All, 2]][[selectedResults]], 
       PlotRange -> {{0, 1}, {0, 1}}, Frame -> True, 
       PlotStyle -> {Red}]
     }]
   ];
ClearAll[delButton];
delButton[] := Row[{Button["Delete all results",
    ClearAll[allResults, numOfResults, selectedResults];
    allResults = {};
    selectedResults = {};
    numOfResults = 0],
   "   Number of results = ", Dynamic[numOfResults]}]  

"versatile" because I often use it including on MSE. (look for "myCheckbox")

$\endgroup$

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.