D3.js Geo Maps — Geographic Data Visualization
In this tutorial, you will learn about D3.js Geo Maps. We cover key concepts, practical examples, and best practices to help you master this topic.
D3.js geo maps render geographic data using GeoJSON and TopoJSON formats with configurable projections for creating choropleths, point maps, and interactive cartographic visualizations.
What You'll Learn
By the end of this guide, you will load TopoJSON data, configure d3.geoMercator and other projections, draw country boundaries, create choropleth maps with color scales, add zoom behavior, and plot data points on maps.
Why Geo Maps Matter
Geographic context makes data meaningful. Durga Antivirus Pro uses geo maps to show the geographic origin of cyber attacks in real time, with color gradients indicating threat intensity by region.
flowchart LR
A[GeoJSON/TopoJSON] --> B[Map Projection]
B --> C[d3.geoPath]
C --> D[SVG Path Elements]
E[Data Values] --> F[Color Scale]
F --> D
D --> G[Interactive Map]
Basic Map Setup
var width = 960, height = 600;
var projection = d3.geoMercator()
.scale(150)
.translate([width / 2, height / 1.5]);
var path = d3.geoPath().projection(projection);
var svg = d3.select('#map')
.append('svg')
.attr('width', width)
.attr('height', height);
Drawing Countries From TopoJSON
d3.json('https://unpkg.com/world-atlas@2/countries-110m.json')
.then(function(world) {
var countries = topojson.feature(world, world.objects.countries);
svg.selectAll('path')
.data(countries.features)
.enter()
.append('path')
.attr('d', path)
.attr('fill', '#4ecdc4')
.attr('stroke', '#fff')
.attr('stroke-width', 0.5);
});
Choropleth Map
var colorScale = d3.scaleThreshold()
.domain([10, 50, 100, 200, 500, 1000])
.range(d3.schemeBlues[6]);
d3.json('https://unpkg.com/world-atlas@2/countries-110m.json')
.then(function(world) {
var countries = topojson.feature(world, world.objects.countries);
svg.selectAll('path')
.data(countries.features)
.enter()
.append('path')
.attr('d', path)
.attr('fill', function(d) {
var value = dataMap.get(d.id) || 0;
return colorScale(value);
})
.attr('stroke', '#fff')
.attr('stroke-width', 0.5)
.append('title')
.text(function(d) {
return d.properties.name + ': ' + (dataMap.get(d.id) || 0);
});
});
Zoom and Pan
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', function(event) {
svg.selectAll('path').attr('transform', event.transform);
});
svg.call(zoom);
Adding Data Points
var cities = [
{ name: 'London', coords: [-0.1278, 51.5074] },
{ name: 'Tokyo', coords: [139.6917, 35.6895] },
{ name: 'New York', coords: [-74.0060, 40.7128] }
];
svg.selectAll('circle')
.data(cities)
.enter()
.append('circle')
.attr('cx', function(d) { return projection(d.coords)[0]; })
.attr('cy', function(d) { return projection(d.coords)[1]; })
.attr('r', 4)
.attr('fill', '#ff6b35');
Common Mistakes
1. Using Wrong Projection for the Region
Mercator distorts areas near the poles. Use d3.geoAlbersUsa for US maps, d3.geoOrthographic for globe view.
2. Forgetting topojson.feature
TopoJSON stores data as arcs. Convert to GeoJSON features with topojson.feature() before passing to d3.geoPath.
3. Path Data Not Visible
If path fills are invisible, check the projection scale and translate. Features may be rendered off-screen.
4. Not Handling Missing Data
Choropleth maps need data for all regions. Use default values for regions with no data.
5. Map Not Centered
Adjust the projection translate to center your map on the region of interest.
Practice Questions
Q1: What is the difference between GeoJSON and TopoJSON? A: GeoJSON stores geometry as coordinates. TopoJSON stores arcs and deduplicates shared boundaries, making files smaller.
Q2: What does d3.geoPath do? A: It converts GeoJSON geometry to SVG path data strings, using the specified projection.
Q3: How do you create a choropleth color scale? A: Use d3.scaleThreshold or d3.scaleQuantize with domain values and a color scheme like d3.schemeBlues.
Q4: How do you add tooltips to map regions? A: Append title elements inside path elements, or use SVG text labels that appear on hover.
Q5: What projection is best for world maps? A: d3.geoEqualEarth or d3.geoNaturalEarth1 for visually pleasing world maps. Mercator for navigation.
Challenge: Build a map showing the locations of the top 10 most populous cities. Size the circles by population. Add a legend showing population ranges.
FAQ
Try It Yourself
Build a choropleth world map with color-coded countries and hover tooltips.
<!DOCTYPE html>
<html>
<head>
<title>World Choropleth</title>
<style>
body { font-family: sans-serif; padding: 20px; background: #1a1a2e; }
svg { display: block; margin: auto; background: #16213e; border-radius: 12px; }
.country { stroke: #fff; stroke-width: 0.3; cursor: pointer; }
.country:hover { stroke-width: 2; }
#tooltip { position: absolute; background: rgba(0,0,0,0.8); color: white; padding: 8px 12px; border-radius: 6px; font-size: 13px; pointer-events: none; display: none; }
</style>
</head>
<body>
<div id="tooltip"></div>
<svg width="800" height="500" id="map"></svg>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script>
var width = 800, height = 500;
var svg = d3.select('#map');
var tooltip = d3.select('#tooltip');
var projection = d3.geoNaturalEarth1().scale(170).translate([width / 2, height / 1.3]);
var path = d3.geoPath().projection(projection);
d3.json('https://unpkg.com/world-atlas@2/countries-110m.json').then(function(world) {
var countries = topojson.feature(world, world.objects.countries);
var values = new Map();
countries.features.forEach(function(d) {
values.set(d.id, Math.random() * 500);
});
var color = d3.scaleSequential(d3.interpolateBlues).domain([0, 500]);
svg.selectAll('path')
.data(countries.features).enter()
.append('path').attr('class', 'country')
.attr('d', path)
.attr('fill', function(d) { return color(values.get(d.id)); })
.on('mouseover', function(e, d) {
d3.select(this).attr('stroke', '#ff6b35');
tooltip.style('display', 'block')
.html('<strong>' + d.properties.name + '</strong><br>Value: ' + values.get(d.id).toFixed(0))
.style('left', (e.pageX + 12) + 'px').style('top', (e.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).attr('stroke', '#fff');
tooltip.style('display', 'none');
});
});
</script>
</body>
</html>
What's Next
Load external data from APIs and files.
Request Data — Loading data with D3.js. Localization — Localization and formatting.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro