Public
Edited
Sep 14, 2024
Insert cell
Insert cell
Insert cell
data = FileAttachment("players_20.csv").csv()
Insert cell
datagroup = d3.group(data, (d) => d.nationality)

Insert cell
output = Array.from(datagroup, ([key, values]) => ({
nationality: key,
number_of_players: values.length,
average_age: d3.mean(values, (d) => +d.age)
}))

Insert cell
outcome = output.sort((a, b) => d3.ascending(a.nationality, b.nationality))

Insert cell
table = {
const table = d3.create("table");
const thead = table.append("thead");

thead
.append("tr")
.selectAll("th")
.data(["nationality", "number_of_players", "average_age"])
.join("th")
.text((d) => d);

const tbody = table.append("tbody");
tbody
.selectAll("tr")
.data(outcome)
.join("tr")
.selectAll("td")
.data((d) => [d.nationality, d.number_of_players, d.average_age.toFixed(3)])
.join("td")
.text((d) => d);

return table.node();
}

Insert cell
scatterplot = {
const margin = { top: 20, right: 20, bottom: 50, left: 50 },
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;

// Create an SVG container
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

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

// Set x and y scales
const x = d3
.scaleLinear()
.domain([0, d3.max(output, (d) => d.number_of_players)])
.range([0, width]);

const y = d3
.scaleLinear()
.domain([16, d3.max(output, (d) => d.average_age)]) // Start y-axis at 16
.range([height, 0]);

// Add x-axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));

// Add y-axis
g.append("g").call(d3.axisLeft(y));

// Add labels
g.append("text")
.attr("x", width / 2)
.attr("y", height + margin.bottom - 10)
.attr("text-anchor", "middle")
.attr("class", "axis-label")
.text("Number of Players");

g.append("text")
.attr("x", -height / 2)
.attr("y", -margin.left + 15)
.attr("text-anchor", "middle")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.text("Average Age");

// Define a color scale for number_of_players
// Using a different color scale for better visualization
const color = d3
.scaleSequential(d3.interpolateViridis) // Changed color scale to Viridis
.domain([0, d3.max(output, (d) => d.number_of_players)]);

// Add dots to scatter plot
g.selectAll(".dot")
.data(output)
.join("circle")
.attr("class", "dot")
.attr("cx", (d) => x(d.number_of_players))
.attr("cy", (d) => y(d.average_age))
.attr("r", 5)
.attr("fill", (d) => color(d.number_of_players)) // Encode the number of players with color
.append("title")
.text((d) => d.nationality); // Tooltip for nationality

// Return the full svg element, not just the 'g' element
return svg.node();
}
Insert cell
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