supergroup
Version:
Nested groups on arrays of objects where groups are Strings that know what you want them to know about themselves and their relatives.
153 lines (137 loc) • 7.75 kB
HTML
<html>
<head>
<meta charset="utf-8">
<base data-ice="baseUrl" href="../">
<title data-ice="title">Overview</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
<script src="script/prettify/prettify.js"></script>
<script src="script/manual.js"></script>
</head>
<body class="layout-container manual-root" data-ice="rootContainer">
<header>
<a href="./">Home</a>
<a href="./manual/index.html" data-ice="manualHeaderLink">Manual</a>
<a href="identifiers.html">Reference</a>
<a href="source.html">Source</a>
<a data-ice="repoURL" href="https://github.com/Sigfried/supergroup.git" class="repo-url-github">Repository</a>
<div class="search-box">
<span>
<img src="./image/search.png">
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
</span>
<ul class="search-result"></ul>
</div>
</header>
<nav class="navigation" data-ice="nav"><div class="manual-toc-root">
<div data-ice="manual" data-toc-name="overview">
<h1 class="manual-toc-title"><a href="manual/overview.html" data-ice="title">Overview</a></h1>
<ul class="manual-toc">
<li data-ice="manualNav" class="indent-h1"><span class="manual-dot"></span><a href="manual/overview.html#supergroup-js" data-ice="link">Supergroup.js</a></li>
</ul>
</div>
<div data-ice="manual" data-toc-name="reference">
<h1 class="manual-toc-title"><a href="identifiers.html" data-ice="title">Reference</a></h1>
<ul class="manual-toc">
<li data-ice="manualNav" class="indent-h1"><span class="manual-dot"></span><a href="identifiers.html#class" data-ice="link">Class</a></li>
</ul>
</div>
</div>
</nav>
<div class="content" data-ice="content"><div class="github-markdown">
<div class="manual-breadcrumb-list">
<a href="./manual/./index.html">Manual</a>
<span>»</span>
<span data-ice="title">Overview</span>
</div>
<div data-ice="content"><h1 id="supergroup-js">Supergroup.js</h1>
<p>Supergroup brings extreme convenience and understandability to the manipulation of
Javascript data collections, especially in the context of D3.js visualization
programming.</p>
<p>As if in submission to the great programmers commandment--<em>Don't
Repeat Yourself</em>--every time I find myself writing a piece of code
that solves basically the same problem I've solved a dozen times
before, a little piece of my soul dies.</p>
<p>Utilities for grouping record collections into maps or nests abound:
<a href="https://github.com/mbostock/d3/wiki/Arrays#-nest">d3.nest</a>,
<a href="https://github.com/mbostock/d3/wiki/Arrays#associative-arrays">d3.map</a>,
<a href="http://underscorejs.org/#groupBy">Underscore.groupBy</a>,
<a href="https://github.com/iros/underscore.nest">Underscore.Nest</a>, to name
a few. But after these tools relieve us of a certain amount of
repetitive stress, we're often left with a tangle of hairy details
that fill us with a dreadful sense of deja vu. Supergroup may seem
like the kind of tacky wonder gadget you'd find on a late-night
Ronco ad, but, for the low, low price of free, it makes data-centric
Javascript programming fun again. <strong>And</strong>, when you find yourself
in a D3.js callback routine holding a datum object that might have
come from anywhere--for instance, with a tooltip callback used on
disparate object types--everything you want to know about your
object and its associated metadata and records is right there at
your fingertips.</p>
<p>Just to be clear about the problem—you start with tabular data from a CSV
file, a SQL query, or some AJAX call:</p>
<p><div><div class="label">Some very fake hospital data in a CSV file...</div>
<pre class="rendercode language-javascript" id="csv"><code>
tabulate(d3.select('pre#csv'), data, ['Patient','Patient Age','PatientVisit','Date','Time','Unit','Physician','Charge','Copay','Insurance','Inpatient']); // # run
</code></pre></div>
</p>
<p><div><div class="label">...turned into canonical array of Objects (using d3.csv, for instance)</div>
<pre class="rendercode language-javascript" height="150px"><code>
data; // # render result.replace(/{/g,'\n {').replace(/]/,'\n]');
</code></pre></div>
</p>
<p>Without Supergroup, you'd group the records on the values of one or more fields
with a standard grouping function, giving you data like:</p>
<p><pre class="rendercode language-javascript" id="nestmap" height="150px"><code>
d3.nest().key(function(d) { return d.Physician; })
.key(function(d) { return d.Unit; })
.map(data); // # show render indent2
</code></pre>
</p>
<p>or</p>
<p><pre class="rendercode language-javascript" id="nestentries" height="150px"><code>
d3.nest().key(function(d) { return d.Physician; })
.key(function(d) { return d.Unit; })
.entries(data); // # show render indent2 result.replace(/,\n/g, ", ").replace(/("key".<em>, )/g,"$1\n").replace(/, </em>/g, ", ")
</code></pre>
</p>
<p>To my mind, these are awkward data structures (not to mention the awkwardness
of the calling functions.) The <code>map</code> version looks ok in the console, but
D3 wants data in arrays, not as objects. The <code>entries</code> version gives us
arrays of key/value pairs, but on upper levels <code>values</code> is another array of
key/value pairs while on the bottom level <code>values</code> is an array of records. In
both <code>entries</code> and <code>map</code>, you can't tell from a node at any level what
dimension was being grouped at that level. </p>
<p>Supergroup gives you almost everything you'd want for every item in your nest
(or in your single array if you have a one-level grouping):</p>
<ul>
<li>An array of the values grouped on (could be strings, numbers, or dates) (<a href="#basics:aplainarrayofstringsenhancedwithchildrenandrecords">Basics</a>)</li>
<li>The records associated with each group</li>
<li>Parents of nested groups (<a href="#dimensionnamesandpaths">Dimension Names and Paths</a>)</li>
<li>Immediate child groups if any</li>
<li>All descendant groups (<a href="#retrievingsetsofvalues">Retrieving sets of values</a>)</li>
<li>Only descendant groups at the leaf level</li>
<li>For a group at any level, the name of the dimension (attribute, column, property, etc.) grouped on</li>
<li>Path of group names from root to current group</li>
<li>Path of group dimension names from root to current group</li>
<li>Aggregate calculations on records for that group and its descendants (<a href="#aggregates">Aggregates</a>)</li>
<li>Ability to look up specific values (<a href="#findingspecificvalues">Finding specific values</a>)</li>
<li>Any of these in a format D3 or some other tool expects (<a href="#usingsupergroupford3hierarchylayouts">Using Supergroup for D3 hierarchy layouts</a>)</li>
<li>Ability to include records in multiple groups if appropriate (<a href="#multi-valuedgroups">Multi-valued Groups</a>)</li>
</ul>
</div>
</div>
</div>
<footer class="footer">
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(0.4.3)</span></a>
</footer>
<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>