Public
Edited
Mar 12, 2023
Fork of Untitled
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
i1 = FileAttachment("i1.png").image()
Insert cell
Insert cell
data=FileAttachment("data.csv").csv()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/* Dans ce code j ai utilisé la méthode Promise.all() de JavaScript pour charger deux sources de données , le premier fichier c'est un fichier JSON contenant des données cartographiques (le fichier JSON contient les données géographiques utilisées pour dessiner la carte, telles que les coordonnées de chaque pays et de ses frontières. En utilisant d3.json() pour charger ce fichier dans notre script, nous pouvons facilement extraire ces données et les utiliser pour dessiner la carte.) et un fichier CSV contenant des données sur les émissions . Les données CSV sont transformées en un objet JavaScript avec des propriétés spécifiques et sont stockées dans la variable data.

Une fois les données chargées, le code utilise les données pour créer une carte, un graphique à secteurs et un graphique à barres pour visualiser les émissions de gaz à effet de serre dans différents pays et régions au fil du temps. j'ai fait également des événements pour permettre à l'utilisateur de sélectionner une année et un type de données spécifique à afficher.

So enfin, le code crée une infobulle (tooltip) qui affiche des informations détaillées sur les pays, régions et données affichées lorsque l'utilisateur passe la souris sur les éléments de la carte, des graphiques à secteurs ou des graphiques à barres.

*/

Promise.all([
d3.json("https://unpkg.com/world-atlas@1.1.4/world/50m.json"),
d3.csv("https://raw.githubusercontent.com/Manal1Hachhach/visu/main/all_data.csv", function(row) {

return {
continent: row.Continent,
country: row.Country,
countryCode: row["Country Code"],
emissions: +row["Emissions"],
emissionsPerCapita: +row["Emissions Per Capita"],
region: row.Region,
year: +row.Year
}
})
]).then(function([mapData, data]) {
/* j'ai utilisé les données récupérées précédemment à partir du fichier JSON et du fichier CSV pour créer différentes visualisations de données. Il commence par trouver les années les plus anciennes et les plus récentes dans les données et stocke la plus ancienne dans la variable currentYear. Ensuite, il utilise la méthode d3.select pour sélectionner l'élément HTML correspondant à la case à cocher radio pour le type de données sélectionné par user et stocke sa valeur dans la variable currentDataType.
et les fonctions createMap, createPie et createBar sont appelées pour créer les différents types de visualisations, suivies des fonctions drawMap, drawPie et drawBar
*/


var extremeYears = d3.extent(data, d => d.year);
var currentYear = extremeYears[0];
var currentDataType = d3.select('input[name="data-type"]:checked')
.attr("value");
var geoData = topojson.feature(mapData, mapData.objects.countries).features;

var width = +d3.select(".chart-container")
.node().offsetWidth;
var height = 300;

createMap(width, width * 4 / 5);
createPie(width, height);
createBar(width, height);
drawMap(geoData, data, currentYear, currentDataType);
drawPie(data, currentYear);
drawBar(data, currentDataType, "");

const tooltip = d3.select("body").append("div")
.attr("class", "tooltip2")
.style("position", "absolute")
.text("I'm a MAP!");
d3.select("#year")
.property("min", currentYear)
.property("max", extremeYears[1])
.property("value", currentYear)
.on("input", () => {
currentYear = +d3.event.target.value;
drawMap(geoData, data, currentYear, currentDataType);
drawPie(data, currentYear);
highlightBars(currentYear);
});
d3.selectAll('input[name="data-type"]')
.on("change", () => {
var active = d3.select(".active").data()[0];
var country = active ? active.properties.country : "";
currentDataType = d3.event.target.value;
drawMap(geoData, data, currentYear, currentDataType);
drawBar(data, currentDataType, country);
});

d3.selectAll("svg")
.on("mousemove touchmove", updateTooltip);
function updateTooltip() {
var tooltip = d3.select(".tooltip2");
var tgt = d3.select(d3.event.target);
var isCountry = tgt.classed("country");
var isBar = tgt.classed("bar");
var isArc = tgt.classed("arc");
var dataType = d3.select("input:checked")
.property("value");
var units = dataType === "emissions" ? "milliers de tonnes métriques" : "milliers de tonnes métriques";
var data;
var percentage = "";
if (isCountry) data = tgt.data()[0].properties;
if (isArc) {
data = tgt.data()[0].data;
percentage = `<p>Percentage of total: ${getPercentage(tgt.data()[0])}</p>`;
}
if (isBar) data = tgt.data()[0];
tooltip
.style("opacity", +(isCountry || isArc || isBar))
.style("left", (d3.event.pageX - tooltip.node().offsetWidth / 2) + "px")
.style("top", (d3.event.pageY - tooltip.node().offsetHeight - 10) + "px");
if (data) {
var dataValue = data[dataType] ?
data[dataType].toLocaleString() + " " + units :
"Data Not Available";
tooltip
.html(`
<pstyl>Country: ${data.country}</p>
<p>${formatDataType(dataType)}: ${dataValue}</p>
<p>Year: ${data.year || d3.select("#year").property("value")}</p>
${percentage}
`);
}
}

})

Insert cell
/*j'ai fait cettee fonction pour créer un conteneur SVG pour le graphique circulaire et ajoute un élément <g> qui sera utilisé pour dessiner le graphique. Elle ajoute également un titre pour le graphique circulaire */

function createPie(width, height) {
var pie = d3.select("#pie")
.attr("width", width)
.attr("height", height);

pie.append("g")
.attr("transform", "translate(" + width/2 + ", " + (height / 2 + 10) + ")")
.classed("chart", true);

pie.append("text")
.attr("x", width / 2)
.attr("y", "2em")
.attr("font-size", "1.5em")
.style("text-anchor", "middle")
.classed("pie-title", true);
}
Insert cell
/* Cette fonction drawPie() dessine un graphique en forme de "pie chart" représentant les émissions totales de CO2 par continent et région pour une année donnée
La fonction sélectionne l'élément HTML correspondant au graphique en utilisant la méthode d3.select().
Ensuite, j'ai utilise la méthode d3.pie() pour générer une structure de données pour les angles des secteurs du "pie chart" à partir des données d'émissions de CO2 par continent et région.
La méthode d3.arc() est utilisée pour créer une fonction qui génère les chemins SVG pour chaque secteur du graphique.
La fonction sélectionne les données d'émissions de CO2 pour l'année donnée à l'aide de la méthode data.filter().
Ensuite, elle crée une liste des continents présents dans les données pour cette année.
Elle crée une échelle de couleurs (colorScale) en utilisant la méthode d3.scaleOrdinal() pour associer une couleur à chaque continent présent dans les données.
La fonction met à jour les éléments SVG correspondant à chaque secteur du graphique en utilisant les données générées par la méthode d3.pie(), en ajoutant les nouveaux éléments SVG nécessaires avec la méthode enter() et en retirant les éléments inutiles avec la méthode exit().
*/
function drawPie(data, currentYear) {
var pie = d3.select("#pie");

var arcs = d3.pie()
.sort((a,b) => {
if (a.continent < b.continent) return -1;
if (a.continent > b.continent) return 1;
return a.emissions - b.emissions;
})
.value(d => d.emissions);

var path = d3.arc()
.outerRadius(+pie.attr("height") / 2 - 50)
.innerRadius(0);

var yearData = data.filter(d => d.year === currentYear);
var continents = [];
for (var i = 0; i < yearData.length; i++) {
var continent = yearData[i].continent;
if (!continents.includes(continent)) {
continents.push(continent);
}
}

var colorScale = d3.scaleOrdinal()
.domain(continents)
.range(["#853CF5", "#380881", "#6500FF", "#0C00FF", "#00B9FF"]);

var update = pie
.select(".chart")
.selectAll(".arc")
.data(arcs(yearData));

update
.exit()
.remove();

update
.enter()
.append("path")
.classed("arc", true)
.attr("stroke", "#dff1ff")
.attr("stroke-width", "0.25px")
.merge(update)
.attr("fill", d => colorScale(d.data.continent))
.attr("d", path);

pie.select(".pie-title")
.text("Les émissions totales par continent et région, " + currentYear);
}


Insert cell
/*j'ai crée cette fonction createMap pour créer un élément svg avec une largeur et une hauteur spécifiées et ajoute un élément text pour afficher le titre de la carte */
function createMap(width, height) {
d3.select("#map")
.attr("width", width)
.attr("height", height)
.append("text")
.attr("x", width / 2)
.attr("y", "1em")
.attr("font-size", "1.5em")
.style("text-anchor", "middle")
.classed("map-title", true);
}

Insert cell
/*La fonction définit une projection géographique utilisant la méthode d3.geoMercator(). Elle définit également une variable "path" utilisant la méthode d3.geoPath() pour dessiner les chemins des pays sur la carte.
Ensuite, elle boucle à travers chaque objet dans les données géographiques. Si des données sont trouvées, elles sont stockées dans la propriété "properties" de l'objet géographique. Si aucune donnée n'est trouvée, la propriété "properties" stocke simplement le nom du pays.
La fonction sélectionne tous les éléments avec la classe "country" (pays) sur la carte et les associe aux données géographiques. Si des nouveaux pays sont ajoutés, ils seront créés en tant que nouveaux éléments "path". Chaque élément "path" est défini avec une classe "country", un attribut "d" contenant les coordonnées pour dessiner le pays sur la carte, et un événement "click" qui déclenche la fonction drawBar() avec les données climatiques correspondantes pour le pays sélectionné. La fonction drawMap() met également à jour l'état de la classe "active" pour chaque pays afin de maintenir un seul pays sélectionné à la fois.
Enfin, la fonction met à jour la couleur de chaque pays sur la carte en fonction des données de la propriété "properties" et du type de données sélectionné. Elle définit également le texte de la classe "map-title" pour afficher l'année sélectionnée et le type de données.
*/
function drawMap(geoData, climateData, year, dataType) {
var map = d3.select("#map");

var projection = d3.geoMercator()
.scale(190)
.translate([
+map.attr("width") / 2,
+map.attr("height") / 1.4
]);

var path = d3.geoPath()
.projection(projection);

d3.select("#year-val").text(year);

geoData.forEach(d => {
var countries = climateData.filter(row => row.countryCode === d.id);
var name = '';
if (countries.length > 0) name = countries[0].country;
d.properties = countries.find(c => c.year === year) || { country: name };
});

var colors = ["#AED6F1", "#0398FE", "#1671AF", "#094671"];

var domains = {
emissions: [0, 2.5e5, 1e6, 5e6],
emissionsPerCapita: [0, 0.5, 2, 10]
};

var mapColorScale = d3.scaleLinear()
.domain(domains[dataType])
.range(colors);

var update = map.selectAll(".country")
.data(geoData);

update
.enter()
.append("path")
.classed("country", true)
.attr("d", path)
.on("click", function() {
var currentDataType = d3.select("input:checked")
.property("value");
var country = d3.select(this);
var isActive = country.classed("active");
var countryName = isActive ? "" : country.data()[0].properties.country;
drawBar(climateData, currentDataType, countryName);
highlightBars(+d3.select("#year").property("value"));
d3.selectAll(".country").classed("active", false);
country.classed("active", !isActive);
})
.merge(update)
.transition()
.duration(750)
.attr("fill", d => {
var val = d.properties[dataType];
return val ? mapColorScale(val) : "#ccc";
})

d3.select(".map-title")
.text("Année " +year +":"+" Dioxyde de carbone " + graphTitle(dataType));
}









Insert cell
/*La fonction graphTitle prend en entrée une chaîne de caractères et renvoie une version formatée de cette chaîne, où chaque lettre majuscule est remplacée par un espace suivi de la lettre en minuscule correspondante. Par exemple, si l'entrée est "emissionsPerCapita", la sortie sera "emissions per capita" */
function graphTitle(str) {
return str.replace(/[A-Z]/g, c => " " + c.toLowerCase());
}
Insert cell
/* Cette fonction crée un élément SVG représentant un diagramme à barres */
function createBar(width, height) {
var bar = d3.select("#bar")
.attr("width", width)
.attr("height", height);

bar.append("g")
.classed("x-axis", true);

bar.append("g")
.classed("y-axis", true);

bar.append("text")
.attr("transform", "rotate(-90)")
.attr("x", - height / 2)
.attr("dy", "1em")
.style("text-anchor", "middle")
.style("font-size", "1em")
.classed("y-axis-label", true);

bar.append("text")
.attr("x", width / 2)
.attr("y", "1em")
.attr("font-size", "1.5em")
.style("text-anchor", "middle")
.classed("bar-title", true);
}
Insert cell
/* Cette fonction a pour but de mettre en évidence les barres du graphique qui correspondent à une année donnée. Elle prend en paramètre l'année à mettre en évidence et utilise la méthode d3.select pour sélectionner l'élément SVG avec l'id "bar". Elle utilise ensuite la méthode selectAll pour sélectionner tous les éléments "rect" ( Les éléments <rect> ont des attributs tels que x, y, width, height, fill, ext...)à l'intérieur de cet élément SVG. Elle applique ensuite une fonction à chaque élément sélectionné, qui vérifie si l'année de l'élément correspond à l'année donnée en paramètre. Si c'est le cas, elle change la couleur de remplissage de l'élément en bleu foncé, sinon elle utilise une couleur bleu plus clair.*/

function highlightBars(year) {
d3.select("#bar")
.selectAll("rect")
.attr("fill", d => d.year === year ? "#5555E7":"#3131B9");
}

