Built with blockbuilder.org
forked from jcnesci's block: Stacked Barchart with Transitions
forked from jcnesci's block: Stacked Barchart with Transitions - v3
license: mit |
Built with blockbuilder.org
forked from jcnesci's block: Stacked Barchart with Transitions
forked from jcnesci's block: Stacked Barchart with Transitions - v3
State | Under 5 Years | 5 to 13 Years | 14 to 17 Years | 18 to 24 Years | 25 to 44 Years | 45 to 64 Years | 65 Years and Over | |
---|---|---|---|---|---|---|---|---|
AL | 310504 | 552339 | 259034 | 450818 | 1231572 | 1215966 | 641667 | |
AK | 52083 | 85640 | 42153 | 74257 | 198724 | 183159 | 50277 | |
AZ | 515910 | 828669 | 362642 | 601943 | 1804762 | 1523681 | 862573 | |
AR | 202070 | 343207 | 157204 | 264160 | 754420 | 727124 | 407205 | |
CA | 2704659 | 4499890 | 2159981 | 3853788 | 10604510 | 8819342 | 4114496 | |
CO | 358280 | 587154 | 261701 | 466194 | 1464939 | 1290094 | 511094 | |
CT | 211637 | 403658 | 196918 | 325110 | 916955 | 968967 | 478007 | |
DE | 59319 | 99496 | 47414 | 84464 | 230183 | 230528 | 121688 | |
DC | 36352 | 50439 | 25225 | 75569 | 193557 | 140043 | 70648 | |
FL | 1140516 | 1938695 | 925060 | 1607297 | 4782119 | 4746856 | 3187797 | |
GA | 740521 | 1250460 | 557860 | 919876 | 2846985 | 2389018 | 981024 | |
HI | 87207 | 134025 | 64011 | 124834 | 356237 | 331817 | 190067 | |
ID | 121746 | 201192 | 89702 | 147606 | 406247 | 375173 | 182150 | |
IL | 894368 | 1558919 | 725973 | 1311479 | 3596343 | 3239173 | 1575308 | |
IN | 443089 | 780199 | 361393 | 605863 | 1724528 | 1647881 | 813839 | |
IA | 201321 | 345409 | 165883 | 306398 | 750505 | 788485 | 444554 | |
KS | 202529 | 342134 | 155822 | 293114 | 728166 | 713663 | 366706 | |
KY | 284601 | 493536 | 229927 | 381394 | 1179637 | 1134283 | 565867 | |
LA | 310716 | 542341 | 254916 | 471275 | 1162463 | 1128771 | 540314 | |
ME | 71459 | 133656 | 69752 | 112682 | 331809 | 397911 | 199187 | |
MD | 371787 | 651923 | 316873 | 543470 | 1556225 | 1513754 | 679565 | |
MA | 383568 | 701752 | 341713 | 665879 | 1782449 | 1751508 | 871098 | |
MI | 625526 | 1179503 | 585169 | 974480 | 2628322 | 2706100 | 1304322 | |
MN | 358471 | 606802 | 289371 | 507289 | 1416063 | 1391878 | 650519 | |
MS | 220813 | 371502 | 174405 | 305964 | 764203 | 730133 | 371598 | |
MO | 399450 | 690476 | 331543 | 560463 | 1569626 | 1554812 | 805235 | |
MT | 61114 | 106088 | 53156 | 95232 | 236297 | 278241 | 137312 | |
NE | 132092 | 215265 | 99638 | 186657 | 457177 | 451756 | 240847 | |
NV | 199175 | 325650 | 142976 | 212379 | 769913 | 653357 | 296717 | |
NH | 75297 | 144235 | 73826 | 119114 | 345109 | 388250 | 169978 | |
NJ | 557421 | 1011656 | 478505 | 769321 | 2379649 | 2335168 | 1150941 | |
NM | 148323 | 241326 | 112801 | 203097 | 517154 | 501604 | 260051 | |
NY | 1208495 | 2141490 | 1058031 | 1999120 | 5355235 | 5120254 | 2607672 | |
NC | 652823 | 1097890 | 492964 | 883397 | 2575603 | 2380685 | 1139052 | |
ND | 41896 | 67358 | 33794 | 82629 | 154913 | 166615 | 94276 | |
OH | 743750 | 1340492 | 646135 | 1081734 | 3019147 | 3083815 | 1570837 | |
OK | 266547 | 438926 | 200562 | 369916 | 957085 | 918688 | 490637 | |
OR | 243483 | 424167 | 199925 | 338162 | 1044056 | 1036269 | 503998 | |
PA | 737462 | 1345341 | 679201 | 1203944 | 3157759 | 3414001 | 1910571 | |
RI | 60934 | 111408 | 56198 | 114502 | 277779 | 282321 | 147646 | |
SC | 303024 | 517803 | 245400 | 438147 | 1193112 | 1186019 | 596295 | |
SD | 58566 | 94438 | 45305 | 82869 | 196738 | 210178 | 116100 | |
TN | 416334 | 725948 | 336312 | 550612 | 1719433 | 1646623 | 819626 | |
TX | 2027307 | 3277946 | 1420518 | 2454721 | 7017731 | 5656528 | 2472223 | |
UT | 268916 | 413034 | 167685 | 329585 | 772024 | 538978 | 246202 | |
VT | 32635 | 62538 | 33757 | 61679 | 155419 | 188593 | 86649 | |
VA | 522672 | 887525 | 413004 | 768475 | 2203286 | 2033550 | 940577 | |
WA | 433119 | 750274 | 357782 | 610378 | 1850983 | 1762811 | 783877 | |
WV | 105435 | 189649 | 91074 | 157989 | 470749 | 514505 | 285067 | |
WI | 362277 | 640286 | 311849 | 553914 | 1487457 | 1522038 | 750146 | |
WY | 38253 | 60890 | 29314 | 53980 | 137338 | 147279 | 65614 |
<!-- | |
Features: | |
- No object constancy (if same State column remains, should just move to new position) | |
- Exit and Enter transitions currently overlap (should be sequential instead) | |
- Transitions per rect, per column, are not currently staggered | |
--> | |
<!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.16.4/lodash.min.js"></script> | |
<style>s | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<script> | |
var margin = {top: 20, right: 20, bottom: 30, left: 40}, | |
outerWidth = 960, | |
outerHeight = 500, | |
width = outerWidth - margin.left - margin.right, | |
height = outerHeight - margin.top - margin.bottom, | |
svg = d3.select("body").append("svg") | |
.attr("width", outerWidth) | |
.attr("height", outerHeight), | |
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"), | |
data = undefined, | |
serie, | |
serieEnter, | |
rect, | |
rectEnter; | |
var x = d3.scaleBand() | |
.rangeRound([0, width]) | |
.padding(0.1) | |
.align(0.1); | |
var y = d3.scaleLinear() | |
.rangeRound([height, 0]); | |
var z = d3.scaleOrdinal() | |
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]); | |
var stack = d3.stack(); | |
d3.csv("data.csv", type, function(error, iData) { | |
if (error) throw error; | |
data = iData; | |
data.sort(function(a, b) { return b.total - a.total; }); | |
x.domain(data.map(function(d) { return d.State; })); | |
y.domain([0, d3.max(data, function(d) { return d.total; })]).nice(); | |
z.domain(data.columns.slice(1)); | |
// Button to generate new data. | |
g.append("rect") | |
.attr("class", "btn-update-data") | |
.attr("width", 60) | |
.attr("height", 20) | |
.attr("transform", "translate("+ (width-200) +", 0)") | |
.attr("fill", "red") | |
.on("click", function() { | |
updateChart(jumbleData(data), false); | |
}); | |
var legend = g.selectAll(".legend") | |
.data(data.columns.slice(1).reverse()) | |
.enter().append("g") | |
.attr("class", "legend") | |
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }) | |
.style("font", "10px sans-serif"); | |
legend.append("rect") | |
.attr("x", width - 18) | |
.attr("width", 18) | |
.attr("height", 18) | |
.attr("fill", z); | |
legend.append("text") | |
.attr("x", width - 24) | |
.attr("y", 9) | |
.attr("dy", ".35em") | |
.attr("text-anchor", "end") | |
.text(function(d) { return d; }); | |
updateChart(data, true); | |
}); | |
// Update the chart with the specified data. | |
function updateChart(iData, initializing) { | |
console.log("************* ENTER-updateChart") | |
console.log("iData", iData) | |
x.domain(iData.map(function(d) { return d.State; })); | |
y.domain([0, d3.max(iData, function(d) { return d.total; })]).nice(); | |
// ---------------------------------------------------------------- | |
// SERIE | |
// ---------------------------------------------------------------- | |
// SERIE ENTER ----------------------- | |
var stacks = stack.keys(iData.columns.slice(1))(iData); | |
console.log("stacks", stacks); | |
// flatten stacks array | |
var stackData = []; | |
for (var i = 0; i < stacks.length; i++) { | |
for (var j = 0; j < stacks[i].length; j++) { | |
stacks[i][j].key = stacks[i].key; | |
// var factor = Math.random() + 0.5; | |
// factor = factor <= 1 ? factor : factor - 1; | |
// var diff = Math.round(stacks[i][j][0] * factor); | |
// stacks[i][j][0] = stacks[i][j][0] - diff; | |
stackData.push(stacks[i][j]); | |
} | |
} | |
console.log("stackData", stackData); | |
if (initializing) { | |
// Parent bar | |
serieEnter = g.append("g").attr("class", "rects"); | |
} else { | |
serieEnter = g.select("g.rects"); | |
console.log("serieEnter", serieEnter); | |
rect = serieEnter.selectAll("rect.chart-rect") | |
.data(stackData, function(d){ return d.data.State; }); | |
rect.enter().append("rect") | |
.attr("class", "chart-rect") | |
.attr("state", function(d) {return d.data.State; }) | |
.attr("fill", function(d) { return z(d.key)}) | |
.attr("x", function(d) { return x(d.data.State); }) | |
.attr("y", function(d) { return y(d[1]); }) | |
.attr("width", x.bandwidth()) | |
.attr("height", 0) | |
.transition() | |
.duration(1000) | |
.attr("height", function(d) { return y(d[0]) - y(d[1]); }); | |
rect | |
.attr("state", function(d) {return d.data.State; }) | |
.attr("fill", function(d) { return z(d.key)}) | |
.attr("x", function(d) { return x(d.data.State); }) | |
.attr("y", function(d) { return y(d[1]); }) | |
.attr("width", x.bandwidth()) | |
.attr("height", 0) | |
.transition() | |
.duration(1000) | |
.attr("height", function(d) { return y(d[0]) - y(d[1]); }); | |
rect.exit() | |
.transition() | |
.duration(1000) | |
.attr("height", 0) | |
.remove(); | |
/* | |
// 1. exit | |
var exitTransition = d3.transition().each(function() { | |
rect.exit() | |
.transition().duration(1000) | |
.style("opacity", 0) | |
.remove(); | |
}); | |
// 2. update | |
console.log("update 1", exitTransition.transition()) | |
var updateTransition = exitTransition.transition().each(function() { | |
console.log("update", this) | |
rect | |
.attr("state", function(d) {return d.data.State; }) | |
.attr("fill", function(d) { return z(d.key)}) | |
.attr("x", function(d) { return x(d.data.State); }) | |
.attr("y", function(d) { return y(d[1]); }) | |
.attr("width", x.bandwidth()) | |
.attr("height", 0) | |
.transition().duration(1000) | |
.delay(function(d, i) { return i * 10; }) | |
.attr("height", function(d) { return y(d[0]) - y(d[1]); }); | |
}); | |
// 3. enter | |
var enterTransition = updateTransition.transition().each(function() { | |
rect.enter().append("rect") | |
.attr("class", "chart-rect") | |
.attr("state", function(d) {return d.data.State; }) | |
.attr("fill", function(d) { return z(d.key)}) | |
.attr("x", function(d) { return x(d.data.State); }) | |
.attr("y", function(d) { return y(d[1]); }) | |
.attr("width", x.bandwidth()) | |
.attr("height", 0) | |
.transition().duration(1000) | |
.delay(function(d, i) { return i * 1000; }) | |
.attr("height", function(d) { return y(d[0]) - y(d[1]); }); | |
}); | |
*/ | |
} | |
// ---------------------------------------------------------------- | |
// AXES | |
// ---------------------------------------------------------------- | |
if (initializing) { | |
// X axis | |
g.append("g") | |
.attr("class", "axis axis-x") | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x)); | |
// Y axis | |
g.append("g") | |
.attr("class", "axis axis-y") | |
.call(d3.axisLeft(y).ticks(10, "s")) | |
.append("text") | |
.attr("x", 2) | |
.attr("y", y(y.ticks(10).pop())) | |
.attr("dy", "0.35em") | |
.attr("text-anchor", "start") | |
.attr("fill", "#000") | |
.text("Population"); | |
} else { | |
// // remove xAxis | |
// g.select("g.axis-x").remove(); | |
// // X axis | |
// g.append("g") | |
// .attr("class", "axis axis-x") | |
// .attr("transform", "translate(0," + height + ")") | |
// .call(d3.axisBottom(x)); | |
d3.transition(g).select("g.axis-x").call(d3.axisBottom(x)); | |
d3.transition(g).select("g.axis-y").call(d3.axisLeft(y).ticks(10, "s")); | |
} | |
} | |
function jumbleData() { | |
console.log("*************** ENTER-jumbleData") | |
// console.log("data", data) | |
var _result = undefined; | |
var _oldColumns = data.columns; | |
var _data = _.cloneDeep(data); // for some reason, clone() removes the 'columns' obj in iData, so we don't need to remove it after cloning... nice | |
var _numRandomStates = Math.floor(Math.random() * data.length); | |
console.log("_data", _data) | |
_result = _.sampleSize(_data, _numRandomStates); | |
_result.columns = _oldColumns; | |
console.log("_result", _result) | |
return _result; | |
} | |
/* | |
// Jumble the data so we can test transitioning to new data. | |
function jumbleData(iData) { | |
// console.log("*************** ENTER-jumbleData") | |
// console.log("iData", iData) | |
var result = undefined; | |
var oldColumns = iData.columns; | |
var data = _.cloneDeep(iData); // for some reason, clone() removes the 'columns' obj in iData, so we don't need to remove it after cloning... nice | |
// console.log("data", data) | |
for (var i = 0; i < data.length; i++) { | |
// console.log("------------- i", i) | |
var cur = data[i]; | |
var itemToSwapDataWith = _.sample(data) | |
// console.log("cur", cur) | |
// console.log("itemToSwapDataWith", itemToSwapDataWith) | |
// Swap state names for the 2 objects, so their data is swaped, essentially. | |
var curState = cur.State; | |
cur.State = itemToSwapDataWith.State; | |
itemToSwapDataWith.State = curState; | |
// console.log("----- SWAP -----") | |
// console.log("cur", cur) | |
// console.log("itemToSwapDataWith", itemToSwapDataWith) | |
} | |
data.columns = oldColumns; | |
result = data; | |
// console.log("result", result) | |
return result; | |
} | |
*/ | |
function type(d, i, columns) { | |
for (i = 1, t = 0; i < columns.length; ++i) t += d[columns[i]] = +d[columns[i]]; | |
d.total = t; | |
return d; | |
} | |
</script> | |
</body> |