Public
Edited
May 1
Insert cell
Insert cell
Insert cell
Insert cell
// Select the five countries to compare
selectedCountries = ["United States", "China", "India", "Germany", "Brazil"]
Insert cell
// Generate an array of year strings: ["1990", ..., "2019"]
years = d3.range(1990, 2020).map(String)
Insert cell
Insert cell
// Build the data structure for the line chart
lineData = data
.filter(d => selectedCountries.includes(d["Country Name"]))
.map(d => ({
country: d["Country Name"],
values: years.map(year => ({
year: +year, // convert year string to number
value: +d[year]
}))
}))
Insert cell
Insert cell
Insert cell
viewof lineChart = {
const width = 800, height = 400;
const margin = { top: 40, right: 100, bottom: 40, left: 60 };

// Create SVG container
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

// X scale: years
const x = d3.scaleLinear()
.domain(d3.extent(years, d => +d)) // e.g., [1990, 2019]
.range([margin.left, width - margin.right]);

// Y scale: emissions value
const y = d3.scaleLinear()
.domain([0, d3.max(lineData, d => d3.max(d.values, v => v.value))]).nice()
.range([height - margin.bottom, margin.top]);

// Color scale for lines
const color = d3.scaleOrdinal()
.domain(selectedCountries)
.range(d3.schemeTableau10);

const xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickFormat(d3.format("d"))); // format tick labels as plain numbers

// Create left Y axis
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

// Append axes to the SVG
svg.append("g").call(xAxis);
svg.append("g").call(yAxis);

// Define the line generator function for each country
const line = d3.line()
.x(d => x(d.year)) // map year to x-axis
.y(d => y(d.value)); // map emissions value to y-axis

// Draw one path per country
svg.selectAll(".line")
.data(lineData)
.join("path")
.attr("fill", "none")
.attr("stroke", d => color(d.country))
.attr("stroke-width", 2)
.attr("d", d => line(d.values)); // generate line path for this country's data

// Add legend
svg.selectAll(".legend")
.data(selectedCountries)
.join("text")
.attr("x", width - margin.right + 5)
.attr("y", (d, i) => margin.top + i * 20) // stack vertically
.attr("dy", "0.35em")
.attr("fill", d => color(d))
.text(d => d);

return svg.node();
}



Insert cell
Insert cell
// Load GeoJSON data for all world countries from an external source?
countries = fetch("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson")
.then(res => res.json())
Insert cell
Insert cell
// Create a Map that links country name → CO₂ emissions per capita in 2019
co2_2019_by_name = {
const map = new Map();
for (const d of data) {
const name = d["Country Name"]; // for example "China"
const value = +d["2019"];
if (!isNaN(value)) {
map.set(name, value); // Add to map only if it's a valid number
}
}
return map;
}

Insert cell
Insert cell
Insert cell
{
const width = 960;
const height = 600;
// Create an SVG container for the map
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Set up a projection to convert lat/lon to screen coordinates
const projection = d3.geoNaturalEarth1()
.scale(160)
.translate([width / 2, height / 2]);
// Create a path generator
const path = d3.geoPath().projection(projection);
// Set up a color scale
const color = d3.scaleSequentialSqrt()
.domain([0, d3.max(Array.from(co2_2019_by_name.values()))])
.interpolator(d3.interpolateBlues);
// Draw the countries
svg.append("g")
.selectAll("path")
.data(countries.features)// GeoJSON features
.join("path")
.attr("fill", d => {
const value = co2_2019_by_name.get(d.properties.name);// Match by country name
return value != null ? color(value) : "#ccc";
})
.attr("d", path)
.append("title")
.text(d => {
const value = co2_2019_by_name.get(d.properties.name);
return `${d.properties.name}: ${value != null ? value.toFixed(2) : "N/A"}`;
});

return svg.node();
}

Insert cell
Insert cell
// Prepare streamgraph data in long format:
streamLong = {
const years = d3.range(1990, 2020).map(String);
const entries = [];//This will hold our final flat list of region-year-value entries

const regions = [...new Set(data.map(d => d.Region))];

for (const year of years) {
for (const region of regions) {
const filtered = data.filter(d => d.Region === region);
// Extract numeric values for the given year and filter out missing or invalid values
const values = filtered.map(d => +d[year]).filter(v => !isNaN(v));
// Compute the regional average for the year
const avg = d3.mean(values);
if (avg !== undefined) {
entries.push({
year: +year,
region,
value: avg
});
}
}
}

return entries;
}


Insert cell
Insert cell
Insert cell
// Draw the streamgraph
Plot.plot({
width: 900,
height: 500,
x: { label: "Year" }, // X-axis: time
y: {
label: "Per-capita CO₂ Emissions (tons)",
stack: true // Stack values vertically by region
},
color: {
type: "categorical", // Use region categories for fill
scheme: "tableau10", // Use Tableau color palette for good contrast
legend: true
},
marks: [
// Use area chart for stacked display across years
Plot.areaY(streamLong, {
x: "year", // Map X-axis to year
y: "value", // Map Y-axis to average CO₂
fill: "region", // Fill area by region name
curve: "natural" // Use smooth curves between points
})
]
})


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