Published
Edited
Oct 6, 2020
1 fork
Importers
1 star
Insert cell
md`# COVID-19 in Illinois - Current statewide demographics`
Insert cell
IllinoisCovidDemographicTableEn = {
const lang = 'en';
await triggerEmbedAnalytics(`IL statewide demographics table`);
return html`
<h2>${messageFormatter("table.title", lang).format()}</h2>

<p>${messageFormatter("table.description", lang).format()}</p>

<div class="covid-table-row">
<div class="covid-table race">
${await demographicTableTwo("race", lang)}
</div>
<div class="covid-table age">
${await demographicTableTwo("age", lang)}
</div>
</div>

${footer()}

${style(lang)}
`;
}
Insert cell
IllinoisCovidDemographicTableEs = {
const lang = 'es';
await triggerEmbedAnalytics(`IL statewide demographics table`);
return html`
<h2>${messageFormatter("table.title", lang).format()}</h2>

<p>${messageFormatter("table.description", lang).format()}</p>

<div class="covid-table-row">
<div class="covid-table race">
${await demographicTableTwo("race", lang)}
</div>
<div class="covid-table age">
${await demographicTableTwo("age", lang)}
</div>
</div>

${footer(lang)}

${style(lang)}
`;
}
Insert cell
style = lang => html`
<style>
.covid-chart-row, .covid-table-row {
display: flex;
margin-top: 10px;
margin-bottom: 10px;
}

.covid-table-row .covid-table, .covid-chart-row .covid-chart {
width: 100%;
margin-right: 40px;
}
.covid-table-row .covid-table:last-child, .covid-chart-row .covid-chart:last-child {
margin-right: 0;
}
.covid-table-row .covid-table.race {
width: 63%;
}
.covid-table-row .covid-table.age {
width: 37%;
}

.covid-table-row h3 {
font-size: 16px;
line-height: 26px;
margin: 0;
}

table.demographic-table, table.demographic-table caption, table.demographic-table tbody, table.demographic-table tfoot, table.demographic-table thead, table.demographic-table tr, table.demographic-table th, table.demographic-table td {
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline;
}
table.demographic-table {
border-collapse: collapse;
border-spacing: 0;
}
table.demographic-table tbody td {
padding: 1px;
}
table.demographic-table tbody td > span {
display: block;
line-height: 1.5;
}
table.demographic-table tbody td.description {
border-bottom: 1px solid #bbb;
padding-right: 8px;
max-width: 160px;
width: 35%;
}

table.demographic-table tbody td.description span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
table.demographic-table tbody td.description span.blank {
font-style: italic;
color: #555;
}
table.demographic-table td.number {
text-align: right;
width: 70px;
background-color: #fff;
}
table.demographic-table .number span {
padding: 3px 7px 3px 2px;
}
table.demographic-table .number span.too-low, table.demographic-table .number span.na {
color: #333;
background-color: #f5f5f5;
background-image: linear-gradient(-45deg, #ddd 25%, transparent 25%, transparent 50%, #ddd 50%, #ddd 75%, transparent 75%, transparent);
background-size: 6px 6px;
}

table.demographic-table thead th {
padding-bottom: 2px;
}

table.demographic-table td.legend svg > g > g.tick:first-child text {
text-anchor: start;
}
table.demographic-table td.legend svg > g > g.tick:last-child text {
text-anchor: end;
}
table.demographic-table td.legend svg > g > g.tick line {
stroke: #444;
}
@media screen and (max-width: 600px) {
.covid-zip-selector { margin-top: 20px; }
.covid-table-row, .covid-chart-row, .covid-zip-map .covid-topper { display: block; }
.covid-table-row .covid-table, .covid-chart-row .covid-chart { width: 100%; margin-top: 15px; }
.covid-table-row .covid-table.age, .covid-table-row .covid-table.race {
width: 100%;
}
.covid-zip-map .covid-topper .covid-infobox {
margin: 0;
margin-top: 20px;
}
table.demographic-table tbody td.description {
max-width: 50px;
width: 25%;
}
table.demographic-table {
font-size: 12px;
}
}

/*.text-bold {
font-weight: bold;
}
.border-bottom-dotted {
border-bottom: 1px dotted grey !important;
}*/
</style>
`
Insert cell
demographicKeyLabelMap = new Map([
['age', { descColumn: 'age_group', en: 'Age' }],
['race', { descColumn: 'description', en: 'Race' }],
['gender', { descColumn: 'description', en: 'Gender' }]
])
Insert cell
d3 = require("d3@5")
Insert cell
import {
IllinoisCountyCovidData,
triggerEmbedAnalytics,
footer
} from "@chicagoreporter/coronavirus-illinois-county-counts"
Insert cell
Insert cell
import {messageFormatter} with {translations} from "@chicagoreporter/formatjs-helpers"
Insert cell
import { legend } from "@d3/color-legend"

