Published
Edited
Nov 21, 2020
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { renderInfographic } from '@nuuuwan/infographic-utils'
Insert cell
import { optionsCartogram } from '@nuuuwan/topojson-utils'
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
TABLE_NAME_TO_ID = Object.entries(TABLE_TO_NAME).reduce(function(
TABLE_NAME_TO_ID,
[tableID, tableName]
) {
TABLE_NAME_TO_ID[tableName] = tableID;
return TABLE_NAME_TO_ID;
},
{})
Insert cell
FIELD_TO_HUE = Object({
Sinhalese: 355,
SL_Tamil: 21,
Ind_Tamil: 21,
SL_Moor: 140,
Malay: 140,
Burgher: 330,

Buddhism: 43,
Hindu: 21,
Islam: 140,
'Other Christian': 330,
'Roman Catholic': 240
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function getTableDataForRegionType(tableID, regionType) {
const religionData = await getTableData(tableID);
return religionData.filter(x => getRegionType(x.id) === regionType);
}
Insert cell
async function getEthnoReligoData() {
const ethnoData = await getTableData('000001');
const religoData = await getTableData('000002');

return ethnoData.map(function(ethnoDatum, i) {
const religoDatum = religoData[i];
if (religoDatum.id !== ethnoDatum.id) {
return null;
}

const totalPopulation = ethnoDatum['Total Population'];

function p(x) {
return x / totalPopulation;
}

return {
id: ethnoDatum.id,
'Sinhala-All': p(ethnoDatum['Sinhalese']),
'Sinhala-Buddhist': p(religoDatum['Buddhist']),
'Sinhala-Non-Buddhist': p(
ethnoDatum['Sinhalese'] - religoDatum['Buddhist']
),

'Tamil-All': p(ethnoDatum['SL_Tamil'] + ethnoDatum['Ind_Tamil']),
'Tamil-SL': p(ethnoDatum['SL_Tamil']),
'Tamil-Indian': p(ethnoDatum['Ind_Tamil']),

Muslim: p(ethnoDatum['SL_Moor'] + ethnoDatum['Malay']),
'Moor-SL': p(ethnoDatum['SL_Moor']),
Malay: p(ethnoDatum['Malay'])
};
});
}
Insert cell
(await getEthnoReligoData())[0]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function optionsCensusSingleFieldMap(
tableID,
fieldName,
regionID,
subRegionType,
options = {}
) {
options = addDefaults(options, {
maxRadius: 150,
isAbsolute: false,
maxLabelCount: 10
});

const tableData = await getTableData(tableID);

const subRegionIDList = getSubRegionIDList(regionID, subRegionType);

const regionIDToPInfo = tableData
.filter(function(datum) {
return subRegionIDList.includes(datum.id);
})
.reduce(function(regionIDToPInfo, datum) {
const total = datum['Total Population']
? datum['Total Population']
: datum['Total Households'];
regionIDToPInfo[datum.id] = {
p: datum[fieldName] / total,
n: datum[fieldName],
total: total
};
return regionIDToPInfo;
}, {});

const maxTotal = sum(
Object.values(regionIDToPInfo).map(d =>
options.isAbsolute ? d.total : d.n
)
);

const nList = Object.values(regionIDToPInfo)
.map(d => d.n)
.sort((a, b) => b - a);
const nMaxLabel = nList[options.maxLabelCount];
const nToRadius = n => options.maxRadius * Math.sqrt(n / maxTotal);
const maxLabelRadius = nToRadius(nMaxLabel);

options = addDefaults(options, {
funcDataToRadius: function(data) {
const regionID = data.properties.id;
const pInfo = regionIDToPInfo[regionID];
return nToRadius(pInfo.n);
},
funcDataToColor: function(data) {
const regionID = data.properties.id;
const pInfo = regionIDToPInfo[regionID];
const [h, s, l, a] = [
FIELD_TO_HUE[fieldName] ? FIELD_TO_HUE[fieldName] : 0,
100,
20 + 80 * (1 - pInfo.p),
0.5
];
return hsla(h, s, l, a);
}
});
options = addDefaults(options, {
funcDrawLabel: function(data, svg, [x, y], options) {
const r = options.funcDataToRadius(data);
if (r < maxLabelRadius) {
return;
}
drawText(
svg,
[x, y - DEFAULT_STYLE.fontSize * 0.8],
data.properties.name,
{
fill: 'black',
fontSize: DEFAULT_STYLE.fontSize / 2
}
);

const regionID = data.properties.id;
const pInfo = regionIDToPInfo[regionID];
drawText(svg, [x, y], formatPercent(pInfo.p), {
fill: 'black',
fontSize: DEFAULT_STYLE.fontSize
});

drawText(
svg,
[x, y + DEFAULT_STYLE.fontSize * 0.8],
formatNumberHuman(pInfo.n),
{
fill: 'black',
fontSize: DEFAULT_STYLE.fontSize / 2
}
);
},
kicker: await getTableLabel(tableID),
title: getRegionLabel(regionID),
subTitle: fieldName + ' by ' + REGION_TYPE_TO_NAME[subRegionType],
footer: '2012 Census of Sri Lanka (https://www.statistics.gov.lk)'
});
return options;
}
Insert cell
async function renderSingleFieldMapInfographic(
tableID = '000001',
fieldName = 'Sinhalese',
regionID = 'LK-11',
subRegionType = REGION_TYPE.DSD,
options = {}
) {
options = await optionsCensusSingleFieldMap(
tableID,
fieldName,
regionID,
subRegionType,
addDefaults(options, {
funcDrawInner: function(svg) {
drawRegionMap(svg, regionID, subRegionType, options);
}
})
);
options = optionsCartogram(options);
return renderInfographic(options);
}
Insert cell
renderSingleFieldMapInfographic(
TABLE_ID,
FIELD_NAME,
'LK',
REGION_TYPE.DISTRICT
)
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