Insert cell
/*la fonction dessine un graphique à barres pour les émissions de CO2 d'un pays donné sur une période de temps donnée. La fonction prend en entrée les données, le type de données (émissions totales ou émissions par habitant) et le pays pour lequel le graphique doit être dessiné.

Ensuite, la fonction crée une échelle linéaire pour l'axe x (l'année) en utilisant la fonction d3.scaleLinear(). L'échelle utilise les valeurs minimales et maximales de l'année dans les données pour définir le domaine de l'échelle et la largeur et le rembourrage pour définir la plage de l'échelle. La fonction crée également une échelle linéaire pour l'axe y (les émissions de CO2) en utilisant la fonction d3.scaleLinear(). L'échelle utilise la valeur maximale des émissions pour le pays spécifié pour définir le domaine de l'échelle et la hauteur et le rembourrage pour définir la plage de l'échelle.

La fonction crée également un axe x en utilisant la fonction d3.axisBottom() et un axe y en utilisant la fonction d3.axisLeft(). Les fonctions d3.select() et d3.transition() sont utilisées pour sélectionner les éléments d'axe correspondants et les mettre à jour avec les nouvelles échelles et formats d'axe. La fonction utilise également les données de type de données pour mettre à jour le label d'axe correspondant.
*/

function drawBar(data, dataType, country) {
var bar = d3.select("#bar");
var padding = {
top: 30,
right: 30,
bottom: 30,
left: 110
};
var barPadding = 1;
var width = +bar.attr("width");
var height = +bar.attr("height");
var countryData = data.filter(d => d.country === country)
.sort((a, b) => a.year - b.year);

var xScale = d3.scaleLinear()
.domain(d3.extent(data, d => d.year))
.range([padding.left, width - padding.right]);

var yScale = d3.scaleLinear()
.domain([0, d3.max(countryData, d => d[dataType])])
.range([height - padding.bottom, padding.top]);

var barWidth = xScale(xScale.domain()[0] + 1) - xScale.range()[0];

var xAxis = d3.axisBottom(xScale)
.tickFormat(d3.format(".0f"));

d3.select(".x-axis")
.attr("transform", "translate(0, " + (height - padding.bottom) + ")")
.call(xAxis);

var yAxis = d3.axisLeft(yScale);

d3.select(".y-axis")
.attr("transform", "translate(" + (padding.left - barWidth / 2) + ",0)")
.transition()
.duration(1000)
.call(yAxis);

var axisLabel = dataType === "emissions" ?
"CO2 emissions, thousand metric tons" :
"CO2 emissions, metric tons per capita";

var barTitle = country ?
"Les émissions de CO2, " + country :
"Cliquez sur un pays pour voir les tendances annuelles ";

d3.select(".y-axis-label")
.text(axisLabel);

d3.select(".bar-title")
.text(barTitle);

var t = d3.transition()
.duration(1000)
.ease(d3.easeBounceOut);

var update = bar
.selectAll(".bar")
.data(countryData);

update
.exit()
.transition(t)
.delay((d, i, nodes) => (nodes.length - i - 1) * 100)
.attr("y", height - padding.bottom)
.attr("height", 0)
.remove();

update
.enter()
.append("rect")
.classed("bar", true)
.attr("y", height - padding.bottom)
.attr("height", 0)
.merge(update)
.attr("x", d => (xScale(d.year) + xScale(d.year - 1)) / 2)
.attr("width", barWidth - barPadding)
.transition(t)
.delay((d, i) => i * 100)
.attr("y", d => yScale(d[dataType]))
.attr("height", d => height - padding.bottom - yScale(d[dataType]));
}
Insert cell
/* La fonction "getPercentage()" est utilisée pour calculer le pourcentage de l'angle d'un secteur d'un graphique
le pourcentage est égal à l'angle (en radians) divisé par 2 fois pi, multiplié par 100. Le résultat est renvoyé en tant que chaîne de caractères avec deux décimales après la virgule et le symbole % */
function getPercentage(d) {
var angle = d.endAngle - d.startAngle;
var fraction = 100 * angle / (Math.PI * 2);
return fraction.toFixed(2) + "%";
}
Insert cell
function formatDataType(key) {
return key[0].toUpperCase() + key.slice(1).replace(/[A-Z]/g, c => " " + c);
}
Insert cell
html`
<style>

.tooltip2 {
opacity: 0;
position: absolute;
pointer-events: none;
border: 4px solid #2c3e50;
background-color: #ecf0f1;
padding: 10px;
border-radius: 6px;
}

.tooltip2 p {
margin: 2px;
}

.tooltip2:after {
content: ' ';
position: absolute;
left: 50%;
border: 8px solid transparent;
border-top-color: #2c3e50;
bottom: -20px;
margin-left: -4px;
}

</style>`
Insert cell
{
var data = await d3.csv("https://raw.githubusercontent.com/Manal1Hachhach/visu/main/all_data.csv");
return data[0];
}
Insert cell
d3.json("https://unpkg.com/world-atlas@1.1.4/world/50m.json")
Insert cell
d3 = require("d3@5")
Insert cell
m = FileAttachment("50m.json").json()
Insert cell
Insert cell
import {bannerTitle} from "@observablehq/banner"
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