Description
A connection map draws lines or arcs between geographic points to show that relationships, routes, or links exist between locations. Unlike a flow map, which emphasizes the magnitude of movement through line width, a connection map focuses on the topology of the network: which places are connected, how many connections each place has, and what the overall spatial pattern of connectivity looks like. The classic example is an airline route map showing all flights from a hub airport.
Connection maps occupy the intersection of network visualization and cartography. They leverage geographic context to give meaning to abstract network structure — a flight route between New York and London means something different when seen on a map than when seen as an abstract edge in a node-link diagram. The geographic grounding helps viewers understand distances, regional clustering, and the spatial logic of connectivity patterns.
The primary challenge is visual clutter. A hub with hundreds of connections radiates lines in every direction, and multiple hubs create a dense web that obscures individual connections. Strategies to address this include interactive filtering (show connections for one selected node), edge bundling (routing lines through shared corridors), opacity modulation, and progressive disclosure (showing only the strongest or most relevant connections at any time).
When to Use
- Showing airline routes, shipping lanes, or communication links between cities
- Visualizing the geographic structure of a network (who is connected to whom, and where)
- Highlighting connectivity hubs and peripheral nodes in spatial context
- Comparing network coverage across regions (which areas are well-connected vs. isolated)
- Revealing geographic clustering in social or business networks
When NOT to Use
- When the volume of flow matters more than the existence of connections — use a flow map with width-encoded lines
- When there is no meaningful geographic dimension — use a network diagram or adjacency matrix
- When the number of connections is very large (>1,000) and filtering is not available — the map becomes an unreadable web
- When exact routes matter (e.g., road navigation) — use a routing map, not abstract arcs
Anatomy
- Base map: Geographic reference layer (world, country, or regional boundaries).
- Nodes: Points at geographic locations (cities, airports, facilities), often sized by degree or importance.
- Connection lines/arcs: Lines or curves connecting pairs of nodes, drawn as straight lines, great-circle arcs, or bundled paths.
- Node labels: City or location names, shown directly or on hover.
- Color encoding: Lines colored by type (domestic vs. international), by cluster, or by a quantitative attribute.
- Opacity: Applied to lines to handle overlap; denser overlap areas naturally appear darker, conveying intensity.
Variations
- Great-circle connection map: Arcs follow the shortest path on a sphere, producing curved lines that reveal true geographic relationships.
- Hub-and-spoke map: Connections radiate from one or more central hubs, as in airline route displays.
- Edge-bundled connection map: Lines are routed through shared corridors to reveal aggregate patterns and reduce clutter.
- Filtered connection map: Only connections for a selected node or meeting a threshold are shown, making dense networks navigable.
- Animated connection map: Connections appear sequentially or pulse to show temporal evolution of the network.
Code Reference
// D3 connection map with great-circle arcs
import * as d3 from "d3";
const projection = d3.geoNaturalEarth1().fitSize([width, height], world);
const path = d3.geoPath(projection);
const svg = d3.select("#chart").append("svg")
.attr("viewBox", [0, 0, width, height]);
// Base map
svg.append("path").datum(world).attr("d", path)
.attr("fill", "#f7f7f7").attr("stroke", "#ddd");
// Great-circle arcs
svg.selectAll(".connection").data(connections).join("path")
.attr("d", d => path({
type: "LineString",
coordinates: [[d.lon1, d.lat1], [d.lon2, d.lat2]]
}))
.attr("fill", "none")
.attr("stroke", "#6366f1")
.attr("stroke-opacity", 0.3)
.attr("stroke-width", 1);
// Nodes
svg.selectAll("circle").data(cities).join("circle")
.attr("cx", d => projection([d.lon, d.lat])[0])
.attr("cy", d => projection([d.lon, d.lat])[1])
.attr("r", d => Math.sqrt(d.connections) * 2)
.attr("fill", "#f59e0b");