1
$\begingroup$

I have a dataset or records, I want to select records with a GUI (manually ticking on the selected item). Then, I want to apply functions to those items (not in this question).

I think Im almost there, but missing final step for DynamicModule.

Can you please show what is missing in these two examples?

The Dataset is called db, with Keys "name", "id". :

db = Dataset[Map[<|"name" -> 10 + #, "id" -> 20 + #, "T2" -> 30 + #|> &, Range[4]]]

1

I want to select with Checkbox

createViewDb[] := DynamicModule[{x = False, chosenRecords = {}},
  (*original db is expanded with a column of Checkboxes, initialised to False * )

  dbx = db[All, <|"selected" -> Checkbox[x], #|> &];

  (* chosenRecords is a filter of records where Checkbox == True - selected *) 
  chosenRecords = Select[dbx, #["selected"] == True &];

  Column[{dbx, Dynamic[chosenRecords]}]
  ]

enter image description here

Results: I tick my checkboxes, but no chosen records is returned.

2

I want to select with TogglerBar:

(* query column names by "name" first*)
dbColumnNames = Query[All, "name"]@db // Normal;

(* now create a toggle bar *) 
TogglerBar[Dynamic[chosenRecords], dbColumnNames, 
 Appearance -> "Vertical"]

(* if I evaluate selected, it will return chosen records *)

(* though, dynamic module show an empty db *)
(* here I query the db against the selected items: *)
(* by checking if each db's row with key "name" is a Member in the selected list chosenRecords *)
DynamicModule[{chosenRecords}, Select[db, MemberQ[chosenRecords, #["name"]] &]]

Results: I toggle my column names, but no chosen records is returned.

Could you help showing what is missing in the two example above?

Question is about filtering in DynamicModule, as a bonus could you comment about applying a function to chosen records, after selection:

should the function be within DyamicModule, or could I call it after DynamicModule with something like:

myGUI = DynamicModule[... (*do something and return chosenRecords as result *)
f/@Evaluate[chosenRecords]  ?

Edited

I also tried this approach (welcome suggestions to simplify: how to apply ListPicker to a Dataset in a smooth way that does not need to convert first to a list? ):

While the approach without Dynamics works,

{ListPicker[Dynamic[x], Query[All, "title"]@Normal@db], 
Dynamic[x]] &]}

(* now evaluate *)
Select[db, MemberQ[x, #["title"]] &]

however, Dynamic[x] in Select does not work.

{ListPicker[Dynamic[x], Query[All, "title"]@Normal@db], 
 Select[db, MemberQ[Dynamic[x], #["title"]] &]}
$\endgroup$
  • 2
    $\begingroup$ Don't have time to answer now but please read mathematica.stackexchange.com/questions/5817/… which addresses some of your concerns. Additionaly, could you describe the flow a little bit more? Is the gui meant to be anpart of a single evaluation sequence, like DialogInput or other kernel blocking dialogs? Or should it stay around and be used to interactively change some global variable which contains your db subset which can be used later in manual calculations. Or do you plan to have all operations within a single gui where user can filter db, process it etc? $\endgroup$ – Kuba Dec 26 '18 at 8:44
  • $\begingroup$ Thank you @Kuba - I plan to have all operations within a single gui, but I see dynamic can be quite heavy for performance with complex objects. Thank you for suggesting the links, they gave some more clarity on Dynamic - still not clear how to make best use to it, but gave a direction :) $\endgroup$ – user305883 Dec 28 '18 at 11:39
  • $\begingroup$ @andre314 sorry Andre, you are right I only focused on the Dynamic part without a mockup sample of db. as an example on the answer of @Emerson I have something initialised like this: db = Map[<|"selected" -> False, "id" -> #, "T1" -> #, "T2" -> # + 1|> &, Range[40]]; $\endgroup$ – user305883 Dec 28 '18 at 11:43
2
$\begingroup$

Try this.

data = Map[<|"id" -> #, "T1" -> #, "T2" -> # + 1|> &, Range[40]];

createViewDb[Dynamic@output_, Dynamic@selected_,Dynamic@data_] := 
(selected = Table[True, {i, 1, Length@data}];
DynamicWrapper[
Dataset[Query[All, 
   KeySort@<|#, "" -> Checkbox[Dynamic@selected[[#id]]]|> &]@
  data], output = Query[Select[TrueQ@selected[[#id]] &]]@data]);

Column[{createViewDb[Dynamic@output, Dynamic@selected, Dynamic@data], 
Dynamic@selected, Dynamic@Dataset@output}]

Note the annoying behaviour of Dynamic@Dataset@output when displaying the output. This is why I avoided putting Dynamic around Dataset in createViewDb.

enter image description here

$\endgroup$
1
$\begingroup$

The following solution uses a state variable named collection which is a list of the positions of all the checked checkbox :

collection = {};
Dynamic[collection]  

Dataset @ 
 MapIndexed[
  Association["choice" -> TogglerBar[Dynamic[collection], {#2 -> 0}] , #1] &, 
  data]  

Dynamic @ Dataset @ Delete[data, collection]  

enter image description here

Some variants

This solution is visually better, but it uses the undocumented function BoxForm`TogglerBarFunction :

data = Map[<|"T0" -> 10 + #, "T1" -> 20 + #, "T2" -> 30 + #|> &, 
   Range[4]];

collection = {};
Dynamic[collection]
Dataset @ 
 MapIndexed[
  With[{indexation = #2}, 
    Association[
     "choice" -> 
      Checkbox[
       Dynamic[MemberQ[collection, #2], 
        BoxForm`TogglerBarFunction[collection, 
          indexation] &]] , #1]] &, data]
Dynamic @ Dataset @ Delete[data, collection]

enter image description here

This solution is a generalisation for multi-level and multiform nested structures (multiform means nested Associations, Lists, others things) :

 data = Map[<|"T0" -> 10 + #, "T1" -> 20 + #,"T2" -> 30 + #|> &, 
   Range[4]];

(*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]] &]]

myAddCheckbox[elt_, indexation_: {_Integer ..}] := Switch[
  Head[elt],
  Association,
  Association["choice" -> myCheckbox[collection, indexation], elt],
  List,
  Prepend[myCheckbox[collection, indexation], elt],
  _,
  {myCheckbox[collection, indexation], elt}]

collection = {};
Dynamic[collection]
Dataset[data][MapIndexed[myAddCheckbox, #, {1, 2}] &]
Dynamic @ Dataset @ Delete[data, collection] 

enter image description here

$\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.