Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Map design

From a plot with coordinates to a map someone can read

Eindhoven University of Technology

A plot shows data. A map answers a question about a place. The difference is mostly a dozen small decisions about what the reader sees first, what colours mean, and what text is on the image. None of them need design training, and together they are the difference between a map people scroll past and one they stop at.

Start from the question

Before choosing a colour, write the title as a statement or a question: “Eindhoven’s cafés are packed into one square kilometre”, rather than “Cafés in Eindhoven”. Once you know what the map is for, most of the other decisions make themselves: what to emphasise, what to leave out, and which comparison the colours should make easy.

Visual hierarchy

The reader’s eye goes to the strongest contrast first. Use that on purpose:

Anatomy of a map shows these choices on the Day 1 map.

Colour

Choose the palette by the kind of data, not by taste:

DataPalette typeGood choices
Ordered, low to high (density, income)sequential, one hue light to darkviridis, cividis, Blues, YlOrRd
Above or below a meaningful middle (change, difference from average)diverging, two hues through a neutralRdBu, PuOr, BrBG
Categories with no order (land use, cuisine)qualitative, distinct hues, similar lightnessSet2, tab10, Okabe-Ito

Three rules that prevent most problems:

ColorBrewer is the standard tool for picking map palettes, with colour-blind-safe and print-safe filters.

Classification: the choice that changes the story

A choropleth (areas coloured by a value) has to turn numbers into colours. You can use a continuous scale, or group the values into classes. The way you group them can make the same data tell opposite stories. To show it, here is a 500 m grid over Eindhoven with the number of cafés in each square.

count 416.00000 mean 0.21875 50% 0.00000 max 18.00000 Name: cafes, dtype: float64

Most squares have no café; a few in the centre have many. That kind of skewed distribution is normal for anything urban, and it is exactly where the classification choice matters.

<Figure size 1300x480 with 3 Axes>

There is no neutral choice. Pick the one that answers your question honestly, use round numbers for the class edges when you can (scheme="user_defined", classification_kwds={"bins": [1, 2, 5, 10, 20]}), and always show the legend. In R, the classInt package and tmap offer the same schemes (style = "jenks").

Text on the map

A map image travels without its caption, so the essentials go on the image:

ElementNeeded?Notes
Titlealwaysthe statement or question, not the dataset name
Subtitleusuallywhat exactly is shown, where, and when
Legendwhenever colour or size means a valuewith units; remove it if a direct label works better
Credit linealwaysdata sources with licence, your name, the CRS. “© OpenStreetMap contributors” is required for OSM data
Scale barwhen distance mattersnot needed for a city everyone knows, useful for anywhere else
North arrowrarelyonly if north is not up
Labelsa fewname the two or three places that matter, not all of them

Matplotlib has no built-in scale bar, but drawing one is a few lines when the map is in metres. Here is the grid map again, finished: a stated title, round class edges written as plain ranges, one label, a scale bar and a credit line.

<Figure size 700x700 with 1 Axes>

Typography and layout

In matplotlib, plt.rcParams["font.family"] = "DejaVu Sans" (or any installed font) sets it once for the whole script. In ggplot2, theme_void(base_family = "Helvetica").

Before you post

Run through this list. It catches nearly everything a reviewer, a supervisor or a stranger on the internet will point out.