Skip to content
Switch branches/tags


Failed to load latest commit information.
Latest commit message
Commit time

Topographic Maps of Planets and Moons

License: GPL v3 Twitter Follow GitHub Follow

This repository explains how to make topographic maps of planets and moons using open-source data from the USGS, IAU, and NASA. Software used includes Python 3.7.1, GDAL 2.4.1, Illustrator CC 2019 and Photoshop CC 2019. If you have comments or suggestions for this tutorial, please let me know on my blog! You can also buy these topographic maps for Mars, Venus, Mercury, and the Moon.

Python dependencies: matplotlib numpy pandas os cartopy json osgeo math scipy jupyter. Dependencies can be installed with pip install -r requirements.txt.

Snapshot of final product

Special instructions for beginners

If you're new to coding:

Software Carpentry has great tutorials for installing Python (scroll down and follow the directions in the Bash Shell and Python sections), getting starting with Jupyter Notebooks, and beginner-friendly Python programming. After you've installed Python using these tutorials, you can use Git Desktop and the instructions in this tutorial to download the code and data in this tutorial. For the code in this repository you will also need to install GDAL. The installation instructions in the Conda section are probably the most relevant if you've installed Python as described above.

If you're new to design:

You'll need software for editing raster and vector images (this article explains the difference). I use Adobe Photoshop and Illustrator, but you can also use the free open-source programs Gimp and Inkscape. There is no perfect software that fits everyone's needs, so you'll want to understand the pros and cons for the different raster and vector programs before choosing.

Table of Contents

  1. Gathering and processing data
  2. Map design in Python
  3. Map design in Illustrator and Photoshop
  4. References
  5. License

Gathering and processing data

Data layers used to design this map

Digital Elevation Models

Digital Elevation Models (DEMs) are data files that provide height information. For this project I'm using the United States Geologic Survey's DEMs for Mars, Mercury, Venus, and the Earth's Moon. Each pixel in these GeoTIFF files describes the elevation at that specific location on the planet. GeoTIFF files also have embedded geographic data that allows tools like GDAL to correctly position the elevation data onto a globe.

To run the code in this tutorial, you will need to download one of the DEM files linked above. Note: Many software programs can't read this kind of file, so it's normal if the downloaded DEM looks strange in Preview or other default image applications.

DEM files for Mercury, Mars, Venus, and the Moon

Map Projections

A Quick Introduction: Before we get into the details of map projection transformations, here's a quick overview of what this actually means. To map a 3D object in 2D space, the surface must be transformed using a map projection. There are many different projections, and for the maps in the Atlas of Space series I used Eckert IV, Orthographic, and Plate Carrée projections. To visually compare these different map projections, you can use a Tissot's indicatrix - a set of circles of the same size plotted at different places on the globe. All map projections distort space, but you can see that the effects are quite different depending on the projection:

Tissots indicatrices and map projections

The choice of projection depends on the purpose of the map. For example, Eckert IV preserves area measurements, so I used Eckert IV in geologic maps to show how much area on the planet was made up of each geological formation. I used an Orthographic projection for these topographic maps to visualize what planets look like from outer space. And finally I used a Plate Carrée projection for constellation charts, because the perpendicular gridlines make it easy to read coordinates (which are essential for finding stars that rise and set throughout the night).

Changing the Map Projection of a DEM File: In this project I wanted to use an orthographic projection to show each hemisphere of the planet (North, South, East and West). However, the original DEM data file uses a Plate Carrée projection. To create a new orthographic map, I used the command line installation of GDAL - short for Geospatial Data Abstraction Library.

The code below, typed into a bash shell, uses the original intif file to create a new file outtif centered at a latitude of 90 degrees and longitude of 0 degrees in the ortho (orthographic) projection.

gdalwarp -t_srs "+proj=ortho +lat_0=90 +lon_0=0" ./path_to_intif.tif ./path_to_outtif.tif

Transformed orthographic DEM files

Next I downsample the DEM by decreasing the resolution of each pixel to 1500x1500 meters using the average method. It's useful to decrease file size to lower computation times, and it's much faster to downsample at this point than to scale images later on in the process.

gdalwarp -tr 1500 1500 -r average ./path_to_intif.tif ./path_to_outtif.tif

Hillshade and Slope

Next, I used the downsampled DEM to generate hillshade and slope maps for each hemisphere of the planet.

Hillshade maps show the shadows cast by a hypothetical light source suspended above the map. It’s hypothetical because in the real world, a single light source would cast different shadow angles at different places on a globe. The GDAL hillshade calculation sets the light source angle to be the same everywhere. In this hillshade I set z, or the vertical exaggeration, to 20. This multiplies the real elevation values by 20 to increase visual contrast and help the hillshade show up under all of the other map elements.

gdaldem hillshade -z 20 ./path_to_intif.tif ./path_to_hillshade.tif

Global hillshade

Slope maps emphasize the steep parts of a map, and adds more information to the topographic hillshade (which emphasizes absolute height rather than steepness).

gdaldem slope ./path_to_intif.tif ./path_to_slope.tif

Global slope

Automating Repetitive Tasks in Bash

