forked from Prasham8897/Mortality-Analysis-in-R
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mortality_rate_time_series.html
281 lines (231 loc) · 9.82 KB
/
Mortality_rate_time_series.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>d3 choropleth map</title>
<style>
#wrapper {
width: 960px;
margin: -30px auto 0;
}
#map {
width: 960px;
height: 580px;
position: relative;
}
.stroke {
fill: none;
stroke: #888;
stroke-width: 2px;
}
.fill {
fill: #fff;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}
.land {
fill: #222;
}
.boundary {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
.country {
fill: steelblue;
stroke: white;
}
#play, #clock {
position: absolute;
top: 15px;
}
#play {
left: 15px;
}
#clock {
left: 65px;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="map"></div>
<button id="play">play</button>
<span id="clock">year</span>
</div>
<div style="float: left; position: absolute; top: 550px; left:200px;">
<div class="start" style="float: left;margin-top: 8px; margin-right: 4px"></div>
<div style="float: left;">
<svg id="legend" width="200" height="50">
</svg>
</div>
<div class="end" style="float: left;margin-top: 8px"></div>
<div class="l_name" align="center" style="top: 1100px; left:300px"></div>
</div>
<div class="title" style="float: left; position: absolute; height: 100px; width: 500px; text-align: center;top: 550px; left:500px; font-size: 20px; font-weight: bold;" align="center">
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
//globals
var width, height, projection, path, graticule, svg, attributeArray = [], currentAttribute = 0, playing = false;
function init() {
setMap();
animateMap();
}
function setMap() {
width = 960, height = 580; // map width and height, matches
projection = d3.geo.eckert5() // define our projection with parameters
.scale(170)
.translate([width / 2, height / 2])
.precision(.1);
path = d3.geo.path() // create path generator function
.projection(projection); // add our define projection to it
graticule = d3.geo.graticule(); // create a graticule
svg = d3.select("#map").append("svg") // append a svg to our html div to hold our map
.attr("width", width)
.attr("height", height);
svg.append("defs").append("path") // prepare some svg for outer container of svg elements
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
svg.append("use") // use that svg to style with css
.attr("class", "stroke")
.attr("xlink:href", "#sphere");
svg.append("path") // use path generator to draw a graticule
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
loadData(); // let's load our data next
}
function loadData() {
queue() // queue function loads all external data files asynchronously
.defer(d3.json, "https://raw.githubusercontent.com/biswaspritam/edav_repo/master/world-topo.json") // our geometries
.defer(d3.csv, "https://raw.githubusercontent.com/biswaspritam/edav_repo/master/mortality_d3_data.csv")
//https://raw.githubusercontent.com/biswaspritam/edav_repo/master/countriesRandom.csv
//"https://raw.githubusercontent.com/biswaspritam/edav_repo/master/mortality_d3_data.csv"
// and associated data in csv file
.await(processData); // once all files are loaded, call the processData function passing
// the loaded objects as arguments
}
function processData(error,world,countryData) {
// function accepts any errors from the queue function as first argument, then
// each data object in the order of chained defer() methods above
var countries = world.objects.countries.geometries; // store the path in variable for ease
for (var i in countries) { // for each geometry object
for (var j in countryData) { // for each row in the CSV
if(countries[i].properties.id == countryData[j].id) { // if they match
for(var k in countryData[i]) { // for each column in the a row within the CSV
if(k != 'name' && k != 'id') { // let's not add the name or id as props since we already have them
if(attributeArray.indexOf(k) == -1) {
attributeArray.push(k); // add new column headings to our array for later
}
console.log(i);
console.log(k);
console.log(j);
countries[i].properties[k] = Number(countryData[j][k]*100000) // add each CSV column key/value to geometry object
}
}
break; // stop looking through the CSV since we made our match
}
}
}
d3.select('#clock').html(attributeArray[currentAttribute]); // populate the clock initially with the current year
drawMap(world); // let's mug the map now with our newly populated data object
}
function drawMap(world) {
svg.selectAll(".country") // select country objects (which don't exist yet)
.data(topojson.feature(world, world.objects.countries).features) // bind data to these non-existent objects
.enter().append("path") // prepare data to be appended to paths
.attr("class", "country") // give them a class for styling and access later
.attr("id", function(d) { return "code_" + d.properties.id; }, true) // give each a unique id for access later
.attr("d", path); // create them using the svg path generator defined above
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
d3.selectAll('.country') // select all the countries
.attr('fill-opacity', function(d) {
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // give them an opacity value based on their current value
});
var color = d3.scale.linear()
.domain([0,10])
.range(["rgb(204, 230, 255)","rgb(0, 51, 102)"]);
var sectionWidth = 20
d3.select("svg#legend").selectAll('rect')
.data(d3.range(10))
.enter()
.append('rect')
.attr("x", function(d) { return d*25; })
.attr("y", 10)
.attr("height", 20)
.attr("width", sectionWidth)
.attr('fill', function(d, i) { return color(i)});
var rng=getDataRange();
d3.select("div.start").transition().duration(5000).text(rng[0]+"%");
d3.select("div.end").transition().duration(5000).text(Math.round(rng[1]/100000)+"%");
d3.select("div.l_name").transition().duration(5000).text("LEGEND (%)");
d3.select("div.title").transition().duration(5000).text("Time series of mortality rate(%) around the world");
}
function sequenceMap() {
console.log("enter seq map")
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
d3.selectAll('.country').transition() //select all the countries and prepare for a transition to new values
.duration(200) // give it a smooth time period for the transition
.attr('fill-opacity', function(d) {
// console.log(d.properties[attributeArray[currentAttribute]])
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // the end color value
})
}
function getColor(valueIn, valuesIn) {
var color = d3.scale.linear() // create a linear scale
.domain([valuesIn[0],valuesIn[1]]) // input uses min and max values
.range([0.2,2]); // output for opacity between .3 and 1 %
return color(valueIn); // return that number to the caller
}
function getDataRange() {
// function loops through all the data values from the current data attribute
// and returns the min and max values
var min = Infinity, max = -Infinity;
d3.selectAll('.country')
.each(function(d,i) {
var currentValue = d.properties[attributeArray[currentAttribute]];
if(currentValue <= min && currentValue != -99 && currentValue != 'undefined') {
min = currentValue;
}
if(currentValue >= max && currentValue != -99 && currentValue != 'undefined') {
max = currentValue;
}
});
return [min,max]; //boomsauce
}
function animateMap() {
var timer; // create timer object
d3.select('#play')
.on('click', function() { // when user clicks the play button
if(playing == false) { // if the map is currently playing
timer = setInterval(function(){ // set a JS interval
if(currentAttribute < attributeArray.length-1) {
currentAttribute +=1; // increment the current attribute counter
} else {
currentAttribute = 0; // or reset it to zero
}
sequenceMap(); // update the representation of the map
d3.select('#clock').html(attributeArray[currentAttribute]); // update the clock
}, 200);
d3.select(this).html('stop'); // change the button label to stop
playing = true; // change the status of the animation
} else { // else if is currently playing
clearInterval(timer); // stop the animation by clearing the interval
d3.select(this).html('play'); // change the button label to play
playing = false; // change the status again
}
});
}
window.onload = init(); // magic starts here
</script>
</body>
</html>