Published
Edited
Mar 1, 2022
1 fork
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
titleLines = [
['The "Big 3"', 'black'],
['Roger Federer (20 Major Wins, 46 Semifinals)', playerScale('RF')],
['Rafael Nadal (19, 33)', playerScale('RN')],
['Novak Djokovic (17, 37)', playerScale('ND')]
]
Insert cell
legendLabels = [
["Nadal in Semis", width / 2 + 160, headerHeight / 2 + 50],
["Federer in Semis", width / 2 + 170, headerHeight / 2 - 33],
["Djokovic not in Semis", width / 2 - 40, headerHeight / 2 - 33],
["Champion Color", width / 2 - 34, headerHeight / 2 + 33]
]
Insert cell
legendLines = [
[width / 2 + 40, 20, width / 2 + 90, 40],
[width / 2 + 175, 20, width / 2 + 125, 40],
[width / 2 + 170, 90, width / 2 + 120, 70],
[width / 2 + 50, 80, width / 2 + 100, 90]
]
Insert cell
getSemiColors({ RN: 'SF', RF: 'SF', ND: 'NA' })
Insert cell
getSemiColors = d =>
Object.entries(d)
.slice(2)
.map(p =>
["SF", "F", "W"].includes(p[1]) ? playerScale(p[0]) : 'lightgray'
)
Insert cell
getWinnerColor = row => {
const winner = Object.entries(row).filter(e => e[1] === "W")[0];
return winner ? playerScale(winner[0]) : 'lightgray';
}
Insert cell
arc = d3
.arc()
.innerRadius(0)
.outerRadius(yearScale.bandwidth() / 2 - 10)
Insert cell
pie = d3
.pie()
.sort(null)
.value(1)
Insert cell
playerScale = d3.scaleOrdinal(d3.schemeTableau10)
Insert cell
yearAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom + headerHeight})`)
.call(
d3
.axisBottom(yearScale)
.tickFormat(i => i)
.tickSizeInner(0)
.tickSizeOuter(0)
)
.call(g => g.select(".domain").remove())
.call(g =>
g
.selectAll("text")
.attr("font-weight", "bold")
.attr("font-size", 14)
)
Insert cell
yearScale = d3
.scaleBand()
.domain(years)
.range([margin.left, width - margin.right])
Insert cell
eventAxis = g =>
g
.attr("transform", `translate(${margin.left},-40)`)
.call(
d3
.axisRight(eventScale)
.tickFormat(i => i)
.tickSizeInner(0)
.tickSizeOuter(0)
)
.call(g => g.select(".domain").remove())
.call(g =>
g
.selectAll("text")
.attr("font-weight", "bold")
.attr("font-size", 14)
)
Insert cell
eventScale = d3
.scaleBand()
.domain(events)
.range([margin.top + headerHeight, height - margin.bottom + headerHeight])
Insert cell
margin = ({ top: 30, right: 0, bottom: 30, left: 10 })
Insert cell
headerHeight = 100
Insert cell
height = 400
Insert cell
width = 960
Insert cell
events = data.slice(0, 4).map(d => d.event)
Insert cell
years = [...new Set(data.map(d => d.year))]
Insert cell
cancelledOrPostponed = [
{ year: 2020, event: "French Open", status: "Postponed" },
{ year: 2020, event: "Wimbledon", status: "Cancelled" }
]
Insert cell
data = {
const roger = await FileAttachment("roger.csv").csv();
const nadal = await FileAttachment("nadal.csv").csv();
const novak = await FileAttachment("novak.csv").csv();
const rawData = [roger, nadal, novak].map(p =>
p.map(({ season, name: event, result }) => ({
season: +season,
event: event === "Roland Garros" ? "French Open" : event,
result
}))
);
const years = [...new Set(rawData[0].map(d => d.season))].reverse().slice(4);
const eventOrder = ["Australian Open", "French Open", "Wimbledon", "US Open"];
const data = [];
years.forEach(year => {
eventOrder.forEach(event => {
const row = { year, event };
rawData.forEach((player, i) => {
const resultRow = player.filter(
d => d.season === year && d.event == event
)[0];
const result = resultRow != null ? resultRow.result : "NA";
row[['RF', 'RN', 'ND'][i]] = result;
});
data.push(row);
});
});
return data;
}
Insert cell
import { swatches } from "@d3/color-legend"
Insert cell
d3 = require('d3')
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more