Public
Edited
Dec 5, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg").attr("viewBox", `0, 0, ${width}, ${height}`)
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
svg.selectAll("path")
.data(countries.features)
.enter()
.append("g")
.attr("class", "country-group")
.each(function (d) {
const countryGroup = d3.select(this);
// Append path element
countryGroup.append("path")
.attr("d", path)
.attr("stroke", "#111")
.attr("stroke-width", 0.5)
.on("mouseover", function(event, d) {
let text = d.properties.name
const mean_homo = d.properties.dataJoined.get(year)[0].mean_homo
const mean_homo_rounded = Math.round((mean_homo + Number.EPSILON) * 100) / 100
text = text + "\nJustifiability: " + mean_homo_rounded
showToolTip(text, [event.pageX, event.pageY])
})
.on("mousemove", function(event) {
d3.select(".tooltip")
.style("top", event.pageY - 10 + "px")
.style("left", event.pageX + 10 + "px")
})
.on("mouseout", function() {
d3.select(".tooltip").style("visibility", "hidden")
})
.attr("fill", d => d.properties.dataJoined?.get(year)
? cScale(d.properties.dataJoined.get(year)[0].mean_homo)
: "lightgrey");

// Append checkmark symbol if when_legal equals the displayed year and not already added
const whenLegalYear = d.properties.dataJoined?.get(year) ? d.properties.dataJoined.get(year)[0].when_legal : null;
const checkmarkAdded = whenLegalYear !== null && whenLegalYear <= year;

if (checkmarkAdded) {
const symbolSize = calculateSymbolSize(d.area);

countryGroup.append("text")
.attr("class", "checkmark")
.attr("x", path.centroid(d)[0])
.attr("y", path.centroid(d)[1])
.text("\u2726") // Unicode for symbol
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.style("font-size", `${symbolSize}px`) // Use dynamic size
.style("fill", "orange");
}
});

return svg.node()
}
Insert cell
showToolTip = (text, coords) => {
d3.select(".tooltip")
.text(text)
.style("top", coords[1] + "px")
.style("left", coords[0] + "px")
.style("visibility", "visible");
}
Insert cell
cScale = d3.scaleLinear()
.domain([
1,
10])
.range([-1, 0, 1])
.interpolate((a, b) => a < 0
? t => d3.interpolateBlues(t)
: t => d3.interpolateReds(1-t))

Insert cell
outline = ({ type: "Sphere" })
Insert cell
projection = d3.geoNaturalEarth1()
Insert cell
path = d3.geoPath(projection)
Insert cell
height = {
const [[x0, y0], [x1, y1]] = d3.geoPath(projection.fitWidth(width, outline)).bounds(outline);
const dy = Math.ceil(y1 - y0), l = Math.min(Math.ceil(x1 - x0), dy);
projection.scale(projection.scale() * (l - 1) / l).precision(0.2);
return dy;
}
Insert cell
countries = {
// group entities by name and year
const entities = d3.group(dataJoined, d => d.country, d => d.year);
// attach data to each country in properties
const countries = topojson.feature(world, world.objects.countries);
countries.features.forEach(country => {
country.properties.dataJoined = entities.get(country.properties.name);
})
return countries
}
Insert cell
data = d3.csvParse(await FileAttachment("Interpolated_Data_Cleaned.csv").text(), d => {
if (d.country === "United States") {
d.country = "United States of America"
}
return {
country: d.Country,
year: +d.Year,
wave: +d.Wave,
country_code: +d.Country_Code,
mean_homo: +d.mean_homo }
} )

Insert cell
// Assuming your second CSV file is named "legality_1.csv"
legalityData = await FileAttachment("legality_3.csv").csv({typed: true});


Insert cell
// Merge data from the second CSV into the original data array
dataJoined = data.map(d => {
const matchingRow = legalityData.find(row => row.country === d.country);

// Add the new property 'when_legal' based on the additional data
return {
...d,
when_legal: matchingRow ? +matchingRow.year : null
}
});

// Now, each object in the output array has a new 'when_legal' property based on the legality data
Insert cell
dataJoined.forEach(d => {
delete d.Year;
});
Insert cell
// Function to calculate symbol size based on country area
function calculateSymbolSize(area) {
// You can adjust the scaling factor based on your preference
const scaleFactor = 50;
return Math.sqrt(area) * scaleFactor;
}
Insert cell
{for (let i = 0; i < data.length; i++) {
data[i].Year += cars[i] + "<br>";
}}
Insert cell
Insert cell
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