Public
Edited
Oct 22, 2022
Insert cell
Insert cell
Insert cell
Insert cell
data = FileAttachment("PetSupplies.json").json()
Insert cell
Insert cell
nodeSize = 20
Insert cell
mutable cachedColumnData = null
Insert cell
columns = [
// {// item's raw prop
// label: "Age",
// // data: root.copy().descendants(),
// value: d => d.data.age,
// format: (value, d) => value ? format(value) : "",
// x: 450,
// // fill: colors['byTotalSize']
// },
// {//aggregated using postFn for each group (having children)
// label: "Score",
// data: diplayingTree=>subtotalForNodes(diplayingTree, d=>d.value),
// value: d=>d.value,
// format: (value, d) => value ? format(value) : "",
// x: 550,
// // fillBy:d=>d.data.len,//after hireachy summmed up
// // fill: colors['byTagSize']
// },
{//aggregated using postFn for each group (having children)
label: "Size",
data: diplayingTree=>cachedColumnData?cachedColumnData:(mutable cachedColumnData = subtotalForNodes(diplayingTree, d=>d.value)),
value: d=>d.value,
format: (value, d) => value ? format(value) : "",
x: 550,
},
{//count for groups. identifyDescendants() is important
label: "Count",
data: diplayingTree=>identifyDescendants(root.copy()).count().descendants(),
format: (value, d) => value>1 ? format(value) : "",
x: 640,
}
]
Insert cell
Insert cell
Insert cell
/*
for large trees, use this function to determin if a node should be collapsed when first-time loading.
@returns true|false
*/
defaultCollapsed = node => node.depth>1 || node.id>3 || node.data.name =='animate'
Insert cell
function initDescendantDefaultCollapseState(d){
// console.log('ddc',d)
if(d.children){
d.collapsed = defaultCollapsed(d);
d._children = d.children;
if (!!d.collapsed) d.children = null;
// console.log('initCollapse',d.data.name)
}
return d;
}
Insert cell
/*
* This is for descendant mapping between 'root' and UI tree root (copy of root with 'collapsed' prop)
* @param postFn additional operation to perform for each tree descendant
*/
function identifyDescendants(r,...postFns){
r.descendants().forEach((d,i) => {
d.id = i++;
if(postFns && postFns.length){
for(const j in postFns){
const fn = postFns[j]
fn.call(r,d)
}
}
})
return r;//make it chainable
}
Insert cell
//hook for looping through root's descendants
postIdentifyFns=[initDescendantDefaultCollapseState]
Insert cell
//put index to each tree node using eachBefore
function indexEachBefore(r){
let i=0;
r.eachBefore(n => {
n.index = i++;
})
return r
}
Insert cell
function subtotalForNodes(displayingTree, sumFn=d=>d.value){
// const ids = displayingTree.descendants().map(d=>d.id)||[]
let rcopy = root.copy()
let ds = identifyDescendants(rcopy).sum(sumFn).descendants();
// ds = ds.filter(d=>ids.indexOf(d.id)>-1)
// ds = ds.sort(sortByIndex).slice(0,ids.length)
// console.log('ids',ids)
return ds
}
Insert cell
Insert cell
Insert cell
//import {DescribeObject} from "@tsenyi/json-object-statistics"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more