block by zeffii 07ba5ec7e577ecf581ca2a788cc7a6d3

Glucose - nested v5 - comments

Full Screen

sleep over time

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

milestones

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

index.html

<!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>

dillitant.js

/*

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}
      ]
  },
  ....

  - could color grade using 0-5 5-10 10-15 15-20 20-25 25-up


  intentionally left blank.


*/





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 (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"}}
}

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 circle_push_vertical = 1.210360414208;  // <---- use to push hourly circles up / down
    var time_index = 0;
    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)
          .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', height/circle_push_vertical)
             .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),
                  (height/circle_push_vertical)+time_offset_down ] + 
                ')')
             .style({'fill': "#7c7c7c"})
             .text(tick.slice(0,2))
        
        }
        time_index += 1;
    }
}

style.css

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.axis text {
  font: 10px sans-serif;
}

times.json

{
    "2016/06/23": {
        "comments": "",
        "glucose": [
            {
                "time": "08:05",
                "value": 7.22
            },
            {
                "time": "12:58",
                "value": 18.76
            },
            {
                "time": "18:17",
                "value": 25.64
            },
            {
                "time": "22:45",
                "value": 30.25
            }
        ],
        "times": ""
    },
    "2016/06/24": {
        "comments": "",
        "glucose": [
            {
                "time": "08:11",
                "value": 7.44
            },
            {
                "time": "12:25",
                "value": 19.09
            },
            {
                "time": "17:34",
                "value": 23.76
            },
            {
                "time": "22:05",
                "value": 16.26
            }
        ],
        "times": ""
    },
    "2016/06/25": {
        "comments": "",
        "glucose": [
            {
                "time": "08:17",
                "value": 9.66
            },
            {
                "time": "12:23",
                "value": 11.82
            },
            {
                "time": "19:21",
                "value": 22.37
            },
            {
                "time": "22:49",
                "value": 22.04
            }
        ],
        "times": ""
    },
    "2016/06/26": {
        "comments": "",
        "glucose": [
            {
                "time": "07:03",
                "value": 7.44
            },
            {
                "time": "12:24",
                "value": 11.71
            },
            {
                "time": "16:47",
                "value": 20.65
            },
            {
                "time": "16:50",
                "value": 20.54
            },
            {
                "time": "22:05",
                "value": 20.93
            }
        ],
        "times": ""
    },
    "2016/06/27": {
        "comments": "",
        "glucose": [
            {
                "time": "07:32",
                "value": 6.72
            },
            {
                "time": "12:11",
                "value": 14.76
            },
            {
                "time": "16:46",
                "value": 18.37
            },
            {
                "time": "21:47",
                "value": 21.04
            }
        ],
        "times": ""
    },
    "2016/06/28": {
        "comments": "",
        "glucose": [
            {
                "time": "08:04",
                "value": 9.38
            },
            {
                "time": "12:21",
                "value": 23.53
            },
            {
                "time": "17:17",
                "value": 18.48
            },
            {
                "time": "22:48",
                "value": 22.31
            }
        ],
        "times": ""
    },
    "2016/06/29": {
        "comments": "",
        "glucose": [
            {
                "time": "07:40",
                "value": 10.88
            },
            {
                "time": "13:40",
                "value": 17.48
            },
            {
                "time": "18:45",
                "value": 28.86
            },
            {
                "time": "22:01",
                "value": 20.54
            }
        ],
        "times": ""
    },
    "2016/06/30": {
        "comments": "",
        "glucose": [
            {
                "time": "08:08",
                "value": 8.38
            },
            {
                "time": "13:23",
                "value": 21.65
            },
            {
                "time": "20:08",
                "value": 22.2
            },
            {
                "time": "22:39",
                "value": 23.15
            }
        ],
        "times": ""
    },
    "2016/07/01": {
        "comments": "",
        "glucose": [
            {
                "time": "08:07",
                "value": 10.32
            },
            {
                "time": "13:44",
                "value": 21.2
            },
            {
                "time": "17:37",
                "value": 20.26
            },
            {
                "time": "21:23",
                "value": 15.82
            }
        ],
        "times": ""
    },
    "2016/07/02": {
        "comments": "",
        "glucose": [
            {
                "time": "07:41",
                "value": 10.38
            },
            {
                "time": "12:31",
                "value": 18.93
            },
            {
                "time": "18:52",
                "value": 22.42
            },
            {
                "time": "22:14",
                "value": 17.6
            }
        ],
        "times": ""
    },
    "2016/07/03": {
        "comments": "",
        "glucose": [
            {
                "time": "07:33",
                "value": 7.99
            },
            {
                "time": "13:09",
                "value": 17.1
            },
            {
                "time": "16:09",
                "value": 17.71
            },
            {
                "time": "22:32",
                "value": 20.98
            }
        ],
        "times": ""
    },
    "2016/07/04": {
        "comments": "",
        "glucose": [
            {
                "time": "08:08",
                "value": 13.88
            },
            {
                "time": "12:24",
                "value": 25.14
            },
            {
                "time": "14:09",
                "value": 22.04
            },
            {
                "time": "21:57",
                "value": 10.55
            }
        ],
        "times": ""
    },
    "2016/07/05": {
        "comments": "",
        "glucose": [
            {
                "time": "08:09",
                "value": 7.88
            },
            {
                "time": "12:30",
                "value": 8.05
            },
            {
                "time": "17:51",
                "value": 20.04
            },
            {
                "time": "21:47",
                "value": 16.26
            }
        ],
        "times": ""
    },
    "2016/07/06": {
        "comments": "",
        "glucose": [
            {
                "time": "07:25",
                "value": 16.71
            },
            {
                "time": "07:26",
                "value": 16.32
            },
            {
                "time": "12:07",
                "value": 17.65
            },
            {
                "time": "16:31",
                "value": 19.7
            },
            {
                "time": "21:49",
                "value": 17.37
            }
        ],
        "times": ""
    },
    "2016/07/07": {
        "comments": "",
        "glucose": [
            {
                "time": "08:04",
                "value": 11.49
            },
            {
                "time": "11:54",
                "value": 11.21
            },
            {
                "time": "18:24",
                "value": 16.04
            },
            {
                "time": "21:31",
                "value": 11.66
            }
        ],
        "times": ""
    },
    "2016/07/08": {
        "comments": "",
        "glucose": [
            {
                "time": "08:05",
                "value": 9.99
            },
            {
                "time": "13:43",
                "value": 12.54
            },
            {
                "time": "18:44",
                "value": 18.04
            },
            {
                "time": "21:33",
                "value": 18.82
            }
        ],
        "times": ""
    },
    "2016/07/09": {
        "comments": "",
        "glucose": [
            {
                "time": "07:46",
                "value": 7.94
            },
            {
                "time": "12:49",
                "value": 16.82
            },
            {
                "time": "16:21",
                "value": 12.93
            },
            {
                "time": "22:04",
                "value": 22.15
            }
        ],
        "times": ""
    },
    "2016/07/10": {
        "comments": "",
        "glucose": [
            {
                "time": "08:09",
                "value": 7.55
            },
            {
                "time": "12:50",
                "value": 11.21
            },
            {
                "time": "18:43",
                "value": 22.65
            },
            {
                "time": "21:37",
                "value": 21.31
            }
        ],
        "times": ""
    },
    "2016/07/11": {
        "comments": "",
        "glucose": [
            {
                "time": "08:14",
                "value": 11.27
            },
            {
                "time": "12:30",
                "value": 12.66
            }
        ],
        "times": ""
    }
}