Marimekko chart of Scottish termination statistics
Last active
September 9, 2022 16:40
-
-
Save stuwilmur/9ac70b9ddd1bd9c97a871e6f18dc2635 to your computer and use it in GitHub Desktop.
terminations-categorised: marimekko/mosaic chart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
HB16CD | HB16NM | OBJECTID | |
---|---|---|---|
S08000015 | Ayrshire and Arran | 0 | |
S08000016 | Borders | 1 | |
S08000017 | Dumfries and Galloway | 2 | |
S08000029 | Fife | 3 | |
S08000019 | Forth Valley | 4 | |
S08000020 | Grampian | 5 | |
S08000031 | Greater Glasgow and Clyde | 6 | |
S08000022 | Highland | 7 | |
S08000032 | Lanarkshire | 8 | |
S08000024 | Lothian | 9 | |
S08000025 | Islands | 10 | |
S08000030 | Tayside | 12 | |
S00000000 | Other / Unknown | 13 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Scotland termination of pregnancy figures by Health board Marimekko chart</title> | |
<meta charset="utf-8"> | |
<!-- Load d3.js --> | |
<script src="https://d3js.org/d3.v4.js"></script> | |
<!-- Color Scale --> | |
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script> | |
<!-- Font --> | |
<link href="https://fonts.googleapis.com/css?family=Merriweather&display=swap" rel="stylesheet"> | |
<style> | |
body { | |
font: 12px Merriweather, sans-serif; | |
position: relative; | |
} | |
.caption { | |
font-size : 150%; | |
} | |
.subcaption { | |
font-size : 80%; | |
} | |
.node { | |
box-sizing: border-box; | |
line-height: 1em; | |
overflow: hidden; | |
position: absolute; | |
white-space: pre; | |
background: #ddd; | |
} | |
.node-value { | |
font-weight: bold; | |
} | |
.tooltip { | |
pointer-events: none; | |
} | |
</style> | |
</head> | |
<body> | |
<!-- Create a div where the graph will take place --> | |
<div id="my_dataviz"></div> | |
<div> | |
<select id="measureButton"></select> | |
<select id="yearButton"></select> | |
</div> | |
<p class="caption">Termination of pregnancy in Scotland across health board categorised by age, deprivation, estimated gestation, method of termination and parity.<br /><strong>Click on the map</strong> to select/deselect health boards. Use the menus below to select categorisation and year.</p> | |
<p class="subcaption">Data from the <a href="https://beta.isdscotland.org/find-publications-and-data/population-health/sexual-health/termination-of-pregnancy-statistics/">Termination of Pregnancy report, Public Health Scotland Data and Intelligence, published 29 June 2021</a>.</p> | |
<script> | |
var width = 800; | |
var pageWidth = 1600; | |
var height = 800; | |
var measuresMap = new Map(); | |
// append the svg object to the body of the page | |
var svg = d3.select("#my_dataviz") | |
.append("svg") | |
.attr("id", "thesvg") | |
.attr("width", pageWidth ) | |
.attr("height", height) | |
// create a tooltip | |
var Tooltip = d3.select("#my_dataviz") | |
.append("div") | |
.style("opacity", 0) | |
.attr("class", "tooltip") | |
.style("background-color", "white") | |
.style("border", "solid") | |
.style("border-width", "1px") | |
.style("border-radius", "0px") | |
.style("padding", "5px") | |
.style("position", "absolute") | |
.style("font-family", "Merriweather") | |
.style("font-size", "130%") | |
// create a tooltip for the map | |
var mapTooltip = d3.select("#my_dataviz") | |
.append("div") | |
.style("opacity", 0.1) | |
.attr("class", "tooltip") | |
.style("background-color", "white") | |
.style("border", "none") | |
.style("border-width", "1px") | |
.style("border-radius", "0px") | |
.style("padding", "5px") | |
.style("position", "absolute") | |
.style("font-family", "Merriweather") | |
.style("font-size", "150%") | |
// Three functions that change the tooltip when user hover / move / leave a cell | |
var mouseover = function(d) { | |
Tooltip | |
.style("opacity", .8) | |
} | |
var mousemove = function(d) { | |
Tooltip | |
.html(getNodeText(d, true)) | |
.style("left", d3.event.pageX + 10 + "px") | |
.style("top", d3.event.pageY + 10 + "px") | |
.style("z-index", 2) | |
} | |
var mouseleave = function(d) { | |
Tooltip | |
.style("opacity", 0) | |
d3.select("svg").selectAll("text.data").remove(); | |
} | |
// Parse the csv file | |
function parseData(d) { | |
d.Year = +d.Year; | |
d.Value = d.Value == "*" ? 0 : d.Value = +d.Value; //!! handle the missing data. | |
return d; | |
} | |
var measure = "Age"; | |
var year = "2020"; | |
var boards = new Map(); | |
function getNodeText(d, value = false) | |
{ | |
var text = boards.get(d.data.ID) + "\n" + d.data.Group; | |
if (value) | |
{ | |
text += "<br /><strong>" + d.data.Value + "</strong>"; | |
} | |
return text; | |
} | |
var IDs | |
var measuresList | |
var rolled | |
var nested | |
var theData; | |
var years; | |
var year; | |
var durationTime = 1000; | |
var geojson; | |
d3.csv("terminations data.csv", parseData, function(inData) { | |
d3.csv("measures_descriptors.csv", function(measures) { | |
//Read and parse the data | |
d3.csv('Health_Boards_May_2016_Names_and_Codes_in_Scotland.csv', function(lookup){ | |
lookup.reduce(function(map, obj) { | |
boards.set(obj.HB16CD, obj.HB16NM); | |
}, {}); | |
d3.json('sco_nhs_boards.geojson', function(err, json) { | |
theData = inData; | |
geojson = json; | |
d3.csv("measures_descriptors.csv", function(measuresData) { | |
measuresData.reduce(function(map, obj) { | |
measuresMap.set(obj.measure, obj); | |
}, {}); | |
IDs = ["S00000000"]; | |
//console.log(IDs); | |
measures.reduce(function(map, obj) { | |
measuresMap.set(obj.measure, obj); | |
}, {}); | |
measuresList = Array.from(measuresMap.keys()); | |
// add the options to the measures button | |
d3.select('#measureButton') | |
.on('change', function(d) | |
{ | |
update(); | |
}) | |
.selectAll('option') | |
.data(measuresList) | |
.enter() | |
.append('option') | |
.attr('value', function(d) {return d;}) | |
.text(function(d) {return measuresMap.get(d).description;}); | |
rolled = d3.nest() | |
.key(function(d) { return d.Measure; }) | |
.key(function(d) { return d.Year; }) | |
.key(function(d) { return d.ID; }) | |
.rollup(function(v) { return d3.sum(v, function(d) { return d.Value; }); }) | |
.entries(theData); | |
nested = d3.nest() | |
.key(function(d) { return d.Measure; }) | |
.key(function(d) { return d.Year; }) | |
.key(function(d) { return d.ID; }) | |
.entries(theData); | |
var yearNested = d3.nest() | |
.key(function(d) { return d.Year; }) | |
.entries(theData); | |
//console.log(yearNested); | |
years = yearNested.map(function(d) { return d.key;}).sort() | |
console.log(years); | |
// add the options to the measures button | |
d3.select('#yearButton') | |
.on('change', function(d) | |
{ | |
update(); | |
}) | |
.selectAll('option') | |
.data(years) | |
.enter() | |
.append('option') | |
.attr('value', function(d) {return d;}) | |
.text(function(d) {return d;}); | |
//console.log(rolled); | |
update(); | |
}) | |
}) | |
}) | |
}) | |
}) | |
function update() | |
{ | |
measure = d3.select("#measureButton").property("value"); | |
//console.log(measure); | |
year = d3.select("#yearButton").property("value"); | |
updateGeo(geojson); | |
var rolledSelect = rolled | |
.filter(function(e) {return e.key == measure; }) | |
[0] | |
.values | |
.filter(function(e) {return e.key == year; }) | |
[0] | |
.values | |
.filter(function(e) {return IDs.includes(e.key); }); | |
var nestedSelect = nested | |
.filter(function(e) {return e.key == measure; }) | |
[0] | |
.values | |
.filter(function(e) {return e.key == year; }) | |
[0] | |
.values | |
.filter(function(e) {return IDs.includes(e.key); }); | |
//console.log(nestedSelect); | |
//console.log(root); | |
var nestedData = {name : "data", values : nestedSelect}; | |
//console.log(nestedData); | |
//console.log(data); | |
var treemapLayout = d3.treemap() | |
.size([width, height]) | |
.tile(d3.treemapSliceDice) | |
.padding(1) | |
.round(true); | |
var myroot = d3.hierarchy(nestedData, function(d) { return d.values; }).sum(function(d) { return d.Value; }); | |
treemapLayout(myroot); | |
//console.log(root); | |
//console.log(myroot); | |
catNestedData = d3.nest() | |
.key(function(d) { return d.Measure; }) | |
.key(function(d) { return d.Group; }) | |
.entries(theData); | |
var allCategories = catNestedData.filter(function(f) | |
{ return f['key'] == measure; | |
}); | |
var categories = allCategories[0].values.map( function(d) { return d.key; }); | |
//console.log(categories); | |
color = d3.scaleOrdinal() | |
.domain(categories) | |
.range(d3.schemeSet3) | |
var node = d3.select("#my_dataviz").selectAll(".node").data(myroot.leaves()); | |
//console.log(myroot.leaves()); | |
node | |
.enter() | |
.append("div") | |
.on("mouseover", mouseover) | |
.on("mousemove", mousemove) | |
.on("mouseleave", mouseleave) | |
.merge(node) | |
.transition() | |
.duration(durationTime) | |
.attr("class", "node") | |
.text(function(d) {return getNodeText(d, false) + "\n" + d.data.Value;}) | |
.style("left", function(d) { return d.x0 + "px"; }) | |
.style("top", function(d) { return d.y0 + "px"; }) | |
.style("width", function(d) { return d.x1 - d.x0 + "px"; }) | |
.style("height", function(d) { return d.y1 - d.y0 + "px"; }) | |
.style("background", function(d,i) { | |
//console.log(d.data.Group); | |
//console.log(color(d.data.Group)); | |
return color(d.data.Group); | |
}) | |
node.exit().remove(); | |
} | |
var projection = d3.geoMercator() | |
.scale(3000) | |
.translate([pageWidth * .75, height / 2]) | |
.center([-4, 58]); | |
var geoGenerator = d3.geoPath() | |
.projection(projection); | |
var colours = { teal : "#69b3a2", grey : "#aaa" }; | |
function getRegionColour(d) { | |
return IDs.includes(d.properties.HBCode) ? colours.teal : colours.grey; | |
} | |
var mapmouseenter = function(d) { | |
mapTooltip | |
.style("opacity", .8) | |
d3.select(this) | |
.style('fill', colours.teal) | |
.style("opacity", 0.5) | |
} | |
var mapmousemove = function(d) { | |
mapTooltip | |
.html(boards.get(d.properties.HBCode)) | |
.style("left", (d3.mouse(this)[0] + 20) + "px") | |
.style("top", (d3.mouse(this)[1]) + "px") | |
} | |
var mapmouseleave = function(d) { | |
mapTooltip | |
.style("opacity", 0) | |
d3.select(this) | |
.style('fill', getRegionColour(d)) | |
.style("opacity", 1) | |
} | |
var mapmouseclick = function(d) { | |
var hb = d.properties.HBCode; | |
if (IDs.includes(hb)) | |
{ | |
if (IDs.length > 1) | |
{ | |
IDs.splice(IDs.indexOf(hb), 1); | |
} | |
} | |
else | |
{ | |
IDs.push(hb) | |
} | |
d3.select(this) | |
.style('fill', getRegionColour(d)) | |
.style("opacity", 1) | |
update(); | |
} | |
function updateGeo(geojson) { | |
var u = d3.select('svg') | |
.selectAll('path.region') | |
.data(geojson.features); | |
u.enter() | |
.append('path') | |
.attr("class", "region") | |
.attr('d', geoGenerator) | |
.style("fill", getRegionColour) | |
.on("mouseenter", mapmouseenter) | |
.on("mousemove", mapmousemove) | |
.on("mouseleave", mapmouseleave) | |
.on("click", mapmouseclick) | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
measure | description | unit | |
---|---|---|---|
Age | Age group | Number | |
Gestation | Estimated gestation in completed weeks | Number | |
Parity | Previous completed pregnancies | Number | |
Method | Method of termination (medical or surgical) | Number | |
Previous | Previous terminations of pregnancy (none, 1 or more) | Number | |
SIMD | Scottish Index of Multiple Deprivation quintile (1 = least deprived, 5 = most deprived) | Number |
View raw
(Sorry about that, but we can’t show files that are this big right now.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment