Created
August 2, 2013 17:07
-
-
Save robu3/6141560 to your computer and use it in GitHub Desktop.
Jawbone Up Spiral Visualization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<style> | |
body { | |
font-family: sans-serif; | |
} | |
h1 { | |
font-size: 24px; | |
margin-left: 350px; | |
} | |
p { | |
margin-left: 300px; | |
font-size: 12px; | |
width: 400px; | |
} | |
.line { | |
fill: none; | |
stroke: #000000; | |
} | |
.point { | |
fill: blue; | |
stroke: #000; | |
} | |
.reference-point { | |
stroke: #000; | |
fill: #FFF; | |
fill-opacity: 0; | |
} | |
.tooltip { | |
visibility: hidden; | |
color: #000; | |
stroke: #000; | |
fill: #FFF; | |
stroke-width: 4px; | |
fill-opacity: .9; | |
} | |
.tooltip-text { | |
stroke: none; | |
fill: #000; | |
text-anchor: start; | |
font-family: sans-serif; | |
font-size: 14px; | |
} | |
.tooltip-title { | |
font-weight: bold; | |
font-size: 16px; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Jawbone Up Visualization</h1> | |
<p>My (in)activity over the past 30 days. Each day is a point on the spiral, with the points closest to the center being the most recent. Color indicates activity and size indicates the number of hours slept on that day.</p> | |
<div id="canvas"></div> | |
<script src="up.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
date | m_active_time | m_calories | m_distance | m_inactive_time | m_lcat | m_lcit | m_steps | m_workout_count | m_workout_time | s_asleep_time | s_awake | s_awake_time | s_awakenings | s_bedtime | s_deep | s_duration | s_light | s_quality | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
20130617 | 5536 | 736.072444384 | 6566 | 27240 | 1701 | 11640 | 8107 | 2 | 3962 | 95 | 4141 | 448 | 1 | 78 | 14580 | 20649 | 6069 | 76 | |
20130618 | 1655 | 113.300000288 | 2170 | 29520 | 162 | 10020 | 2886 | 0 | 0 | 1438 | 2345 | 356 | 0 | 1401 | 14280 | 21481 | 7201 | 83 | |
20130619 | 1721 | 126.421999279 | 2407 | 29220 | 188 | 3780 | 3114 | 0 | 0 | 119 | 1582 | 448 | 0 | 103 | 12780 | 19740 | 6960 | 72 | |
20130620 | 1218 | 89.2879992612 | 1657 | 30000 | 205 | 9120 | 2184 | 0 | 0 | 110 | 3299 | 484 | 1 | 94 | 12384 | 20260 | 7876 | 70 | |
20130621 | 5701 | 626.405809723 | 6388 | 27060 | 1602 | 8460 | 7948 | 2 | 4078 | 1416 | 7429 | 515 | 2 | 1400 | 15840 | 25920 | 10080 | 95 | |
20130622 | 2621 | 187.760000497 | 3501 | 27720 | 382 | 6120 | 4635 | 0 | 0 | 182 | 1750 | 430 | 0 | 160 | 10680 | 15000 | 4320 | 56 | |
20130623 | 2018 | 169.07199949 | 3046 | 30600 | 466 | 14520 | 3814 | 0 | 0 | 1429 | 2153 | 473 | 0 | 1418 | 15181 | 29160 | 13979 | 99 | |
20130624 | 1503 | 107.459000323 | 2086 | 30720 | 338 | 6300 | 2715 | 0 | 0 | 9 | 3036 | 453 | 1 | 1433 | 13303 | 24703 | 11400 | 85 | |
20130625 | 1814 | 126.360999916 | 2488 | 30300 | 276 | 8220 | 3258 | 0 | 0 | 68 | 4013 | 532 | 1 | 57 | 16230 | 24690 | 8460 | 89 | |
20130626 | 5105 | 562.23639028 | 6155 | 27240 | 1924 | 13980 | 7576 | 2 | 3742 | 31 | 692 | 430 | 0 | 20 | 15540 | 24120 | 8580 | 89 | |
20130627 | 1497 | 107.551999599 | 1978 | 29040 | 368 | 7920 | 2630 | 0 | 0 | 159 | 5254 | 543 | 1 | 138 | 13272 | 19272 | 6000 | 71 | |
20130628 | 4662 | 605.813001946 | 9231 | 24300 | 2093 | 4680 | 9778 | 1 | 1927 | 190 | 3913 | 514 | 0 | 169 | 11881 | 19440 | 7559 | 68 | |
20130629 | 5891 | 239.570999503 | 4501 | 24660 | 363 | 2340 | 5860 | 1 | 2917 | 91 | 755 | 495 | 0 | 80 | 13980 | 24180 | 10200 | 83 | |
20130630 | 2643 | 194.369999349 | 3645 | 25560 | 329 | 3660 | 4766 | 0 | 0 | 125 | 6666 | 629 | 1 | 104 | 11760 | 25320 | 13560 | 80 | |
20130701 | 1320 | 96.6280005462 | 1791 | 30480 | 143 | 5700 | 2352 | 0 | 0 | 255 | 2491 | 462 | 1 | 247 | 7450 | 10511 | 3061 | 37 | |
20130702 | 1419 | 100.484999884 | 1926 | 30720 | 171 | 4800 | 2538 | 0 | 0 | 50 | 5752 | 554 | 1 | 39 | 17760 | 25859 | 8099 | 96 | |
20130703 | 1795 | 125.791000623 | 2369 | 28860 | 234 | 7860 | 3143 | 0 | 0 | 64 | 5500 | 548 | 2 | 53 | 16221 | 24343 | 8122 | 88 | |
20130704 | 3390 | 247.416999221 | 4610 | 26580 | 1137 | 4620 | 6054 | 0 | 0 | 179 | 5530 | 678 | 1 | 168 | 16860 | 25500 | 8640 | 89 | |
20130705 | 5079 | 425.573692427 | 5912 | 29100 | 1661 | 24060 | 7335 | 2 | 3738 | 90 | 3232 | 561 | 1 | 86 | 10159 | 25459 | 15300 | 76 | |
20130706 | 5281 | 343.028000057 | 6531 | 23700 | 1715 | 4320 | 8919 | 0 | 0 | 150 | 7174 | 573 | 3 | 133 | 14687 | 19307 | 4620 | 71 | |
20130707 | 4786 | 654.656000763 | 9738 | 23040 | 2228 | 3240 | 10232 | 1 | 1938 | 1419 | 1263 | 513 | 1 | 1408 | 20639 | 31550 | 10911 | 100 | |
20130708 | 1502 | 109.121000692 | 2053 | 31080 | 272 | 8400 | 2685 | 0 | 0 | 164 | 4069 | 473 | 2 | 153 | 12074 | 15291 | 3217 | 58 | |
20130709 | 23402 | 105.160999753 | 1967 | 29880 | 179 | 8880 | 2611 | 1 | 22158 | 71 | 3787 | 567 | 1 | 67 | 16075 | 26275 | 10200 | 91 | |
20130710 | 1266 | 91.520999182 | 1723 | 30120 | 203 | 9840 | 2274 | 0 | 0 | 91 | 1264 | 490 | 0 | 75 | 15240 | 24000 | 8760 | 87 | |
20130711 | 2100 | 135.838000312 | 2567 | 29400 | 244 | 4620 | 3518 | 0 | 0 | 151 | 4170 | 534 | 1 | 134 | 14238 | 19986 | 5748 | 74 | |
20130712 | 5308 | 298.472001024 | 5382 | 27900 | 1422 | 8640 | 6754 | 2 | 3625 | ||||||||||
20130713 | 1946 | 137.576999631 | 2621 | 26940 | 166 | 4260 | 3461 | 0 | 0 | 105 | 5154 | 596 | 2 | 101 | 15362 | 24813 | 9451 | 86 | |
20130714 | 27 | 2.1660000384 | 41 | 18300 | 20 | 18300 | 52 | 0 | 0 | ||||||||||
20130715 | 928 | 66.6670001931 | 1227 | 31440 | 224 | 17160 | 1627 | 0 | 0 | ||||||||||
20130716 | 6292 | 180.592999429 | 3423 | 27360 | 384 | 7080 | 4515 | 1 | 3886 | 13 | 6485 | 522 | 2 | 2 | 15180 | 24935 | 9755 | 87 | |
20130717 | 3289 | 239.090999722 | 4423 | 27360 | 610 | 4800 | 5842 | 0 | 0 | 1431 | 1918 | 425 | 1 | 1415 | 15481 | 25821 | 10340 | 93 | |
20130718 | 1496 | 106.443999439 | 2022 | 30540 | 194 | 10500 | 2667 | 0 | 0 | 101 | 4197 | 500 | 2 | 90 | 11899 | 20520 | 8621 | 71 | |
20130719 | 5526 | 360.946000315 | 6540 | 26040 | 1720 | 4680 | 8201 | 2 | 3633 | 3 | 5182 | 543 | 1 | 1418 | 15961 | 28981 | 13020 | 100 | |
20130720 | 78 | 6.4430000372 | 111 | 26640 | 37 | 20460 | 144 | 0 | 0 | 236 | 4665 | 794 | 2 | 224 | 21060 | 29700 | 8640 | 100 | |
20130721 | 1846 | 133.220000178 | 2487 | 26940 | 210 | 7260 | 3277 | 0 | 0 | ||||||||||
20130722 | 3762 | 298.082999837 | 5498 | 21900 | 786 | 2580 | 6984 | 0 | 0 | ||||||||||
20130723 | 1731 | 126.228999734 | 2339 | 29700 | 155 | 4920 | 3080 | 0 | 0 | 1426 | 916 | 445 | 0 | 1415 | 16983 | 27540 | 10557 | 100 | |
20130724 | 1045 | 75.4680002183 | 1419 | 31380 | 174 | 22680 | 1868 | 0 | 0 | 4 | 830 | 443 | 0 | 1433 | 13980 | 26460 | 12480 | 91 | |
20130725 | 3179 | 204.916999795 | 3649 | 28140 | 1627 | 8640 | 4549 | 1 | 2014 | 95 | 5494 | 544 | 1 | 84 | 14289 | 22149 | 7860 | 81 | |
20130726 | 1706 | 131.128999341 | 2419 | 30000 | 441 | 10020 | 3133 | 0 | 0 | ||||||||||
20130727 | 3826 | 268.222999323 | 4971 | 23700 | 1168 | 2760 | 6644 | 0 | 0 | 211 | 4676 | 610 | 1 | 205 | 12510 | 19748 | 7238 | 66 | |
20130728 | 4786 | 637.933998216 | 9537 | 22620 | 2054 | 2700 | 10080 | 1 | 1900 | 74 | 2757 | 501 | 1 | 51 | 13920 | 24434 | 10514 | 83 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global d3*/ | |
// global app variable | |
var up = { | |
width: 960, | |
height: 700 | |
}; | |
// ## loadData(rows) | |
// Loads the data into the chart | |
function loadData(rows) { | |
rows = rows.reverse(); | |
console.log(rows); | |
var maxSteps, | |
maxSleep, | |
goalSteps = 10000, // 一日万歩 | |
goalSleep = 28800, | |
minRadius = 2, | |
radius = 25, | |
svg = d3.select("svg"), | |
colorScale; | |
// find upper bounds of steps and sleep | |
maxSteps = d3.max(rows, function (r) { | |
return parseInt(r.m_steps); | |
}); | |
maxSleep = d3.max(rows, function (r) { | |
return parseInt(r.s_duration); | |
}); | |
var s = goalSteps / 5; | |
colorScale = d3.scale.linear() | |
.domain([s, s * 2, s * 3, s * 4, goalSteps]) | |
.range(["#3333FF", "#9933FF", "#FF33FF", "#FF3399", "#FF3333"]); | |
// draw reference circles / points | |
svg.selectAll("circle.reference-point") | |
.attr("r", radius); | |
// color and size data points | |
var rSleep = (radius - minRadius) / goalSleep; | |
svg.selectAll("circle.datapoint") | |
.data(rows) | |
.attr("class", "point") | |
.attr("r", function (d) { return minRadius + d.s_duration * rSleep; }) | |
.attr("style", function (d) { | |
return "fill: " + colorScale(d.m_steps); | |
}); | |
} | |
// ## generateSpiral | |
// Archimedean spiral | |
// in polar coords: r = a + b * (theta) | |
function generateSpiral(width, points, step) { | |
var a = 0, | |
i, | |
x, | |
y, | |
r, | |
theta, | |
buffer = []; | |
// initialize | |
points = points || 10; | |
step = step || Math.PI * 0.25; | |
for (i = 0; i < points; i++) { | |
theta = step * i; | |
r = a + width * theta; | |
x = r * Math.cos(theta); | |
y = r * Math.sin(theta); | |
buffer.push({ x: x, y: y }); | |
} | |
return buffer; | |
} | |
// ## drawSpiral() | |
// Draws the spiral and data points that make up the graph | |
function drawSpiral() { | |
var step = Math.PI * .05, | |
points = generateSpiral(22, 100, step), | |
i, | |
x = up.width / 2, | |
y = up.height / 2, | |
svg = d3.select("#canvas") | |
.append("svg") | |
.attr("width", up.width) | |
.attr("height", up.height), | |
line = d3.svg.line() | |
.x(function (d) { return x + d.x; }) | |
.y(function (d) { return y + d.y; }) | |
.interpolate("cardinal"), | |
// connect dots | |
spiral = svg.append("path") | |
.datum(points) | |
.attr("class", "line") | |
.attr("d", line), | |
// simple tooltip | |
tooltip = svg | |
.append("g") | |
.attr("class", "tooltip"); | |
// add rectangle | |
tooltip.append("rect") | |
.attr("width", 125) | |
.attr("height", 70) | |
.attr("rx", 5) | |
.attr("ry", 5); | |
// add text elements for tooltip | |
var tooltipTextTop = tooltip | |
.append("text") | |
.attr("x", 5) | |
.attr("y", 40) | |
.attr("class", "tooltip-text"), | |
tooltipTextBottom = tooltip | |
.append("text") | |
.attr("x", 5) | |
.attr("y", 60) | |
.attr("class", "tooltip-text"), | |
tooltipTextTitle = tooltip | |
.append("text") | |
.attr("x", 5) | |
.attr("y", 20) | |
.attr("class", "tooltip-text tooltip-title"); | |
// draw points | |
for (i = 0; i < points.length; i++) { | |
// skip points because they are bunched together at the beginning of the spiral | |
// the first entire revolution is skipped | |
if (i * step < Math.PI * 2) { | |
continue; | |
} | |
// use every other spiral vertex as a data point position | |
if (i % 2 > 0) { | |
continue; | |
} | |
// add data point circle | |
svg.insert("circle", ".tooltip") | |
.attr("class", "datapoint") | |
.attr("r", 0) | |
.attr("cx", x + points[i].x) | |
.attr("cy", y + points[i].y) | |
.on("mouseover", function (d) { | |
var me = d3.select(this), | |
x = parseFloat(me.attr("cx")) + parseFloat(me.attr("r")) + 10, | |
y = parseFloat(me.attr("cy")) - parseFloat(tooltip.select("rect").attr("height")) / 2; | |
// set tooltip text | |
tooltipTextTitle | |
.text(d.date.substring(4, 6) + "/" + d.date.substring(6, 8) + "/" + d.date.substring(0, 4)) | |
.style("fill", me.style("fill")); | |
tooltipTextTop.text("Steps: " + parseInt(d.m_steps).toLocaleString()); | |
tooltipTextBottom.text("Sleep: " + parseFloat(d.s_duration / 3600).toFixed(2) + " hours"); | |
return tooltip | |
.style("visibility", "visible") | |
.attr("transform", "translate(" + x + "," + y + ")") | |
.select("rect") | |
.style("stroke", me.style("fill")); | |
}) | |
.on("mouseout", function (d) { | |
return tooltip.style("visibility", "hidden"); | |
}); | |
} | |
} | |
function bootstrap() { | |
// draw the spiral | |
drawSpiral(); | |
d3.csv("up-data.csv", function (rows) { | |
loadData(rows); | |
}); | |
} | |
bootstrap(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment