Skip to content

Instantly share code, notes, and snippets.

@mattykuch
Last active July 17, 2022 05:51
Show Gist options
  • Save mattykuch/f8bb2e87035929bbba5be86666fccaee to your computer and use it in GitHub Desktop.
Save mattykuch/f8bb2e87035929bbba5be86666fccaee to your computer and use it in GitHub Desktop.
[COMPLETE] Immunization Coverage in Uganda 2016 (Using D3.js)
id district pop_16 dpt16 bcg16 mea16 polio16 ipv16 pcv16 hpv16 dpt_droprate16 pentapcv_gap16 score16
1 ABIM 121,540 164 91 170 157 81 155 7 -17 9 89
2 ADJUMANI 229,324 111 91 102 106 44 105 4 0 7 100
3 AGAGO 236,066 120 91 105 204 49 120 0 -8 1 89
4 ALEBTONG 240,462 87 78 73 88 43 83 2 8 4 89
5 AMOLATAR 157,953 106 87 87 106 51 98 2 8 8 78
6 AMUDAT 115,059 103 70 96 103 59 101 0 -6 2 78
7 AMURIA 289,664 131 94 102 120 36 111 2 -3 20 78
8 AMURU 196,914 96 82 90 93 36 81 1 5 15 67
9 APAC 393,357 77 67 69 77 32 74 1 4 4 56
10 ARUA 826,486 86 91 82 83 44 80 1 11 6 89
11 BUDAKA 222,383 81 92 67 75 33 76 1 20 5 56
12 BUDUDA 229,514 85 65 93 85 47 84 4 3 1 89
13 BUGIRI 406,232 123 120 108 118 53 112 3 9 11 78
14 BUHWEJU 128,321 97 77 75 99 65 95 4 3 2 100
15 BUIKWE 440,714 87 88 78 84 35 82 1 15 5 78
16 BUKEDEA 221,486 89 72 85 87 49 80 1 -1 9 89
17 BUKOMANSIMBI 153,540 65 63 56 62 36 60 1 14 5 11
18 BUKWO 98,515 103 84 97 102 54 101 3 3 2 100
19 BULAMBULI 192,029 64 58 55 62 36 59 2 4 5 33
20 BULIISA 124,285 79 84 61 76 58 69 1 14 10 44
21 BUNDIBUGYO 237,590 122 93 124 169 44 114 0 2 8 78
22 BUSHENYI 239,626 100 102 85 96 44 95 3 0 5 100
23 BUSIA 343,373 91 88 77 88 44 74 4 3 17 89
24 BUTALEJA 262,555 95 104 87 93 37 91 1 17 4 78
25 BUTAMBALA 103,479 89 103 68 83 52 82 2 7 7 78
26 BUVUMA 101,573 99 83 89 98 46 89 0 13 10 67
27 BUYENDE 352,122 106 151 88 92 45 96 1 16 10 67
28 DOKOLO 193,866 97 81 85 97 51 96 1 5 1 100
29 GOMBA 164,756 108 80 90 106 51 106 2 6 2 100
30 GULU 464,718 118 103 110 145 42 93 2 -2 25 89
31 HOIMA 623,322 100 103 101 87 51 94 5 11 6 89
32 IBANDA 259,201 114 96 91 99 40 104 8 -2 10 89
33 IGANGA 533,864 84 93 68 80 39 83 3 13 1 67
34 ISINGIRO 522,008 134 109 112 148 47 122 4 10 12 78
35 JINJA 486,442 112 109 102 111 37 110 2 10 2 78
36 KAABONG 162,550 128 95 115 117 67 125 1 5 3 89
37 KABALE 540,985 89 78 80 85 41 85 2 1 4 100
38 KABAROLE 491,069 117 103 88 132 58 105 5 -8 12 89
39 KABERAMAIDO 233,020 95 90 81 93 47 92 0 1 3 89
40 KALANGALA 58,385 100 76 91 101 60 94 2 5 7 100
41 KALIRO 253,022 104 119 86 103 40 100 1 25 4 78
42 KALUNGU 187,285 71 77 62 71 38 69 2 11 3 56
43 KAMPALA 1,567,966 126 153 122 114 51 106 2 11 20 78
44 KAMULI 510,939 119 112 112 111 49 112 1 15 7 78
45 KAMWENGE 446,551 101 95 108 99 46 98 4 -1 3 100
46 KANUNGU 260,790 90 76 77 83 36 83 2 -1 7 89
47 KAPCHORWA 111,375 92 86 78 91 55 88 5 -1 3 100
48 KASESE 728,752 107 99 95 98 51 91 2 2 16 89
49 KATAKWI 175,670 138 82 110 136 72 126 1 -13 12 89
50 KAYUNGA 382,181 113 120 103 106 57 105 1 12 8 67
51 KIBAALE 873,823 100 89 85 91 33 90 0 7 10 56
52 KIBOGA 156,026 89 96 67 88 55 88 2 10 2 78
53 KIBUKU 217,679 88 92 76 84 48 86 4 15 2 89
54 KIRUHURA 352,124 92 78 79 83 44 85 3 7 7 100
55 KIRYANDONGO 281,860 129 121 164 126 48 108 1 10 22 78
56 KISORO 293,661 93 94 81 88 47 93 4 2 0 100
57 KITGUM 211,045 78 73 71 78 31 74 2 5 3 89
58 KOBOKO 222,916 86 82 77 87 33 86 5 8 0 78
59 KOLE 254,395 85 81 76 83 33 89 1 6 -4 89
60 KOTIDO 193,196 126 73 109 122 55 125 0 -2 2 89
61 KUMI 254,333 97 78 86 96 38 92 3 -5 5 89
62 KWEEN 98,986 107 87 95 107 55 104 1 8 2 78
63 KYANKWANZI 235,798 99 84 81 95 50 89 1 7 10 67
64 KYEGEGWA 327,286 86 82 77 73 38 82 2 7 4 78
65 KYENJOJO 455,778 97 97 90 92 43 81 1 7 16 67
66 LAMWO 137,896 107 80 95 105 49 100 5 2 7 100
67 LIRA 431,213 97 89 84 102 36 95 6 5 2 89
68 LUUKA 248,122 122 103 99 118 51 113 1 12 9 78
69 LUWERO 479,155 106 96 95 94 34 90 5 4 15 78
70 LWENGO 281,035 96 87 91 86 34 88 0 15 8 67
71 LYANTONDE 99,270 92 112 82 118 56 87 4 10 5 89
72 MANAFWA 371,737 146 121 122 145 50 122 2 4 25 89
73 MARACHA 193,654 108 87 124 100 41 101 1 5 7 89
74 MASAKA 310,216 92 115 80 86 30 82 2 8 10 67
75 MASINDI 307,644 88 87 83 87 35 86 1 10 2 78
76 MAYUGE 503,035 87 95 72 78 32 75 1 21 12 67
77 MBALE 520,754 125 135 122 117 51 110 3 14 15 78
78 MBARARA 493,653 89 88 83 84 48 80 4 5 8 89
79 MITOOMA 187,502 90 70 78 85 43 87 2 0 3 100
80 MITYANA 340,913 95 97 92 83 43 89 3 8 6 89
81 MOROTO 108,456 100 72 104 96 43 97 2 -8 3 100
82 MOYO 131,336 72 59 70 71 31 69 3 -7 3 67
83 MPIGI 262,719 115 103 98 109 41 105 2 0 10 89
84 MUBENDE 740,179 122 126 102 106 43 109 1 7 13 78
85 MUKONO 631,921 91 93 87 88 38 86 1 6 5 78
86 NAKAPIRIPIRIT 171,437 107 80 88 104 59 98 1 -2 10 78
87 NAKASEKE 209,389 87 116 75 83 39 84 1 16 3 78
88 NAKASONGOLA 192,871 77 67 65 71 34 72 4 6 5 67
89 NAMAYINGO 229,896 133 112 115 175 43 112 1 15 21 67
90 NAMUTUMBA 270,028 120 133 108 117 50 136 1 20 -16 78
91 NAPAK 147,680 152 117 157 148 80 154 1 3 -2 89
92 NEBBI 423,415 103 99 85 95 44 92 3 9 11 78
93 NGORA 149,978 114 96 106 110 65 110 3 5 4 100
94 NTOROKO 70,123 118 88 87 115 57 109 1 -1 10 78
95 NTUNGAMO 503,388 91 77 75 81 50 79 3 -5 12 89
96 NWOYA 161,249 95 69 83 86 54 89 1 0 6 78
97 OTUKE 113,413 115 111 107 103 48 109 2 7 6 89
98 OYAM 407,008 111 112 102 107 43 103 4 9 7 89
99 PADER 184,832 190 163 184 185 56 176 1 5 13 89
100 PALLISA 414,446 103 92 82 100 52 97 1 10 7 78
101 RAKAI 537,168 101 93 81 94 41 94 1 9 6 78
102 RUBIRIZI 134,367 127 92 108 123 54 117 3 2 10 89
103 RUKUNGIRI 321,655 88 111 76 83 44 83 5 4 4 100
104 SSEMBABULE 266,940 115 95 98 114 75 114 2 9 1 89
105 SERERE 309,233 100 90 82 100 39 99 1 -2 1 89
106 SHEEMA 212,349 77 81 71 77 41 74 4 9 3 89
107 SIRONKO 253,206 122 86 119 115 52 107 0 -2 15 78
108 SOROTI 318,590 97 86 81 94 30 93 1 0 5 89
109 TORORO 544,320 103 101 96 96 30 97 2 2 6 89
110 WAKISO 2,269,778 81 62 79 77 33 76 1 6 5 67
111 YUMBE 539,619 71 45 68 71 41 69 3 3 2 67
112 ZOMBO 254,209 105 101 101 92 51 89 1 7 16 67
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Uganda: Immunisation coverage map</title>
<!-- CSS libraries -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet" type="text/css">
<!-- Custom CSS styles -->
<link href="style.css" rel="stylesheet" type="text/css" >
</head>
<body>
<div class="container">
<h3> UGANDA IMMUNISATION COVERAGE MAP 2016</h3>
<div id="initial">
<strong>Instructions</strong>
<ul>
<li>Click on a district to show the details</li>
<li>The map color-key is like traffic lights: Green (High Coverage) to Red (Low Coverage)</li>
</ul>
</div>
<div id="map"> <!-- Map container --> </div>
<div id="details"><!-- Details container --></div>
</div>
<div id="footer">
<strong>Note</strong> : Data and Score (Aggregate) used are only for test purposes, in building this map visualisation, and should not be used to inform interventions.
</div>
<!-- Mustache template, rendered later to show the details of a feature -->
<script id="template" type="x-tmpl-mustache">
<h3 >{{ district }}</h3>
<table>
<tr>
<th> Aggregated Coverage Score:</th>
<td>{{ score16 }} %</td>
</tr>
<tr>
<th> Population:</th>
<td>{{ pop_16 }} </td>
</tr>
<tr>
<th> DPT Coverage:</th>
<td>{{ dpt16 }} %</td>
</tr>
<tr>
<th> DPT Dropout Rate:</th>
<td>{{ dpt_droprate16 }} %</td>
</tr>
<tr>
<th> BCG Coverage:</th>
<td>{{ bcg16 }} %</td>
</tr>
<tr>
<th> MEASLES Coverage:</th>
<td>{{ mea16 }} %</td>
</tr>
<tr>
<th> Polio Coverage:</th>
<td>{{ polio16 }} %</td>
</tr>
<tr>
<th> IPV Coverage:</th>
<td>{{ ipv16 }} %</td>
</tr>
<tr>
<th> PCV Coverage:</th>
<td>{{ pcv16 }} %</td>
</tr>
<tr>
<th> PENTA Vs PCV Gap:</th>
<td>{{ pentapcv_gap16 }} %</td>
</tr>
<tr>
<th> HPV Coverage:</th>
<td>{{ hpv16 }} %</td>
</tr>
</table>
</script>
<!-- Tooltip div -->
<div id="tooltip">
<p class="name"></p>
<p class="value"></p>
</div>
<!-- JS Libraries -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.2.1/mustache.min.js"></script>
<!-- Custom JS code -->
<script src="map.js"></script>
</body>
</html>
// Assign dimensions for map container
var width = 500,
height = 500;
// Field refernce to csv column
var field = "score16"
//Number formatting
//
//Create a function that take a number, adds commas for thousands,
//and removes decimal values, e.g. 1234567.89 --> 1,234,567
//
var valueFormat = d3.format(",");
// Get and prepare the Mustache template; parsing it speeds up future uses
var template = d3.select('#template').html();
Mustache.parse(template);
// Logic to handle hover event when its firedup
var hoveron = function(d) {
console.log('d', d, 'event', event);
var div = document.getElementById('tooltip');
div.style.left = event.pageX + 'px';
div.style.top = event.pageY + 'px';
//Fill yellow to highlight
d3.select(this)
.style("fill", "white");
//Show the tooltip
d3.select("#tooltip")
.style("opacity", 1);
//Populate name in tooltip
d3.select("#tooltip .name")
.text(d.properties.dist);
//Populate value in tooltip
d3.select("#tooltip .value")
.text(valueFormat(d.properties.field) + "%");
}
var hoverout = function(d) {
//Restore original choropleth fill
d3.select(this)
.style("fill", function(d) {
var value = d.properties.field;
if (value) {
return color(value);
} else {
return "#ccc";
}
});
//Hide the tooltip
d3.select("#tooltip")
.style("opacity", 0);
}
// Create SVG inside map container and assign dimensions
var svg = d3.select("#map").append('svg')
.attr("width", width)
.attr("height", height);
// Define a geographical projection
// Also, set initial zoom to show the features
var projection = d3.geo.mercator()
.scale(1);
// Prepare a path object and apply the projection to it
var path = d3.geo.path()
.projection(projection);
// We prepare an object to later have easier access to the data.
var dataById = d3.map();
//Define quantize scale to sort data values into buckets of color
//Colors by Cynthia Brewer (colorbrewer2.org), 9-class YlGnBu
var color = d3.scale.quantize()
//.range(d3.range(9),map(function(i) { return 'q' + i + '-9';}));
.range([ "#a50026",
"#d73027",
"#f46d43",
"#fdae61",
"#fee08b",
"#ffffbf",
"#d9ef8b",
"#a6d96a",
"#66bd63",
"#1a9850",
"#006837" ]);
// Load in coverage score data
d3.csv("coverage16_v3.csv", function(data) {
//Set input domain for color scale
color.domain([
d3.min(data, function(d) { return +d[field]; }),
d3.max(data, function(d) { return +d[field]; })
]);
// This maps the data of the CSV so it can be easily accessed by
// the ID of the district, for example: dataById[2196]
dataById = d3.nest()
.key(function(d) { return d.id; })
.rollup(function(d) { return d[0]; })
.map(data);
// Load features from GeoJSON
d3.json('ug_districts3.geojson', function(error, json) {
// Get the scale and center parameters from the features.
var scaleCenter = calculateScaleCenter(json);
// Apply scale, center and translate parameters.
projection.scale(scaleCenter.scale)
.center(scaleCenter.center)
.translate([width/2, height/2]);
// Merge the coverage data amd GeoJSON into a single array
// Also loop through once for each coverage score data value
for (var i=0; i < data.length ; i++ ) {
// Grab district name
var dataDistrict = data[i].district;
//Grab data value, and convert from string to float
var dataValue = +data[i][field];
//Find the corresponding district inside GeoJSON
for (var j=0; j < json.features.length ; j++ ) {
// Check the district reference in json
var jsonDistrict = json.features[j].properties.dist;
if (dataDistrict == jsonDistrict) {
//Copy the data value into the GeoJSON
json.features[j].properties.field = dataValue;
//Stop looking through JSON
break;
}
}
}
// Add a <g> element to the SVG element and give a class to style later
svg.append('g')
.attr('class', 'features')
// Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.on("mouseover", hoveron)
.on("mouseout", hoverout)
.on('click', showDetails)
.style("cursor", "pointer")
.style("stroke", "#777")
.style("fill", function(d) {
// Get data value
var value = d.properties.field;
if (value) {
// If value exists ...
return color(value);
} else {
// If value is undefines ...
return "#ccc";
}
});
}); // End d3.json
}); // End d3.csv
// NEW: function to dynamically calculate the scale factror and center
function calculateScaleCenter(features) {
// Get the bounding box of the paths (in pixels) and calculate a scale factor based on box and map size
var bbox_path = path.bounds(features),
scale = 0.95 / Math.max(
(bbox_path[1][0] - bbox_path[0][0]) / width,
(bbox_path[1][1] - bbox_path[0][1]) / height
);
// Get the bounding box of the features (in map units) and use it to calculate the center of the features.
var bbox_feature = d3.geo.bounds(features),
center = [
(bbox_feature[1][0] + bbox_feature[0][0]) / 2,
(bbox_feature[1][1] + bbox_feature[0][1]) / 2];
return {
'scale':scale,
'center':center
};
}
// NEW: function to show details on click
function showDetails(f) {
var id = getIdOfFeature(f); //Get the ID of the feature
var d = dataById[id]; // Use the ID to get the data entry
//console.log(d) //testing
var detailsHtml = Mustache.render(template, d); // Render the Mustace template with the data object
//Hide the initial container.
d3.select('#initial').classed('hidden', true);
// Put the HTML output in the details container and show (unhide) it.
d3.select('#details').html(detailsHtml);
d3.select('#details').classed('hidden', false);
}
// NEW: Defining getIdOfFeature
function getIdOfFeature(f) {
return f.properties.idug;
}
body {
margin:25px;
}
#map {
width: 500px;
height: 500px;
border: 1px solid silver;
background: #E6E6E6;
float: left;
}
#tooltip {
position: absolute;
z-index: 2;
background: rgba(255,255,255,0.8);
border-radius: 4px;
width: 105px;
height: 35px;
color: black;
font-size: 14px;
padding: 5px;
top: -150px;
left: -150px;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}
#tooltip p {
margin: 0;
}
#tooltip p.value {
font-weight: bold;
}
#details {
margin-top: 2rem;
float: right;
overflow: hidden;
}
#initial {
font-size: 1.2rem;
float: left;
}
table {
margin-bottom: 0;
}
td, th {
padding: 6px 9px;
}
td {
text-align: right;
}
.container {
width: 1900px;
margin: 25px auto 25px auto;
padding: 50px 50px 50px 50px;
background-color: white;
box-shadow: 0 0 20px #ccc;
}
#footer {
border-top: 1px solid silver;
color: #888888;
font-size: 1.25rem;
text-align: center;
margin-top: 1rem;
padding: 0.5rem;
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment