Little Design Details in a Simple Map

I wanted to title this post: You Won’t Believe This Cartographer’s 4 Weird Tricks for a Nicer Map. That seemed like a bit much (plus the length of this post got away from me so it’s now more Longreads than Upworthy), but the sentiment isn’t entirely untrue. Design (big-D Design—I would’ve capitalized it even if it didn’t start the sentence) is an intimidating and amorphous topic. Academic cartography provides good guidelines for thematic cartography, but interactivity and user-interface design are often “I know it when I see it” type of things. What follows are 4 quick design concepts and techniques that can be applied in many situations to improve the look and feel of an interactive map.

These concepts were taken from a map we made for the Eshhad project tracking sectarian violence in Egypt. It’s a relatively straightforward map with:

  1. A point dataset with a handful of attributes of various types (date, categories, short / long text, URLs)
  2. A Leaflet implementation with basemap tiles
  3. A responsive design for mobile

These are 3 very common circumstances for an interactive map, which should make these tips transferrable to a wide variety of projects.

Use color sparingly

This is a concept that I first encountered with Edward Tufte, but I think has been best put into practice time and time again by NYT Graphics. This map is hugely effective in its judicious use of color because:

  1. Elements with color draw more attention than elements without.
  2. The most important things on the map should attract most of the reader’s attention.
  3. Therefore, the most important things on the map should have color, while less important elements should not.

What’s the most important thing on the map? It’s the thing that the map is about. For this map, it was the point dataset of sectarian attacks.

Colored points on a subtle map

While the UI elements are certainly necessary for using the map, their importance is communicated through their size and position. The Positron basemap from CartoDB), though necessary to provide geographic context for these points, fades into the background and does not compete for visual attention. It’s great to have so many nice basemaps to choose from!

Color variation

Not only are the points one of the few elements on the map that are colored, they also use a categorical color scheme to display the target type. We decided to map this particular variable for the sole reason of bringing color variation to the map. In doing so, we greatly reduce visual intimidation for the users of the map as lots of 1 kind of point on the map becomes a few groups of slightly less points. Egypt’s geography, clustered around the Nile River and delta, make this even more important. The color variation allows users to more easily pick out single points for probing when they are tightly clustered together.

Color echoes

Color is also an extremely useful tool for reiterating connections between different features in the map. When color is used sparingly, you can easily communicate to the user that things that are the same color are related in some way. We’ve used a colored heading in the fixed data probe, not only to give it some visual weight, but also connect it to the point and tell the user this text here is about that point there.

Color in the fixed data probe

Also—and there’s more on this below—because the fixed data probe is so heavy with text and categorical attributes, we’ve used a subtle color variation to break up the text box from the other attributes in the fixed probe. This is partly to highlight the longer text, but mostly to create visual differentiation to the probe and reduce the text intimidation.

Data probes

Data probes provide information to the user on-demand. For a more in depth look at their design, this post by Ben is still fantastic (though the examples are showing their age). This map uses a 2-stage data probe technique that we’ve been using more and more in out maps that have a similar level of attribute detail.

Floating probe

The floating probe appears over the map. It is visually connected to the corresponding point through its position and a small change in state (larger, highlighted) for the selected point. It appears on an investigative action (mouseover) and shows just a few details, enough for the reader to decide if they’d like to get information about the point. We often include a call-to-action here (click to read more), but given the simplified nature of the map, didn’t feel like us was necessary.

Floating data probe

Fixed probe

The fixed probe appears on the left side of the screen. Its large height allows it to contain scrolling text, which removes the limits on the length of content it can contain. It’s activated through a deliberate action (click) and the corresponding point increases in size again, changes state, and remains persistently active.

Fixed data probe

To avoid text intimidation (in addition to the small color variation), we’ve used headings and changes in font to break the text up into smaller visual chunks and organize it for easier reading.

Mobile probing

For the mobile version of the map, we had to make a few simple changes to the probe:

  1. The floating data probe is removed. More accurately, it’s still there, but you can’t activate it because you can’t hover on a touchscreen. Fortunately, the data is replicated entirely on the fixed probe.
  2. The fixed probe now covers nearly all of the map. It’s not fully modal because we wanted to keep the reader still somewhat connected to the map while they were viewing the details on the probe.

