Public
Edited
Jun 12, 2023
1 fork
Importers
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
width,
inset: 10,
projection: { type: "orthographic", rotate: [-longitude, -30] },
length: { domain: [0, 41e6], range: [0, 100] },

marks: [
Plot.graticule({ strokeOpacity: 0.05 }),

// LAND
() => insetShadow,
Plot.geo(basemap[0], {
fill: "#c9d8df",
imageFilter: effect ? "url(#inset-shadow)" : null
}),

// BORDERS
Plot.geo(basemap[1], { stroke: "white", strokeOpacity: 0.7 }),

// BARS
Plot.vector(ghs_urban_centres_2015, {
// CHANNELS
x: "LON",
y: "LAT",
r: 2,
length: "P15",
shape: barMap,
// STYLE
anchor: "start",
fill: "#D80B8C",
fillOpacity: 0.8,
imageFilter: effect ? "drop-shadow(0.07rem 0.07rem 0.07rem white)" : null,
// TOOLTIP
tip: true,
title: (d) =>
`${d.NAME} (${d.COUNTRY})\n
Pop 2015: ${d.P15.toLocaleString(undefined, {
maximumFractionDigits: 0,
maximumSignificantDigits: 3
})}`
}),

Plot.sphere({
stroke: "grey",
imageFilter: effect ? "blur(5px)" : null,
clip: "sphere"
}),

legendBar([1e6, 1e7, 2e7, 4e7], { fill: "#D80B8C", fillOpacity: 0.8 })
],
caption:
"Source: GHS Urban Centre Database 2015. European Commission, Joint Research Centre (JRC)"
})
Insert cell
Insert cell
Insert cell
Insert cell
barMap = ({
draw(context, length, r) {
context.rect(-r / 2, 0, r, -length); // (x, y, width, height)
}
})
Insert cell
Insert cell
// From CSS-TRICKS
// https://css-tricks.com/adding-shadows-to-svg-icons-with-css-and-svg-filters/#aa-inset-shadows
insetShadow = htl.svg`<filter id='inset-shadow'>
<!-- Shadow offset -->
<feOffset
dx='0'
dy='0'
/>

<!-- Shadow blur -->
<feGaussianBlur
stdDeviation='4'
result='offset-blur'
/>

<!-- Invert drop shadow to make an inset shadow -->
<feComposite
operator='out'
in='SourceGraphic'
in2='offset-blur'
result='inverse'
/>
<!-- Cut color inside shadow -->
<feFlood
flood-color='black'
flood-opacity='.95'
result='color'
/>
<feComposite
operator='in'
in='color'
in2='inverse'
result='shadow'
/>

<!-- Placing shadow over element -->
<feComposite
operator='over'
in='shadow'
in2='SourceGraphic'
/>
</filter>`
Insert cell
Insert cell
function legendBar(
values,
{
frameAnchor = "bottom-right",
format = "~s",
stroke,
strokeWidth,
fill,
fillOpacity
} = {}
) {
if (!Array.isArray(values)) values = Array.from(values);
if (typeof format !== "function") format = d3.format(format);
return Plot.marks(
values.map((v, i) => {
const dx = (i - values.length) * 28;
return [
Plot.vector([v], {
length: [v],
shape: barMap,
anchor: "start",
dx,
dy: -20,
frameAnchor,
stroke,
strokeWidth,
fill,
fillOpacity
}),
Plot.text([v], {
text: [format(v)],
dx,
dy: -10,
frameAnchor,
textAnchor: "middle"
})
];
})
);
}
Insert cell
Insert cell
basemap = topohelper
.from(world50m)
.innerlines({ layer: "countries", name: "borders" })
.toGeojson({ layer: ["land", "borders"] })
Insert cell
Insert cell
Insert cell
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