block by zeffii 33a264d3944748e372db484ca71a0c55

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

forked from zeffii‘s block: Glucose - nested v8

forked from anonymous‘s block: Glucose - nested v8

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 = 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+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/03/01": {
        "comments": "",
        "glucose": [
            {
                "time": "08:05",
                "value": 7.55
            },
            {
                "time": "12:52",
                "value": 15.49
            },
            {
                "time": "22:29",
                "value": 20.54
            }
        ],
        "times": ""
    },
    "2017/03/02": {
        "comments": "",
        "glucose": [
            {
                "time": "08:16",
                "value": 6.49
            },
            {
                "time": "12:34",
                "value": 8.66
            },
            {
                "time": "22:54",
                "value": 11.99
            }
        ],
        "times": ""
    },
    "2017/03/03": {
        "comments": "",
        "glucose": [
            {
                "time": "08:12",
                "value": 8.94
            },
            {
                "time": "13:03",
                "value": 21.48
            },
            {
                "time": "22:30",
                "value": 12.49
            }
        ],
        "times": ""
    },
    "2017/03/04": {
        "comments": "",
        "glucose": [
            {
                "time": "07:53",
                "value": 7.88
            },
            {
                "time": "12:31",
                "value": 12.43
            },
            {
                "time": "19:03",
                "value": 12.21
            }
        ],
        "times": ""
    },
    "2017/03/05": {
        "comments": "",
        "glucose": [
            {
                "time": "08:25",
                "value": 8.55
            },
            {
                "time": "18:03",
                "value": 12.32
            }
        ],
        "times": ""
    },
    "2017/03/06": {
        "comments": "",
        "glucose": [
            {
                "time": "12:35",
                "value": 9.66
            },
            {
                "time": "18:21",
                "value": 14.76
            },
            {
                "time": "22:15",
                "value": 12.43
            }
        ],
        "times": ""
    },
    "2017/03/07": {
        "comments": "",
        "glucose": [
            {
                "time": "12:47",
                "value": 10.77
            }
        ],
        "times": ""
    },
    "2017/03/08": {
        "comments": "",
        "glucose": [
            {
                "time": "08:09",
                "value": 7.33
            },
            {
                "time": "18:52",
                "value": 13.88
            }
        ],
        "times": ""
    },
    "2017/03/09": {
        "comments": "",
        "glucose": [
            {
                "time": "08:35",
                "value": 7.22
            },
            {
                "time": "12:16",
                "value": 14.43
            }
        ],
        "times": ""
    },
    "2017/03/10": {
        "comments": "",
        "glucose": [
            {
                "time": "13:15",
                "value": 10.21
            },
            {
                "time": "18:13",
                "value": 11.66
            }
        ],
        "times": ""
    },
    "2017/03/11": {
        "comments": "",
        "glucose": [
            {
                "time": "17:57",
                "value": 11.16
            }
        ],
        "times": ""
    },
    "2017/03/13": {
        "comments": "",
        "glucose": [
            {
                "time": "08:15",
                "value": 9.1
            }
        ],
        "times": ""
    },
    "2017/03/14": {
        "comments": "",
        "glucose": [
            {
                "time": "13:22",
                "value": 12.77
            },
            {
                "time": "19:28",
                "value": 16.65
            }
        ],
        "times": ""
    },
    "2017/03/15": {
        "comments": "",
        "glucose": [
            {
                "time": "08:18",
                "value": 9.44
            },
            {
                "time": "12:37",
                "value": 14.76
            },
            {
                "time": "18:03",
                "value": 21.31
            },
            {
                "time": "22:57",
                "value": 20.93
            }
        ],
        "times": ""
    },
    "2017/03/16": {
        "comments": "",
        "glucose": [
            {
                "time": "08:08",
                "value": 8.71
            },
            {
                "time": "13:21",
                "value": 11.71
            },
            {
                "time": "18:19",
                "value": 18.76
            }
        ],
        "times": ""
    },
    "2017/03/17": {
        "comments": "",
        "glucose": [
            {
                "time": "08:02",
                "value": 10.66
            },
            {
                "time": "13:08",
                "value": 16.15
            },
            {
                "time": "17:32",
                "value": 17.65
            },
            {
                "time": "22:07",
                "value": 17.04
            }
        ],
        "times": ""
    },
    "2017/03/18": {
        "comments": "",
        "glucose": [
            {
                "time": "07:50",
                "value": 6.88
            },
            {
                "time": "12:47",
                "value": 10.27
            },
            {
                "time": "18:18",
                "value": 12.77
            },
            {
                "time": "21:53",
                "value": 20.48
            }
        ],
        "times": ""
    },
    "2017/03/19": {
        "comments": "",
        "glucose": [
            {
                "time": "08:26",
                "value": 8.99
            },
            {
                "time": "13:05",
                "value": 12.43
            },
            {
                "time": "18:22",
                "value": 18.76
            },
            {
                "time": "22:22",
                "value": 16.04
            }
        ],
        "times": ""
    },
    "2017/03/20": {
        "comments": "",
        "glucose": [
            {
                "time": "08:17",
                "value": 8.83
            },
            {
                "time": "11:48",
                "value": 10.1
            },
            {
                "time": "19:54",
                "value": 12.21
            },
            {
                "time": "22:16",
                "value": 14.15
            }
        ],
        "times": ""
    },
    "2017/03/21": {
        "comments": "",
        "glucose": [
            {
                "time": "07:44",
                "value": 13.71
            },
            {
                "time": "18:47",
                "value": 18.37
            },
            {
                "time": "21:52",
                "value": 16.15
            }
        ],
        "times": ""
    },
    "2017/03/22": {
        "comments": "",
        "glucose": [
            {
                "time": "08:20",
                "value": 7.6
            },
            {
                "time": "12:21",
                "value": 12.27
            },
            {
                "time": "20:01",
                "value": 19.15
            }
        ],
        "times": ""
    },
    "2017/03/23": {
        "comments": "",
        "glucose": [
            {
                "time": "08:29",
                "value": 8.6
            },
            {
                "time": "13:02",
                "value": 17.43
            },
            {
                "time": "22:28",
                "value": 31.53
            },
            {
                "time": "22:29",
                "value": 29.42
            }
        ],
        "times": ""
    },
    "2017/03/24": {
        "comments": "",
        "glucose": [
            {
                "time": "00:07",
                "value": 23.98
            },
            {
                "time": "07:17",
                "value": 6.99
            },
            {
                "time": "12:48",
                "value": 10.71
            },
            {
                "time": "18:44",
                "value": 13.32
            },
            {
                "time": "22:56",
                "value": 14.54
            }
        ],
        "times": ""
    },
    "2017/03/25": {
        "comments": "",
        "glucose": [
            {
                "time": "19:21",
                "value": 17.54
            },
            {
                "time": "22:50",
                "value": 15.21
            }
        ],
        "times": ""
    },
    "2017/03/26": {
        "comments": "",
        "glucose": [
            {
                "time": "07:29",
                "value": 8.83
            },
            {
                "time": "11:54",
                "value": 13.88
            },
            {
                "time": "17:45",
                "value": 17.37
            },
            {
                "time": "21:30",
                "value": 17.98
            }
        ],
        "times": ""
    },
    "2017/03/27": {
        "comments": "",
        "glucose": [
            {
                "time": "07:23",
                "value": 11.49
            },
            {
                "time": "21:31",
                "value": 15.04
            }
        ],
        "times": ""
    },
    "2017/03/28": {
        "comments": "",
        "glucose": [
            {
                "time": "06:59",
                "value": 9.38
            },
            {
                "time": "19:10",
                "value": 13.82
            }
        ],
        "times": ""
    },
    "2017/03/29": {
        "comments": "",
        "glucose": [
            {
                "time": "00:05",
                "value": 12.32
            },
            {
                "time": "12:27",
                "value": 17.37
            },
            {
                "time": "21:52",
                "value": 16.93
            }
        ],
        "times": ""
    },
    "2017/03/30": {
        "comments": "",
        "glucose": [
            {
                "time": "07:36",
                "value": 8.71
            }
        ],
        "times": ""
    }
}