forked from micahstubbs's block: vertical boxplot
forked from anonymous's block: vertical boxplot
forked from jzgit's block: vertical boxplot
forked from jzgit's block: vertical boxplot
forked from anonymous's block: mastery over time
license: mit |
forked from micahstubbs's block: vertical boxplot
forked from anonymous's block: vertical boxplot
forked from jzgit's block: vertical boxplot
forked from jzgit's block: vertical boxplot
forked from anonymous's block: mastery over time
date | score | error | |
---|---|---|---|
2016-12-20 | -0.3 | 0.1 | |
2016-12-21 | -0.2 | 0.2 | |
2016-12-22 | 0.2 | 0.3 | |
2016-12-23 | 0.2 | 0.4 | |
2016-12-24 | 0.2 | 0.5 | |
2016-12-25 | 0.2 | 0.1 | |
2016-12-26 | 0.3 | 0.2 | |
2016-12-27 | 0.25 | 0.3 | |
2016-12-28 | 0.5 | 0.4 | |
2016-12-29 | 0.4 | 0.5 | |
2016-12-30 | 0.5 | 0.1 | |
2016-12-31 | 0.35 | 0.2 | |
2017-1-1 | 0.0 | 0.3 | |
2017-1-2 | 0.3 | 0.4 | |
2017-1-3 | -0.2 | 0.5 | |
2017-1-4 | -0.1 | 0.1 | |
2017-1-5 | 0.0 | 0.2 | |
2017-1-6 | 0.1 | 0.3 | |
2017-1-7 | 0.2 | 0.4 | |
2017-1-8 | 0.3 | 0.5 | |
2017-1-9 | 0.3 | 0.1 | |
2017-1-10 | 0.3 | 0.2 | |
2017-1-11 | 0.2 | 0.3 | |
2017-1-12 | 0.1 | 0.4 | |
2017-1-13 | 0.0 | 0.5 | |
2017-1-14 | -0.2 | 0.1 | |
2017-1-15 | -0.3 | 0.2 | |
2017-1-16 | -0.4 | 0.3 | |
2017-1-17 | -0.3 | 0.4 | |
2017-1-18 | 0.1 | 0.5 |
<html> | |
<head> | |
<title>vertical boxplot</title> | |
<meta charset="utf-8" /> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" type="text/JavaScript"></script> | |
</head> | |
<style> | |
svg { | |
border: 1px solid gray; | |
background: #3de7b3; | |
} | |
line { | |
shape-rendering: crispEdges; | |
stroke: #000000; | |
} | |
line.minor { | |
stroke: #777777; | |
stroke-dasharray: 2,2; | |
} | |
path.domain { | |
fill: none; | |
stroke: black; | |
} | |
</style> | |
<body> | |
</body> | |
<script> | |
d3.csv("data.csv", boxplot) | |
function boxplot(data) { | |
const height = 300; | |
const width = 900; | |
const daysLength = 30; | |
const margin = { | |
'top': 20, | |
'bottom': 20, | |
'left': 20, | |
'right': 30 | |
} | |
const xAxisLength = width - margin.left - margin.right; | |
const yAxisLength = height - margin.top - margin.bottom; | |
d3.select("body") | |
.append("svg") | |
.attr("height", height) | |
.attr("width", width); | |
const days = data.map(d => d.date).slice(-daysLength); | |
const startDay = new Date(days[0]); | |
const endDay = new Date(days[days.length - 1]); | |
const maxScoreValue = 2; | |
const minScoreValue = -2; | |
const score = [minScoreValue, maxScoreValue]; | |
// --- scales --- | |
const xScale = d3.time.scale() | |
.domain([ | |
startDay, | |
endDay, | |
]) | |
.range([ | |
0, | |
xAxisLength | |
]); | |
const yScale = d3.scale.linear() | |
.domain(score) // 0% to 100% | |
.range([ | |
yAxisLength, | |
0 | |
]); | |
// --- axis --- | |
const xAxis = d3.svg.axis() | |
.scale(xScale) | |
.orient("bottom") | |
.tickSize(-5) | |
.ticks(daysLength) | |
.tickFormat(d3.time.format("")); | |
// .tickValues(days); | |
const yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient("right") | |
.ticks(18) | |
.tickSize(-10) | |
// .tickSubdivide(true); // deprecated, I know | |
// --- render axis --- | |
const xAxisTransform = `translate(${margin.left},${height/2})`; | |
d3.select("svg").append("g") | |
.attr("transform", xAxisTransform) | |
.attr("id", "xAxisG") | |
.call(xAxis); | |
const yAxisTransform = `translate(${width-margin.left},${margin.top})`; | |
d3.select("svg").append("g") | |
.attr("transform", yAxisTransform) | |
.attr("id", "yAxisG") | |
// .call(yAxis); | |
// --- set x y for data --- | |
const dataCoords = data.map(d => { | |
d.x = xScale(new Date(d.date)); | |
d.y = yScale(d.score); | |
return d; | |
}); | |
// console.log(dataCoords, 'dataCoords'); | |
// --- render shapes --- | |
d3.select("svg").selectAll("g.box") | |
.data(dataCoords) | |
.enter() | |
.append("g") | |
.attr("class", "box") | |
.attr("transform", function(d){ | |
return `translate(${(margin.left)},${(margin.top)})`; | |
}) | |
.each(function(d,i){ | |
const xLineCoord = (xScale(new Date(d.date))); | |
const lineWidth = 6; | |
if (i === dataCoords.length - 1) { | |
d3.select(this) | |
.append("line") | |
.attr("class", "max") | |
.attr("x1", (xLineCoord - lineWidth/2) + 15) | |
.attr("x2", (xLineCoord + lineWidth/2) + 15) | |
.attr("y1", yScale(maxScoreValue)) | |
.attr("y2", yScale(maxScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "median") | |
.attr("x1", (xLineCoord - lineWidth/2) + 15) | |
.attr("x2", (xLineCoord + lineWidth/2) + 15) | |
.attr("y1", yScale(0)) | |
.attr("y2", yScale(0)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "min") | |
.attr("x1", (xLineCoord - lineWidth/2) + 15) | |
.attr("x2", (xLineCoord + lineWidth/2) + 15) | |
.attr("y1", yScale(minScoreValue)) | |
.attr("y2", yScale(minScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
} | |
d3.select(this) | |
.append("line") | |
.attr("class", "max") | |
.attr("x1", (xLineCoord - lineWidth/2) - 15) | |
.attr("x2", (xLineCoord + lineWidth/2) - 15) | |
.attr("y1", yScale(maxScoreValue)) | |
.attr("y2", yScale(maxScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "median") | |
.attr("x1", (xLineCoord - lineWidth/2) - 15) | |
.attr("x2", (xLineCoord + lineWidth/2) - 15) | |
.attr("y1", yScale(0)) | |
.attr("y2", yScale(0)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "min") | |
.attr("x1", (xLineCoord - lineWidth/2) - 15) | |
.attr("x2", (xLineCoord + lineWidth/2) - 15) | |
.attr("y1", yScale(minScoreValue)) | |
.attr("y2", yScale(minScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "max") | |
.attr("x1", xLineCoord - lineWidth/2) | |
.attr("x2", xLineCoord + lineWidth/2) | |
.attr("y1", yScale(maxScoreValue)) | |
.attr("y2", yScale(maxScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "median") | |
.attr("x1", xLineCoord - lineWidth/2) | |
.attr("x2", xLineCoord + lineWidth/2) | |
.attr("y1", yScale(0)) | |
.attr("y2", yScale(0)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
d3.select(this) | |
.append("line") | |
.attr("class", "min") | |
.attr("x1", xLineCoord - lineWidth/2) | |
.attr("x2", xLineCoord + lineWidth/2) | |
.attr("y1", yScale(minScoreValue)) | |
.attr("y2", yScale(minScoreValue)) | |
.style("stroke", "#ffffff") | |
.style("stroke-width", "1px"); | |
const widthRect = 6; | |
const heightRect = yScale(+d.score - +d.error) - yScale(+d.score + +d.error) | |
d3.select(this) | |
.append("rect") | |
.attr("class", "range") | |
.attr("width", widthRect) | |
.attr("x", (xScale(new Date(d.date))) - widthRect/2) | |
.attr("y", yScale(+d.score + +d.error)) | |
.attr('rx', 4) | |
.attr('ry', 4) | |
.attr("height", heightRect) | |
.style("fill", "#76eeca"); | |
const radius = 3; | |
d3.select(this) | |
.append("circle") | |
.attr("cx", (xScale(new Date(d.date)))) | |
.attr("cy", yScale(d.score)) | |
.attr("r", radius) | |
.style("fill", "white") | |
.style("stroke-width", "1px"); | |
}) | |
} | |
</script> | |
</footer> | |
</html> |