block by zeffii 4c7722f6a8fc10b3eca02a8478a8890e

Glucose - nested v8

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

forked from zeffii‘s block: Glucose - nested v6

forked from zeffii‘s block: Glucose - nested v6

forked from anonymous‘s block: Glucose - nested v6

forked from zeffii‘s block: Glucose - nested v6

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

  [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 = true;



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+225)
          .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;
    }
}

style.css

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

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

times.json

{
    "2017/02/02": {
        "comments": "",
        "glucose": [
            {
                "time": "08:22",
                "value": 8.55
            },
            {
                "time": "13:30",
                "value": 13.88
            }
        ],
        "times": ""
    },
    "2017/02/04": {
        "comments": "",
        "glucose": [
            {
                "time": "18:48",
                "value": 5.05
            },
            {
                "time": "22:21",
                "value": 10.16
            }
        ],
        "times": ""
    },
    "2017/02/05": {
        "comments": "",
        "glucose": [
            {
                "time": "08:13",
                "value": 6.49
            },
            {
                "time": "13:44",
                "value": 8.83
            },
            {
                "time": "18:37",
                "value": 9.21
            },
            {
                "time": "22:16",
                "value": 9.1
            }
        ],
        "times": ""
    },
    "2017/02/06": {
        "comments": "",
        "glucose": [
            {
                "time": "08:20",
                "value": 6.88
            },
            {
                "time": "13:06",
                "value": 11.93
            },
            {
                "time": "19:40",
                "value": 9.44
            }
        ],
        "times": ""
    },
    "2017/02/07": {
        "comments": "",
        "glucose": [
            {
                "time": "08:20",
                "value": 5.94
            },
            {
                "time": "12:41",
                "value": 6.99
            },
            {
                "time": "18:23",
                "value": 9.94
            },
            {
                "time": "22:35",
                "value": 7.99
            }
        ],
        "times": ""
    },
    "2017/02/08": {
        "comments": "",
        "glucose": [
            {
                "time": "08:14",
                "value": 8.1
            },
            {
                "time": "12:18",
                "value": 9.49
            },
            {
                "time": "17:31",
                "value": 12.99
            },
            {
                "time": "22:17",
                "value": 6.88
            }
        ],
        "times": ""
    },
    "2017/02/09": {
        "comments": "",
        "glucose": [
            {
                "time": "08:27",
                "value": 5.61
            },
            {
                "time": "12:43",
                "value": 8.71
            },
            {
                "time": "19:14",
                "value": 9.55
            },
            {
                "time": "22:27",
                "value": 13.43
            }
        ],
        "times": ""
    },
    "2017/02/10": {
        "comments": "",
        "glucose": [
            {
                "time": "07:48",
                "value": 7.22
            },
            {
                "time": "17:43",
                "value": 12.66
            }
        ],
        "times": ""
    },
    "2017/02/11": {
        "comments": "",
        "glucose": [
            {
                "time": "08:02",
                "value": 7.88
            },
            {
                "time": "13:53",
                "value": 7.55
            },
            {
                "time": "17:00",
                "value": 12.66
            },
            {
                "time": "21:09",
                "value": 13.54
            }
        ],
        "times": ""
    },
    "2017/02/12": {
        "comments": "",
        "glucose": [
            {
                "time": "08:42",
                "value": 7.44
            },
            {
                "time": "13:17",
                "value": 10.88
            },
            {
                "time": "19:02",
                "value": 11.6
            }
        ],
        "times": ""
    },
    "2017/02/13": {
        "comments": "",
        "glucose": [
            {
                "time": "08:20",
                "value": 6.94
            },
            {
                "time": "12:05",
                "value": 16.43
            },
            {
                "time": "19:13",
                "value": 11.99
            }
        ],
        "times": ""
    },
    "2017/02/14": {
        "comments": "",
        "glucose": [
            {
                "time": "08:24",
                "value": 6.05
            },
            {
                "time": "18:27",
                "value": 13.04
            }
        ],
        "times": ""
    },
    "2017/02/15": {
        "comments": "",
        "glucose": [
            {
                "time": "08:27",
                "value": 5.33
            },
            {
                "time": "19:23",
                "value": 11.82
            }
        ],
        "times": ""
    },
    "2017/02/16": {
        "comments": "",
        "glucose": [
            {
                "time": "07:43",
                "value": 7.72
            },
            {
                "time": "19:05",
                "value": 18.15
            },
            {
                "time": "22:28",
                "value": 12.32
            }
        ],
        "times": ""
    },
    "2017/02/17": {
        "comments": "",
        "glucose": [
            {
                "time": "08:31",
                "value": 8.49
            }
        ],
        "times": ""
    }
}