Although these GDAL commands are fairly straightforward, some of them take a long time to run on my computer. I wanted to write a single script that would make all of my orthographic maps without having to sit and wait for each command to finish running.

The bash file generates all four orthographic plots for Mars, Mercury, Venus, and the Moon, and then downsamples the data and creates hillshades and slopes for each projection. This bash script is a little more complex because you can specify the central longitude for the central map (for the Moon I decided to make maps of the near side and far side instead of the Eastern and Western hemispheres). I run bash scripts directly through my bash shell:

bash ./path_to/

Additional notes about GDAL

It's worth noting that hillshades and slopes can also be generated in Python using the osgeo library. I haven't included this code because I'm less familiar with osgeo, but this tutorial may be helpful if you prefer pure Python. You can also customize hillshade and slope in many ways not mentioned here, as well as make other kinds of generated maps by looking through the list of available GDAL commands.

Planetary Nomenclature

The International Astronomical Union is responsible for naming features of extraterrestrial objects. You can download a CSV file of all features from each planet from the IAU website (though the data for this project is already included in the ./data/planetary_features folder).

To download nomenclature data, use the Advanced Search Function and select All Feature Types from your Target of only an Approval Status of Adopted by IAU. In the Columns to Include section, select Feature ID, Feature Name, Clean Feature Name, Target, Diameter, Center Lat/Lon, Feature Type, and Feature Type Code. You can also include Origin if you'd like additional information about each feature, such as who it is named after. The Output Format should be CSV.

Map design in Python

Next, I made five Python plots with the contour fills, contour lines, text labels, and two types of gridlines. I often split up data for plotting so I can easily apply section-specific effects in Photoshop or Illustrator. The plotting code for all of these maps are shared in 2_plot_maps.ipynb.

For this project I wanted all of my maps to fit nicely inside the decorative border I designed in Photoshop. To do this in Python, I use matplotlib gridspec to set up my figures so that each of my subplots occupy the exact pixel locations inside my decorative border.

Different pieces of Matplotlib plotting

Smoothing and Filling in Data

There are two steps in this map where I smoothed or cleaned the original data. First, I needed to display the data at different scales for the smaller inset maps in the corners of the design. This is similar to what we see in apps like Google Maps: as you zoom out, the map removes smaller features like streets and buildings. Earth maps also use several different coastline shapes at different zoom levels.

Because I only had one DEM file, I made these coarser shapes myself by applying a Gaussian filter. Smoothing map data is a legibility step that's fairly subjective. The arrow in the diagram below shows the smoothing level I picked for my own Mercury maps, but other people might pick smoother or finer detail levels.

Example of Gaussian filtering

I also filled in missing pixels in the original data using the information in the surrounding pixels. Again, this is a data cleaning step that other people might implement differently. The limit and limit_small parameters in the configuration file describe the maximum sized hole that can be filled in (extremely large areas of missing data are left empty).

Configuration Files for Multiple Designs

Although the code is more or less the same for every map, I wanted to use different colors and input files for each planet. I organized all of these parameters inside the config.json configuration file. Configuration files are helpful because it's very easy to add or remove new planets - I could easily make a topographic map of Earth or Pluto by adding a new entry. The parameters include topographic levels, color, input files, and the amount of smoothing to apply to each map:

    "cmap": ["#e6dfcf", "#ef9f30", "#638b71", "#24293c"],
    "levels": [-10000, 10000, 1000],
    "levels_small": [-20000, 20000, 5000],
    "file_large": "A:/ATLAS_OF_SPACE/image_outputs/ortho_DEMs/moon_lat30_lon0_downsampled.tif",
    "file_small": [ "A:/ATLAS_OF_SPACE/image_outputs/ortho_DEMs/moon_lat90_lon0_downsampled.tif",
    "save_head": "A:/ATLAS_OF_SPACE/image_outputs/topography/",
    "labelfile": "./data/planetary_features/moon.csv",
    "limit": 10,
    "limit_small": 10,
    "gauss": 10,
    "gauss_small": 30,
    "ortho": [0, 30]

Planet Core Diagrams

For each planet I also wanted to make a cutaway diagram showing the interior layers. But when I started to plot this data, I ran into an issue where you couldn't actually see some of the layers because they were so thin. To solve this problem, I decided to use an adjusted visualization where every layer has a minimum visible thickness (I also added a disclaimer in the key that the figures were not to scale). This code is shared in 3_plot_cores.ipynb.

In the diagram below, the left half shows the actual thickness of each layer, and the right half shows the adjusted version. For Mercury and the Moon there's actually no difference, but the effect is much stronger for the other planets with a very thin crust or atmosphere.

Diagram of planet core layers

Each of the planet core diagrams also has a blurred image of the surface on the outside of the sphere. To make these I used the open-source stock images from Stellarium, which I transformed from a Plate Carrée to an Orthographic projection in 3_plot_cores.ipynb. I also intentionally blurred these images in Photoshop, because a more detailed surface illustration would take the focus away from the cutaway core diagram layers.

Diagram of Stellarium core images

Saving Matplotlib figures

I usually save figures as a PDF so I can edit the text and shapes in Illustrator. There are a couple standard commands I use to export Matplotlib figures so they're easy to edit:

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.backends.backend_pdf as pdf

# Export text as editable text instead of shapes:
matplotlib.rcParams['pdf.fonttype'] = 42

# Preserve the vertical order of embedded images:
matplotlib.rcParams['image.composite_image'] = False

# Remove borders and ticks from subplots:

# Remove padding and margins from the figure and all its subplots
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)

