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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more