Skip to content

Instantly share code, notes, and snippets.

@claudialexa
Created March 15, 2016 02:13
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 claudialexa/e6b45285be80cdcb0d34 to your computer and use it in GitHub Desktop.
Save claudialexa/e6b45285be80cdcb0d34 to your computer and use it in GitHub Desktop.
Changing Bars: The Sad Reality of My Fitbit Data
Date Total Calories Burned Minutes Sedentary Minutes Active Activity Calories
Monday 4 3468 1660 1378 62 367
Tuesday 5 3131 1512 1398 42 178
Wednesday 6 3480 1644 1317 123 394
Thursday 7 4923 2290 1158 282 1185
Friday 8 4900 2294 1193 247 1158
Monday 11 3368 1614 1388 52 313
Tuesday 12 3942 1882 1357 83 619
Wednesday 13 3552 1669 1296 144 441
Thursday 14 4261 2002 1247 193 816
Friday 15 4822 2278 1236 204 1097
Tuesday 19 4648 2184 1210 230 1020
Wednesday 20 4582 2166 1228 212 970
Thursday 21 3832 1786 1238 202 603
Friday 22 4840 2270 1205 235 1123
Monday 25 6644 3124 1080 360 2076
Tuesday 26 10780 3200 887 308 1988
Wednesday 27 3561 1674 1299 141 445
Thursday 28 4289 1995 1204 236 850
Friday 29 4314 2038 1030 298 943
Saturday 30 3743 1767 1213 178 583
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fitbit Data</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<style>
body {
background: #ffffff;
color: #333;
margin: 1em auto 4em auto;
position: relative;
width: 960px;
font-family: sans-serif;
}
svg {
font: 10px sans-serif;
}
.bar rect {
fill: #00A388;
}
.bar rect:hover {
fill: #BEEB9F;
}
.value {
fill: white;
}
.axis {
shape-rendering: crispEdges;
}
.axis path {
fill: none;
stroke: none;
}
.x.axis path {
fill: none;
stroke: white;
}
.x.axis line {
stroke: #fff;
stroke-opacity: .8;
}
.y.axis path {
stroke: black;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8">
<h2>Fitbit Data: January Active Days</h2>
<p>By: Claudia Aguirre<br/>
Like every other person in the world, I set myself to start the year off by committing to going to the gym more. To understand the patterns of my gym attendance (and efficiency) I exported all of my Fitbit's January data (excluding the data of any days I may not have worn my Fitbit).</p>
</div>
</div>
<div class="row">
<div class="col-md-8">
<p id="menu"><b>Activity Indicators: </b>
<select class="form-control"></select>
</div>
</div>
<div class="row">
<div class="col-md-8"><p id="chart"></p>
</div>
</div>
</div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script>
var fullwidth = 800,
fullheight = 400;
var margin = {top: 30, right: 40, bottom: 10, left: 80},
width = fullwidth - margin.right - margin.left;
height = fullheight - margin.top - margin.bottom;
var prevWorkout;
var xScale = d3.scale.linear()
.range([0, width]);
var yScale = d3.scale.ordinal()
.rangeRoundBands([0, height], .1);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("top")
.ticks(7);
var svg = d3.select("#chart").append("svg")
.attr("width", fullwidth)
.attr("height", fullheight)
.style("margin-left", -margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis");
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("class", "domain")
.attr("y2", height);
var menu = d3.select("#menu select")
.on("change", redraw);
d3.csv("fitbit.csv", function(data) {
fitbit = data;
// remember d3.keys gets us the column names from these objects, using first row:
var workouts = d3.keys(fitbit[0]).filter(function(key) {
return key != "Date" && key != "Total";
});
console.log(workouts);
// build menu from the data; could have been done by hand.
menu.selectAll("option")
.data(workouts)
.enter().append("option")
.text(function(d) { return d; });
menu.property("value", "Calories Burned");
// redraw in this case draws the UI - it uses a variable to determine data column.
redraw();
}); // end load csv
function redraw() {
// get the age for the data access off the menu:
var currentWorkout = menu.property("value");
// sort by it and then take the top 10 using slice!
var top10 = fitbit.sort(function(a, b) {
return b[currentWorkout] - a[currentWorkout];
})
.slice(0, 15);
yScale.domain(top10.map(function(d) { return d.Date; })); // the y scale is ordinal, all the state names
var bar = svg.selectAll(".bar")
.data(top10, function(d) { return d.Date; }); // key function!
var barCreate = bar.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(0," + (yScale(d.Date) + height) + ")"; })
.style("fill-opacity", 0);
console.log("date", prevWorkout); // this is undefined the first time thru.
barCreate.append("rect")
//.attr("width", age && function(d) { return x(d[age]); })
.attr("width", function(d) {
if (prevWorkout) {
return xScale(d[prevWorkout]);
}
})
.attr("height", yScale.rangeBand());
barCreate.append("text")
.attr("class", "mylabel")
.attr("x", -3)
.attr("y", yScale.rangeBand() / 2)
.attr("dy", ".35em")
.attr("text-anchor", "end")
.text(function(d) { return d.Date; });
barCreate.append("text")
.attr("class", "value")
//.attr("x", age && function(d) { return x(d[age]) - 3; })
.attr("x", function(d) {
if (prevWorkout) {
return xScale(d[prevWorkout]) - 3;
}
})
.attr("y", yScale.rangeBand() / 2)
.attr("dy", ".35em")
.attr("text-anchor", "end");
prevWorkout = currentWorkout;
// they are sorted, so take the top value for the max on the domain here:
xScale.domain([0, top10[0][currentWorkout]]);
// sets the d.yLocation for the bar that's used in the exit transition.
var barUpdate = bar.transition()
.attr("transform", function(d) {
d.yLocation = yScale(d.Date);
return "translate(0," + yScale(d.Date) + ")"; })
.style("fill-opacity", 1);
barUpdate.select("rect")
.attr("width", function(d) { return xScale(d[currentWorkout]); });
barUpdate.select(".value")
.attr("x", function(d) { return xScale(d[currentWorkout]) - 3; })
.text(function(d) { return (d[currentWorkout]); });
var barExit = bar.exit().transition()
.attr("transform", function(d) { return "translate(0," + (d.yLocation + height) + ")"; })
.style("fill-opacity", 0)
.remove();
barExit.select("rect")
.attr("width", function(d) { return xScale(d[currentWorkout]); });
barExit.select(".value")
.attr("x", function(d) { return xScale(d[currentWorkout]) - 3; })
.text(function(d) { return (d[currentWorkout]); });
// transition the axis, so easy if you fixed the domain!
svg.transition().select(".x.axis")
.call(xAxis);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment