bbClear

a Presentation Framework
for Health Records

bbClear is an open-source framework for rendering more usable health records. It enables developers of electronic health record systems to output a printed health record that is more helpful for patients, their families, and caregivers.

Quickstart

If you have CCDA or VA-C32 XML patient data ready to go, you can create a visually-appealing and patient-understandable bbClear document quickly and easily:

  1. Download the blank bbClear template.
  2. Search the document for the data placeholder: <!-- Inject XML Data Here -->
  3. Replace this placeholder with your patient data in its entirety.

That's it! Now, by viewing that file in a browser, patients will be able to see their health data, just like this sample. This can be served remotely or stored locally. If you're interested in other options for changing the appearance of the document, read on to learn how to create themes for it.

Overview

bbClear was created as a result of a community-driven effort that stemmed from the Health Design Challenge. The Department of Veterans Affairs and California HealthCare Foundation contributed engineering resources to the development of the framework.

  • Patient Record in CCD/XML format
  • bluebutton.js conversion library
  • Assorted JS libraries like jQuery
  • Functional logic using JavaScript
  • Styles using CSS and/or SASS
  • Markup template using swig.js
  • The contents of a bbClear health record HTML file

bbClear produces a patient-consumable version of a health record in the form of a monolithic HTML file, including inline scripts, styles, and a simple but powerful templating framework. By including the content of industry-standard XML documents like the CCD in the source of the HTML document, you can structure and style the record data more easily than ever.

While you can include almost any front-end web technology in a bbClear document, there are some core components in play:

In addition to these, the default bbClear theme includes familiar libraries like Modernizr and jQuery.

  • The Build Tool — This is a relatively simple Python script that collects the assets for use in the final document, processes them, and compiles them into the monolithic HTML file.
  • BlueButton.js — a library developed by Tom Black and the bbClear team, which ingests health record documents (especially CCD) and produces a friendly Javascript API.
  • bbclear.js — This script initializes a bbClear theme, configuring the templating system, as well as providing several useful filters and tools for working with data.

bbClear is Apache licensed, which provides very broad permission to take, adapt, and modify bbClear to your own needs. We'd love to see the community make bbClear even better.

Build Tool & Themes

Usage

The bbClear build tool is a Python script that collects assets and templates from themes and assembles them into the final, self-contained BlueButton HTML file. Typically, you use it from the command line:

$ python build.py [-h | --help] [-v | --verbose] [-w | --watch] [-t | --theme THEME]

Where the options are as follows:

-h | --help
Displays syntax help, describing these options.
-v | --verbose
Displays extra output, useful for debugging or more information.
-f | --force
Forces a build, even if no asset files have changed since the last build.
-w | --watch
Watch. Continues running the build tool, watches for file changes to assets (scripts, styles, or the template), and rebuilds when one is found. Cannot be used at the same time as --force.
-d | --data [DATA_FILE]
Specifies the file to use when data is injected, found in the same folder as build.py. Defaults to data.xml. Note that data files are optional -- if one is not found, the build tool will insert a placeholder into the final document.
-t | --theme [THEME]
Builds a particular theme, where [THEME] is a directory under themes/. Defaults to official.

Notes

The bbClear build tool currently expects a few things:

  • It looks for a file in the same directory called data.xml to embed into the final document. If this file does not exist, it creates a placeholder for injecting XML data later.
  • It looks for a themes/ directory in the same directory as the build script. Inside, it expects to find one directory for each theme.
  • Within theme directories, it expects to find a js directory with scripts to include, a stylesheets directory with CSS to include, and a template.html file.

In the future, more of these options will be configurable.

Templates

The bbClear templating system uses swig.js as its foundation, providing a Django-like syntax that is easy for anyone familiar with HTML to work with. bbClear supports all of swig's template tags and filters, so it's recommended that you take a look through the swig documentation.

In addition, bbclear.js provides additional functionality for use in your templates.

Basics of outputting data

See also: swig basics documentation.

Objects from BlueButton.js

The bbClear templating system provides several objects via Bluebutton.js for access. Refer to that module's documentation for more information about data inside these objects:

  • demographics — Information about the patient.
  • allergies — This patient's allergies.
  • encounters — This patient's known medical encounters.
  • immunizations — This patient's known immunization record.
  • labs — Laboratory results grouped by lab panel.
  • medications — This patient's known medications, both prescription and OTC.
  • problems — This patient's current and past diagnoses.
  • procedures — Medical procedures (ie. surgeries) performed on this patient.
  • vitals — Vital signs readings for this patient.

Variables

To display a variable in a template, use double-braces:

{{demographics.name.last}}

If a variable is not defined, an empty string will be output.

Logic Tags

