Published
Edited
Apr 9, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = {
const data = d3.tsvParse(await FileAttachment("unemployment.tsv").text()); // on télécharge le fichier .tsv dans l'objet data
const columns = data.columns.slice(1); // on indique les colonnes de data
return {
y: "% Unemployment",
series: data.map(d => ({
name: d.name.replace(/, ([\w-]+).*/, " $1"), // on créé une liste de tableaux contenant le nom de villes
values: columns.map(k => +d[k]) // on créé la colonne des valeurs des taux de chômage associées
})),
dates: columns.map(d3.utcParse("%Y-%m")) // on créé la colonne des dates
};
}
Insert cell
Insert cell
Insert cell
function hover(svg, path) {
if ("ontouchstart" in document) svg
.style("-webkit-tap-highlight-color", "transparent")
.on("touchmove", moved)
.on("touchstart", entered)
.on("touchend", left)
else svg
.on("mousemove", moved)
.on("mouseenter", entered)
.on("mouseleave", left);

const dot = svg.append("g")// construction d'un conteneur
.attr("display", "none");
// création du panneau qui s'affichera au-dessus des courbes
dot.append("polyline") // construction du panneau vide --> on utilise polyline plutôt que de fusionner un rectangle et un triangle
.attr("points","0,0 0,144 198,144 216,162 234, 144, 432, 144, 432,0 0,0") // dimensions du panneau
.style("fill", "#fafafa")
.style("stroke"," #5dade2 ")
.style("opacity","0.8") // légère transparence
.style("stroke-width","1")
.attr("transform", "translate(-215, -170)"); // translation du panneau

// création du cercle noir sous le panneau qui indique le point précis où l'on se situe
dot.append("circle")
.attr("r", 6.5);

// texte pour les noms de lieux
dot.append("text")
.attr("font-weight", "bold")
.attr("font-size", 18)
.attr("text-anchor", "middle")
.attr("id", "dot-name") // on donne un identifiant à ce texte
.attr("transform", "translate(0, -130)");
// création d'une puce (rond bleu dans le panneau)
dot.append("text")
.attr("font-size", 20)
.style("fill", "#FF0000")
.attr("dx", "-100")
.attr("dy", "-90")
.text("●");
// création du texte pour les dates
dot.append("text")
.attr("font-family", "sans-serif")
.attr("font-size", 16)
.attr("dx", "-80")
.attr("dy", "-90")
.attr("id", "dot-date"); // identifiant date

// création de la deuxième puce
dot.append("text")
.attr("font-size", 20)
.style("fill", "#FF0000")
.attr("dx", "-100")
.attr("dy", "-50")
.text("●");
// texte pour les taux de chômage
dot.append("text")
.attr("font-size", 16)
.attr("dx", "-80")
.attr("dy", "-50")
.attr("id", "dot-values") // identifiant
// associe l'affichage du panneau et la transparence des courbes non sélectionnées aux actions de la souris
function moved(event) {
event.preventDefault(); // change les valeurs par défaut affectées aux actions (clics, mouvement de la souris...)
const pointer = d3.pointer(event, this); // on construit un pointeur (tableau des coordonnées pour l'évènement this)
const xm = x.invert(pointer[0]); // retourne le range associé à la coordonnée en x
const ym = y.invert(pointer[1]); // retourne le range associé à la coordonné en y
const i = d3.bisectCenter(data.dates, xm); // index de la valeur de la date la plus proche de xm
const s = d3.least(data.series, d => Math.abs(d.values[i] - ym)); // retourne les taux de chômage tels que la distance entre ym et ces taux à la date xm soit minimale
const dateFormat = d3.timeFormat("%d/%m/%Y"); // on change le format des dates pour un plus joli affichage
path.attr("stroke", d => d === s ? null : "#ddd").filter(d => d === s).raise(); // trace une ligne avec les valeurs précédentes, raise() sert à faire passer cette ligne au premier plan
dot.attr("transform", `translate(${x(data.dates[i])},${y(s.values[i])})`); // translation
dot.select("#dot-name")
.text(s.name); // le texte avec l'identifiant dot-name renverra les noms de villes
d3.select('#dot-date')
.text("Date : " + dateFormat(data.dates[i])); // le texte avec l'identifiant dot-date renverra les dates
d3.select('#dot-values')
.text("Taux de chômage : " + s.values[i] + " %"); // le texte avec l'identifiant dot-values renverra lestaux de chômage
}
// définit ce qu'il se passe à l'entrée de la souris dans le graphe
function entered() {
path.style("mix-blend-mode", null).attr("stroke", "#ddd");
dot.attr("display", null); // aucun affichage
}

// définit ce qu'il se passe à la sortie de la souris dans le graphe
function left() {
path.style("mix-blend-mode", "multiply").attr("stroke", null);
dot.attr("display", "none"); // aucun affichage
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(data.dates))
.range([margin.left, width - margin.right])
Insert cell
Insert cell
Insert cell
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`) // on déplace l'axe en bas du graphe
.call(d3.axisBottom(x).ticks(width / 40).tickSizeOuter(0)) // ticks permet de spécifier le nombre de graduation
//tickSizeOuter(0) supprime les bordures verticales sur l'axe
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg") // on créé un objet svg qui "contiendra" le graphe
.attr("viewBox", [0, 0, width, height]) // dimensions
.style("overflow", "visible");
// on créé un conteneur pour afficher l'axe x
svg.append("g")
.call(xAxis);
// on créé un conteneur pour afficher l'axe y
svg.append("g")
.call(yAxis);
// On rajoute un titre
svg.append("text")
.attr("x", (width / 2))
.attr("y", 5)
.attr("text-anchor", "middle")
.style("fill", "#5a5a5a")
.style("font-family", "Raleway")
.style("font-weight", "300")
.style("font-size", "24px")
.text("Evolution des taux de chômage dans différentes \n villes des Etats-Unis"); // titre
const path = svg.append("g")
.attr("fill", "none") // on laisse l'arrière-plan vide
.attr ('stroke', d3.rgb(rouge, vert, bleu)) // la couleur est une nuance de bleu, rouge et vert défini par nos curseurs
.attr("stroke-width", 1.5) // taille de la ligne
.attr("stroke-linecap", "round") //type de ligne
.selectAll("path")
.data(data.series)
.join("path")
.style("mix-blend-mode", "multiply") // option de style
.attr("d", d => line(d.values)); // trace la valeur du taux de chômage (values) associée à un lieu (y) à la date i (x)

svg.call(hover, path); // on passe path en argument pour la fonction hover

return svg.node(); // on retourne le noeud pour que le graphe s'affiche finalement !!
}
Insert cell
Insert cell
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