var data = [{
"State": "AL",
"Under 5 Years": 52,
"5 to 13 Years": 29,
"14 to 17 Years": 10
},
{
"State": "AK",
"Under 5 Years": 56,
"5 to 13 Years": 21,
"14 to 17 Years": 20
},
{
"State": "AZ",
"Under 5 Years": 28,
"5 to 13 Years": 62,
"14 to 17 Years": 15
},
{
"State": "AR",
"Under 5 Years": 43,
"5 to 13 Years": 17,
"14 to 17 Years": 20
},
{
"State": "CA",
"Under 5 Years": 49,
"5 to 13 Years": 15,
"14 to 17 Years": 30
},
{
"State": "CO",
"Under 5 Years": 87,
"5 to 13 Years": 1,
"14 to 17 Years": 11
}
];
var keys = Object.keys(data[0]).slice(2);
var states = [...new Set(data.map(d => d.State))]
var yTicks = [0,1,2,3,4,5,6,7,8,9,10,30,50,70,100];
function getRange(from, to) {
const interpolator = d3.interpolate(from, to);
return new Array(yTicks.length)
.fill(undefined)
.map((_, i) => interpolator(i / yTicks.length));
}
var svg = d3.select("#chart"),
margin = {
top: 35,
left: 35,
bottom: 0,
right: 0
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand()
.range([margin.left, width - margin.right])
.padding(0.1)
var y = d3.scaleLinear()
.range(getRange(height - margin.bottom, margin.top))
.domain(yTicks)
var xAxis = svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.attr("class", "x-axis")
var yAxis = svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.attr("class", "y-axis")
var z = d3.scaleOrdinal()
.range(["steelblue", "darkorange", "lightblue"])
.domain(keys);
data.forEach(function(d) {
d.total = d3.sum(keys, k => +d[k])
return d
});
svg.selectAll(".y-axis")
.call(d3.axisLeft(y).tickValues(yTicks))
data.sort((a, b) => states.indexOf(a.State) - states.indexOf(b.State))
x.domain(data.map(d => d.State));
svg.selectAll(".x-axis")
.call(d3.axisBottom(x).tickSizeOuter(0))
var group = svg.selectAll("g.layer")
.data(d3.stack().keys(keys)(data), d => d.key)
group.exit().remove()
group.enter().append("g")
.classed("layer", true)
.attr("fill", d => z(d.key));
var bars = svg.selectAll("g.layer").selectAll("rect")
.data(d => d, e => e.data.State);
bars.exit().remove()
bars.enter().append("rect")
.attr("width", x.bandwidth())
.merge(bars)
.attr("x", d => x(d.data.State))
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
var text = svg.selectAll(".text")
.data(data, d => d.State);
text.exit().remove()
text.enter().append("text")
.attr("class", "text")
.attr("text-anchor", "middle")
.merge(text)
.attr("x", d => x(d.State) + x.bandwidth() / 2)
.attr("y", d => y(d.total) - 5)
.text(d => d.total)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
<svg id="chart" width="650" height="400"></svg>