swig and bbClear provide several tags that perform logic at the template level. These are enclosed in curly-percents:

{% if demographics.name.last %}
    {{demographics.name.last}}
{% endif %}

See the documentation for other logic tags at your disposal.

Looping through Data

Much of the data coming from BlueButton.js comes in the form of arrays. You can use swig's for tag to loop through any lists necessary:

{% for allergy in allergies %}
    {% if loop.first %}<ul>{% endif %}
    <li>{{allergy.severity}}: {{allergy.allergen.name}}</li>
    {% if forloop.last %}</ul>{% endif %}
{% endfor %}

In the above example, allergy is the variable name for each item in the allergies array.

Template Tags

See also: swig template tag documentation.

insert

The insert tag is used to pull in assets, like data, scripts, and stylesheets. It can be used three ways:

  • {% insert scripts %} — pulls in scripts from the themes/[theme]/js/ directory, minifies them, and inserts them into the final document in alphabetical order.
  • {% insert styles %} — pulls in CSS stylesheets from the themes/[theme]/stylesheets/ directory, minifies them, and inserts them into the final document in alphabetical order.
  • {% insert data %} — looks for data.xml in the bbClear root directory. If found, it's inserted in place of the tag. If not, a placeholder is created for later insertion.

Template Filters

See also: swig template filter documentation.

Template filters may be applied to variables or to tags themselves

display_name

Takes a name object (eg: from demographics) and outputs a reasonable first name. If a preferred name is specified, this is returned. Otherwise, the first of the patient's given names is returned.

format_phone

Takes a phone number (eg: demographics.phone.home) and returns a predictably-formatted North American phone number in the XXX.YYY.ZZZZ format.

format_unit

Takes a unit from lab results and reformats scientific notation from 10+3 to 103.

full_name

Takes a name object (eg: from demographics) and outputs the person's full name, including prefixes, suffixes, given and family names.

gender_pronoun(possessive, absolute)

Given a gender value (eg: from demographics), returns an appropriate pronoun. Takes up to two parameters:

  • possessive — returns "his," "hers," or "her."
  • absolute — (only if posessive) returns "her" instead of "hers".

eg: {{demographics.gender|gender_pronoun(true, true)}} returns "his" or "her".

group(key)

Modeled after Django's regroup tag, this filter groups items in a list based on a common property. Returning a list of groups, which contains a list of objects in that group. It requires one argument:

  • key — the common property that should be used to group items.

The resulting object contains a list of group objects. Each group item has a grouper property, which contains the value of the key shared by each of this group's items, and list, which contains a list of the items sharing that property value.

For example, this snippet would group immunizations by the name of the immunization (represented by each record's product.name):

{% for group in immunizations|group('product.name') %}
    {% if loop.first %}<ul>{% endif %}
    <li>
        <h2>{{group.grouper}}</h2>
        {% for item in group.list %}
            {% if loop.first %}<ul class="pills">{% endif %}
            <li>{{item.date|date('M j, Y')}}</li>
            {% if loop.last %}</ul>{% endif %}
        {% endfor %}
    </li>
    {% if loop.last %}</ul>{% endif %}
{% else %}
    <p>No known immunizations</p>
{% endfor %}

intersects(comparand)

Given two arrays, this filter returns values found in both.

eg: {{ list1|intersects(list2) }}

max_severity

Given a list of allergies, this tag returns the maximum severity found. Possible returned values:

  • "severe" or "multiple severe"
  • "moderate" or "multiple moderate"
  • "mild" or "multiple mild"
  • "no"

Only the highest of these groups will be returned. So a patient with one severe allergy and two moderate allergies will return "severe".

related_by_date(kind)

Given an object with either a date or date_range attribute, this filter finds other objects of of type kind that share the same dates.

This filter currently supports encounters, procedures, problems, immunizations, medications, and labs for the value of kind.

slice(start, end)

Provides an interface to Javascript's slice function, returning a subset of the filtered list. Takes two arguments:

  • start — An integer, the index of the first item that should be returned. The first item has an index of 0.
  • end — Optional, an integer, the index where the selection should end.

Contributing

This is just the beginning — there's far more to do, and we can use all the help we can get. If you're interested, here are a few places to start:

  • Report Bugs — Find something amiss? Please let us know by logging an issue over at GitHub.
  • Submit Patches — If you have an interesting enhancement to offer, we're happy to review pull requests via GitHub as well.
  • Build Themes — We created a very simple theme to start with, but we encourage you to take things much further. If you'd like to offer your theme to the public, consider submitting it as a pull request for inclusion in the codebase.
  • Make Suggestions — There's plenty more to do already, but if you have a terrific idea, don't hold back. Submit your enhancement ideas as issues on GitHub and we'll see what we can do.