ICM Final Project / Databetes Data Visualization

This week, I completed my Intro to Computational Media final project. I created a data visualization of 7729 blood sugar readings from the month of November. The data was all drawn from my Dexcom 7 continuous glucose monitor (CGM).

This was the mock-up I did before starting the process, imagining how it should look. The yellow circle represents in-range readings (80-140 mg/dL). The gray circle shows hypoglycemic (low blood sugar readings of 40-79 mg/dL). The remaining white area shows hyperglycemic readings greater than 140 mg/dL. For the month view, November 1st is at the top of the circle, moving clockwise through days until the 30th.

After generating the month view, I then went ahead and generated individual views for each day in November. This is helpful to see peaks each day around breakfast, lunch and dinner (midnight is at the top of the circle and noon is at the bottom).

 

I imported the data as an XML file exported from the Dexcom software. As a user of this technology, I rather happy with the hardware functionality but quite frustrated by their proprietary software. These devices cost thousands of dollars, yet Dexcom and others like Medtronic consistently underwhelm when it comes to managing the data. First, Dexcom hasn’t even bothered to make software that works on my Apple computer. I installed a Bootcamp partition to run Windows so that I could get this working. The device connects to the computer over a USB cable. I then exported the data and transferred it back to my Mac.

Using Processing, I began by importing the readings. This was more complicated than I expected because the beta version of Processing 2.0 uses different protocols for importing XML. Most of the documentation suggested I use proXML, but this didn’t work. With some help from my professor Dan Shiffman, I got that sorted.

It took a few meetings with ITP residents before I was able to map the data along a circle as I wanted using cosine and sine. The very talented Rune Madsen was particularly helpful. Rune makes beautiful data visualizations for the likes of the NYTimes and others.

I had a total of 7729 total readings for the month of November. The device normally takes a new reading every 5 minutes. But there are times when the communication between the transmitter and the receiver gets blocked and data is lost. There is also a 3 hour setup time when a new needle is inserted. These occasional gaps in the readings had to factored into graphing the data. I calculated the total number of minutes in November (43,200) and then converted each data/time reading into a calculation referencing that minute to the total.

notes from my meeting with Patrick

When I began, I was also hoping to import a .csv file from my other glucose monitor, the OneTouch UltraMini. The readings from this monitor are used to calibrate the CGM because they are supposedly more accurate. The CGM tests blood sugar in interstitial fluid (the fluid between cells) instead of blood like a UltraMini. In the end, I didn’t import this second file because I simply ran out of time. Since this is a different brand of device, it formats the data differently and would have required an additional process to merge the data sets. I will incorporate this into a future version of this project.

I must admit, I was a bit surprised by the visualization after I finally got it working. The total number of big fluctuations in blood sugar surprised me. My diabetes control is good and falls within the suggestions of the American Diabetes Association. Yet when I look at this, it makes me think I have a lot more work to do. The visualization highlights the latency issue of taking insulin. When I get a reading that my blood sugar is either high or heading high, I take an additional dose of insulin. But it takes about 20 minutes for that to start working and a full 2 hours before it reaches peak efficacy. Some of these trends are easier to see when viewing the data by day rather than by month.

This work is intended to give patients a “bigger picture” view of their readings. Unlike traditional graphs that are intended to show individual readings, this is intended to see whether they are generally doing well or still have improvements to make. I think it is important for patients to have a proactive attitude towards their control. Yet it is a definite challenge to maintain that attitude over the months, years and decades of living with a disease. Also, with thousands upon thousands of data points a month (and that’s just blood sugar readings!), it easy to be overwhelmed by it all.

But finally, I am hoping to make a visualization that succeeds as a design on its own, even if you know nothing about diabetes. After a few more tweaks, I intend to make it into a poster to hang on the wall. It would be great to look at as a graphic, subtly reminding me to eat right, keep on exercising and aiming for the best possible control.

XML xml;

//datapoints array contains all parsed data pointreadings (value, date, time)
SensorData[] datapoints;

void setup() {
size (800, 800);

// full set of 7729 readings
xml = loadXML(“dexcom1111.xml”);

// children array is an array of all the sensor data, unparsed
XML[] children = xml.getChildren(“Sensor”);

//initiate datapoints array
datapoints = new SensorData[children.length];

//parse SensorData
for (int i = 0; i < children.length; i++) {
//SensorData s = new SensorData();
SensorData s = new SensorData (children[i].getInt(“Value”), children[i].getString(“DisplayTime”));

//define sensor data readings to datapoints array
datapoints[i] = s;
}
}

void draw() {
smooth ();
translate(width / 2, height / 2);
background (255);

//background circles
noStroke ();
fill (237, 212, 0);
ellipse(0, 0, 280, 280);
fill (210);
ellipse(0, 0, 160, 160);

float TOTALTIME = 43200;

// for future PVector
beginShape();
for (int i = 0; i < datapoints.length; i++) {

float currDeg = map(datapoints[i].timeInMinutes, 0, TOTALTIME, 0, 360);

// plot the points
float x = cos(radians(currDeg)) * map(datapoints[i].value, 40, 400, 100, 250);
float y = sin(radians(currDeg)) * map(datapoints[i].value, 40, 400, 100, 250);

noFill();
stroke(255,0,0);
vertex(x, y);
}
endShape();

saveFrame(“output/November.png”);
noLoop();
}

class SensorData {
int value;
//String dateTime;
int ye;
int mo;
int da;
int ho;
int mi;
int se;

int timeInMinutes;

//    value = theValue;
//    dateTime = theDate;
SensorData(int tempValue, String dateTime) {
value = tempValue;
ye = int(dateTime.substring(0, 4));
mo = int(dateTime.substring(5, 7));
da = int(dateTime.substring(8, 10));
ho = int(dateTime.substring(11, 13));
mi = int(dateTime.substring(14, 16));
convertTime();
}

/*by minutes
number of minutes in November = 43200
number of days in November = 30
number of minutes in a week = 10080
number of minutes in a day = 1440
number of seconds in an hour = 60
November 1 12:00:00 is 00000. this date/time is currently stored as (da)(ho)(mi) (01)(00)(00)(00).
Formula ((da – 1) *1440) + (ho * 60) + (mi)
test Nov. 30, 23:59 = (29 * 1440) + (23 * 60) + 59) = 41760 + 1380 + 59 = 43199 = Great Success!
*/

void convertTime() {
timeInMinutes = ((da – 1) * 1440) + (ho * 60) + mi;
}
}

About these ads

One comment

  1. Pingback: Databetes 7729 | dougkanter