Public
Edited
Oct 11, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chartElem = Plot.plot({
// size and margins
height: 540,
width: 600,
margin: 0,

projection: {
type: "azimuthal-equal-area",
domain: nutsGeo,
inset: 8
},

marks: [
// background (oceans and lakes)
Plot.frame({ fill: "#f7fbfd" }),

// "fuzzy" outline filter and missing data pattern
() =>
svg`
<defs>
<filter id="shadow" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="0" dy="0" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="4" />
<feComponentTransfer result="opacityOut" in="blurOut">
<feFuncA type="linear" slope="0.3"/>
</feComponentTransfer>
<feBlend in="SourceGraphic" in2="opacityOut" mode="normal" />
</filter>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" width="4" height="4">
<path d="M-1,1 l2,-2
M0,4 l4,-4
M3,5 l2,-2"
style="stroke:#eeeeee; stroke-width:1" />
</pattern>
</defs>
`,

// base map
Plot.geo(worldGeo, {
fill: "#fff",
strokeWidth: 0.5,
stroke: "#cdcdcd"
}),

// outline of data map
/*
Plot.geo(nutsGeo, {
fill: "#fff",
stroke: "#222",
strokeOpacity: (d) => (d.id.length === 2 ? 1 : 0),
imageFilter: "url(#shadow)"
}),*/

// missing data map
Plot.geo(nutsGeo, {
fill: "url(#diagonalHatch)"
}),

// data map
Plot.geo(nutsGeo, {
fill: (d) =>
gdpMilMap.has(d.id) ? gdpMilMap.get(d.id).color : "transparent"
}),

// country (data) level outline map
Plot.geo(nutsGeo, {
stroke: (d) => (d.properties.LEVL_CODE === 0 ? "#222" : "none"),
strokeOpacity: 0.4
}),

// legend
(a, b, c, layout) =>
svg`
<g transform="translate(${layout.width - 106 - 48},${48 - 16})">
${Plot.plot({
height: 120,
width: 120,
margin: 0,
inset: 16,
marks: [
Plot.rect(d3.cross([0, 1, 2], [0, 1, 2]), {
x: ([a, b]) => a,
y: ([a, b]) => b,
interval: 1,
fill: ([a, b]) => colors[a + b * 3],
stroke: "#222"
}),

Plot.text(["GDP →"], {
fontWeight: "bold",
fontSize: 14,
x: 0,
y: 0,
rotate: 0,
textAnchor: "middle",
dx: 60 - 16,
dy: 10
}),

Plot.text(["MILITARY →"], {
fontWeight: "bold",
fontSize: 14,
x: 0,
y: 0,
rotate: 0,
textAnchor: "middle",
rotate: -90,
dx: -10,
dy: -60 + 16
})
]
})}
</g>`
]
})
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
Insert cell
Insert cell
Insert cell
gdpScale = d3.scaleQuantile(
Array.from(milGdpData, (d) => d.gdp).concat(0),
d3.range(3)
)
Insert cell
milScale = d3.scaleQuantile(
Array.from(milGdpData, (d) => d.mil).concat(0),
d3.range(3)
)
Insert cell
Plot.plot({
title: "GDP in Euros (€)",
height: 200,
width: 700,
marks: [
Plot.barY(gdp2022, {
marginLeft: 58,
x: "code",
y: "value",
fill: (d) => colors[gdpScale(d.value)],
sort: { x: "y" }
})
]
})
Insert cell
Plot.plot({
title: "Military spending as a percentage of GDP",
height: 200,
width: 700,
marks: [
Plot.barY(milSpending2022, {
marginLeft: 58,
x: "code",
y: "value",
fill: (d) =>
colors[milScale(d.value) === 0 ? 0 : milScale(d.value) === 1 ? 3 : 6],
sort: { x: "y" }
})
]
})
Insert cell
Array.from(gdpMilMap)
Insert cell
sortedData = Array.from(gdpMilMap)
.sort((a, b) => (a[1].mil < b[1].mil ? -1 : 1))
.map((d) => ({ ...d[1] }))
Insert cell
numberformatter = new Intl.NumberFormat("en-GB", {
notation: "compact",
compactDisplay: "short",
})
Insert cell
Plot.plot({
title: "Totals (GDP and Military spending)",
height: 200,
width: 800,
y: {
grid: true
},
marginTop: 32,
marks: [
Plot.barY(sortedData, {
marginLeft: 58,
x: (d) => d.code,
y: (d) => d.gdp,
fill: (d) => d.color,
fillOpacity: 0.4,
stroke: (d) => d.color,
strokeWidth: 1,
inset: 1,
channels: { gdp: (d) => d.gdp * (d.mil / 100) },
sort: { x: "gdp" }
}),

Plot.barY(sortedData, {
marginLeft: 58,
x: (d) => d.code,
y: (d) => d.gdp * (d.mil / 100),
fill: (d) => d.color,
stroke: "#222",
strokeWidth: 1,
inset: 1,
channels: { gdp: (d) => d.gdp * (d.mil / 100) },
sort: { x: "gdp" }
}),

Plot.text(sortedData, {
x: "code",
y: "gdp",
text: (d) =>
`${numberformatter.format(d.gdp)}\n${numberformatter.format(
d.gdp * (d.mil / 100)
)}`,
dy: -6,
fontSize: 8,
lineAnchor: "bottom"
})
]
})
Insert cell
Plot.plot({
title: "GDP vs Military spedning (% GDP)",
grid: true,
marginLeft: 64,
insetBottom: 24,
y: { label: "GDP" },
x: { label: "Military spending" },
marks: [
Plot.dot(Array.from(gdpMilMap), {
x: (d) => d[1].mil,
y: (d) => d[1].gdp,
r: 7,
fill: (d) => d[1].color,
fillOpacity: 0.8,
stroke: "#222",
strokeWidth: 0.5
})
]
})
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