Here’s a typical example of what the horizon might look like across an intersection or parking lot as you walk around Boulder, Colorado:

bearpeakgreenmountain

The picture above shows Bear Peak, the Flatirons, and Green Mountain, which are all part of the Front Range. Depending on where you are in town, it’s also possible to see through valleys back to the Indian Peaks, which are considerably higher and further west. There are also some interesting and distinctive hills in the plains north of Boulder. I got tired of not knowing the names of mountains and hills that I see all the time when walking around town, so I made a map.

After shopping around for existing printed maps, I decided that none of my available options showed the data I wanted at an appropriate scale. What I really needed was a specialized topo map which had four main layers:

  1. Sparse elevation contours with enough detail to pick up hills in the plains, but not so much as to turn into mushy hill-shading up in the Indian Peaks.

  2. State and Interstate highways to provide a sparse summary of the city of Boulder’s road network.

  3. A significantly filtered subset of the POI data from the United States Board on Geographic Names’ Geographic Names Information System (GNIS) for the state of Colorado.

  4. A graticule with longitude lines spaced no more than about an inch or two apart so that they can be used with the alignment marks on the dial of a compass like this:

compasstapemeasure

What it looks like

Here’s a closeup:

closeup

Here’s what the first version looked like:

bouldermap

And here’s the full-sized 270dpi 8.5”x11” image.

How I did it

To make this map I used TileMill with public domain data from the USGS and Natural Earth.

My TileMill layers look like this: layers

  • #markers: This CSV layer adds a POI marker for the office of some friends in Boulder.
  • #boulderGNIS01: This is the filtered-down list of GNIS POI’s for Colorado. My Python script to do the filtering and the resulting .csv output are at wsnook/hiking-toys/gnis.
  • #graticule: This is a 0.05° GeoJSON graticule with named latitude and longitude lines. My Python script to create it, and the resulting JSON, are at wsnook/hiking-toys/graticule.
  • #majorRoads: This is Mapbox’s hosted copy of Natural Earth North American roads: /natural-earth-1.4.0/cultural/10m-roads-north-america.zip.
  • #contour2.contour and #contour1.contour: USGS 1°x1° contour shapefiles that I downloaded from The National Map Viewer: Elev_321499_Greeley_W_1X1 and Elev_321379_Denver_W_1X1. Those files include a mix of 40ft and 10ft contours, but what I really needed was 80ft contours, so I used a gigantic brute-force CartoCSS selector to enumerate each and every contour elevation that I wanted to include in the map (i.e. [CONTOURELE=4680],...,[CONTOURELE=15000] {...}). My approach was kind of quick and dirty, but it was effective and less trouble than the equivalent GDAL work to create my own contour shapefiles from the USGS 1°x1° NED image files.
  • #countries: The Mapbox default Natural Earth countries layer. The borders aren’t necessary, but I left it alone since #fff was a good background color.

You can also download my stylesheet for the 8.5”x11” US Letter-sized version of the map.

Preparing to print, round one

By way of some experimentation, I decided that I wanted to start off by exporting a 2250x1683 image at zoom 13 for a -105.7032,39.9082,-105.0983,40.2544 bounding box to produce approximately 270dpi output when scaled to fit an 8.5”x11” sheet of US Letter paper. I arrived at the somewhat unusual resolution of 270dpi by trial and error as I attempted to find a combination of font sizes, line widths, zoom level, bounding box, and export resolution which looked good on paper. Because TileMill doesn’t automatically scale sizes and line widths as export resolution is adjusted, finding the right combination of sizes and widths was a challenging process.

For font sizes, I just experimented until it looked good when I printed a draft. Similarly for the 0.05° graticule divisions, I just guessed until it came out right. In this case, “right” means the line spacing in the printed output is narrow enough (one to two inches) to allow using a compass as a protractor to project angles relative to any point of interest on the map. It’s worth noting that increasing the map’s printed size can require finer graticule divisions to maintain a good spacing to match the fixed real-world size of the compass dial.

Preparing to print, round two

Once I got the small map working and showed it around a bit, it seemed like the thing to do was make a bigger one. A 20”x30” poster seemed about right, so my next step was to create a 18”x28” map image for printing on a large format printer with a 1” margin. Scaling the map up turned out to be another challenge. I ended up needing to use a bounding box with a different aspect ratio (1:1.5 instead of 1:1.29), a different zoom level (14 instead of 13), a different DPI (600 instead of 300), and differently scaled font sizes, marker sizes, and line widths.

To improve my ability to iterate changes to the style, I wrote a Python script to generate CartoCSS. That let me create the final version of the style for 20”x30” and a 600dpi image of the big map. Because of how TileMill handles the auto-scaling math for latitude/longitude bounding boxes and export sizes in pixels, I ended up exporting -105.746,39.8975,-105.024,40.2525 at a size of 16807x10800, then cropping that image to a final size of 16800x10800 using OS X’s Preview app.

Currently we’re looking at proofs to get a big map printed for some friends in Boulder.

bigmapproof