Published
Edited
Mar 3, 2022
Importers
Insert cell
Insert cell
Insert cell
bar_chart(select_object["metric"])
Insert cell
select_object
Insert cell
filter_data = function (select_object) {
let tournament_data;
let continent_data;
var value = 0.6;
if (select_object["tournament"] == "all") {
tournament_data = dataset2.slice();
} else {
tournament_data = dataset1.filter(function (d) {
return d.tournament == select_object["tournament"];
});
}
if (select_object["continent"] == "all") {
continent_data = tournament_data.slice();
} else {
continent_data = tournament_data.filter(function (d) {
return d.continent == select_object["continent"];
});
}
if (select_object["continent"] == "Africa") {
value = 0.1;
} else if (select_object["continent"] == "Oceania") {
value = 0;
} else if (select_object["continent"] == "Asia") {
value = 0.1;
} else if (select_object["tournament"] == "UEFA Euro") {
value = 0.1;
} else if (select_object["continent"] == "America") {
value = 0.1;
}
//This line helps to remove teams that have not played a lot of matches
// they are outliers in some sense
// to do so, we rely on the comparison
// with a quantile of number of matches played
var matches_quantile = d3.quantile(continent_data, value, (d) => d.matches);
var filtered_data = continent_data.filter(function (d) {
return d.matches >= matches_quantile;
});
return filtered_data;
}
Insert cell
data = filter_data(select_object)
Insert cell
import { form } from "@mbostock/form-input"
Insert cell
bar_chart = function (metric) {
//Width and height
var w = 500;
var h = 250;

const best_n_data = data
.sort(function (a, b) {
return d3.descending(a[metric], b[metric]);
})
.slice(0, 10);

var xScale = d3
.scaleBand()
.domain(d3.range(10))
.rangeRound([0, w])
.paddingInner(0.1);

let ymax = d3.max(best_n_data, (d) => d[metric]);
let ymin = d3.min(best_n_data, (d) => d[metric]);
let ymean = d3.mean(best_n_data, (d) => d[metric]);

var yScale = d3.scaleLinear().domain([ymin, ymax]).range([50, h]);

const tip = d3tip()
.attr("class", "d3-tip")
.style("border", "solid 3px black")
.style("background-color", "white")
.style("border-radius", "7px")
.style("float", "left")
.style("font-size", "12px")
.style("font-family", "sans-serif")
.html(function (event, d) {
let metric_str;
let rounded_metric_value = Math.round(d[metric] * 100) / 100;
if (metric == "gd_avg") {
metric_str = "Goal difference average";
} else {
metric_str = "Win ratio";
}
let base_str = `<div style='text-align: center'>
<span style='color:#2f7ebc'>
<strong>${d.team}</strong><br>
</span>
<span>
<strong>${metric_str} : ${rounded_metric_value}<strong><br>
</span>
<span>
<strong>Matches : ${d.matches}<strong>
</span>
</div>`;
d3.select(this).attr("fill", "orange");
return base_str;
});

tip.offset(function (event, d) {
let result;
// Tooltip for first values :
if (metric == "gd_avg" && d[metric] >= ymean) {
result = [0, 55];
} else if (metric == "win_ratio" && d[metric] >= ymean) {
result = [0, 25];
// Tooltip for the rest :
} else {
result = [0, 0];
}
return result;
});

//Create SVG element
var svg = d3
.create("svg")
.attr("width", w)
.attr("height", 1.01 * h);

//Create bars
svg
.selectAll("rect")
.data(best_n_data)
.enter()
.append("rect")
.on("mouseover", tip.show)
.on("mouseout", function (d) {
tip.hide(d);
d3.select(this).attr("fill", "#0a4a90");
})
.attr("y", h)
.attr("x", function (d, i) {
return xScale(i);
})
.transition(1000)
.delay(function (d, i) {
return i * 50;
})
.attr("y", function (d) {
return h - yScale(d[metric]);
})
.attr("id", function (d) {
return `rect-${flag_data[d.team]}`;
})
.attr("width", xScale.bandwidth())
.attr("height", function (d) {
return yScale(d[metric]);
})
.attr("fill", "#0a4a90")
.attr("opacity", 0.4);

svg
.selectAll("image")
.data(best_n_data)
.enter()
.append("image")
.attr("y", h)
.attr("x", function (d, i) {
return xScale(i) + xScale.bandwidth() / 6;
})
.transition(1000)
.delay(function (d, i) {
return i * 50;
})
.attr("xlink:href", function (d) {
//We use API from Flagpedia to add the flags (https://flagpedia.net/download/api)
return `https://flagcdn.com/w40/${flag_data[d.team]}.webp`;
})
.attr("id", function (d) {
return `bar-flag-${flag_data[d.team]}`;
})
.attr("y", function (d) {
return h - yScale(d[metric]) + 0.01 * h;
})
.attr("width", (2 * xScale.bandwidth()) / 3);

svg.call(tip);

return svg.node();
}
Insert cell
rowConverter1 = function (d) {
return {
team: d.team,
tournament: d.tournament,
continent: d.continent,
gd_avg: parseFloat(d.goal_difference_average), //Convert to float
win_ratio: parseFloat(d.win_ratio),
matches: parseInt(d.matches) //Convert to int
};
}
Insert cell
rowConverter2 = function (d) {
return {
team: d.team,
continent: d.continent,
gd_avg: parseFloat(d.goal_difference_average), //Convert to float
win_ratio: parseFloat(d.win_ratio),
matches: parseInt(d.matches) //Convert to int
};
}
Insert cell
dataset1 = d3.csv(
await FileAttachment("goal_difference_by_tournament_and_team@2.csv").url(),
rowConverter1
)
Insert cell
dataset2 = d3.csv(
await FileAttachment("all_tournaments_goal_difference@5.csv").url(),
rowConverter2
)
Insert cell
flag_array = FileAttachment("flags_dataset_flagcdn.csv").csv()
Insert cell
flag_data = flag_array[0]
Insert cell
d3tip = require("d3-tip")
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