All thirty days

Day 13: Interactions

The fastest drive between every pair of Canada's 50 largest metropolitan areas, both ways: 2,450 drives from unmap's own routing, and the one road 561 of the 1,225 pairs share.

interactions.json
Loading 2,450 drives
City pairs that drive the road
Click a city for its drives, or a road for its count.

We drove every pair of Canada's 50 largest metropolitan areas, both ways: 1,225 pairs, 2,450 drives, 5,689,569 km on the road. Each road is drawn as wide and as bright as the number of pairs whose fastest drive uses it. The cities are the 50 census metropolitan areas and agglomerations with the most people in 2021, from Toronto down to Medicine Hat, and none is in the territories.

Between Thunder Bay and Nipigon, one road carries 561 of the 1,225 pairs, 45.8%: every pair with one city from Thunder Bay west and the other east of it, 17 cities times 33. West of Thunder Bay, the Trans-Canada carries 544 to the Manitoba border. East of Nipigon the stream splits around Lake Superior: 306 pairs follow Highway 17 along the shore through Wawa, and 255 turn north on Highway 11 through Geraldton.

The Atlantic end hangs on narrow links. 141 pairs, every drive between Halifax, Cape Breton or St. John's and the other 47 cities, cross the Chignecto Isthmus, the neck of land that joins Nova Scotia to New Brunswick. All 49 of St. John's drives cross the Cabot Strait by ferry, and all 49 of Charlottetown's cross the Confederation Bridge. The longest drive, St. John's to Nanaimo, is 7,216 km and 81.3 hours, with a ferry at each end.

Click a city to see only its own drives, to and from the other 49, or click a road for how many pairs use it.

How it's made

One basemap and one layer. This is the whole map, minus the legend.

import { Unmap, createMap } from '@unmap/sdk'

const unmap = new Unmap({ key: 'um_pk_live_...' })

// Canada's 50 largest metropolitan areas (2021 Census), as [lng, lat] at each core city.
const cities = await fetch('/cities.json').then((r) => r.json())

// Drive every pair both ways, and count the drives along each stretch of road.
const uses = new Map()
for (const from of cities) {
  for (const to of cities) {
    if (from === to) continue
    const route = await unmap.router.route(from, to, { mode: 'car' })
    const coords = route.geometry.coordinates
    for (let i = 1; i < coords.length; i++) {
      const segment = coords[i - 1] + '>' + coords[i]
      uses.set(segment, (uses.get(segment) ?? 0) + 1)
    }
  }
}

// A stretch counts city pairs in its busier direction. Each carriageway of a divided highway
// then carries every pair once, and so does a two-lane road driven both ways.
const features = []
for (const [segment, n] of uses) {
  const [a, b] = segment.split('>')
  const back = uses.get(b + '>' + a) ?? 0
  if (back > n || (back === n && a > b)) continue // keep one direction of each road
  features.push({
    type: 'Feature',
    properties: { n: Math.max(n, back) },
    geometry: { type: 'LineString', coordinates: [a, b].map((p) => p.split(',').map(Number)) },
  })
}

const map = createMap({ key: 'um_pk_live_...', container: '#map', style: 'muted', mode: 'dark' })
map.on('load', () => {
  const labels = map.getStyle().layers.find((l) => l.type === 'symbol').id
  map.addSource('roads', { type: 'geojson', data: { type: 'FeatureCollection', features } })
  map.addLayer({
    id: 'roads',
    type: 'line',
    source: 'roads',
    paint: {
      // Width and colour by pair count, on a log scale: 1 to 561 of the 1,225 pairs.
      'line-width': ['interpolate', ['linear'], ['ln', ['get', 'n']], 0, 0.35, 6.4, 6],
      'line-color': ['interpolate', ['linear'], ['ln', ['get', 'n']],
        0, '#43263F', 4.1, '#C9307C', 5.5, '#FF3E9A', 6.4, '#FFC9E1'],
    },
  }, labels) // under the place names
})

The cities are the 50 census metropolitan areas and census agglomerations with the largest 2021 populations, summed from the census blocks in Statistics Canada's Geographic Attribute File. Each one is routed from a single point: the Canadian Geographical Names Database's point for its largest municipality, or for the city it is known by (Victoria, not Saanich; Sudbury and Sydney for Greater Sudbury and Cape Breton). We sent each pair to unmap's routing API both ways (mode=car), 2,450 requests, two at a time. A road's count is the number of pairs whose drive uses it in its busier direction, so the two carriageways of a divided highway and a two-lane road both count a pair once. The routing graph covers Canada only, so no drive crosses the United States: a driver allowed into Michigan or Minnesota can skip the north shore of Lake Superior, so the Thunder Bay stretch is a fact of Canada's own roads, not of every trip. Times are the engine's estimates with no traffic, and a ferry is timed by its crossing, not its schedule. The routing engine refuses a car route whose ends are more than 5,000 km apart in a straight line, so the six drives between St. John's and Vancouver, Victoria or Nanaimo are routed in two legs that meet on the Trans-Canada just inside Manitoba, a road every drive between them takes anyway. The script is scripts/build-challenge-interactions.mjs in the unmap repository.

Data

  • Drives: unmap routing on OpenStreetMap data, © OpenStreetMap contributors (ODbL).
  • Cities and populations: Statistics Canada, 2021 Census, Geographic Attribute File. Used under the Statistics Canada Open Licence.
  • City points: Canadian Geographical Names Database, Natural Resources Canada. Contains information licensed under the Open Government Licence - Canada.
  • Basemap: unmap, © OpenStreetMap contributors.

Share this map

Post it, or make your own and tag it #30DayMapChallenge.