Mobile data probe        Mobile data probe

One more data probe

One more thing on data probes! It’s not just the thematic features on the map that should be probe-able. Any time you use a visual variable to encode data, a data probe can quickly answer the first question about the graphic: How much is that exactly? We’ve added a small little probe to the histogram to quickly clarify both the quantity and the bin (time period) for the selected bar.

Chart data probe

Integrated legends

Not every map needs a legend. This map doesn’t need a persistent legend because:

  1. The categorical color scheme was done for its own sake, to create color variation amongst the points
  2. All of the attribute data (including the categories used to color the map) is available in the data probe

However, this doesn’t mean we should throw the legend out entirely, just be clever about how much space we give it. For this map, we present the legend to the user when they first load the map. After that, it is available integrated into the filter menu for the attribute that we’re mapping.

Integrated legend

By integrating it into an existing control, not only do we save valuable map / UI space, we reinforce the connection between the controls and the map.

Non-map controls

The final thing I wanted to point out is the prev / next buttons at the top of the data probe. These buttons are used to move between points in the map. Clicking this button will activate the next / prev point in time, mirroring a click event that populates the fixed data probe and changes the point to the active marker.

We like including these alternative browsing methods in our maps because—as much as we hate to admit it—not everyone wants to access this information using a map. Some users are interested in a narrative that is entirely non-spatial (and since our data has a temporal element, that’s even more likely). Furthermore, not everyone is comfortable with the basic mechanics of interactive maps (panning / zooming / probing), and we want to make sure the content is still accessible to them.

Eshhad Map - TIMEP
Mapping religious conflict

SVG Effects in Leaflet

We recently finished work on a live election map as part of The Tahrir Institue for Middle Eastern Policy’s parliamentary election coverage. Egypt’s complex (and ever-changing) election laws made this an interesting and challenging project, one that required novel mapping techniques to represent the data.


The overview map uses value-by-alpha to display the results. Each district is colored according to the party that won the most seats. Transparency is controlled by the number of seats won in that district (not the number of seats available). Because Egypt uses a proportional system representation for each district, a party wins seats in proportion to how much of the vote they won. This leads to lots of ties, especially in the individual results list where the districts are very small with only 2 - 4 seats up for grabs, and many candidates running unaffiliated with any political party.


Our original solution to this issue was to treat ties as no data. This ended up not working because:

  1. It failed at giving an overall impression of the geographic distribution of the election results by party
  2. There were lots of ties

This was aside from the other challenges of no data on this map, including:

  1. Unaffiliated candidates could also be considered no data because they don’t have a party, but make up a huge section of the candidates running
  2. The Al Nour party is associated with the color black. With the varying transparency of a value-by-alpha map, this reserved every shade of gray (usually used for no data) for this party’s results
  3. Because this was a live map, with updating election results, the real no data was results that hadn’t been released yet

We settled on using a striped pattern to display both parties’ colors when the results are a tie. Fortunately—and as often is the case—there was a fantastic Leaflet plugin that did nearly all of the hard work for us:

//check to see if there are multiple parties stored as an array
if( _.isArray( party ) ) {
  //name the pattern after both parties
  var patternName = party.join( "-" );
  //create the pattern if it doesn't exist
  if( polygonPatterns[ patternName ] === undefined ){
    polygonPatterns[ patternName ] = new L.StripePattern({
      //2 stripes defined as color + space
      color: parties[ party[ 0 ] ].color,
      spaceColor: parties[ party[ 1 ] ].color,
      spaceOpacity: 1,
      angle: -45
    //patterns must be added to the map before use
    polygonPatterns[ patternName ].addTo( map );
  //create a new style object using the pattern
  style = {
    fillPattern: polygonPatterns[ patternName ],
    color: "#ccc",
    //number of seats won controls fill opacity
    fillOpacity: alphaScale( seats, maxSeats ),
    weight: 1
//apply the style
layer.setStyle( style );


The most challenging part of the brief for this map was in dealing with displaying the changes to the electoral system between the 2011 and 2015 elections. Outside of changes to the law, the most visible change was to the electoral districts themselves, and this was something we needed to show on an already visually complicated map.


To display the former boundaries, we decided to use a shadowy / gradienty type line style. We wanted something that was heavy enough to be visible on top of the complex polygon fills, but transparent and fuzzy enough to suggest that it is no longer present on the map. To achieve this style, we used a simple SVG filter.

To start, create the filter as a standalone SVG in the HTML file that contains your map:

<!-- Be sure to set the width / height to 0 -->
<svg xmlns="" version="1.1" style="width:0;height:0">
    <!-- Reference this filter in the code using the id -->
    <filter id='dropshadow'>
      <feGaussianBlur in='SourceAlpha' stdDeviation='4' />

Apply the filter to each _container in the layer group. You may need to include a nested group to get to all levels:

formerGroup.eachLayer( function( l ){
  //if the layer is a LayerGroup, loop through and apply filter to each _container
  if( l._layers ){
    _.each( l._layers, function( m ){
      $( m._container ).css({ filter: "url(#dropshadow)" });
    $( l._container ).css({ filter: "url(#dropshadow)" })

American Election maps are so ubiquitous and it was nice to have a change to embrace the challenges of a new election with new geography and new data. You can view the full map to see more of the data and design challenges and how we worked around them. The exciting thing was being able to solve these problems from a design perspective, and be completely confident we could easily implement whatever solution was deemed best.

Egyptian Parliamentary Election Map - TIMEP
Live parliamentary election map

Zooming In On History

Last weekend saw the close of a six-month exhibition by the Norman B. Leventhal Map Center at the Boston Public Library titled “We Are One: Mapping America’s Road from Revolution to Independence,” a piece of which we at Axis Maps had the pleasure of creating. A commemoration of the 250th anniversary of the Stamp Act, the exhibition featured an impressive collection of contemporary maps from the years prior to the American Revolution through the early years of the new nation, documenting and providing context for the events leading to American independence.

A few maps from 'We Are One' 'We Are One' exhibition

As part of the exhibit, we designed interactive features for two large touchscreen displays, which allowed visitors to explore many of the maps on display more closely. (This was handy, because one of the display cases literally yelled at you to stand back if you got too close.) The two interactive displays featured maps of different themes, georectified and overlaid on a modern map. Visitors could search for locations and see them in the context of the historic maps, and also browse a curated set of map details.

Touchscreen at 'We Are One' exhibition

If you didn’t have the great fortune of being in Boston during the past six months, don’t worry! Though the touchscreens are gone, the interactive map browser is on the web—and will work nicely on your phone if you still want to touch it: (The exhibition itself will be at Colonial Williamsburg in 2016 and at the New York Historical Society after that.)

Zooming In On History

This was a fun project to work on, not least because as the lucky local Axis Mapper, I got to pay a few visits with behind-the-scenes looks at the exhibition and other collections of the Leventhal Map Center, as well as attend a fancy opening reception.

More than that, it was an interesting opportunity to make something for a public space where all sorts of different people would see it. This meant some different design choices from our typical web maps. For example, we used a lot of animation with Animate.css. Almost everything touchable triggers an animated transition. Even when it’s idle, maps still move. The idea was to catch people’s eyes as they walk past, and draw them in to explore.

We found that there are special challenges to this kind of work. Put an interactive map in a room with a bunch of tourists for a few months, and you will learn all kinds of new ways in which your map can break. We recommend testing your map by placing a bored yet excitable 4-year-old in front of it.

The touchscreen feature ran simply as a web page in full screen mode. We thought of some precautions to prevent this from breaking—for example, when the screen keyboard appeared, we needed to remove or disable some keys so that someone couldn’t press Control-W and kill the whole thing—but didn’t fully anticipate the effects of impatient fingers banging on everything in sight, or what would happen when a lot of CSS transitions run for hours on end. So it broke occasionally, and I’d get nerve-wracking video messages from my friends.

While we easily fixed bugs, implementing a fix was tricky for the exhibition staff. In the exhibition, the interactives ran on local machines, not the web, to ensure connectivity. And in a public space, they couldn’t exactly have the computers sitting where visitors could reach them. So to date, this is probably our only project where deploying and update required a ladder.

Go explore, see some cool maps, and learn something about American history—no ladder required!

Zooming In On History - BPL
Interactive touchscreen feature for a map exhibition

Quick tip about Javascript architecture

Most of the work we do here at Axis involves coding Javascript interactive maps. Frequently, the map will have elements controlled by UI components and/or charts and/or timelines. Calling each of the map functions after a UI component gets interacted with (or chart/timeline/etc…), can get exponentially convoluted if you aren’t careful.

If you are fairly new to coding you may not be familiar that code can have design patterns. Just like there are cartographic principles that help with everything from layout to typography to color, there are coding principles that help with code clarity, maintainability, and efficiency.

A good book to refer to on code design patterns for Javascript is Learn JavaScript Design Patterns by Addy Osmani. The particular pattern I found recently useful is Publish/Subscribe (nested under the Observer pattern in the above book). There are a couple of ways to implement it, but since we use jQuery in most everything anyways, I’ll talk about jQuery’s implementation.

jQuery has the ability to register and listen for custom events. How this works in practice is fairly easy. First you need to sort out what events are actually going to happen. These aren’t events like ‘click’, but custom events like ‘yearchange’ or ‘dataupdated’ or ‘mapmove’. Once you have that set, whenever you create a component that is going to be affected by one of these custom events, you register it on the document.

function createMap() {
  //Create map code
  $(document).on('yearchange:', function(newyear) {
    //update map with new year information

Then on any and all UI elements that affect the year (menus, animation controls, etc…), all you need to do is call $(document).trigger('yearchange:', newyear). The great thing about this is that you can attach listeners on multiple different components (e.g. maybe the timeline and the chart and the map all get updated with a yearchange) and the UI element doesn’t need to know a thing about any of them.

Couple of notes:

  • There is a colon after the word yearchange. That is completely optional, but is a way to future-proof your custom event in the off chance that jQuery (or a jQuery plugin) decides to use the same event name. You could also achieve this by using slashes and creating a nesting effect (e.g. /yearchange, /yearchange/increase, /yearchange/decrease, etc…) which might be helpful to group events if you have a lot of them.
  • Why register on the document element? Because of the way Javascript handles bubbling through the DOM, you can always be sure that if the listener is on document, it’s going to be heard; plus it keeps separation of concerns (another code design thing). If you put the listener on the map object for example, then the UI element needs to know where the listener is (breaking the entire reason for this system which was that the UI didn’t need to know anything).

That’s it. If you have a several different components being updated or changed by several other components, consider the Pub/Sub pattern and if you are using jQuery already in your project, consider using custom events.

D3 web maps for static cartography production

We’re a mapping company that’s most at home on the web. So when a more traditional static cartography job came along, we even took that to the web.

The ongoing project involves producing a set of four maps for each of thirty-three different countries, showing GDP along with flood and earthquake risk. To make 132 maps, clearly we need to set up a good, easily-repeatable workflow. Because the map themes and symbologies are the same for each country, essentially we need a set of templates into which we can throw some data and get an appropriately styled map that we can export for refinement in Illustrator, and finally layout in InDesign.

Ordinarily that’s where GIS software like QGIS or ArcGIS comes in. But using GIS can be a slow, repetitive task. In the interest of creating a faster process suited to our purpose specifically, we thought it would be easier to develop our own web-based tool to handle the parts of the workflow normally handled by GIS. Fortunately, it’s easy to do such a thing with D3.

Here’s a shot of the tool. It looks rough, certainly, but it does its job: quickly get a country map as close as possible to final form, ready to be dropped into our Illustrator and InDesign templates.

D3 tool for static maps

In contrast to GIS, there are only a couple of moving parts here. All we have to do is select a country, adjust the map position and scale, and choose the map theme. Everything else is automated. For me, someone who usually accomplishes cartography via web development, it was a lot easier and faster to build this simple customized tool than to figure out how to get GIS to do exactly what we want. It’s also easy to keep up with any change requests, which usually only mean a few lines of code.

Below is a bit more about how this thing works, which leads to some tips we’ve learned about using a D3 web map in a static cartography workflow.


Data here are in two forms: topojson for the map layers (boundaries, cities, lakes, etc.) and CSV for the numeric data. All are loaded at runtime, where the CSV is joined to Admin 1 (province-level) geodata. We avoided pre-joining the CSV to the shape data because that would make updates more complicated, i.e., saving a new topojson file for any little data change.

Page setup

It’s important to get sizes and positioning exactly right so that the exported map drops perfectly into our templates without the need for any transformations. Our maps are A4 size and we’re working in millimeters, but of course in the browser we need pixel dimensions. It works out to be 841.89 x 595.28 pixels. Illustrator converts measurements at 72 pixels per inch, which is a lower resolution than modern screens, and thus the map appears suspiciously small in the browser—but don’t worry, it all turns out right in the end!

It’s also important to note the lat/lon bounds of the map in case outside geodata needs to match. In this case we generate a hillshade separately using GDAL. The extent values listed above the map—easily derived from D3’s projection.invert() method—plug right into the GDAL commands, producing a hillshade image that will fit perfectly on this map.

Map layout

D3 really shines with projecting and drawing geographic data, and this tool takes full advantage of that. It goes through the standard routine of drawing GeoJSON data to SVG paths, putting each data layer into a named <g> element that will later show up as a layer in Illustrator. We use the Mercator projection (sorry, cartographic hard-liners, it was by request) and use D3’s geo centroid() and bounds() functions to center the map on the country of interest and scale it approximately to fit. After that we can manually adjust position or scale to get the layout just right, fitting the country into some guides we added on top of the map.

Importantly, in addition to the standard map-drawing code, we use the projection’s clipExtent() method to clip everything to the page extent. Otherwise, when imported to Illustrator, we’d have a whole world’s worth of extraneous paths outside the artboard. While setting the clipExtent is enough to chop off polygons and anything drawn directly with the path generator, hiding labels takes a little extra effort. We have to check manually whether they’re outside the clip extent and hide them if so.

  .each( function(d){
    var c = path.centroid(d);
    if ( !isNaN(c[0]) && !isNaN(c[1]) ){
          x: c[0],
          y: c[1],
          opacity: 1
    } else {

Thematic symbols

D3’s scale functions really come in handy for these maps’ thematic layers. For the most part, we can create scales that have a constant range (such as the purple color scheme or the proportional symbol size) and set the domain to according to a particular country’s data if needed. GDP data (the choropleth map) is classified using the Jenks algorithm in Simple Statistics.

For the most part we leave legends to the Illustrator end of things. Values of the choropleth class breaks are simply listed in the containing HTML page, and then entered into the template in Illustrator. We do draw a simple proportional symbol legend because while the maximum size is constant, the size of good sample values (such as 1 or 5) changes from map to map. Flood and earthquake maps use bar chart symbols that, like the choropleth map, simply get some explanation in text.

Flood symbols

Mapping via code provides a big advantage if you’re looking for complex symbols. D3 in particular makes it easy to draw symbols tied to data—with almost total freedom of form.


Luckily, there’s not a lot to explain here. SVG Crowbar, created by New York Times Graphics people specifically with D3 in mind, does a great job of exporting the SVG map to a layered file ready to use with Illustrator. We just have to make sure our various map layers are properly grouped and have id attributes, and we end up with a nice and neat file.

Map layers

A command line

Finally, a nice thing about doing the basic map work in the browser is that it’s easy for a web developer to do advanced things by entering code right in the console, without having to be familiar with more specialized code that might be used in GIS or other tools. We didn’t do much of that here, other than as a shortcut to set zoom levels, but theoretically we could invoke, change, or extend any other functions of the page to do things that might be needed in unique cases.

Adjusting the map in the console

Coder-friendly mapping

In closing, it merits noting that this kind of workflow might be good for us (and people like us) because JavaScript is much of what we do on a day-to-day basis. Everything that I’ve said is “easy” with D3 is, well, very difficult if you’re unfamiliar with this kind of coding. A good philosophy and habit is to use the right tool for the job, but it’s also wise, for expediency’s sake, not to dismiss just using the tool that you know. Sometimes the right tool is the easy tool.