Skip to content

Instantly share code, notes, and snippets.

@rjweise
Last active August 29, 2015 14:20
Show Gist options
  • Save rjweise/fc753c2a499080b56868 to your computer and use it in GitHub Desktop.
Save rjweise/fc753c2a499080b56868 to your computer and use it in GitHub Desktop.
Personal project: 10,000 hours tracking
year mintotalhrs maxtotalhrs MinCum MaxCum minttlhrs maxttlhrs mincumu maxcumu
1998 388.2666667 499.2 388.2666667 499.2 388.3 499.2 388.3 499.2
1999 776.5333333 998.4 1164.8 1497.6 863.2 1085.1 1251.5 1584.3
2000 260 520 1511.466667 2104.266667 260.0 520.0 1511.5 2104.3
2001 832 1331.2 2343.466667 3435.466667 832.0 1331.2 2343.5 3435.5
2002 998.4 1331.2 3341.866667 4766.666667 998.4 1331.2 3341.9 4766.7
2003 998.4 1331.2 4340.266667 6097.866667 998.4 1331.2 4340.3 6097.9
2004 998.4 1331.2 5338.666667 7429.066667 998.4 1331.2 5338.7 7429.1
2005 998.4 1331.2 6337.066667 8760.266667 998.4 1331.2 6337.1 8760.3
2006 384 512 6721.066667 9272.266667 384.0 512.0 6721.1 9272.3
2007 832 1164.8 7553.066667 10437.06667 832.0 1164.8 7553.1 10437.1
2008 208 291.2 7761.066667 10728.26667 849.0 1186.6 8402.1 11623.7
2009 832 1164.8 9234.053333 12788.50667 919.4 1277.1 9321.4 12900.8
2010 624 873.6 9945.413333 13774.42667 711.4 985.9 10032.8 13886.7
2011 624 873.6 10656.77333 14760.34667 711.4 985.9 10744.1 14872.7
2012 624 1019.2 11368.13333 15891.86667 624.0 1019.2 11368.1 15891.9
2013 104 169.8666667 11472.13333 16061.73333 459.8 974.9 11827.9 16866.8
2014 182 356.72 12009.9 17223.5 355.3 793.5 12183.2 17660.3
2015 104 291.2 12287.23333 17951.5 343.1 566.8 12526.3 18227.1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>The 10,000 hour rule for data visualization - RJ Weise on NoTime2Read</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
body {
background-color: rgb(253, 232, 221);
font-family: Helvetica, Arial, sans-serif, Georgia, serif;
width: 100%;
margin: 10px, 10px, 10px, 10px;
color: black;
}
h1 {
font-size: 24px;
font-family: Helvetica, sans-serif;
color: rgb(90, 90, 90);
}
#Header {
width: 90%;
}
p {
font-size: 14px;
font-family: Georgia, serif;
max-width: 90%;
word-wrap: break-word;
}
#logo {
width: 25px;
position: fixed;
top: 0;
right: 0;
}
svg {
background-color: rgb(253, 232, 221);
font-size: 14px;
font-family: Georgia, serif;
margin-top: 20px;
}
path:hover {
stroke: rgb(242,107,33);
}
rect:hover {
fill: rgb(242,107,33);
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: Georgia, sans-serif;
font-size: 11px;
stroke: none;
fill: black;
}
.label {
font-size: 11px;
font-family: Georgia;
stroke: none;
fill: black;
}
</style>
</head>
<body>
<h1 ID="Header">The 10,000 hour rule on my data visualization experience</h1>
<div ID="logo">
<img src="http://rjweise.neocities.org/logoRJW2.png" alt="Logo NT2R RJ" style="width:25px;height:25px">
</div>
<p>After taking part in the Information Visualization MOOC by the University of Indiana, and the D3 MOOC at the Knight Center for Journalism I got curious how many hours I have spent in my career on work related to data visualization.
I created a simple table in which I estimated my experience in number of hours worked per year, the productivity on the job (actual work excluding meetings, flex days, training and such) and what percentage of these productive hours were applicable to count towards data visualization.<br /><br />
The following graph shows three cumulative-hours-lines: one for a bare minimum estimate, one based on generous estimates, and a last line showing the average between the two. The bar graph at the bottom shows the average (non-cumulative) hours per year.</p>
<script type="text/javascript">
//Majority of code based on Knight D3 MOOC, module 6, example 4, by @alignedleft (Scott Murray)
// Setting Dimensions and padding of the SVG
var w = 960;
var h = 600;
var padding = [ 20, 120, 20, 60 ]; //Top, right, bottom, left
// Setting up date formatting and years
var dateFormat = d3.time.format("%Y");
// Setting up scales (range is pixels)
var xScale = d3.time.scale()
.range([ padding[3], w - padding[1] - 30]);
var yScale = d3.scale.linear()
.range([ padding[0], h - padding[2] ]);
// Configuring the axis generators
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(15)
.tickFormat(function(d) {
return dateFormat(d);
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(20);
// Configuring the minimum value line generator
var linemin = d3.svg.line()
.x(function(d) {
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale(d.mincumu);
});
// Configuring the maximum value line generator
var linemax = d3.svg.line()
.x(function(d) {
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale(d.maxcumu);
});
// Configuring a reference line generator
var lineref = d3.svg.line()
.x(function(d) {
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale(10000);
});
//configuring a reference area for 10,000 hours
var arearef = d3.svg.area()
.x(function(d) {
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale(10000);
})
.y0(function(d) {
return yScale(0);
});
// Configuring an average line generator
var lineavg = d3.svg.line()
.x(function(d) {
return xScale(dateFormat.parse(d.year));
})
.y(function(d) {
return yScale((+d.maxcumu + +d.mincumu)/2)
//, console.log((+d.maxcumu + +d.mincumu) / 2)
;
});
// Creating the empty SVG canvas
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Loading the 10000hours data - mincumu
d3.csv("10000hoursValuesYear.csv", function(Dataset) {
// Using the data to determine the min and max values, for setting scale domains (domains is data)
xScale.domain([
d3.min(Dataset, function(d) {
return dateFormat.parse(d.year);
}),
d3.max(Dataset, function(d) {
return dateFormat.parse(d.year)
//, console.log(d.year)
;
})
]);
yScale.domain([
d3.max(Dataset, function(d) {
return +d.maxcumu +2000
//, console.log(d.maxcumu)
;
}),
0
]);
//Adding circles at intersections
// var circles = svg.selectAll("circle")
// .data(Dataset)
// .enter()
// .append("circle");
// circles.attr("cx", function(d) {
// return xScale(dateFormat.parse(d.year));
// })
// .attr("cy", function(d) {
// return yScale(d.maxcumu);
// })
// .attr("r", 4)
// .attr("fill", "steelblue")
// .attr("opacity", "0.7")
// .append("title")
// .text(function(d) {
// return d.year + "'s life satisfaction score is " + d.mincumu + ", and " + d.maxcumu + "% report good health";
// });
//Append the reference area for 10,000 hours to the svg
svg.data([Dataset])
.append("path")
.attr("d", arearef)
.attr("fill", "dimgray")
.attr("opacity", 0.1)
.append("title")
//.text("10.000 hours reference line")
;
//Adding bars for average of min. and max total hours
var rects = svg.selectAll("rect")
.data(Dataset)
.enter()
.append("rect");
rects.attr("x", function(d) {
return xScale(dateFormat.parse(d.year)) - 5;})
.attr("y", function(d) {
return yScale(((+d.minttlhrs + +d.maxttlhrs) / 2));})
.attr("height", function(d) {
return (h - padding[2] - yScale(((+d.minttlhrs + +d.maxttlhrs) / 2)));
})
.attr("width", "10")
.attr("fill", "rgb(242,107,33)")
.append("title")
.text(function(d) {
return "Avg. hours (" + d.year + "): " + d3.round(((+d.minttlhrs + +d.maxttlhrs) / 2),1)+ ")";
})
// .text(function(d) {
// return yScale(((+d.minttlhrs + +d.maxttlhrs) / 2));
// })
;
//Set stroke-width of the reference line
var REFsw = 3;
//Append the reference line to the svg
svg.data([Dataset])
.append("path")
.attr("d", lineref)
.attr("fill", "none")
.style("stroke-dasharray", ("5, 4"))
.attr("stroke", "grey")
.attr("stroke-width", REFsw)
.attr("opacity", 0.5)
.append("title")
.text("10.000 hours reference line")
;
//Append the min. value line to the svg
svg.data([ Dataset ])
.append("path")
//.attr("class", "mincumu")
.attr("d", linemin)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2)
.attr("opacity", 0.7)
.append("title")
.text("Minimum number of hours");
//Append the max. value line to the svg
svg.data([ Dataset ])
.append("path")
//.attr("class", "maxcumu")
.attr("d", linemax)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2)
.attr("opacity", 0.7)
.append("title")
.text("Maximum number of hours");
//Append the reference line to the svg
svg.data([ Dataset ])
.append("path")
//.attr("class", "maxcumu")
.attr("d", lineavg)
.attr("fill", "none")
.style("stroke-dasharray", ("10, 5"))
.attr("stroke", "rgb(242,107,33)")
.attr("stroke-width", 2)
.attr("opacity", 0.5)
.append("title")
.text("Average number of hours");
//Axes
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding[2]) + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", w-padding[1] + 10)
// .attr("x", w-padding[1])
.attr("y", -10)
//.style("text-anchor", "end")
.style("font-size", "20")
//.text("Years");
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + (padding[3]) + ",0)")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("y", padding[2]-5)
.style("text-anchor", "left")
.style("font-size", "20")
.text("Hours");
//line labels
//calculating the values for min., max., average (nr.) and average (string) line labels
var MAXdisp = d3.format(",")(d3.round((Dataset[17].maxcumu),1));
var MINdisp = d3.format(",")(d3.round((Dataset[17].mincumu),1));
var AVGcalc = d3.round((((( +Dataset[17].maxcumu + +Dataset[17].mincumu) / 2))));
var AVGdisp = d3.format(",")(d3.round((((( +Dataset[17].maxcumu + +Dataset[17].mincumu) / 2))),1));
//Appending labels to end of min., max. and average lines
svg.append("text")
.attr("class", "label")
.attr("x", w - padding[1] - 15)
.attr("y", yScale(Dataset[17].maxcumu))
.text(function(d) {
return (MAXdisp + " cum. hours (max.)");
});
svg.append("text")
.attr("class", "label")
.attr("x", w - padding[1] - 15)
.attr("y", yScale(Dataset[17].mincumu))
.text(function(d) {
return (MINdisp + " cum. hours (min.)");
});
svg.append("text")
.attr("class", "label")
.attr("x", w - padding[1] - 15)
.attr("y", yScale(AVGcalc))
.text(function(d) {
return (AVGdisp + " cum. hours (avg.)");
});
//Adding label for 10,000 hours
svg.append("text")
.attr("class", "label")
.attr("x", w - padding[1] - 15 )
.attr("y", yScale(10000) + REFsw/4)
.text("10,000 hours");
;
//Adding some annotation where lines cross 10,000 ref. line
// svg.append("text")
// .attr("class", "label")
// .attr("width", "100px")
// .attr("x", 610)
// .attr("y", yScale(10000))
// .text("Minimum estimate crossess reference line in 2010");
// ;
}); //End Dataset data load function
</script>
<p><br />From Wikipedia: "<i>Gladwell repeatedly mentions the "10,000-Hour Rule", claiming that the key to success in any field is, to a large extent, a matter of practicing a specific task for a total of around 10,000 hours.</i></p>
</body>
</html>
Based on a Google Sheet file (https://docs.google.com/spreadsheets/d/1eCYmMgMAOuB2ExfNUTr2kEDKTrDiudrFj-vQymhY8_Y/edit?usp=sharing) I estimated the number of hours I spent on data visualizations related activities at work, on courses, reading books, etc.
This visualization uses D3 to represent these hours: a minimal line based on a "at least" estimate, and a maximal line where I was generous in my estimations.
The third line, showing the average, is calculated.
UPDATE May 6
I added labels (which took me forever) and did a little cleaning up to make it look a bit nicer. Nothing too fancy.
Can't believe how much time I spent on the labels. And they are really not exciting or special. Just had a hard time figuring out how to append them to the svg. Learnt that it doesn't always work to re-use other examples.
Also learnt some more about using classes, and formatting of numbers through using vars, so in the end all useful stuff.
UPDATE May 10
Worked more on the bar graph at the bottom, changed some colouring and other visual details.
Status: IN PROGRESS
Created: May 4th 2015
Last updated: May 10th 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment