Published
Edited
Apr 15, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
table = {
const rows = Math.ceil(width / 240), padding = width * .01;
const tileSize = 100/rows - 3;
const chartWidth = width * (tileSize/100)
const chartHeight = chartWidth * .25;

const container = d3.select(html`<div></div>`)
.style('font-family', 'sans-serif');
const facets = container.selectAll('div')
.data(dataFacets.show)
.join('div')
.style('width', `${tileSize}%`)
.style('display', 'inline-block')
.style('background', '#f8f8f8')
.style('margin', `0 ${padding}px ${padding}px 0`)
.style('padding', `${padding * 2}px ${padding}px ${padding}px ${padding}px`)
facets.append('h4')
.style('font-size', '.9em')
.html(d => d[d.length - 1].city);
facets.append('p')
.style('font-size', '.8em')
.style('color', '#808080')
.style('margin-bottom', 0)
.html(d =>
`<span style="font-size:1.2em;font-weight:bold;color:#ff9500">${number(d[d.length - 1].confirmed)}</span> confirmed cases`
);
facets.append('p')
.style('font-size', '.8em')
.style('color', '#808080')
.style('margin-bottom', 0)
.html(d =>
`<span style="font-size:1.2em;font-weight:bold;color:#c9166a">${number(d[d.length - 1].deaths)}</span> deaths`
);
const chartsTop = facets.append('svg')
.attr("viewBox", [0, -1, chartWidth, 2 * chartHeight + padding * 2 + 1]);
const chartsConf = chartsTop.append('g')
const chartsDR = chartsTop.append('g')
drawChart(chartsConf, 'confirmed', '#ff9500', chartWidth, 2 * chartHeight, padding);
drawStack(chartsDR, chartWidth, 2 * chartHeight, padding);
facets.append('p')
.style('font-size', '.8em')
.style('color', '#808080')
.style('margin-bottom', 0)
.html(d =>
`<span style="font-size:1.2em;font-weight:bold">+${number(d[d.length - 1].new)}</span> novos casos em ${new Date(d[d.length - 1].date).toLocaleDateString()}`
);
const chartsNew = facets.append('svg')
.attr("viewBox", [0, -1, chartWidth, chartHeight + padding * 2 + 1]);
drawChart(chartsNew, 'new', '#808080', chartWidth, chartHeight, padding);
facets.append('p')
.style('font-size', '.7em')
.style('color', '#999')
.style('margin-bottom', 0)
.style('line-height', 1.2)
.html(d =>
`A <span style="color:#505050; font-weight: bold">linha cinza grossa</span> mostra a média semanal dos casos diários`
);
return container.node();
}
Insert cell
Insert cell
dataFacets = {
const obj = {};
obj.confirmed = allTimeseries
.sort((a,b) => b[b.length - 1].confirmed - a[a.length - 1].confirmed)
.filter(d => d[d.length - 1].confirmed > viewThreshold);
obj.deaths = allTimeseries
.sort((a,b) => b[b.length - 1].deaths - a[a.length - 1].deaths)
.filter(d => d[d.length - 1].deaths > viewThreshold);
obj.new = allTimeseries
.sort((a,b) => b[b.length - 1].new - a[a.length - 1].new)
.filter(d => d[d.length - 1].new > viewThreshold);
if (order === 'confirmed cases') obj.show = obj.confirmed;
else if (order === 'new daily cases') obj.show = obj.new;
else if (order === 'deaths') obj.show = obj.deaths;
else obj.show = obj.confirmed
return obj;
}
Insert cell
Insert cell
Insert cell
Insert cell
allTimeseries = confirmedByCountryTimeseries.map(d => {
const city = d[0].city
d.stack = stackedDeathsAndRecovered.find(d => d[0][0].data.city === city)
return d;
})
Insert cell
Insert cell
confirmedByCountryTimeseries = {
confirmedWithNew.flat()
const byCountry = Array.from(d3.group(confirmedWithNew.flat(), d=> `${d.city}${d.state}`), ([key, value]) => value);
let addNew = byCountry.map(d => d.map((dd,i) => {
dd.new = (i > 0) ? dd.confirmed - d[i - 1].confirmed : 0;
return dd;
}))
return addNew.map(d => d.sort((a,b) => a.date - b.date));
}
Insert cell
confirmedUSLatest = {
const data = Array.from(d3.group(confirmedRaw, d => d.date), ([key, value]) => value)
.sort((a,b) => b.date - a.date)
.reverse()
const _data = data.filter((d,i) => i === data.length - 1).flat().sort((a,b) => b.confirmed - a.confirmed);
return _data;
}
Insert cell
deathsLatest = confirmedRaw.map(d => d[d.length - 1]).sort((a,b) => b.deaths - a.deaths)
Insert cell
confirmedLatest = confirmedRaw.map(d => d[d.length - 1]).sort((a,b) => b.confirmed - a.confirmed)
Insert cell
confirmedWithNew = confirmedRaw.map(d => d.filter(dd => dd.state === selectedState))
Insert cell
confirmedRaw = d3.csv('https://brasil.io/dataset/covid19/caso?format=csv', d => (d.place_type === "city" && d.city_ibge_code != "") ? d : null)
.then((dd) => {
dd.forEach(function(d){
d.confirmed = +d.confirmed;
d.deaths = +d.deaths;
});
let data_with_holes = Array.from(d3.group(dd, d => d.date), ([key, value]) => value).sort((a,b) => a.date - b.date).reverse();
let mutableArray = [...data_with_holes].filter(function (el) {
return el != null;
});
for (let i = 1; i < data_with_holes.length; i++) {
for (let j = 0; j < mutableArray[i - 1].length; j++) {
let found = mutableArray[i].find(element => element.state === mutableArray[i - 1][j].state && element.city === mutableArray[i - 1][j].city);
if (found !== undefined) {
continue;
}
let newCase = {...data_with_holes[i - 1][j]};
newCase.date = data_with_holes[i][0].date;
mutableArray[i].push(newCase);
}
}
// // this can also be commented, transition will still be buggy
// // now backtrack to fill the data with zeros
// for (let i = data_with_holes.length - 2; i >= 0; i--) {
// for (let j = 0; j < mutableArray[i + 1].length; j++) {
// let found = mutableArray[i].find(element => element.state === mutableArray[i + 1][j].state && element.city === mutableArray[i + 1][j].city);
// if (found !== undefined) {
// continue;
// }

// let newCase = {...data_with_holes[i + 1][j]};
// newCase.confirmed = 0;
// newCase.deaths = 0;
// newCase.date = mutableArray[i][0].date;
// mutableArray[i].push(newCase);
// }
// // trying to sort
// mutableArray[i] = mutableArray[i].sort((a,b) => `${a.state}${a.city}`.localeCompare(`${b.state}${b.city}`));
// }
return mutableArray;
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function movAvg(data, accessor, window = 7) {
const tArray = [...new Array(Math.floor(data.length))];
const means = tArray.map((d, i) => {
const w = ((i + window < data.length)?window:data.length - i);
const sums = d3.sum(data.slice(i,i+7), d => d[accessor]);
const _d = data[i];
_d.weeklyAvg = sums/w;
return _d;
})
return means;
}
Insert cell
function drawStack(svg, w, h, padding) {
yScale.range([h, 0]);
xScale.range([0, w]);
const area = d3.area()
.x(d => xScale(date(d.data.date)))
.y0(d => yScale(d[0]))
.y1(d => yScale(d[1]))
.curve(d3.curveStepBefore)
const g = svg.append('g')
g.selectAll('path')
.data(d => {
yScale.domain([0, d3.max(d, dd=> dd.confirmed)])
d.stack[0].y = yScale.domain()
d.stack[1].y = yScale.domain()
return d.stack;
})
.join('path')
.attr('d', d => {
yScale.domain(d.y)
return area(d)
})
.attr('fill', ({key}) => colors(key))
}
Insert cell
function drawChart(svg, data, color, w, h, padding) {
yScale.range([h, 0]);
xScale.range([0, w])
const area = d3.area()
.x(d => xScale(date(d.date)))
.y0(d => yScale(d[data]))
.y1(h)
.curve(d3.curveStepBefore)
const line = d3.line()
.x(d => xScale(date(d.date)))
.y(d => yScale(d[data]))
.curve(d3.curveStepBefore)
const avg = d3.line()
.x(d => xScale(date(d.date)))
.y(d => yScale(d.weeklyAvg))
.curve(d3.curveCardinal)
const xAxis = d3.axisBottom(xScale)
.ticks(3);
const g = svg.append('g')
g.append('path')
.attr('d', d => {
yScale.domain([0, d3.max(d, d=> d[(data === 'new')? 'new':'confirmed'])]);
return area(d)
})
.attr('fill', color)
.attr('fill-opacity', (data === 'new' || data === 'confirmed')?.2:1);
g.append('path')
.attr('d', d => {
yScale.domain([0, d3.max(d, d=> d[(data === 'new')?'new':'confirmed'])]);
return line(d)
})
.attr('stroke', color)
.attr('fill', 'none');
if(data === 'new') {
g.append('path')
.attr('d', d => {
yScale.domain([0, d3.max(d, d=> d.new)]);
return avg(d)
})
.attr('stroke', '#505050')
.attr('stroke-width', 2)
.attr('fill', 'none');
}
const xa = g.append("g")
.call(xAxis)
.attr('transform', `translate(${0},${h})`)
xa.select(".domain").remove();
xa.selectAll(".tick text")
.attr('fill', '#999');
xa.selectAll(".tick line")
.attr('stroke', '#999');
// const ya = g.append("g")
// .call(yAxis)
// .attr('transform', `translate(10,${0})`)
// ya.select(".domain").remove();
// ya.selectAll(".tick text")
// .attr('fill', '#AAAAA0');
// ya.selectAll(".tick line")
// .attr('stroke', '#f6f6f4')
// .attr('stroke-opacity', .3);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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