This stacked bar chart is constructed from a CSV file storing the populations of different states by age group. The chart employs conventional margins and a number of D3 features:
xxxxxxxxxx
<style>
.axis .domain {
display: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.05)
.align(0.1);
var y = d3.scaleLinear()
.rangeRound([0, height]);
// var z = d3.scaleOrdinal(d3.schemeAccent);
var z = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var mouseover_text_size = 15;
var date_format = d3.timeFormat("%B %d, %Y")
var int_format = d3.format("02")
d3.csv("data.csv", function(d, i, columns) {
// Format data
//console.log(d);
if (typeof d["start"] == "undefined" || typeof d["end"] == "undefined") {
return null
}
//for (i = 0, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]];
var start_date = new Date(d.start * 1000)
var end_date = new Date(d.end * 1000)
d.day = new Date(start_date.getFullYear(), start_date.getMonth(), start_date.getDate())
d.total = d.end - d.start;
d.start_hour = start_date.getHours()
d.start_minutes = start_date.getMinutes()
d.start_time_of_day = d.start_hour * 60 + d.start_minutes
d.end_hour = end_date.getHours()
d.end_minutes = end_date.getMinutes()
d.end_time_of_day = d.end_hour * 60 + d.end_minutes
return d;
}, function(error, data) {
if (error) throw error;
//var keys = data.columns.slice(1);
var tasks = []
for(var k in data) {
if (k != "columns")
tasks[data[k].activity] = true
}
tasks = Object.keys(tasks)
//console.log(tasks)
var keys = []
for(var k in data) {
if (k != "columns")
keys[data[k].day] = true
}
keys = Object.keys(keys)
//data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.day; }))
//console.log(data)
//console.log(d3.min(data, function(d) {return d.start_time_of_day}))
//console.log(d3.max(data, function(d) { return d.end_time_of_day; }))
//y.domain([d3.min(data, function(d) {return d.start_time_of_day}), d3.max(data, function(d) { return d.end_time_of_day; })]).nice();
y.domain([450, 1170])
z.domain(tasks);
g.append("g")
.selectAll("g")
.data(d3.stack().keys(keys)(data))
.enter().append("g")
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("fill", function(d) { return z(d.data.activity); })
.attr("x", function(d) { return x(d.data.day); })
.attr("y", function(d) { return y(d.data.start_time_of_day); })
.attr("height", function(d) { /*console.log(d);*/return y(d.data.end_time_of_day) - y(d.data.start_time_of_day); })
.attr("width", x.bandwidth())
.on("mouseover", handle_mouseover)
.on("mouseout", handle_mouseout);
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickFormat(date_format));
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).tickValues(d3.range(450, 1170,30)).tickFormat(function (d) {return int_format(parseInt(d / 60)) +":"+ int_format(parseInt(d % 60))}))
//.call(d3.axisLeft(y).ticks(null, "s"))
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(tasks.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) { return d; });
});
function handle_mouseover(rect_d) {
var parent = d3.select(this.parentNode);
d3.select(this)
.attr("fill", function(d) {
return d3.rgb(z(d.data.activity)).brighter(0.25);
})
.attr("stroke-width", "2px")
.attr("stroke", function(d){
return d3.rgb(z(d.data.activity)).brighter(0.25);
})
parent.append("text")
.attr("x", function() { return x(rect_d.data.day) + x.bandwidth() / 2 })
.attr("y", function() {
return y(rect_d.data.end_time_of_day) + (y(rect_d.data.start_time_of_day) - y(rect_d.data.end_time_of_day)) / 2 - mouseover_text_size * 0.6;
})
.classed("mouseover_text", true)
.style("font-size", mouseover_text_size)
.style("text-anchor", "middle")
.text(function() {
return int_format(rect_d.data.start_hour) + "h" + int_format(rect_d.data.start_minutes) +
"-" +
int_format(rect_d.data.end_hour) + "h" + int_format(rect_d.data.end_minutes)
})
.attr("pointer-events", "none")
parent.append("text")
.attr("x", function() { return x(rect_d.data.day) + x.bandwidth() / 2 })
.attr("y", function() {
return y(rect_d.data.end_time_of_day) + (y(rect_d.data.start_time_of_day) - y(rect_d.data.end_time_of_day)) / 2 + mouseover_text_size * 0.6;
})
.classed("mouseover_text", true)
.style("font-size", mouseover_text_size)
.style("text-anchor", "middle")
.text(function() {
return rect_d.data.activity
})
.attr("pointer-events", "none")
}
function handle_mouseout() {
d3.select(this)
.attr("fill", function(d) {return z(d.data.activity);})
.attr("stroke-width", "1px")
d3.selectAll("text.mouseover_text").remove()
}
</script>
https://d3js.org/d3.v4.min.js