Last active
September 17, 2018 15:45
-
-
Save zreese/d0cbf17b1400e2d2ebf132b6b14274c2 to your computer and use it in GitHub Desktop.
CRISPR Trendline
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
@import url(//fonts.googleapis.com/css?family=Karla); | |
svg { | |
font-family: Karla; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
fill: #000; | |
} | |
.axis .tick line { | |
stroke: rgba(0, 0, 0, 0.1); | |
} | |
.area { | |
stroke-width: 1; | |
} | |
.area.outer, | |
.legend .outer { | |
fill: rgba(230, 230, 255, 0.8); | |
stroke: rgba(216, 216, 255, 0.8); | |
} | |
.area.inner, | |
.legend .inner { | |
fill: rgba(127, 127, 255, 0.8); | |
stroke: rgba(96, 96, 255, 0.8); | |
} | |
.median-line, | |
.legend .median-line { | |
fill: none; | |
stroke: #000; | |
stroke-width: 3; | |
} | |
.legend .legend-bg { | |
fill: rgba(0, 0, 0, 0.5); | |
stroke: rgba(0, 0, 0, 0.5); | |
} | |
.marker.client .marker-bg, | |
.marker.client path { | |
fill: rgba(255, 127, 0, 0.8); | |
stroke: rgba(255, 127, 0, 0.8); | |
stroke-width: 3; | |
} | |
.marker.server .marker-bg, | |
.marker.server path { | |
fill: rgba(0, 153, 51, 0.8); | |
stroke: rgba(0, 153, 51, 0.8); | |
stroke-width: 3; | |
} | |
.marker path { | |
fill: none; | |
} | |
.legend text, | |
.marker text { | |
fill: #fff; | |
font-weight: bold; | |
} | |
.marker text { | |
text-anchor: middle; | |
} |
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
function addAxesAndLegend (svg, xAxis, yAxis, margin, chartWidth, chartHeight) { | |
var legendWidth = 200, | |
legendHeight = 100; | |
// clipping to make sure nothing appears behind legend | |
svg.append('clipPath') | |
.attr('id', 'axes-clip') | |
.append('polygon') | |
.attr('points', (-margin.left) + ',' + (-margin.top) + ' ' + | |
(chartWidth - legendWidth - 1) + ',' + (-margin.top) + ' ' + | |
(chartWidth - legendWidth - 1) + ',' + legendHeight + ' ' + | |
(chartWidth + margin.right) + ',' + legendHeight + ' ' + | |
(chartWidth + margin.right) + ',' + (chartHeight + margin.bottom) + ' ' + | |
(-margin.left) + ',' + (chartHeight + margin.bottom)); | |
var axes = svg.append('g') | |
.attr('clip-path', 'url(#axes-clip)'); | |
axes.append('g') | |
.attr('class', 'x axis') | |
.attr('transform', 'translate(0,' + chartHeight + ')') | |
.call(xAxis); | |
axes.append('g') | |
.attr('class', 'y axis') | |
.call(yAxis) | |
.append('text') | |
.attr('transform', 'rotate(-90)') | |
.attr('y', 6) | |
.attr('dy', '.71em') | |
.style('text-anchor', 'end') | |
.text('Time (s)'); | |
var legend = svg.append('g') | |
.attr('class', 'legend') | |
.attr('transform', 'translate(' + (chartWidth - legendWidth) + ', 0)'); | |
legend.append('rect') | |
.attr('class', 'legend-bg') | |
.attr('width', legendWidth) | |
.attr('height', legendHeight); | |
legend.append('rect') | |
.attr('class', 'outer') | |
.attr('width', 75) | |
.attr('height', 20) | |
.attr('x', 10) | |
.attr('y', 10); | |
legend.append('text') | |
.attr('x', 115) | |
.attr('y', 25) | |
.text('5% - 95%'); | |
legend.append('rect') | |
.attr('class', 'inner') | |
.attr('width', 75) | |
.attr('height', 20) | |
.attr('x', 10) | |
.attr('y', 40); | |
legend.append('text') | |
.attr('x', 115) | |
.attr('y', 55) | |
.text('25% - 75%'); | |
legend.append('path') | |
.attr('class', 'median-line') | |
.attr('d', 'M10,80L85,80'); | |
legend.append('text') | |
.attr('x', 115) | |
.attr('y', 85) | |
.text('Median'); | |
} | |
function drawPaths (svg, data, x, y) { | |
var upperOuterArea = d3.svg.area() | |
.interpolate('basis') | |
.x (function (d) { return x(d.date) || 1; }) | |
.y0(function (d) { return y(d.pct95); }) | |
.y1(function (d) { return y(d.pct75); }); | |
var upperInnerArea = d3.svg.area() | |
.interpolate('basis') | |
.x (function (d) { return x(d.date) || 1; }) | |
.y0(function (d) { return y(d.pct75); }) | |
.y1(function (d) { return y(d.pct50); }); | |
var medianLine = d3.svg.line() | |
.interpolate('basis') | |
.x(function (d) { return x(d.date); }) | |
.y(function (d) { return y(d.pct50); }); | |
var lowerInnerArea = d3.svg.area() | |
.interpolate('basis') | |
.x (function (d) { return x(d.date) || 1; }) | |
.y0(function (d) { return y(d.pct50); }) | |
.y1(function (d) { return y(d.pct25); }); | |
var lowerOuterArea = d3.svg.area() | |
.interpolate('basis') | |
.x (function (d) { return x(d.date) || 1; }) | |
.y0(function (d) { return y(d.pct25); }) | |
.y1(function (d) { return y(d.pct05); }); | |
svg.datum(data); | |
svg.append('path') | |
.attr('class', 'area upper outer') | |
.attr('d', upperOuterArea) | |
.attr('clip-path', 'url(#rect-clip)'); | |
svg.append('path') | |
.attr('class', 'area lower outer') | |
.attr('d', lowerOuterArea) | |
.attr('clip-path', 'url(#rect-clip)'); | |
svg.append('path') | |
.attr('class', 'area upper inner') | |
.attr('d', upperInnerArea) | |
.attr('clip-path', 'url(#rect-clip)'); | |
svg.append('path') | |
.attr('class', 'area lower inner') | |
.attr('d', lowerInnerArea) | |
.attr('clip-path', 'url(#rect-clip)'); | |
svg.append('path') | |
.attr('class', 'median-line') | |
.attr('d', medianLine) | |
.attr('clip-path', 'url(#rect-clip)'); | |
} | |
function addMarker (marker, svg, chartHeight, x) { | |
var radius = 32, | |
xPos = x(marker.date) - radius - 3, | |
yPosStart = chartHeight - radius - 3, | |
yPosEnd = (marker.type === 'Client' ? 80 : 160) + radius - 3; | |
var markerG = svg.append('g') | |
.attr('class', 'marker '+marker.type.toLowerCase()) | |
.attr('transform', 'translate(' + xPos + ', ' + yPosStart + ')') | |
.attr('opacity', 0); | |
markerG.transition() | |
.duration(1000) | |
.attr('transform', 'translate(' + xPos + ', ' + yPosEnd + ')') | |
.attr('opacity', 1); | |
markerG.append('path') | |
.attr('d', 'M' + radius + ',' + (chartHeight-yPosStart) + 'L' + radius + ',' + (chartHeight-yPosStart)) | |
.transition() | |
.duration(1000) | |
.attr('d', 'M' + radius + ',' + (chartHeight-yPosEnd) + 'L' + radius + ',' + (radius*2)); | |
markerG.append('circle') | |
.attr('class', 'marker-bg') | |
.attr('cx', radius) | |
.attr('cy', radius) | |
.attr('r', radius); | |
markerG.append('text') | |
.attr('x', radius) | |
.attr('y', radius*0.9) | |
.text(marker.type); | |
markerG.append('text') | |
.attr('x', radius) | |
.attr('y', radius*1.5) | |
.text(marker.version); | |
} | |
function startTransitions (svg, chartWidth, chartHeight, rectClip, markers, x) { | |
rectClip.transition() | |
.duration(1000*markers.length) | |
.attr('width', chartWidth); | |
markers.forEach(function (marker, i) { | |
setTimeout(function () { | |
addMarker(marker, svg, chartHeight, x); | |
}, 1000 + 500*i); | |
}); | |
} | |
function makeChart (data, markers) { | |
var svgWidth = 960, | |
svgHeight = 500, | |
margin = { top: 20, right: 20, bottom: 40, left: 40 }, | |
chartWidth = svgWidth - margin.left - margin.right, | |
chartHeight = svgHeight - margin.top - margin.bottom; | |
var x = d3.time.scale().range([0, chartWidth]) | |
.domain(d3.extent(data, function (d) { return d.date; })), | |
y = d3.scale.linear().range([chartHeight, 0]) | |
.domain([0, d3.max(data, function (d) { return d.pct95; })]); | |
var xAxis = d3.svg.axis().scale(x).orient('bottom') | |
.innerTickSize(-chartHeight).outerTickSize(0).tickPadding(10), | |
yAxis = d3.svg.axis().scale(y).orient('left') | |
.innerTickSize(-chartWidth).outerTickSize(0).tickPadding(10); | |
var svg = d3.select('body').append('svg') | |
.attr('width', svgWidth) | |
.attr('height', svgHeight) | |
.append('g') | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); | |
// clipping to start chart hidden and slide it in later | |
var rectClip = svg.append('clipPath') | |
.attr('id', 'rect-clip') | |
.append('rect') | |
.attr('width', 0) | |
.attr('height', chartHeight); | |
addAxesAndLegend(svg, xAxis, yAxis, margin, chartWidth, chartHeight); | |
drawPaths(svg, data, x, y); | |
startTransitions(svg, chartWidth, chartHeight, rectClip, markers, x); | |
} | |
var parseDate = d3.time.format('%Y-%m-%d').parse; | |
d3.json('data.json', function (error, rawData) { | |
if (error) { | |
console.error(error); | |
return; | |
} | |
var data = rawData.map(function (d) { | |
return { | |
date: parseDate(d.date), | |
pct05: d.pct05 / 1000, | |
pct25: d.pct25 / 1000, | |
pct50: d.pct50 / 1000, | |
pct75: d.pct75 / 1000, | |
pct95: d.pct95 / 1000 | |
}; | |
}); | |
d3.json('markers.json', function (error, markerData) { | |
if (error) { | |
console.error(error); | |
return; | |
} | |
var markers = markerData.map(function (marker) { | |
return { | |
date: parseDate(marker.date), | |
type: marker.type, | |
version: marker.version | |
}; | |
}); | |
makeChart(data, markers); | |
}); | |
}); |
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": "2014-08-01", | |
"pct05": 5350, | |
"pct25": 6756, | |
"pct50": 7819, | |
"pct75": 9284, | |
"pct95": 13835 | |
}, | |
{ | |
"date": "2014-08-02", | |
"pct05": 4439, | |
"pct25": 5584, | |
"pct50": 6554, | |
"pct75": 8016, | |
"pct95": 12765 | |
}, | |
{ | |
"date": "2014-08-03", | |
"pct05": 4247, | |
"pct25": 5419, | |
"pct50": 6332, | |
"pct75": 7754, | |
"pct95": 12236 | |
}, | |
{ | |
"date": "2014-08-04", | |
"pct05": 3293, | |
"pct25": 4414, | |
"pct50": 5191, | |
"pct75": 6491, | |
"pct95": 10325 | |
}, | |
{ | |
"date": "2014-08-05", | |
"pct05": 3942, | |
"pct25": 5134, | |
"pct50": 6069, | |
"pct75": 7501, | |
"pct95": 11685 | |
}, | |
{ | |
"date": "2014-08-06", | |
"pct05": 2744, | |
"pct25": 5508, | |
"pct50": 6879, | |
"pct75": 9221, | |
"pct95": 17239 | |
}, | |
{ | |
"date": "2014-08-07", | |
"pct05": 1807, | |
"pct25": 3019, | |
"pct50": 4119, | |
"pct75": 5656, | |
"pct95": 8851 | |
}, | |
{ | |
"date": "2014-08-08", | |
"pct05": 1855, | |
"pct25": 3386, | |
"pct50": 4473, | |
"pct75": 5915, | |
"pct95": 10580 | |
}, | |
{ | |
"date": "2014-08-09", | |
"pct05": 1830, | |
"pct25": 3202, | |
"pct50": 4233, | |
"pct75": 5559, | |
"pct95": 8930 | |
}, | |
{ | |
"date": "2014-08-10", | |
"pct05": 1828, | |
"pct25": 3195, | |
"pct50": 4304, | |
"pct75": 5482, | |
"pct95": 9189 | |
}, | |
{ | |
"date": "2014-08-11", | |
"pct05": 2246, | |
"pct25": 3929, | |
"pct50": 5326, | |
"pct75": 7077, | |
"pct95": 11648 | |
}, | |
{ | |
"date": "2014-08-12", | |
"pct05": 2051, | |
"pct25": 3662, | |
"pct50": 4849, | |
"pct75": 6194, | |
"pct95": 10078 | |
}, | |
{ | |
"date": "2014-08-13", | |
"pct05": 1700, | |
"pct25": 3075, | |
"pct50": 4068, | |
"pct75": 5259, | |
"pct95": 9789 | |
}, | |
{ | |
"date": "2014-08-14", | |
"pct05": 2161, | |
"pct25": 3891, | |
"pct50": 5262, | |
"pct75": 6924, | |
"pct95": 11612 | |
}, | |
{ | |
"date": "2014-08-15", | |
"pct05": 1765, | |
"pct25": 3190, | |
"pct50": 4388, | |
"pct75": 5822, | |
"pct95": 9433 | |
}, | |
{ | |
"date": "2014-08-16", | |
"pct05": 2036, | |
"pct25": 3756, | |
"pct50": 4775, | |
"pct75": 6158, | |
"pct95": 9999 | |
}, | |
{ | |
"date": "2014-08-17", | |
"pct05": 2079, | |
"pct25": 3561, | |
"pct50": 4753, | |
"pct75": 6124, | |
"pct95": 9807 | |
}, | |
{ | |
"date": "2014-08-18", | |
"pct05": 2108, | |
"pct25": 3576, | |
"pct50": 4818, | |
"pct75": 6344, | |
"pct95": 10235 | |
}, | |
{ | |
"date": "2014-08-19", | |
"pct05": 2143, | |
"pct25": 3792, | |
"pct50": 5073, | |
"pct75": 6772, | |
"pct95": 11338 | |
}, | |
{ | |
"date": "2014-08-20", | |
"pct05": 2086, | |
"pct25": 3801, | |
"pct50": 5073, | |
"pct75": 6688, | |
"pct95": 12394 | |
}, | |
{ | |
"date": "2014-08-21", | |
"pct05": 1767, | |
"pct25": 3253, | |
"pct50": 4282, | |
"pct75": 5563, | |
"pct95": 9167 | |
}, | |
{ | |
"date": "2014-08-22", | |
"pct05": 1756, | |
"pct25": 3047, | |
"pct50": 3950, | |
"pct75": 5006, | |
"pct95": 7948 | |
}, | |
{ | |
"date": "2014-08-23", | |
"pct05": 2123, | |
"pct25": 3755, | |
"pct50": 5173, | |
"pct75": 7243, | |
"pct95": 12338 | |
}, | |
{ | |
"date": "2014-08-24", | |
"pct05": 1967, | |
"pct25": 3404, | |
"pct50": 4529, | |
"pct75": 5970, | |
"pct95": 9897 | |
}, | |
{ | |
"date": "2014-08-25", | |
"pct05": 1537, | |
"pct25": 2612, | |
"pct50": 3394, | |
"pct75": 4279, | |
"pct95": 7104 | |
}, | |
{ | |
"date": "2014-08-26", | |
"pct05": 2182, | |
"pct25": 3958, | |
"pct50": 5505, | |
"pct75": 7642, | |
"pct95": 12707 | |
}, | |
{ | |
"date": "2014-08-27", | |
"pct05": 1932, | |
"pct25": 3366, | |
"pct50": 4526, | |
"pct75": 6086, | |
"pct95": 9930 | |
}, | |
{ | |
"date": "2014-08-28", | |
"pct05": 1268, | |
"pct25": 2344, | |
"pct50": 3256, | |
"pct75": 4215, | |
"pct95": 6673 | |
}, | |
{ | |
"date": "2014-08-29", | |
"pct05": 1225, | |
"pct25": 2239, | |
"pct50": 3033, | |
"pct75": 4111, | |
"pct95": 7601 | |
}, | |
{ | |
"date": "2014-08-30", | |
"pct05": 1393, | |
"pct25": 2432, | |
"pct50": 3417, | |
"pct75": 4710, | |
"pct95": 8798 | |
}, | |
{ | |
"date": "2014-08-31", | |
"pct05": 1175, | |
"pct25": 2020, | |
"pct50": 2768, | |
"pct75": 3889, | |
"pct95": 7744 | |
}, | |
{ | |
"date": "2014-09-01", | |
"pct05": 989, | |
"pct25": 1655, | |
"pct50": 2218, | |
"pct75": 3167, | |
"pct95": 6018 | |
}, | |
{ | |
"date": "2014-09-02", | |
"pct05": 1249, | |
"pct25": 2069, | |
"pct50": 2738, | |
"pct75": 3938, | |
"pct95": 7574 | |
}, | |
{ | |
"date": "2014-09-03", | |
"pct05": 936, | |
"pct25": 1510, | |
"pct50": 1968, | |
"pct75": 2700, | |
"pct95": 5215 | |
}, | |
{ | |
"date": "2014-09-04", | |
"pct05": 1264, | |
"pct25": 2039, | |
"pct50": 2657, | |
"pct75": 3646, | |
"pct95": 7042 | |
}, | |
{ | |
"date": "2014-09-05", | |
"pct05": 1305, | |
"pct25": 2106, | |
"pct50": 2745, | |
"pct75": 3766, | |
"pct95": 7273 | |
}, | |
{ | |
"date": "2014-09-06", | |
"pct05": 798, | |
"pct25": 1288, | |
"pct50": 1678, | |
"pct75": 2303, | |
"pct95": 4448 | |
}, | |
{ | |
"date": "2014-09-07", | |
"pct05": 1314, | |
"pct25": 2120, | |
"pct50": 2763, | |
"pct75": 3791, | |
"pct95": 7321 | |
}, | |
{ | |
"date": "2014-09-08", | |
"pct05": 1042, | |
"pct25": 1681, | |
"pct50": 2191, | |
"pct75": 3007, | |
"pct95": 5806 | |
} | |
] |
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"> | |
<title>Trend Chart (Area + Line)</title> | |
<link rel="stylesheet" href="app.css"> | |
</head> | |
<body> | |
</body> | |
<script src="http://d3js.org/d3.v3.js"></script> | |
<script src="app.js"></script> | |
</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": "2014-08-06", | |
"type": "Client", | |
"version": "Jennifer Doudna, Emmanuelle Charpentier, and Martin Jinek of the University of California, Berkeley, publish a landmark paper demonstrating the use of CRISPR/Cas9 to edit DNA at specific sites. (0 articles in the 14 days following the announcement)" | |
}, | |
{ | |
"date": "2014-08-20", | |
"type": "Client", | |
"version": "February 15, 2013 – Feng Zhang of Harvard University publishes a paper outlining the use of CRISPR to edit the genomes of both mice and humans. (0 articles)" | |
}, | |
{ | |
"date": "2014-08-27", | |
"type": "Server", | |
"version": "3.5" | |
}, | |
{ | |
"date": "2014-09-03", | |
"type": "Client", | |
"version": "2.2" | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment