Public
Edited
Jun 1
Comments locked
Insert cell
Insert cell
htl.html`<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
body, svg, foreignObject, div, span, text {
font-family: 'Poppins', sans-serif !important;
}
</style>`
Insert cell
htl.html`<style>
.poppins {
font-family: 'Poppins', sans-serif ! important;
}
`
Insert cell
data = [
{ year: 2017, budget: 6768000000 },
{ year: 2018, budget: 6842000000 },
{ year: 2019, budget: 6957000000 },
{ year: 2020, budget: 8188000000 },
{ year: 2021, budget: 7785000000 },
{ year: 2022, budget: 7904000000 },
{ year: 2023, budget: 8373000000 },
{ year: 2024, budget: 8874000000 },
{ year: 2025, budget: 8811000000 }
];
Insert cell
chart = {
const width = 928;
const height = 600;
const marginTop = 40;
const marginRight = 0;
const marginBottom = 30;
const marginLeft = 60;

const myColours = ["#206095", "#27a0cc", "#118c7b", "#871a5b", "#f66068", "#746cb1", "#22d0b6", "#003c57", "#a8bd3a"];
const colour = d3.scaleOrdinal().domain(data.map(d => d.year)).range(myColours);

function formatBillions(d) {
return d >= 1e9 ? (d / 1e9).toFixed(2) + "B" : d3.format(".2s")(d);
}

const x = d3.scaleBand()
.domain(data.map(d => d.year))
.range([marginLeft, width - marginRight])
.padding(0.1);

const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.budget)])
.range([height - marginBottom, marginTop]);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;")
.attr("role", "img")
.attr("aria-labelledby", "chart-title")
.attr("aria-describedby", "chart-desc");

svg.append("title")
.attr("id", "chart-title")
.text("UKRI Budget Allocation by Year (2017–2025)");

svg.append("desc")
.attr("id", "chart-desc")
.text("A bar chart showing UK Research and Innovation (UKRI) budget allocations for each year from 2017 to 2025.");

svg.append("g")
.selectAll()
.data(data)
.join("rect")
.attr("x", d => x(d.year))
.attr("y", d => y(d.budget))
.attr("height", d => y(0) - y(d.budget))
.attr("width", x.bandwidth())
.attr("fill", d => colour(d.year))
.attr("role", "graphics-symbol")
.attr("aria-roledescription", "bar")
.attr("aria-label", d => `Year ${d.year}, Budget ${d3.format(",")(d.budget)}`)
.attr("tabindex", "0");

svg.append("g")
.selectAll()
.data(data)
.join("text")
.attr("x", d => x(d.year) + x.bandwidth() / 2)
.attr("y", d => (y(d.budget) + y(0)) / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.attr("font-family", "Poppins, sans-serif")
.attr("font-size", "26px")
.attr("font-weight", "bold")
.attr("fill", "white")
.attr("transform", d => `rotate(90, ${x(d.year) + x.bandwidth() / 2}, ${(y(d.budget) + y(0)) / 2})`)
.text(d => d3.format(",")(d.budget));
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x))
.attr("font-family", "Poppins, sans-serif")
.attr("font-size", 14)
.attr("font-weight", "bold");

svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y).tickFormat(formatBillions))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("x", -marginLeft)
.attr("y", 10)
.attr("fill", "currentColour")
.attr("text-anchor", "start")
.attr("font-family", "Poppins, sans-serif")
.attr("font-size", 14)
.text("Budget (£)"))
.selectAll(".tick text")
.attr("font-family", "Poppins, sans-serif")
.attr("font-size", 10)
;

return svg.node();
}
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