This repository is a self-contained module library for Tidepool's timeline-style diabetes data visualization(s).
This module is currently under construction; check back often for updates!
More information is also available in the wiki.
Dependencies and Installation
Fonts: Tideline should be used with the Open Sans font.
Development-only dependencies: See the
Install for use in your own web application using:
$ npm install --save tideline
You can use the library directly with Webpack:
var tideline = require('tideline'); // load styles require('tideline/css/tideline.less');
For information on building charts using tideline components, see Using Tideline.
To run the tests you will need to have a couple of tools installed. Everything you need can be installed via
$ npm install
$ npm test
To run the unit tests in watch, use:
$ npm run test-watch
Run JSHint with:
$ npm run lint
You can also watch files for changes and re-run automatically by starting:
$ npm run lint-watch
Code Philosophy and Organization
The main functionality tideline provides is modules for building out various visualizations of multi-typed data sets aligned on various timescales. At present, there is a module (
oneday.js) for creating a horizontal scrolling timeline that shows twenty-four hours of data at a time, a module (
twoweek.js) for creating a vertical scrolling timeline that shows two weeks of data at a time, and a module (
settings.js) for creating an HTML table view of insulin pump settings.
Jargon: The horizontal sections comprising sub-units of visualization plotted against the same x-axis are referred to in this repository as pools.
Almost all of the main tideline components (found in
js/) hew to at least some (but rarely all) of the suggestions in Mike Bostock's Towards Reusable Charts. The data-type specific plotting functions (found in
js/plot/) hew most closely to the suggested pattern, while the higher-level components (i.e.,
settings.js) do not, as their tasks are not quite the same.
While tideline is quite specific to diabetes at the moment, it is designed to be as flexible and modular as possible. We plan to integrate data types not specific to diabetes (e.g., activity tracker data, calendar events, etc.), and it should be possible to create a visualization of any multi-typed dataset using a combination of the higher-level components and additional plotting modules. We welcome any and all contributions of new plotting modules, as well as contributions to the core library modules.
Tideline uses D3.js to create an SVG data visualization. SVG is an extremely powerful graphics format, and there are often many, many ways to accomplish the same visualization task. For the purposes of the code in this repository, two related points of philosophy should be noted upfront:
- Tideline loves SVG group
- Relatedly, Tideline likes to use the
transformattribute (usually just with a
translate(x,y)definition) for positioning.
Tideline makes every attempt to adhere to standard coding conventions. In development, we use the same
.jshintrc file as tideline's parent application blip.
The only coding conventions unique to tideline are conventions of HTML and CSS ID and class names. All of the SVG elements comprising tideline use
camelCase for IDs, with different parts of the ID separated by an underscore
_. Class names, in contrast, are all lowercase, prefixed with
d3 and employ hyphen
- as a separator. These conventions help tideline developers to keep IDs and classes distinct.
css/contains the Less files that compile to tideline's CSS.
tideline.lessprovides the styles and depends on
tideline-colors.lessfor color variables. This makes it possible to customize tideline's color scheme by defining a different
dev/contains a few tools that are (occasionally) useful for development.
demodata/contains a Python script for generating fake data for testing tideline during development. For usage information, run
python demo_data.py --help.
templates/contains two module templates:
plottemplate.jsfor a plot module and
datautil.jsfor a data utility analogous to those found in
img/contains the images used to plot certain types of data (i.e., notes).
js/contains the tideline library. At the top level,
pool.jsare the main components.
tidelinedata.jsdefines the data object that the other core components expect to be passed.
index.jsexports the entire library, which can be used for creating a standalone tideline bundle with browserify.
data/contains a set of mini-modules for munging and calculating statistics around various types of diabetes data.
util/contains some common utilities that are used mainly in the
format.js(for formatting the output of numerical calculations - that is, rounding and displaying numbers to the proper number of significant digits), and
tidelinecrossfilter.js, which wraps the most common uses of Crossfilter in tideline, are also used outside of
plot/contains mini-modules for plotting various types of data, mostly diabetes-specific. These mini-modules are called by
pool.jswhen rendering data. Most of the data types are self-explanatory (at least to those who have some knowledge of type 1 diabetes), but 'cbg' and 'smbg' may require explanation. 'cbg' stands for Continuous Blood Glucose and refers to the readings generated by a Dexcom or Medtronic continuous glucose sensor. 'smbg' stands for Self-Monitored Blood Glucose and refers to the readings generated by a traditional home fingerstick blood glucose meter.
stats/contains a special mini-module for creating a "stats widget" that updates on the fly as the user navigates along the tideline. This is essentially a special type of pool that is hierarchical itself, containing component "puddles," where the relationship between
stats.jsis roughly equivalent to the relationship between
util/contains a couple of small utility modules:
annotationdefinitions.jsgenerate data annotations.
dailyx.jsis a custom axis generator for the x-axis of the tideline one-day view; more custom axis generators will be added here in the future.
shapes.jsencodes the shapes for tideline's custom tooltips and
tooltip.jsprovides methods for adding a tooltip on hover over a plotted datapoint.
bgboundary.jsprovides a utility for determining the class (very-low, low, target, high, very-high) of a blood glucose value given the user's (or the default) target range.
commonbolus.jsprovides a utility for getting information about boluses, whether these are
bolusevents are embedded inside
drawbolus.jsprovides plotting functions for boluses, whether these are
bolusevents are embedded inside
fill.jsgenerates the background fill for each data pool.
legend.jsdefines legend generators for all the pools that require a legend.
scales.jsgenerates D3 scales for various diabetes data types. The functions in this utility module are at the moment specific to the plotting functions in
plot/, not generally useful.
shapeutil.jsprovides methods for manipulating SVG shapes in various ways; it is required by modules in
validationcontains all the code necessary to perform client-side data validation, including schemas for all datatypes currently rendered by tideline, a small module
validate.jsproviding validation functions, and our custom schema construction and validation tools in
plugins/contains modules that do not properly belong in tideline's core functionality. These fall into two categories: application-specific modules and data(-specific) preprocessing modules.
test/contains the tideline test suite. See Test for instructions on running the test suite.
web/contains the GitHub Pages branch for this repository, which sometimes hosts a gallery for proposed additions or enhancements to the tideline example being developed in
example/. If you would like to add something to this gallery, feel free to submit your modifications to the files in
example/(and elsewhere in tideline, if relevant) and open a pull request against
master(although this is not where your changes will be merged). Please comment in the pull request that your changes are intended as an addition to the gallery. If you are also proposing changes to the tideline library (i.e., outside of
example/), a separate pull request containing those changes alone is appreciated.
js/tidelinedata.js/ makes certain assumptions about the data that is passed to it. These assumptions are verified at runtime via the schema and validation code found in
js/validation/. The most important of the requirements are the following:
- The data are valid JSON - specifically, an array of objects.
- Each object has a key
normalTimewhich is an ISO 8601 representation of the date and time at which the datapoint occurred, formatted as UTC time.
- The data are sorted by
normalTime, in ascending order.
Both one-day and two-week charts also expect a Node.js EventEmitter passed as an argument.
As noted above, tideline loves SVG group
<g> elements. The basic structure of the one-day tideline chart is as follows:
|--<svg id='tidelineSVGOneDayContainer'> | |-<g id='tidelineMain'> | | |-<g id='tidelineXAxis'> | | |-<g id='tidelinePools'> | | | |-<g id='pool[Datatype]'> | | | | |-<g id='pool[Datatype]_fill'> | | | | |-<g id='pool[Datatype]_[datatype]'> | | |-<g id='tidelineLabels'> | | | |-<text id='pool_pool[Datatype]_label'> | | | |-<g id='pool_pool[Datatype]_legend_[datatype]'> | | |-<g id='tidelineYAxes'> | | |-<g id='tidelineScrollNav'> | | |-<g id='tidelineAnnotations'> | | |-<g id='tidelineTooltips'>
And the two-week chart differs only minimally:
|--<svg id='tidelineSVGTwoWeekContainer'> | |-<g id='tidelineMain'> | | |-<g id='tidelinePools'> | | | |-<g id='daysGroup'> | | | | |-<g id='poolBG_[date]'> | | | | | |-<g id='poolBG_[date]_fill'> | | | | | |-<g id='poolBG_[date]_smbg'> | | | |-<g id='poolStats'> | | | | |-<g id='poolStats_stats'> | | |-<g id='tidelineXAxisGroup'> | | |-<g id='tidelineYAxisGroup'> | | |-<g id='tidelineScrollNav'> | | |-<g id='tidelineWeeklyLabels'> | | |-<g id='tidelineTooltips'> | | |-<g id='tidelineAnnotations'>
Because SVG has no concept of a z-index, elements are layered according to the order in which they appear in the SVG XML. One of the reasons tideline makes such liberal use of group elements is to control the layering through the order of the group elements. Thus, the ordering of the groups in the two outlines above is often significant.