Public
Edited
Mar 2, 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
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
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]) {

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, "");

// AJOUT DIV
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip2")
.style("position", "absolute")
.text("I'm a circle!");
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("#map")
.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" ? "thousand metric tons" : "metric tons per capita";
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];

// MISE A JOUR DIV
tooltip
.style("opacity", +(isCountry || isArc || isBar))
.style("left", (d3.event.pageX ) + "px")
.style("top", (d3.event.pageY) + "px")
.html("TEST")
}

})


Insert cell
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", "1em")
.attr("font-size", "1.5em")
.style("text-anchor", "middle")
.classed("pie-title", true);
}
Insert cell


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(["#ab47bc", "#7e57c2", "#26a69a", "#42a5f5", "#78909c"]);

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
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
function graphTitle(str) {
return str.replace(/[A-Z]/g, c => " " + c.toLowerCase());
}
Insert cell
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

function highlightBars(year) {
d3.select("#bar")
.selectAll("rect")
.attr("fill", d => d.year === year ? "#16a085" : "#1abc9c");
}

Insert cell


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 ?
"CO2 Emissions, " + country :
"Click on a country to see annual trends.";

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

function drawMap(geoData, climateData, year, dataType) {
var map = d3.select("#map");

var projection = d3.geoMercator()
.scale(110)
.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 = ["#f1c40f", "#e67e22", "#e74c3c", "#c0392b"];

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("Carbon dioxide " + graphTitle(dataType) + ", " + year);
}









Insert cell
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
{
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
styles = html`
<style>

.tooltip {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background: rgba(69,77,93,.9);
border-radius: .1rem;
color: #fff;
display: block;
font-size: 11px;
max-width: 320px;
padding: .2rem .4rem;
position: absolute;
text-overflow: ellipsis;
white-space: pre;
z-index: 300;
}
</style>`
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