Skip to content

Instantly share code, notes, and snippets.

@zeffii
Last active August 9, 2016 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeffii/070d9a293dc513091bc575c12849e2ab to your computer and use it in GitHub Desktop.
Save zeffii/070d9a293dc513091bc575c12849e2ab to your computer and use it in GitHub Desktop.
Glucose - nested v6
license: gpl-3.0

sleep over time

Charting sleep periods over the course of a number of days.

  • vertical axis day
  • horizontal time of day

milestones

  • each day gets unique track

forked from zeffii's block: sleep_tkd - nested v3 - comments

forked from zeffii's block: Glucose - nested v4 - comments

forked from zeffii's block: Glucose - nested v5 - comments

forked from anonymous's block: Glucose - nested v5 - comments

forked from anonymous's block: Glucose - nested v5 - comments

forked from anonymous's block: Glucose - nested v5 - comments

forked from anonymous's block: Glucose - nested v5 - comments

forked from anonymous's block: Glucose - nested v5 - comments

forked from zeffii's block: Glucose - nested v6

/*
MIT License 2016 - Dealga McArdle.
=================================
For now this is moderately light usage of d3.js - maybe to the chagrin of more weathered
d3.js masters - simply to illustrate a problem i'm facing.
typical json to parse:
....
"YYYY/MM/DD": {
"sleeptimes": "00:00->07:00,15:20->18:30,23:00->24:00",
"comments": "AMC visit, Cystoscopy - all clear",
"glucose": [
{"time": "06:35", "value": 6.94},
{"time": "15:18", "value": 14.93},
{"time": "20:28", "value": 11.77},
{"time": "22:13", "value": 12.71}
]
},
....
[x] color determined by sugar value
- [x] option for BW and full color
[x] time bubbles (x axis) auto position in y depending on number of days in record.
intentionally left blank.
*/
var multicolor = false;
function get_ratio_from_time(time_str){
// this function converts a time_str into how far into the day it is
// f.ex 12:00 => 0.5 06:00 => 0.25
var time_parts = time_str.split(':');
var a = +time_parts[0];
var b = +time_parts[1];
return (1/1440*((a*60) + b))
}
function get_color(tval){
if (multicolor){
if (tval < 5.0){return {bg:"#18dff5", tx: "#111"}}
else if (tval >= 5.0 && tval < 10.0){return {bg:"#27f518", tx: "#111"}}
else if (tval >= 10.0 && tval < 15.0){return {bg:"#c8f97f", tx: "#111"}}
else if (tval >= 15.0 && tval < 20.0){return {bg:"#ffb76b", tx: "#111"}}
else if (tval >= 20.0 && tval < 25.0){return {bg:"#fe70bc", tx: "#ffffff"}}
else if (tval >= 25.0){return {bg:"#AA70bc", tx: "#ffffff"}}
} else {
if (tval < 5.0){return {bg:"#FFFFFF", tx: "#050505"}}
else if (tval >= 5.0 && tval < 10.0){return {bg:"#FAFAFA", tx: "#050505"}}
else if (tval >= 10.0 && tval < 15.0){return {bg:"#F0F0F0", tx: "#050505"}}
else if (tval >= 15.0 && tval < 20.0){return {bg:"#EAEAEA", tx: "#050505"}}
else if (tval >= 20.0 && tval < 25.0){return {bg:"#E0E0E0", tx: "#050505"}}
else if (tval >= 25.0){return {bg:"#DADADA", tx: "#050505"}}
}
}
var svg = d3.select("svg")
var format_day = d3.time.format("%Y/%m/%d");
var format_hours = d3.time.format("%H:%M");
var formatTime = d3.time.format("%m / %d");
d3.json("times.json", function(error, times) {
if (error) throw error;
times = json_preprocessor(times);
draw_graph(times);
});
function times_preprocessor(t){
if (!t){return []}
var ts = t.split(',');
var emb = [];
for (var k of ts){
var abl = k.split('->');
if (abl.length === 2){ emb.push(abl); }
}
return emb;
}
function json_preprocessor(p){
var new_object_array = [];
for (var key in p) {
if (p.hasOwnProperty(key)) {
var day_datum = format_day.parse(key);
var time_object = p[key];
var processed_times = times_preprocessor(time_object.sleeptimes);
new_object_array.push({
day: day_datum,
times: processed_times,
comments: time_object.comments,
glucose: time_object.glucose
});
}
}
return new_object_array;
}
function draw_graph(times){
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
svg
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var main_group = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tracks = main_group.append('g').classed('tracks', true)
var yindex = 0;
var begin_time, end_time;
var tab_height = 12;
var bar_height = 15;
var tab_ear = 4;
var vertical_skip = 17;
var time_offset_down = 6;
for (var item of times){
var mg = tracks.append('g');
for (var time_slot of item.times){
begin_time = get_ratio_from_time(time_slot[0]);
end_time = get_ratio_from_time(time_slot[1]);
var rec = mg.append('rect');
rec.attr("width", (end_time - begin_time) * width)
.attr("height", bar_height)
.style({fill: "#badcfc"})
.attr("transform", function(d){
return "translate(" + [
begin_time * width,
yindex * vertical_skip
] + ")"
})
}
var gg = tracks.append('g');
for (var reading of item.glucose){
var gtime = get_ratio_from_time(reading.time);
var gval = reading.value;
var ggroup = gg.append('g');
ggroup.attr({
transform: "translate(" + [0, (yindex * vertical_skip + 8)] + ")"})
var cl = ggroup.append('rect');
cl.attr({transform: "translate(" + [(gtime * width) + tab_ear , -6] +")"})
.attr({'height': tab_height})
.style({fill: get_color(gval).bg})
var cl2 = ggroup.append('path');
cl2.attr({transform: "translate(" + [(gtime * width) + tab_ear , -6] +")"})
.attr({'d': 'M' + [0,0,-tab_ear,tab_height/2,0,tab_height] + 'z'})
.style({fill: get_color(gval).bg})
var cltext = ggroup.append('text');
cltext.text(gval)
.attr({transform: "translate(" + [(gtime * width) + tab_ear , 4] +")"})
.attr({
'text-anchor': "start",
"font-size": 11,
"font-family": "sans-serif"
})
cltext.style({'fill': get_color(gval).tx })
var textwidth = cltext.node().getComputedTextLength();
cl.attr({'width': textwidth +3})
}
// draw comments
if (item.comments.length > 0){
var comment_group = mg.append('g');
comment_group.attr({
transform: "translate(" + [width + 20, yindex * vertical_skip] + ")"
})
var newrec = comment_group.append('rect')
newrec.attr('width', 20).attr('height', 13)
newrec.style({fill: "#fce7ba"})
}
yindex += 1;
mg.append('text')
.text(formatTime(item.day))
.attr("transform", "translate(-21," + (yindex * vertical_skip - 7) + ")")
.attr({'text-anchor': "middle", "font-size": 10, "font-family": "sans-serif"})
}
// instead of appending, I want this group to be added before all existing groups.
// this will ensure that the lines it draws are beneath the rest.
var indicat = main_group.insert('g', ':first-child').classed('indications', true);
var ditimes = "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24".split(" ");
var time_index = 0;
function set_time_bubbles(){
return yindex * vertical_skip + 20;
}
for (var tick of ditimes){
tick = tick + ":00";
var tgl = indicat.append('g');
var tl = tgl.append('line');
var xpostime = Math.floor(get_ratio_from_time(tick) * width);
tl.attr('x1', xpostime)
.attr('x2', xpostime)
.attr('y1', 0)
.attr('y2', height+50)
.style({"stroke-width": 1, stroke: "#cfdbe7"})
if (time_index % 3 === 0){
tl.style({"stroke-width": 1, stroke: "#aabfd4"})
var tcl = tgl.append('circle');
tcl.attr('cx', Math.floor(get_ratio_from_time(tick) * width))
.attr('cy', set_time_bubbles())
.attr('r', 16)
.style({fill: "#e0eeff"})
var txl = tgl.append('text');
txl.attr({
'text-anchor': "middle",
"font-size": 17,
"font-family": "sans-serif"
})
.attr(
'transform',
'translate(' + [
Math.floor(get_ratio_from_time(tick) * width),
set_time_bubbles() + time_offset_down ] +
')')
.style({'fill': "#7c7c7c"})
.text(tick.slice(0,2))
}
time_index += 1;
}
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://d3js.org/d3-time.v0.2.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width:100%; height: 100% }
</style>
</head>
<body>
<svg></svg>
<script src="dillitant.js"></script>
</body>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
font: 10px sans-serif;
}
{
"2016/07/28": {
"comments": "",
"glucose": [
{
"time": "08:09",
"value": 7.55
},
{
"time": "13:10",
"value": 8.21
},
{
"time": "17:26",
"value": 16.43
},
{
"time": "22:08",
"value": 17.93
}
],
"times": ""
},
"2016/07/29": {
"comments": "",
"glucose": [
{
"time": "08:16",
"value": 8.27
},
{
"time": "13:12",
"value": 16.76
},
{
"time": "17:34",
"value": 21.59
},
{
"time": "22:11",
"value": 15.93
}
],
"times": ""
},
"2016/07/30": {
"comments": "",
"glucose": [
{
"time": "07:38",
"value": 7.83
},
{
"time": "16:37",
"value": 19.76
},
{
"time": "23:20",
"value": 18.76
}
],
"times": ""
},
"2016/07/31": {
"comments": "",
"glucose": [
{
"time": "08:17",
"value": 8.33
},
{
"time": "13:04",
"value": 20.09
},
{
"time": "19:28",
"value": 16.21
}
],
"times": ""
},
"2016/08/01": {
"comments": "",
"glucose": [
{
"time": "08:08",
"value": 6.66
},
{
"time": "12:47",
"value": 16.04
},
{
"time": "17:35",
"value": 23.59
},
{
"time": "22:04",
"value": 24.98
}
],
"times": ""
},
"2016/08/02": {
"comments": "",
"glucose": [
{
"time": "08:08",
"value": 6.11
},
{
"time": "08:09",
"value": 6.55
},
{
"time": "12:57",
"value": 11.55
},
{
"time": "17:35",
"value": 14.82
},
{
"time": "21:01",
"value": 14.6
}
],
"times": ""
},
"2016/08/03": {
"comments": "",
"glucose": [
{
"time": "08:16",
"value": 8.44
},
{
"time": "14:15",
"value": 18.21
},
{
"time": "18:48",
"value": 13.65
},
{
"time": "22:11",
"value": 15.32
}
],
"times": ""
},
"2016/08/04": {
"comments": "",
"glucose": [
{
"time": "08:08",
"value": 8.71
},
{
"time": "12:56",
"value": 15.26
},
{
"time": "18:03",
"value": 20.48
},
{
"time": "22:03",
"value": 15.04
}
],
"times": ""
},
"2016/08/05": {
"comments": "",
"glucose": [
{
"time": "08:15",
"value": 8.33
},
{
"time": "12:46",
"value": 14.76
},
{
"time": "17:58",
"value": 14.49
},
{
"time": "21:49",
"value": 12.16
}
],
"times": ""
},
"2016/08/06": {
"comments": "",
"glucose": [
{
"time": "07:15",
"value": 7.16
},
{
"time": "12:21",
"value": 8.1
},
{
"time": "17:26",
"value": 12.04
},
{
"time": "22:06",
"value": 15.43
}
],
"times": ""
},
"2016/08/07": {
"comments": "",
"glucose": [
{
"time": "12:49",
"value": 9.66
},
{
"time": "16:50",
"value": 16.71
},
{
"time": "21:55",
"value": 10.27
}
],
"times": ""
},
"2016/08/08": {
"comments": "",
"glucose": [
{
"time": "17:44",
"value": 15.43
},
{
"time": "21:57",
"value": 21.37
}
],
"times": ""
},
"2016/08/09": {
"comments": "",
"glucose": [
{
"time": "08:09",
"value": 6.94
}
],
"times": ""
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment