Published
Edited
Oct 5, 2022
Insert cell
Insert cell
map = {
// We're going to draw the map on the following SVG.
let svg = d3.create("svg").attr("width", w).attr("height", h);

// Draw the graticule
svg
.append("path")
.attr("d", path(d3.geoGraticule10()))
.attr("fill", "none")
.attr("stroke", "#333")
.attr("stroke-width", 0.4);

// Draw the countries
let country_group = svg.append("g");
country_group
.selectAll("path")
.data(countries.features)
.join("path")
.attr("d", path)
.attr("data-pop", (d) => console.log(d.properties.POP_EST))
.attr("fill", "#eee")
.attr("stroke", "black")
.attr("stroke-width", 1);

// Draw the bubbles.
const tooltip = svg.append("g");
let max_pop = d3.max(countries.features.map((o) => o.properties.POP_EST));
let bubble_group = svg.append("g");
bubble_group
.selectAll("circle")
.data(countries.features)
.join("circle")
.attr("cx", (d) => path.centroid(d)[0])
.attr("cy", (d) => path.centroid(d)[1])
.attr("r", (d) => 20 * Math.sqrt(d.properties.RATE_DIFF*10))
.attr("fill", "lightblue")
.attr("stroke", "black")
.on("touchmove mousemove", function(event, d) {
tooltip.call(callout,`Central bank interest rates change ${d.properties.RATE_DIFF}`);
tooltip.attr("transform", `translate(${d3.pointer(event, this)})`);
})

.on("touchend mouseleave", function() {
tooltip.call(callout, null);
d3.select(this)
.lower();
});

return svg.node();
}
Insert cell
callout = (g, value) => {
if (!value) return g.style("display", "none");

g.style("display", null)
.style("pointer-events", "none")
.style("font", "10px sans-serif");

const path = g.selectAll("path")
.data([null])
.join("path")
.attr("fill", "white")
.attr("stroke", "black");

const text = g.selectAll("text")
.data([null])
.join("text")
.call(text => text
.selectAll("tspan")
.data((value + "").split(/\n/))
.join("tspan")
.attr("x", 0)
.attr("y", (d, i) => `${i * 1.1}em`)
.style("font-weight", (_, i) => i ? null : "bold")
.text(d => d));

const {x, y, width: w, height: h} = text.node().getBBox();
text.attr("transform", `translate(${-w / 2},${25 - y})`);
path.attr("d", `M${-w / 2 - 10},5H-5l5,-5l5,5H${w / 2 + 10}v${h + 20}h-${w + 20}z`);
}
Insert cell
Insert cell
Insert cell
path = d3.geoPath().projection(projection)
Insert cell
projection = d3.geoNaturalEarth1().fitSize([w + 20, h], countries)
Insert cell
h = 0.625 * w
Insert cell
w = width < 1100 ? width : 1100
Insert cell
// Convert the TopoJSON to GeoJSON
countries = topojson.feature(map_data, map_data.objects.countries)
Insert cell
Insert cell
map_data = FileAttachment("RATES2.json").json()
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