Published
Edited
Apr 16, 2020
Insert cell
Insert cell
Insert cell
Covid19Map = {

let map;
let container;

if (shouldInitMap()() || x === 0) {
container = DOM.element('div', { style: `width:${width}px;height:${width/2}px` });
yield container;

map = L.map(container, {}).setView([30, 0], 2.3);
map.options.minZoom = 0.5;
map.options.maxZoom = 3;
let osmLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
cacheMap.reset();
cacheContainer.reset();
cacheMap.cache(map);
cacheContainer.cache(container);
} else {
map = cacheMap.cache();
container = cacheContainer.cache();
yield container;
}
//initialize svg to add to map
L.svg().addTo(map)
//Create selection using D3
const overlay = d3.select(map.getPanes().overlayPane)
const svg = overlay.select('svg')
// create a group that is hidden during zooming
const g = svg.append('g').attr('class', 'leaflet-zoom-hide')
// Use Leaflets projection API for drawing svg path (creates a stream of projected points)
const projectPoint = function(x, y) {
const point = map.latLngToLayerPoint(new L.LatLng(y, x))
this.stream.point(point.x, point.y)
}
const scale = d3.scaleSqrt().domain([0, 100000]).range([2, sigmoid(map.getZoom()) * 15]);
const color = d3.scaleSqrt().domain([0, 50000, 100000]).range(["#efa315", "#ef7115", "#ef3415"])
// Use d3's custom geo transform method to implement the above
const projection = d3.geoTransform({point: projectPoint})
// creates geopath from projected points (SVG)
const pathCreator = d3.geoPath().projection(projection).pointRadius(
function(d) {
if (d.properties.size != 0) {
return scale(d.properties.size);
}
return 0;
}
)
const areaPaths = g.selectAll('path')
.data(finalData.transformed)
.enter()
.append('path')
.attr("fill", function(d) { return color(d.properties.size) })
.attr('r', 110);
// Function to place svg based on zoom
const onZoom = () => areaPaths.attr('d', pathCreator)

// initialize positioning
onZoom()
// reset whenever map is moved
map.on('zoomend', onZoom)
}
Insert cell
shouldInitMap = R.once(() => {
let isInitialised = false;
return (init) => {
if (isInitialised === false) {
isInitialised = true
return true;
}
return false;
}
})
Insert cell
// cacheMap = R.once((map) => (map));

cacheMap = {
let isCached = false;
let map;
return {
reset: () => {
isCached = false;
},
cache: (mapToCache) => {
if (isCached === false) {
map = mapToCache;
}
isCached = true;
return map;
}
}
}
Insert cell
// cacheContainer = R.once((map) => (map));

cacheContainer = {
let isCached = false;
let container;
return {
reset: () => {
isCached = false;
},
cache: (containerToCache) => {
if (isCached === false) {
container = containerToCache;
}
isCached = true;
return container;
}
}
}
Insert cell
d3 = require("d3@5", "d3-tile@1", "d3-geo-projection@2", "d3-scale@3")
Insert cell
R = require("ramda")
Insert cell
rawData = d3.csvParse(await FileAttachment("20200416_confirmed.csv").text());
Insert cell

x = {
let i = 0;
while (true) {
++i
if (i < 60) {
yield Promises.delay(500, i);
} else if (i >= 60 && i < 75) {
yield Promises.delay(1000, i);
} else if (i === 85) {
i = 0;
yield Promises.delay(10000, i);
} else {
yield Promises.delay(2000, i);
}
}
}
Insert cell
// Omit data not needed, find the first day that is not 0 (first death) and use as day 0, prepare for graph
transformFunc = (data, dates) => R.compose(
(item) => {
const all = [];
item.forEach((current, index) => {
if (index == x) {
dates[x] = current[0];
all.push({
"type": "Feature",
"properties": {
"Name": "Data",
"size": parseInt(current[1], 10)
},
"geometry": {
"type": "Point",
"coordinates": [data.Long, data.Lat],
"properties": { "size": parseInt(current[1], 10)}
}
})
}
});
return all;
},
R.toPairs,
R.omit(['Province/State', 'Country/Region', 'Lat', 'Long'])
)(data)
Insert cell
finalData = (() => {
let transformed = [];
let dates = {};
rawData.forEach((item, index) => {
transformed = transformed.concat(transformFunc(item, dates))
});
return { transformed, dates };
})();

Insert cell
topojson = require("topojson-client@3")
Insert cell
L = require('leaflet@1.2.0')
Insert cell
sigmoid = (x) => {
return 1 / (1 + Math.exp(-x));
};
Insert cell
html`<link href='${resolve('leaflet@1.2.0/dist/leaflet.css')}' rel='stylesheet' />`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more