Insert cell
demographicTableTwo = async (demographic = "age", lang = "en") => {
const censusDemographics = IllinoisStatewideDemographics[0].Race;
let data = IllinoisCountyCovidData.demographics[demographic];
if (demographic === "race") {
data = data.sort((a, b) => b.count - a.count);
}

const totalCount = d3.sum(data, d => d.count);
const totalDeaths = d3.sum(data, d => d.deaths);

data = data.map(d => {
d.count_pct = d.count / totalCount;
d.death_pct = d.deaths / totalDeaths;
return d;
});

const countScale = d3
.scaleLinear()
.domain([0, d3.max(data, d => d.count_pct)])
.range(["#fff5eb", "#e25609"]);

const deathScale = d3
.scaleLinear()
.domain([0, d3.max(data, d => d.death_pct)])
.range(["#f1eff6", "#7363ac"]);

const popScale = d3
.scaleLinear()
.domain([0, d3.max(Object.values(censusDemographics), d => d.PE)])
.range(["#e3eef9", "#2f7ebc"]);

const legendScale = (label, color, data, selector) =>
legend({
title: `% of ${label}`,
color: color,
tickFormat: '%',
tickValues: [0, d3.max(data, d => d[selector])],
width: 60,
marginLeft: 5
});

const tableLabelColor = hex => {
const color = d3.hsl(d3.color(hex));
return color.l < .7 ? "#ffffff" : "#000000";
};

return html`
<table class="demographic-table">
<thead>
<tr>
<th>${messageFormatter(
"table.labels." + demographic,
lang
).format()}</th>
<th>${messageFormatter("table.labels.cases", lang).format()}</th>
<th>${messageFormatter("table.labels.deaths", lang).format()}</th>
${
demographic === "race"
? html`<th>${messageFormatter(
"table.labels.population_long",
lang
).format()}</th>`
: ''
}
</tr>
</thead>
<tbody>
${data.map(d => {
const demoValue =
d[demographicKeyLabelMap.get(demographic).descColumn];
let demoLabel = '';
if ('race' === demographic) {
demoLabel = html`${messageFormatter(
"table.labels.races." + demoValue,
lang
).format()}`;
if (demoValue === "Left Blank")
demoLabel = html`<em>${demoLabel}</em>`;
} else {
demoLabel = html`${demoValue}`;
//if (demoValue === "Unknown") demoLabel = html`<em>${messageFormatter("table.labels.unknown",lang).format()}</em>`;
if (demoValue === "Unknown") return html``;
}
return html`
<tr>
<td class="description">
<span class="${
demoValue === "Left Blank" || demoValue === "Unknown"
? "blank"
: ""
}">
${demoLabel}
</span>
</td>
<td class="number text-bold border-bottom-dotted">
<span class="align-right" style="background-color: ${countScale(
d.count_pct
)}; color: ${tableLabelColor(
countScale(d.count_pct)
)};">${d.count.toLocaleString(lang)}</span>
</td>
<td class="number text-bold border-bottom-dotted">
<span class="align-right" style="background-color: ${deathScale(
d.death_pct
)}; color: ${tableLabelColor(
deathScale(d.death_pct)
)};">${d.deaths.toLocaleString(lang)}</span>
</td>
${
demographic === "race"
? html`<td class="number">
${
censusDemographics[d.description]
? censusDemographics[d.description].PE < .01
? html`<span class="too-low"><${(.01).toLocaleString(
lang,
{ style: "percent" }
)}</span>`
: html`<span style="
background-color: ${popScale(
censusDemographics[d.description].PE
)};
color: ${tableLabelColor(
popScale(censusDemographics[d.description].PE)
)};">
${censusDemographics[
d.description
].E.toLocaleString(lang, {})}
</span>`
: html`<span class="na">n/a</span>`
}
</td>`
: ''
}
</tr>`;
})}
<tr class="legend-row">
<td></td>
<td class="legend">
${legendScale(
messageFormatter("table.labels.cases", lang).format(),
countScale,
data,
'count_pct'
)}
</td>
<td class="legend">
${legendScale(
messageFormatter("table.labels.deaths", lang).format(),
deathScale,
data,
'death_pct'
)}
</td>
${
demographic === "race"
? html`<td class="legend">
${legendScale(
messageFormatter("table.labels.population", lang).format(),
popScale,
Object.values(censusDemographics),
'PE'
)}
</td>`
: ''
}
</tr>
</tbody>
</table>
`;
}
Insert cell
IllinoisStatewideDemographics = FileAttachment("IllinoisStatewideDemoData.json").json();
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