1
$\begingroup$

I am trying to use Dataset to contain and label lists of data points. Eventually, I'll throw the lowest level of the Dataset onto a series of ListPlots. However, I'm having a hard time adding points to the dataset in the way I want. I'm brand new to Associations and Datasets, so please let me know if there are other dumb things I'm doing!

days = {2, 3, 4, 5};
weeks = {28, 30, 32, 34, 35};

(*Lowest levels in this dataset should be empty lists, which I would like to fill up with {a,b} points to prepare for plotting*)
divisions = 
 Dataset[<|
   "GA<35 weeks" -> <|
     "No Risk Factors" -> 
      AssociationThread[weeks, Table[{}, Length[weeks]]],
     "Risk Factors" -> 
      AssociationThread[weeks, Table[{}, Length[weeks]]]|>,
   "GA>=35 weeks" -> <|
     "Low" -> AssociationThread[days, Table[{}, Length[days]]],
     "Med" -> AssociationThread[days, Table[{}, Length[days]]],
     "High" -> AssociationThread[days, Table[{}, Length[days]]]|>|>]

(*I can get to the bottom list just fine*)
divisions[["GA>=35 weeks", "Low", 3]]
(*But trying to add anything gives me an error*)
AppendTo[divisions[["GA>=35 weeks", "Low", 3]],{1,2}];

I get the error: Set::partd: Part specification biliDxDivisions[[GA>=35 weeks,Low,3]] is longer than depth of object.

Help appreciated! Thank you!

Update: making divisions just an Association instead of a DataSet allows me to AppendTo the way I want. Still curious why DataSet is different - is it more used for formatting tables?

$\endgroup$
1
  • 1
    $\begingroup$ I came up with divisions = MapAt[Append[{1, 2}], divisions, {"GA>=35 weeks", "Low", Key[3]}]. Probably someone will come along with the proper way. $\endgroup$
    – Michael E2
    Aug 17, 2022 at 19:59

1 Answer 1

1
$\begingroup$

There are probably several ways to do this. Most directly, you could just use Map:

Map["new value" &, divisions, {3}]

I'm guessing that's not very helpful, because I'm assuming that the lowest elements are associated to their keypath somehow. So, instead you might do

MapIndexed[valueFunction, divisions, {3}]

and you can define valueFunction to use the keys that will get passed as the second argument to determine what value to insert.

Side note... both of the above produce a new dataset, they don't mutate divisions.

A question I have is why do you want to insert the data after creating the dataset rather than have a function that builds the dataset with data you give it?

makeDivisions[weeks_, days_, {noRisk_List, risk_List, low_List, medium_List, high_List}] :=
  Dataset[<|
    "GA<35 weeks" -> 
      <|
        "No Risk Factors" -> AssociationThread[weeks, noRisk], 
        "Risk Factors" -> AssociationThread[weeks, risk]|>, 
    "GA>=35 weeks" -> 
      <|
        "Low" -> AssociationThread[days, low], 
        "Med" -> AssociationThread[days, medium], 
        "High" -> AssociationThread[days, high]|>|>]

The association structure could even be saved as a TemplateObject with TemplateSlots for the data cells. Then makeDivisions could use TemplateApply. I couldn't get it to work trying to make an actual Dataset as a TemplateObject, but Association works as a TemplateObject, so makeDivisions would just need to wrap the result of TemplateApply in Dataset. Of course, you'll need something a bit more sophisticated if the structure of the dataset itself can vary.

Edit

I realized later that you were focused on appending things to lists that appeared at the lowest level. I don't think that materially changes my suggestions. The function you pass to MapIndexed, for example, could do append work. And the makeDivisions could have an argument representing the current values.

Also, you can always use Normal to "unwrap" the dataset into an association and then re-wrap it after mutating.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.