Skip to content

Instantly share code, notes, and snippets.

@areologist
Last active January 4, 2018 19:47
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 areologist/7780290de76d884734846515505240cd to your computer and use it in GitHub Desktop.
Save areologist/7780290de76d884734846515505240cd to your computer and use it in GitHub Desktop.
stacked bar experiment
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.chart {
background-color: #f6fafc;
border: 1px solid #333;
}
.bar {
opacity: 0.7;
}
.bar:hover {
opacity: 1;
}
.tick text {
font-size: 10px;
}
</style>
</head>
<body>
<div class="chart"></div>
<script>
const margin = { top: 25, right: 35, bottom: 100, left: 50 };
const width = 720 - margin.left - margin.right;
const height = 450 - margin.top - margin.bottom;
const fullWidth = width + margin.left + margin.right;
const fullHeight = height + margin.top + margin.bottom;
const studentsBySubject = [
{count: 63, subject: 'mathematics', group: 'freshman'},
{count: 19, subject: 'mathematics', group: 'sophomore'},
{count: 45, subject: 'mathematics', group: 'junior'},
{count: 94, subject: 'mathematics', group: 'senior'},
{count: 82, subject: 'geography', group: 'freshman'},
{count: 8, subject: 'geography', group: 'sophomore'},
{count: 46, subject: 'geography', group: 'junior'},
{count: 60, subject: 'geography', group: 'senior'},
{count: 74, subject: 'spelling', group: 'freshman'},
{count: 74, subject: 'spelling', group: 'sophomore'},
{count: 74, subject: 'spelling', group: 'junior'},
{count: 74, subject: 'spelling', group: 'senior'},
{count: 97, subject: 'reading', group: 'freshman'},
{count: 12, subject: 'reading', group: 'sophomore'},
{count: 34, subject: 'reading', group: 'junior'},
{count: 17, subject: 'reading', group: 'senior'},
{count: 52, subject: 'science', group: 'freshman'},
{count: 52, subject: 'science', group: 'sophomore'},
{count: 52, subject: 'science', group: 'junior'},
{count: 52, subject: 'science', group: 'senior'}
];
const colors = ['#333', '#666', '#999', '#ccc'];
const groupCount = 4;
const data = studentsBySubject;
const subjects = _.groupBy(data, 'subject');
const svg = d3.select('.chart')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
const xScale = d3.scaleBand()
.padding(0.2)
.domain(data.map(d => d.subject))
.range([0, width]);
const yMax = Math
.max(...Object
.values(subjects)
.map(m => m.map(x => x.count)
.reduce((acc, x) => acc + x, 0)
)
);
const yScale = d3.scaleLinear()
.domain([0, yMax])
.range([height, 0]);
const yAxis = d3.axisLeft(yScale)
.ticks(10);
svg.append('g')
.call(yAxis);
const xAxis = d3.axisBottom(xScale);
svg.append('g')
.attr('transform', `translate(0, ${height})`)
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('transform', 'rotate(-45)');
const bars = svg.selectAll('.bar')
.data(data)
.enter()
.append('g')
.attr('class', 'bar');
const segmentY = (d, i, nodes) =>
i % groupCount === 0 ?
yScale(d.count) :
yScale(d.count) - (height - parseFloat(
nodes[i-1].attributes.y.value));
bars
.append('rect')
.attr('x', d => xScale(d.subject))
.attr('y', segmentY)
.attr('width', xScale.bandwidth())
.attr('height', d => height - yScale(d.count))
.attr('class', 'segment')
.attr('fill', (d, i) => colors[i % 4]);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment