Published
Edited
Oct 11, 2022
3 stars
Insert cell
Insert cell
Insert cell
raw = {
const scsv = d3.dsvFormat(",") // Important to define the separator of your CSV file
return scsv.parse(await FileAttachment('season-1819_csv.csv').text())
}
Insert cell
teams_stats = {

const teamssummary = {};
const resultset = [];

for(let match of raw){

const hometeam = match.HomeTeam;
const homescore = parseInt(match.FTHG);
const awayteam = match.AwayTeam;
const awayscore = parseInt(match.FTAG);

// setting initial values
if( !(hometeam in teamssummary) ){
teamssummary[hometeam] = {
'goals_for': 0, 'goals_against': 0, 'points': 0}
};
if( !(awayteam in teamssummary) ){
teamssummary[awayteam] = {'goals_for': 0, 'goals_against': 0, 'points': 0}
};

// setting number of goals
teamssummary[hometeam]['goals_for'] += homescore;
teamssummary[awayteam]['goals_for'] += awayscore;
teamssummary[hometeam]['goals_against'] += awayscore;
teamssummary[awayteam]['goals_against'] += homescore;
if(homescore > awayscore){
teamssummary[hometeam]['points'] += 3;
} else if(homescore < awayscore){
teamssummary[awayteam]['points'] += 3;
} else {
teamssummary[awayteam]['points'] += 1;
teamssummary[hometeam]['points'] += 1;
}
}

for(let team in teamssummary){

const currentobj = {
'team': team,
'goals_for': teamssummary[team]['goals_for'],
'goals_against': teamssummary[team]['goals_against'],
'points': teamssummary[team]['points']
};
resultset.push(currentobj);

}
return resultset;
}
Insert cell
Insert cell
margins = {
return {
left: 200,
right: 200,
top: 20,
bottom: 200
}
}
Insert cell
size = {
return {
height: 700,
width: 1000
}
}
Insert cell
Insert cell
d3.extent(teams_stats.map( entry => entry.goals_for))
Insert cell
xScale = d3.scaleLinear().domain(d3.extent(teams_stats.map( entry => entry.goals_for))).range([0, size.width - margins.left - margins.right]);
Insert cell
xScale(22)
Insert cell
yScale = d3.scaleLinear().domain(d3.extent(teams_stats.map( entry => entry.goals_against))).range([size.height - margins.top - margins.bottom, 0]);
Insert cell
rScale = d3.scaleLinear().domain(d3.extent(teams_stats.map( entry => entry.points)) ).range([1,20]);
Insert cell
cScale = d3.scaleSequential(d3.interpolateYlGn).domain(d3.extent(teams_stats.map( entry => entry.points)));
Insert cell
Insert cell
{

const svg = d3.select(DOM.svg(size.width, size.height));

svg.append("g").attr("transform", `translate(${margins.left}, ${size.height - margins.bottom + rScale.domain()[1]} )`).call(d3.axisBottom(xScale));
svg.append("g").attr("transform", `translate(${margins.left - rScale.domain()[1]},${margins.top})`).call(d3.axisLeft(yScale));

const chartGroup = svg.append("g").attr("transform", `translate(${margins.left},${margins.top})`);
render_data(chartGroup, teams_stats);
return svg.node();
}
Insert cell
Insert cell
render_data = (group, data) => {

// render circles
group
.selectAll('circle')
.data(data)
.join(
enter => enter
.append('circle')
.attr("cx", d => xScale(d.goals_for))
.attr("cy", d => yScale(d.goals_against))
.attr("r", d => rScale(d.points))
.style('fill', d => cScale(d.points))
.style('stroke', 'gray')
.style('stroke-width', '2px')
)

// render teams names
group
.attr("font-family", "Roboto")
.attr("font-weight", 400)
.attr("text-anchor", "middle")
.selectAll('text')
.data(data)
.join(
enter => enter
.append('text')
.attr("x", d => xScale(d.goals_for))
.attr("y", d => yScale(d.goals_against) - rScale(d.points) - 5)
.attr('fill', 'gray')
.text( d => d.team)
)

}
Insert cell
d3 = require("d3")
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