Skip to content

Instantly share code, notes, and snippets.

@sarah37
Last active April 8, 2023 19:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sarah37/5856a62f6ac7be5a86296969eacea126 to your computer and use it in GitHub Desktop.
Save sarah37/5856a62f6ac7be5a86296969eacea126 to your computer and use it in GitHub Desktop.
Population Pyramid Scotland 2019
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Population Pyramid Scotland 2019</title>
<link rel="stylesheet" href="style.css" />
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Age Persons Males Females
0 50772 26138 24634
1 52734 27059 25675
2 54266 28045 26221
3 56539 29267 27272
4 57404 29473 27931
5 57837 29750 28087
6 59032 30203 28829
7 60560 31168 29392
8 62408 31913 30495
9 59479 30263 29216
10 61119 31119 30000
11 60860 30969 29891
12 58512 29924 28588
13 57366 29231 28135
14 56817 29244 27573
15 55692 28678 27014
16 54052 27624 26428
17 53713 27457 26256
18 56834 28903 27931
19 61667 31510 30157
20 65838 33412 32426
21 67735 34303 33432
22 70870 35814 35056
23 71430 36286 35144
24 71583 36251 35332
25 73182 36890 36292
26 74857 37228 37629
27 79127 39349 39778
28 79100 39702 39398
29 75989 37976 38013
30 75648 37656 37992
31 75743 37555 38188
32 73301 36029 37272
33 72691 36090 36601
34 72080 35305 36775
35 69835 34205 35630
36 70584 34472 36112
37 71428 34755 36673
38 70962 34853 36109
39 69713 34339 35374
40 67127 33353 33774
41 62229 30309 31920
42 61101 30279 30822
43 64358 31511 32847
44 64617 31338 33279
45 65725 32217 33508
46 69677 34006 35671
47 73842 35622 38220
48 76666 36697 39969
49 75548 36270 39278
50 78567 37782 40785
51 79919 38446 41473
52 80362 39141 41221
53 79788 38547 41241
54 82454 40024 42430
55 81429 39184 42245
56 81224 39315 41909
57 79062 38548 40514
58 77036 37472 39564
59 74372 36256 38116
60 73504 35533 37971
61 71388 34534 36854
62 69244 33646 35598
63 66867 32428 34439
64 63690 30711 32979
65 62599 30358 32241
66 60993 29455 31538
67 58595 28260 30335
68 58657 28175 30482
69 58600 28212 30388
70 59394 28497 30897
71 60782 29071 31711
72 65059 30844 34215
73 48394 22913 25481
74 45227 21014 24213
75 45388 21118 24270
76 42595 19268 23327
77 38406 17046 21360
78 34798 15232 19566
79 34764 15222 19542
80 33039 14311 18728
81 31191 13403 17788
82 28436 11771 16665
83 26237 10682 15555
84 23904 9681 14223
85 21126 8261 12865
86 18701 7296 11405
87 17001 6384 10617
88 14569 5356 9213
89 12032 4185 7847
90 & over 43658 13411 30247
// define variables for spacing, margins, etc.
centreSpacing = 25; // spacing in between the male and female bars
margin = { left: 10, right: 10, top: 20, bottom: 25 };
h = 600 - margin.top - margin.bottom;
w = 600 - margin.left - margin.right;
// set up SVG
var svg = d3
.select("#chart")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom);
// set up three g (group) elements to help position things and organise our chart
// g element for the bars for the male population
var gM = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// g element for the bars for the female population
var gF = svg
.append("g")
.attr(
"transform",
"translate(" +
(margin.left + (w - centreSpacing) / 2 + centreSpacing) +
"," +
margin.top +
")"
);
// g element for the labels
var gLabels = svg
.append("g")
.attr(
"transform",
"translate(" +
(margin.left + (w - centreSpacing) / 2 + "," + margin.top + ")")
);
// scale functions to map data to width/height/position
y = d3.scaleBand().range([h, 0]).padding(0.1);
x = d3.scaleLinear().range([0, (w - centreSpacing) / 2]);
// we will use this to create a reversed axis (right to left) for the male population later
xReverse = d3.scaleLinear().range([0, (w - centreSpacing) / 2]);
// Load data
// Everything that we need the data for has to happen inside of this function
d3.csv("nrs_mid_year_pop2019.csv").then(function (data) {
// prepare the data
data = data.map((d) => ({
age: d.Age,
females: +d.Females,
males: +d.Males,
}));
// to complete our scale functions, we need to set their domains based on the values in the data
// largest value out of all male or female counts for all years
maxVal = d3.max(data, (d) => d3.max([d.males, d.females]));
x.domain([0, maxVal]);
xReverse.domain([maxVal, 0]);
y.domain(data.map((d) => d.age));
// create bars for male population
gM.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d) => (w - centreSpacing) / 2 - x(d.males))
.attr("y", (d) => y(d.age))
.attr("height", y.bandwidth())
.attr("width", (d) => x(d.males))
.style("fill", "teal");
// create bars for female population
gF.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", 0)
.attr("y", (d) => y(d.age))
.attr("height", y.bandwidth())
.attr("width", (d) => x(d.females))
.style("fill", "purple");
// add labels for age groups in the centre of the chart
gLabels
.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("x", centreSpacing / 2)
.attr("y", (d) => y(d.age) + y.bandwidth() / 2)
.text((d, i) => (i != data.length - 1 ? (i % 5 == 0 ? d.age : "") : "90+"));
// add an axis for female pop values
gF.append("g")
.attr("transform", "translate(0," + (h + 3) + ")")
.call(d3.axisBottom(x).ticks(w / 80, "s"));
// add an axis for male pop values
gM.append("g")
.attr("transform", "translate(0," + (h + 3) + ")")
.call(d3.axisBottom(xReverse).ticks(w / 80, "s"));
});
// Additional labeling (we do not need the data for this)
// add a little 'Age' header at the top
gLabels
.append("text")
.text("Age")
.attr("x", centreSpacing / 2)
.attr("y", -14)
.style("font-weight", "bold");
// add Male/Female labels
gF.append("text")
.text("Female Population")
.attr("x", (w - centreSpacing) / 2)
.attr("y", h - 7)
.style("text-anchor", "end");
gM.append("text")
.text("Male Population")
.attr("x", 0)
.attr("y", h - 7)
.style("text-anchor", "start");
svg text {
font-family: sans-serif;
font-size: 12px;
dominant-baseline: central; /*vertically centers text on position*/
text-anchor: middle; /*horizontally centers text on position*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment