Public
Edited
May 6
Insert cell
Insert cell
import {Inputs} from "@observablehq/inputs";

Insert cell
data = FileAttachment("quality_of_life.csv").csv({typed: true});

Insert cell
data.slice(0, 5)

Insert cell
Insert cell
// Sort descending by Safety Index, then take the first 10
top10Safety = data
.slice() // copy so we don’t mutate the original
.sort((a, b) => b["Safety Index"] - a["Safety Index"])
.slice(0, 10);

Insert cell
md`# Top 10 Countries by Safety Index

This chart shows the ten countries with the highest **Safety Index** in our dataset.`

Insert cell
Plot.plot({
inset: 20,
marginLeft: 140,
width: 700,
height: 400,

// Y-axis: country names, reversed so the highest is at the top
y: {
domain: top10Safety.map(d => d.Country).reverse(),
tickSize: 0,
label: null
},

// X-axis: Safety Index values
x: {
label: "Safety Index →",
grid: true
},

marks: [
// Horizontal bars, one per country
Plot.barX(top10Safety, {
x: "Safety Index",
y: "Country",
fill: "#2c7bb6", // a single, clean color
title: d => `${d.Country}: ${d["Safety Index"]}`
}),
// Numeric labels at the end of each bar
Plot.text(top10Safety, {
x: "Safety Index",
y: "Country",
text: d => d["Safety Index"].toFixed(1),
dx: 4, // nudge label to the right of the bar
dy: -1, // vertically center on bar
fontSize: 11
})
]
});

Insert cell
// Replace <PURCHASING> and <PRICE_RATIO> with the exact column names you just discovered.
dataset = data.map(d => ({
...d,
affordability: d["Purchasing Power Index"]
/ d["Property Price to Income Ratio"]
}));

Insert cell
top10Affordability = dataset
.slice()
.sort((a, b) => b.affordability - a.affordability)
.slice(0, 10);

Insert cell
// 3. Title & explanation
md`
# Housing Affordability vs. Purchasing Power

This scatter plot positions each country by its **Property Price / Income Ratio** (housing affordability, lower → better) on the x-axis and its **Purchasing Power Index** on the y-axis.

**Top 10 countries** by our affordability metric (Purchasing Power ÷ Price/Income) are highlighted in red with labels.
`

Insert cell

Plot.plot({
inset: 20,
marginLeft: 140,
width: 700,
height: 400,

// y-axis: the top 10 countries, highest affordability at the top
y: {
domain: top10Affordability.map(d => d.Country).reverse(),
tickSize: 0,
label: null
},

// x-axis: affordability score
x: {
label: "Affordability Score (Purchasing Power ÷ Price/Income)",
grid: true
},

marks: [
// 1) the “sticks”
Plot.ruleX(top10Affordability, {
x1: 0,
x2: "affordability",
y: "Country",
stroke: "#bbb",
strokeWidth: 2
}),

// 2) the “candies”
Plot.dot(top10Affordability, {
x: "affordability",
y: "Country",
fill: "#1f77b4",
r: 7,
title: d => `
Country: ${d.Country}
Affordability: ${d.affordability.toFixed(2)}`
}),

// 3) numeric labels at each dot
Plot.text(top10Affordability, {
x: "affordability",
y: "Country",
text: d => d.affordability.toFixed(2),
dx: 10,
dy: 2,
fontSize: 11,
fill: "#333"
})
]
});

Insert cell
// 2. Compute the top 10 countries by Climate Index
top10Climate = data
.slice() // copy array
.sort((a, b) => b["Climate Index"] - a["Climate Index"]) // descending
.slice(0, 10); // take first ten

Insert cell
// 3. Title & description
md`
# Top 10 Countries by Climate Index

This chart shows the ten countries with the highest **Climate Index** in our dataset.
Hover over any bar to see the exact value, or read the labels at the end of each bar.
`

Insert cell
chart = Plot.plot({
// Give extra bottom margin to accommodate rotated country labels
height: 400,
marginBottom: 100,

// X‐axis: country names, rotated to fit
x: {
domain: top10Climate.map(d => d.Country), // preserve original order
tickRotate: -45,
label: "Country →"
},

// Y‐axis: Climate Index values, gridlines turned on
y: {
grid: true,
label: "Climate Index ↑"
},

marks: [
// Vertical bars, colored green
Plot.barY(top10Climate, {
x: "Country",
y: "Climate Index",
fill: "#2ca02c",
title: d => `${d.Country}: ${d["Climate Index"].toFixed(1)}`
}),

// Text labels on top of each bar
Plot.text(top10Climate, {
x: "Country",
y: "Climate Index",
text: d => d["Climate Index"].toFixed(1),
dy: -6, // lift the labels just above the bar
fontSize: 11,
fill: "black"
})
]
})

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