Public
Edited
Feb 2, 2023
Insert cell
Insert cell
Insert cell
{
const svg = d3
.create("svg")
.attr("width", figWidth)
.attr("viewBox", [0, 0, figWidth, figHeight]);

const g = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);

svg
.append("text")
.text("Footballers' sizes, preferred foot, & overall rating.")
.attr("transform", `translate(${iwidth / 2}, 15)`)
.attr("text-anchor", "middle")
.style("font-size", "1.2em")
.style("font-weight", "bold");

const minisData = [
{ row: 0, col: 0, data: players90, title: "Rating 90-100" },
{ row: 0, col: 1, data: players80, title: "Rating 80-89" },
{ row: 1, col: 0, data: players70, title: "Rating 70-79" },
{ row: 1, col: 1, data: players60, title: "Rating 60-69" },
{ row: 2, col: 0, data: playersOther, title: "Rating 0-59" }
];

const minis = g
.selectAll("g.chart")
.data(minisData)
.join("g")
.attr("class", "chart")
.attr(
"transform",
(d) => `translate(${chartCol(d.col)}, ${chartRow(d.row)})`
);

// Append a background and title for this chart.
minis
.append("rect")
.attr("fill", "#eee")
.attr("width", chartCol.bandwidth())
.attr("height", chartRow.bandwidth());
minis
.append("text")
.text((g) => g.title)
.attr("transform", (g) => `translate(${chartCol.bandwidth() / 2}, -5)`)
.style("font-weight", "bold")
.style("text-anchor", "middle")
.style("font-size", "10pt");

// Plot the data in each chart.
minis
.selectAll("circle")
.data((g) => g.data)
.join("circle")
.attr("cx", (p) => x(p.height_cm))
.attr("cy", (p) => y(p.weight_kg))
.attr("r", 2)
.attr("fill", (p) => color(p.preferred_foot));

// Add axis labels to the first chart.
g.select("g.chart")
.append("text")
.text("↑ Height (cm)")
.attr("transform", `translate(-25, -10)`)
.attr("text-anchor", "start")
.style("font-weight", "bold")
.style("font-size", "8pt");

g.select("g.chart")
.append("text")
.text("Weight (kg) →")
.attr(
"transform",
`translate(${chartCol.bandwidth()}, ${chartRow.bandwidth() + 30})`
)
.attr("text-anchor", "end")
.style("font-weight", "bold")
.style("font-size", "8pt");

// Add axes to each mini.
minis
.append("g")
.attr("class", "x-axis")
.attr("transform", `translate(0, ${chartRow.bandwidth()})`)
.call(d3.axisBottom(x));
minis.append("g").attr("class", "y-axis").call(d3.axisLeft(y));

return svg.node();
}
Insert cell
Insert cell
figWidth = Math.min(width, 800)
Insert cell
figHeight = figWidth * 1.2
Insert cell
margin = ({ left: 30, right: 20, top: 60, bottom: 20 })
Insert cell
iwidth = figWidth - margin.left - margin.right
Insert cell
iheight = figHeight - margin.top - margin.bottom
Insert cell
chartCol = d3
.scaleBand()
.domain(d3.range(2))
.range([0, iwidth])
.paddingInner(0.2)
Insert cell
chartRow = d3
.scaleBand()
.domain(d3.range(3))
.range([0, iheight])
.paddingInner(0.2)
Insert cell
x = d3
.scaleLinear()
.domain(d3.extent(players, (d) => d.height_cm))
.range([0, chartCol.bandwidth()])
.nice()
Insert cell
y = d3
.scaleLinear()
.domain(d3.extent(players, (d) => d.weight_kg))
.range([chartRow.bandwidth(), 0])
.nice()
Insert cell
color = d3.scaleOrdinal(d3.schemeCategory10).domain(categoricals)
Insert cell
Insert cell
players = FileAttachment("players_20.csv").csv({ typed: true })
Insert cell
players90 = players.filter((p) => p.overall >= 90)
Insert cell
players80 = players.filter((p) => p.overall >= 80 && p.overall < 90)
Insert cell
players70 = players.filter((p) => p.overall >= 70 && p.overall < 80)
Insert cell
players60 = players.filter(p => p.overall >= 60 && p.overall < 70)
Insert cell
playersOther = players.filter((p) => p.overall < 60)
Insert cell
categoricals = [...new Set(players.map((p) => p.preferred_foot)).values()]
Insert cell
Insert cell
import { Swatches } from "@d3/color-legend"
Insert cell
d3 = require("d3@6")
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