Public
Edited
Jul 12, 2023
Insert cell
Insert cell
Plot.plot({
width: Math.max(width, 1200),
marginBottom: 10,
projection: {
type: "azimuthal-equidistant",
rotate: [0, -90],
// Note: 1.22° corresponds to max. percentage (1.0), plus some room for the labels
domain: d3.geoCircle().center([0, 90]).radius(1.22)()
},
facet: {
data: points,
x: "fx",
y: "fy",
axis: null
},
marks: [

// Facet name
Plot.text(points, Plot.selectFirst({text: "Region", frameAnchor: "top", fontWeight: "400", fontSize: 18})),
// grey discs
Plot.geo(breaks, { // Use breaks instead of fixed values
geometry: (r) => d3.geoCircle().center([0, 90]).radius(r)(),
stroke: "black",
fill: "black",
strokeOpacity: 0.2,
fillOpacity: 0.02,
strokeWidth: 0.5
}),

// white axes
Plot.link(longitude.domain(), {
x1: longitude,
y1: 90 - 0.8,
x2: 0,
y2: 90,
stroke: "white",
strokeOpacity: 0.5,
strokeWidth: 2.5
}),

// tick labels
Plot.text(breaks, {
fx: 0, fy: 0,
x: 180,
y: (d) => 90 - d,
dx: 2,
textAnchor: "start",
text: (d) => ( d == 0.8 ? `${100 * d}%` : `${100 * d}%`),
fill: "currentColor",
stroke: "white",
fontSize: 12
}),


// axes labels
Plot.text(longitude.domain(), {
fx: 0, fy: 0,
x: longitude,
y: 90 - 1.07,
text: d => d.replace(/_/g, " "), // Remove underscore characters with spaces

lineWidth: 5,
fontSize: 12
}),

// axes labels, initials
Plot.text(longitude.domain(), {
fx: 0, fy: 0, facet: "exclude",
x: longitude,
y: 90 - 1.09,
text: d => d.substring(0, 4), // Display the first three letters
lineWidth: 5
}),
// areas
Plot.area(points, {
x1: ({ key }) => longitude(key),
y1: ({ value }) => 90 - value,
x2: 0,
y2: 90,
fill: "black",
fillOpacity: 0.25,
stroke: "#4269D0",
curve: "cardinal-closed"
}),

// points
Plot.dot(points, {
x: ({ key }) => longitude(key),
y: ({ value }) => 90 - value,
fill: "raw", // Use the color scale based on the raw value
stroke: "white"
}),

// interactive labels
Plot.text(
points,
Plot.pointer({
x: ({ key }) => longitude(key),
y: ({ value }) => 90 - value,
text: (d) => `${d.key.replace(/_/g, "\n")}\n${d.raw}%`,
textAnchor: "start",
dx: 4,
fill: "currentColor",
stroke: "white",
maxRadius: 10,
fontSize: 12
})
)
]
})
Insert cell
cars2 = FileAttachment("index4_20230712-090351.csv").csv({typed: true, header: true})
Insert cell
Insert cell
breaks = {const breaks = d3.extent(points, d => d.value);
const numBreaks = 4;
const roundedBreaks = [];
for (let i = 0; i < numBreaks; i++) {
const roundedValue = +(breaks[0] + (breaks[1] - breaks[0]) * i / (numBreaks - 1)).toFixed(3);
roundedBreaks.push(roundedValue);
}
return roundedBreaks;}// Calculate the extent of values in the data
Insert cell
filteredPoints = {const filteredPoints = points.filter(d => d.key === "Inflation");
return filteredPoints;}// Calculate the extent of values in the data


Insert cell
colorScale = {const colorScale = d3.scaleSequential(d3.interpolateBlues).domain(d3.extent(filteredPoints, d => d.raw));
return colorScale;}// Calculate the extent of values in the data

Insert cell
points = {
const points = d3.sort(cars2, d => d.Price).flatMap(({ Region, ...values }, i) =>
Object.entries(values).map(([key, raw]) => ({
Region,
key,
raw,
value: key === "Month" ? raw : raw / 100, // divide by 100 for non-"Month" columns
fx: (1 + i) % 3,
fy: Math.floor((1 + i) / 3)
}))
);

return points.filter(d => d.key !== "Month");
}

Insert cell
longitude = d3.scalePoint(new Set(Plot.valueof(points, "key")), [180, -180]).padding(0.5).align(1)
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