D3 Map Visualization Example

A choropleth is a bar chart wearing country shapes. Here's a live D3 world map with geoPath, Equal Earth, and a hover tooltip.

D3 Maps Examples
← All posts
D3 Map Visualization Example

A D3 map visualization example is just a chart whose “bars” happen to be country shapes. You still have values. You still have a color scale. The extra piece is a projection that turns longitude and latitude into x and y.

The live map below loads world-atlas country outlines, projects them with geoEqualEarth, and colors a dummy index. Same API you'd use for a GeoJSON export from QGIS. For the rest of D3, see the D3.js page or the graph examples.

What you need

  • Features. A GeoJSON FeatureCollection. Each feature is a place.
  • A projection. geoMercator is the one everyone recognizes. geoEqualEarth is the better default for a choropleth — area stays honest.
  • geoPath. It writes the SVG d for you.
  • A value. Population, rate, whatever. That's what the fill encodes.

I do not start from shapefiles in the browser. Convert once, ship GeoJSON or TopoJSON, draw that.

A D3 map visualization example

Hover a country for the name and a dummy index. Brighter gold is higher. The outlines are Natural Earth 110m. The numbers are fake so you can see the join, the projection, and the scale without a CSV in the way.

Preview

Equal Earth projection · world-atlas countries-110m · hover for the value

The code

fitExtent is the line I forget, then I stare at a tiny smudge in the corner. It scales the projection so the whole FeatureCollection fills the SVG. Drop Antarctica or the fit will leave a huge empty south.

Code

const world = await d3.json(
  "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json"
);
const countries = topojson.feature(world, world.objects.countries);
countries.features = countries.features.filter(
  (d) => d.properties.name !== "Antarctica"
);
const scores = { "United States of America": 96, China: 88, India: 84 };
countries.features.forEach((d) => {
  d.properties.value = scores[d.properties.name] ?? 40;
});

const width = 800;
const height = 440;
const svg = d3.select("#chart").append("svg").attr("viewBox", `0 0 ${width} ${height}`);

const projection = d3.geoEqualEarth()
  .fitExtent([[18, 10], [width - 18, height - 52]], countries);
const path = d3.geoPath(projection);
const color = d3.scaleSequential(d3.interpolateYlOrBr).domain([0, 100]);

svg.append("path").datum({ type: "Sphere" }).attr("d", path).attr("fill", "#0e141c");
svg.append("path")
  .datum(d3.geoGraticule10())
  .attr("d", path)
  .attr("fill", "none")
  .attr("stroke", "rgba(255,255,255,0.08)");

svg.selectAll("path.country")
  .data(countries.features)
  .join("path")
  .attr("class", "country")
  .attr("d", path)
  .attr("fill", (d) => color(d.properties.value))
  .attr("stroke", "#0a0c10");

Join your own numbers

The preview colors a lookup by properties.name. In a real chart you load a CSV, Map it on the country name or ISO code, then color(valueByName.get(d.properties.name)). Names in Natural Earth are picky: it's United States of America, not United States.

Need a closer zoom? Use countries-50m.json or a GeoJSON export. If the “map” is really a flow between countries, a D3 sankey chart is usually clearer than drawing lines across the ocean. And if you meant a node-link diagram, that's a force layout, not a choropleth.

Questions I get

How do I make a D3 map visualization?

Give D3 GeoJSON (or TopoJSON you convert first). geoMercator or geoEqualEarth projects lon/lat to pixels. geoPath turns each feature into an SVG d attribute. A sequential scale colors the regions.

Do I need TopoJSON for a D3 map?

No. GeoJSON is enough. TopoJSON is smaller on the wire. world-atlas and us-atlas ship TopoJSON; topojson.feature() turns it into GeoJSON D3 can draw.

Why does my D3 map look empty?

Usually the projection is not fitted to the data, or the coordinates are lat/lon swapped. fitExtent or fitSize on the FeatureCollection fixes the first. GeoJSON is [longitude, latitude].

Latest posts

All posts

Cytoscape JS Examples

Cytoscape JS examples are node-link graphs, not bar charts. Here are four I actually paste: force, hierarchy, circle, and tap to highlight.

Cytoscape Examples Networks
Read post

Bar Charts Explained

A bar is a number you can compare at a glance. Here's when to use one, the four layouts I actually ship, and the mistakes that make a bar chart lie.

Charts Examples JavaScript
Read post