Public
Edited
Aug 12
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
map = {
// Initialize the map
const m = eurostatmap
.map("choropleth")
.width(width)
.height(height)
.title("Custom geometries test")
.subtitle("Unemployment rate, municipality level, 2023")
.geometries([
{
id: "regions",
class: "regions",
statisticalRegions: true,
features: municipalGeometries.features
// onEach: (elements) => {
// // Add any D3 custom styling or behavior here
// }
},
{
id: "borders",
features: borderGeometries.features,
class: "borders"
}
])
.classificationMethod("threshold")
.thresholds([1, 3, 4, 5, 6, 7, 8, 9])
.colorFunction(d3.interpolateYlGnBu)
.zoomExtent([1, 10])
.projectionFunction(projection)
.legend({
title: "Unemployment %",
x: 5,
y: 180,
boxOpacity: 0.8,
decimals: 0
})
.footnote(
'Source: <a href="https://datos.gob.es/en/catalogo/ea0021425-paro-registrado-por-municipios">datos.gob.es</a>'
)
.insetBoxPosition([5, 490])
.insets([
{
projectionFunction: canariesProjection,
title: "Canarias",
geometries: [
{
id: "canaries",
class: "canaries",
statisticalRegions: true,
features: canariesFeatures
}
],
width: canariesWidth,
height: canariesHeight,
x: 0,
y: 0,
zoomExtent: [1, 10]
},
{
projectionFunction: melillaProjection,
title: "Melilla",
geometries: [
{
id: "melilla",
class: "melilla",
statisticalRegions: true,
features: melillaFeatures
}
],
width: melillaWidth,
height: melillaHeight,
x: 350,
y: 0,
zoomExtent: [1, 10]
}
]);
// .labels({ values: true })

// Set statistical data for the map
m.statData().setData(statisticalData);

// Build the map
m.build();

return m;
}
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
municipalTopojson = FileAttachment("spain-municipalities.topojson.json").json()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lookupCode = 26011
Insert cell
statisticalData[lookupCode]
Insert cell
populationLookup[lookupCode]
Insert cell
unemploymentLookup[lookupCode]
Insert cell
unemploymentCsv.find((d) =>
Object.values(d).some((val) => String(val).includes(lookupCode))
)
Insert cell
mergedData.find((d) => d["Codigo Municipio"] == lookupCode)
Insert cell
mergedData = unemploymentCsv.map((row) => {
// Step 1: Clean whitespace from all keys (in case of leading spaces)
const cleanedRow = {};
for (const key in row) {
cleanedRow[key.trim()] = row[key];
}

// Step 2: Swap code/name fields if necessary
const codeRaw = cleanedRow["Codigo Municipio"];
const nameRaw = cleanedRow["Municipio"];

const isCodeBroken = !/^\d+$/.test(codeRaw?.trim());
const isNameActuallyCode = /^\d+$/.test(nameRaw?.trim());

if (isCodeBroken && isNameActuallyCode) {
// Swap the fields
const temp = cleanedRow["Codigo Municipio"];
cleanedRow["Codigo Municipio"] = cleanedRow["Municipio"];
cleanedRow["Municipio"] = temp;
}

// Step 3: Fix clearly broken "total Paro Registrado" (should be numeric)
if (!/^\d+$/.test(cleanedRow["total Paro Registrado"])) {
// Try to recover from a known column like "Paro hombre edad < 25"
const fallbackTotal = [
"Paro hombre edad < 25",
"Paro mujer edad < 25"
].reduce((sum, k) => {
const val = parseInt(cleanedRow[k]);
return sum + (isNaN(val) ? 0 : val);
}, 0);
cleanedRow["total Paro Registrado"] = fallbackTotal || null;
}

// Step 4: Attempt merge
const code = String(cleanedRow["Codigo Municipio"] || "").replace(/^0+/, "");
const match = populationLookup[code];

return match ? { ...cleanedRow, ...match } : cleanedRow;
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
eurostatmap = require("eurostat-map")
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