Published
Edited
Sep 23, 2021
Insert cell
Insert cell
Insert cell
data = await d3.csv("https://fxjollois.github.io/donnees/scimagojr/scimagojr.csv", d3.autoType)
Insert cell
Insert cell
Inputs.table(data)
Insert cell
Insert cell
viewof annee = Inputs.select(
[...new Set(d3.map(data, d => d.Year))],
{label: "Année choisie", value: d3.max(data, d => d.Year)}
)
Insert cell
Insert cell
Inputs.table(data.filter(d => d.Year == annee).slice(0, 5))
Insert cell
Insert cell
viewof annee2 = Inputs.select(
[...new Set(d3.map(data, d => d.Year))],
{label: "Année choisie", value: d3.max(data, d => d.Year)}
)
Insert cell
viewof critere = Inputs.select(Object.keys(data[0]).slice(1), {label: "Critère choisi"})
Insert cell
viewof tri = Inputs.radio(["ascendant", "descendant"], {label: "Tri de tri", value: "ascendant"})
Insert cell
{
var data_filtre = data.filter(d => d.Year == annee2),
fonction_tri = tri == "descendant" ? d3.descending : d3.ascending;
return Inputs.table(d3.sort(data_filtre, (a, b) => fonction_tri(a[critere], b[critere])).slice(0, 5))
}
Insert cell
Insert cell
Insert cell
viewof pays = Inputs.select([...new Set(d3.map(data, d => d.Country).sort())], {label: "Pays choisi", value: "France"})
Insert cell
Plot.plot({
marks: [
Plot.line(data.filter(d => d.Country == pays), {x: "Year", y: "Documents"})
],
y: {
label: "Nombre de documents produits par année pour : " + pays,
grid: true,
tickFormat: "~s"
}
})
Insert cell
Insert cell
viewof pays_liste = Inputs.select([...new Set(d3.map(data, d => d.Country))].sort(), {label: "Pays choisis (Ctrl+clic ou Shift+clic pour en choisir plusieurs)", value: ["France"], multiple: true})
Insert cell
Plot.plot({
marks: [
Plot.line(d3.filter(data, d => pays_liste.includes(d.Country)),
Plot.normalizeY({x: "Year", y: "Documents", stroke: "Country"})),
Plot.text(d3.filter(data, d => pays_liste.includes(d.Country)), Plot.selectLast(Plot.normalizeY({
x: "Year",
y: "Documents",
stroke: "Country",
text: "Country",
textAnchor: "start",
dx: 3
})))
],
y: {
label: "Evolution du nombre de documents produits (en %)",
grid: true,
tickFormat: x => d3.format("+d")((x - 1) * 100)
},
marginRight: 90
})
Insert cell
Insert cell
data_top10 = d3.map(data, d => { var e = d; e.Rank = d.Rank <= 10 ? d.Rank : NaN; return e; });
Insert cell
Plot.plot({
marks: [
Plot.line(data_top10, {x: "Year", y: "Rank", stroke: "Country", strokeWidth: 3}),
Plot.dot(data_top10, {x: "Year", y: "Rank", stroke: "Country", strokeWidth: 3}),
Plot.text(data_top10, Plot.selectLast({x: "Year", y: "Rank", z: "Country", text: "Country", textAnchor: "start", dx: 5}))
],
y: {reverse: true},
marginRight: 90
})
Insert cell
Insert cell
// Largeur du graphique
width = 1000
Insert cell
// Hauteur du graphique
height = 400
Insert cell
// Marges
margin = ({ "top": 60, "right": 150, "bottom": 30, "left": 60 })
Insert cell
// Données regroupées par pays, et uniquement dans le TOP 10
data_country = d3.groups(data, d => d.Country).filter(d => d3.filter(d[1], e => e.Rank <= 10).length > 0)
Insert cell
// Echelle des X
x = d3.scaleLinear()
.domain(d3.extent(data, d => d.Year))
.range([0, width - margin.left - margin.right])
Insert cell
// Echelle des Y
y = d3.scaleLinear()
.domain([10, 1])
.range([height - margin.bottom - margin.top, 0]);
Insert cell
// Couleur en fonction des pays
color = d3.scaleOrdinal(d3["schemeCategory10"].concat(d3["schemeAccent"]))
.domain(d3.map(data_country, d => d[0]));
Insert cell
// Fonction de dessin en définissant les X et les Y à utiliser
line = d3.line()
.defined(d => d.Rank <= 10)
.x(d => x(d.Year))
.y(d => y(d.Rank))
Insert cell
html`<div id="top10"></div>`
Insert cell
{
// Création du graphique
var svg = d3.select("#top10").html("")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Ajout de l'axe des X
svg.append("g")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).tickFormat(d => d.toString()))
.call(g => g.select(".domain").remove());

// Ajout de l'axe des Y
svg.append("g")
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove());

// Ajout des lignes/points pour chaque pays
data_country.forEach(e => {
// Ligne
svg.append("path")
.attr("fill", "none")
.attr("stroke", color(e[0]))
.attr("stroke-width", 4)
.attr("d", line(e[1]));
// Points
svg.selectAll(".point")
.data(e[1].filter(d => d.Rank <= 10))
.enter()
.append("circle")
.attr("cx", d => x(d.Year))
.attr("cy", d => y(d.Rank))
.attr("r", 6)
.style("fill", d => color(d.Country))
// Interaction souris lorsqu'elle passe sur un point
.on("mouseover", function() {
var infos = d3.select(this).data()[0];
d3.select(this).attr("r", 9);
d3.select("#popup")
.style("visibility", "visible")
.html(infos.Country + " (" + infos.Year + ") : " + infos.Documents + " documents");
})
// Gestion de la sortie de la souris
.on("mouseout", function() {
d3.select(this).attr("r", 6);
d3.select("#popup")
.style("visibility", "hidden")
})
});
// AJout des noms de pays à côté de la dernière année où ils apparaissent dans le TOP 10
svg.selectAll(".pays")
.data(data_country.map(d => {
var r = d[1].filter(d => d.Rank <= 10),
last_year = d3.max(r, d => d.Year),
last_rank = r.filter(d => d.Year == last_year)[0].Rank;
return { Country: d[0], Year: last_year, Rank: last_rank }
}))
.enter()
.append("text")
.attr("x", d => x(d.Year))
.attr("y", d => y(d.Rank))
.attr("dy", d => d.Year == d3.max(data, d => d.Year) ? -10 : 15)
.style("text-anchor",d => d.Year == d3.max(data, d => d.Year) ? "start" : "middle")
.style("fill", d => color(d.Country))
.style("font-size", ".75em")
.html(d => d.Country);

// Création de la zone d'informations contenant le pays, l'année et le nombre de documents
svg.append("g").append("text")
.attr("id", "popup")
.attr("y", -30)
.style("visibility", "hidden")
}
Insert cell
Insert cell
d3 = require("d3")
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