# Save the Matplotlib figure as a PDF file:
pp = pdf.PdfPages('./savename.pdf', keep_empty=False)

# If I don't need to edit vector paths I save the file as a
# PNG so I can import it directly into Photoshop:
plt.savefig('./savename.png', format='png', dpi=600, pad_inches=0, transparent=True)

After saving the figure, the PDF file needs to be edited so that each object can be manipulated individually. In Illustrator, select everything in the file and then go to Object --> Clipping Mask --> Release. At this point you can also delete the background and axis border objects, if you included them in the output file.

Map design in Illustrator and Photoshop

I export Python figures to Illustrator and Photoshop because several great design features are impossible or very time-consuming in Matplotlib. I'm linking tutorials here for the features I use most often - font alternates and ligatures, custom brushes, layering effects, blur effects, gradients along a path, variable width paths, type on a path, and selecting objects by characteristic.

Features not easily available in Python

Layering in Photoshop

I've included a small section of the map in the figures folder as the Photoshop file topography_sample.psd. The file is small enough to upload online, but since it still has the original layers you should be able to use it as a reference for layering effects.

Layers of the map Photoshop file

Text Annotation in Illustrator

I decided to annotate this map using text labels that followed the spherical contour lines of the planet. First I used Python to plot a series of latitude lines up and down the globe. I also made a Python output file that placed each text annotation next to a scatterpoint at the center of the feature. Finally I opened these files in Illustrator and manually combined each label with a nearby latitude line:

  1. Use the Type on a Path tool to copy and paste the text for each object onto an appropriate latitude vector.
  2. Use Character -> Set the baseline shift to center the text vertically to the desired location.

Text annotation in Illustrator

Shadows Underneath Text Labels in Photoshop

To create a shadow effect around the text labels, first save the text as a transparent PNG file and import it into Photoshop. Duplicate this annotation layer and go to Filter --> Blur Gallery --> Field Blur. For shadow text I usually create two blur layers set to 20% opacity - one with a Blur of 4px and the other 10px.

Color and Font

I wanted the maps in this series to look cohesive, so I made a palette of ~70 different colors and picked from these choices in every map. I also used the same two fonts (Redflowers and Moon) in all maps. You're welcome to use the color palette and font styling if you'd like.

Color palette used in all maps

Fonts used in all maps

Designing a color scheme

To develop this set of colors, I started the project by designing 14 different color schemes. My initial idea was to have a unique color palette for every planet, but in the end I used the same collection of colors throughout all of the projects to make the maps look more cohesive.

The initial color palettes designed for this project

Each color palette is shown in several different ways, because I wanted to design versatile color schemes that could work as discrete elements, or as pieces of a complex pattern, or as a gradient in topographic maps. I updated these three visualizations while designing to make sure each color scheme would work for each application.

Decorative illustrations in Photoshop

For this project I wanted to combine large datasets with the hand-crafted design style of artists like William Morris or Alphonse Mucha. To organize my thoughts I collected a big folder of inspiration images from sources like the New York Public Library Digital Database:

Inspiration images

When I started this project I initially wanted to design different border decorations for every topic. I sketched a collection of 18 different repeated patterns, each meant to go alongside a unique astronomy theme like planets, galaxies, space missions, or satellites.

Pencil sketches of border illustrations

But as the project continued I realized there was so much data that the detailed borders made the maps look too cluttered. In the end I removed all of the borders and designed just one scrollwork illustration to wrap around rounded map projections. In these round maps I thought the shift from detailed map to blank paper was a bit too abrupt, so this was a good compromise between data-heavy and illustrative design styles.

Scrollwork design process

For this scrollwork design I started with a pencil sketch, and tried a couple different iterations of leafy scrolls before finally picking a less botanically inspired design. When I paint decorations like these in Photoshop, I begin each design as a solid white shape and then gradually break away pieces into detailed chunks. Next, I brush away pieces of each section with the brush eraser tool until the pieces look like a fully-shaded monochrome design. I wait to add color until the very last step, where I use many different colors and overlay layers for a richer effect.

I've included two different examples of these painted Photoshop illustrations in the figures folder as scrollwork_sample.psd and decorations_sample.psd. These files still have the original layers, so you should be able to use it as a reference for layering, painting, and color effects.

Layers of the scrollwork Photoshop file

Layers of the decoration Photoshop file



Code: All of the code in this repository is shared under the GPL-3.0 license.

Data: The data in this repository belongs to the original authors of the data. Please use the references section to look up the original version. In cases where I edited or revised the data, I impose no additional restrictions to the original license. Any data files I created myself are shared under the ODC Open Database License.

Artwork: The artwork included in this repository are shared under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.


Code and instructions for making topographic maps of planets and moons





No releases published


No packages published