Open-source project
GenericMappingTools/pygmt avatar
GenericMappingTools/pygmt

PyGMT: publication-quality maps from Python, backed by GMT

A Python interface for the Generic Mapping Tools.

878 stars257 forksPythonBSD-3-Clause

At a glance

What is it?
PyGMT is a Python interface for the Generic Mapping Tools, the command line program used across the Earth, Ocean and Planetary sciences, and its job is to let you build a map as objects rather than as shell commands. It ships on PyPI and conda-forge, needs GMT underneath, and the repository carries an unusually complete contributor setup for a scientific library.
Who is it for?
Use PyGMT when you need maps that would otherwise come out of GMT command lines, because the object-oriented Figure API lets you compose a publication figure in a notebook or a script instead of assembling arguments. Do not expect it to run without GMT installed, since the library delegates the actual plotting to that program, and check the Minimum Supported Versions page before pinning dependencies.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A wrapper that keeps the GMT underneath

PyGMT is a library for processing geospatial and geophysical data and making publication-quality maps and figures, and it provides a Pythonic interface for the Generic Mapping Tools, a command line program widely used across the Earth, Ocean and Planetary sciences and beyond. The important structural point is that GMT is still the engine. PyGMT is not a reimplementation of the cartographic algorithms, it is an interface to them, which means you get the same projections, the same coastline data and the same rendering behaviour that the command line tool produces, with a Python calling convention on top. The library lists GMT itself as a dependency alongside NumPy, pandas, xarray and packaging, so the install is really two things: the Python package and the GMT binary it drives. The other official wrappers named in the README are GMT.jl for Julia and gmtmex for Matlab and Octave, so this is one member of a family around the same core.

A Figure object that holds the whole composition

The quickstart example shows the shape of the API, and it is the clearest thing in the README. You create a Figure, add a basemap with a projection and a region and a frame, add a coast layer with land and water colours, add text with a font specification including a size, a font name and a colour with transparency, and then show it.

python
import pygmt

fig = pygmt.Figure()
fig.basemap(projection="R7c", region=[0, 360, -90, 90], frame=True)
fig.coast(land="tan", water="lightblue")
fig.text(position="MC", text="PyGMT", font="40p,AvantGarde-Book,red@75")
fig.show()

The projection name R7c is a cylindrical equidistant projection, the region is given as the four-value list of longitude and latitude bounds, and the font string follows GMT's own syntax with the size in points, the font name and a colour with an alpha channel. The point of the design is that the figure is an object you mutate, so the composition reads in order and can be generated, parameterised and tested, which is not how a shell pipeline reads.

NumPy, pandas and xarray are the data path

The dependency list tells you what kinds of data PyGMT expects. The required set is NumPy, pandas, xarray and packaging. That is a geospatial data stack rather than a plotting-only stack, and it is the reason the library sits naturally in a scientific Python workflow: the arrays you load with xarray, the frames you load with pandas and the grids you compute with NumPy are what the map functions want. The optional set extends that with IPython for notebook work, GeoPandas for vector data, contextily for basemap tiles, rioxarray for reading raster files with geospatial metadata, and PyArrow for columnar data. The README points to a Minimum Supported Versions page for the detailed version requirements, which is the page to read if you are pinning an environment, since the lower bounds in the packaging metadata are already fairly recent.

The xarray backend entry point

One line in the packaging metadata is easy to overlook and it is the most interesting integration point in the project. There is an entry point registered under the group xarray.backends, mapping the name gmt to a function in the pygmt.xarray module. That means PyGMT registers itself as an xarray backend, so an xarray dataset can be opened through the GMT machinery as part of xarray's own open_dataset machinery. For anyone who already works in xarray this is the feature that removes a manual step, since data that lives in GMT's formats becomes available through the same API that handles netCDF. The library's role as a GMT interface extends beyond plotting, and this entry point is where that shows up in the packaging.

A Makefile that treats tests like software

The repository carries a Makefile whose help text is worth reading, because it documents the developer workflow in one place. There is install for an editable install, package to build the source and wheel distributions, test to run the test suite including some doctests with coverage reporting, fulltest to run all doctests, doctest for the doctests only, and test_no_images which runs the suite but skips image comparisons. Then there are format to run Ruff automatically, check to run Ruff in check mode, spellcheck using codespell and typos, typecheck using mypy, and clean and distclean targets for build artefacts and project metadata. The image comparison target is the interesting one for a mapping library, since a plotting test that compares rendered output is exactly the kind of test that either catches regressions or becomes a maintenance trap. The repository also has a pre-commit configuration and a CI directory.

Package metadata and the current version line

The packaging is modern and strict. The build requires setuptools 80 or newer and setuptools-scm 10.0.4 or newer, with the version marked as dynamic, which means the version is derived from the git history rather than typed into a file. The project requires Python 3.12 or newer, and the classifiers list support for 3.12 through 3.15. The development status is recorded as Beta, which is a fair description of a library that has been at version 0.x for years. The runtime dependencies carry lower bounds of numpy 2.2, pandas 2.3, xarray 2024.10 and packaging 24.2, all of which point at a project that requires a fairly current Python environment. The release history shows regular tagged versions, with v0.19.0 published on 2026-07-07, v0.18.0 on 2026-01-12 and v0.17.0 on 2025-10-02, and the last push to the repository was on 2026-10-22.

Contributing, citation and who pays for it

The contributing section opens with what it calls an imposter syndrome disclaimer, adapted from the MetPy project, and it makes the point that being a contributor does not just mean writing code: writing or proof-reading documentation, suggesting or implementing tests, and giving feedback about the project or about the contribution process all count, and that fresh eyes see errors that seasoned contributors have glossed over. Discussion happens on GitHub and on a Discourse forum, and there is a code of conduct. The project also asks for citation, and the README carries a paper badge with a DOI, a Zenodo archive DOI, and a CITATION.cff file in the repository. The funding section is unusually concrete: development has been supported by NSF grants OCE-1558403 and EAR-1948602, which tells you this is academic research infrastructure with a grant history rather than a company project.

Where PyGMT is the wrong choice

Four limits apply. It requires GMT to be installed and working, so a pip-only environment is not enough and a container has to carry the GMT binary and its data files, which is why the package documentation recommends conda. It is aimed at the Earth, Ocean and Planetary sciences, so if you want a general purpose plotting library for something that is not a map, the dependency stack is heavier than you need. It is a 0.x library classified as Beta, so an API change between minor versions is possible and a pin in your environment file is the safe habit. And the licensing of the data is separate from the licensing of the code: PyGMT is BSD 3-clause and free to redistribute, but GMT itself brings its own licence terms and its own coastline and gridded datasets, which is worth reading before you publish a map made with it.

Editorial conclusion

Use PyGMT when you need maps that would otherwise come out of GMT command lines, because the object-oriented Figure API lets you compose a publication figure in a notebook or a script instead of assembling arguments. Do not expect it to run without GMT installed, since the library delegates the actual plotting to that program, and check the Minimum Supported Versions page before pinning dependencies. Verify first that your GMT build exposes the modules you need, that your Python is 3.12 or newer as the packaging metadata requires, and which optional extras you want, since GeoPandas, rioxarray, contextily, PyArrow and IPython are each optional and pulled in by the all extra.

Frequently asked questions

What is PyGMT and what does it need to run?

It is a Python interface for the Generic Mapping Tools, for processing geospatial and geophysical data and making publication-quality maps. It depends on GMT itself plus NumPy, pandas, xarray and packaging, with IPython, GeoPandas, contextily, rioxarray and PyArrow optional.

How do I install PyGMT?

With conda, using conda install --channel conda-forge pygmt, which is the documented route because it also brings GMT. The package is also on PyPI, and the documentation links a page of full installation instructions along with a Minimum Supported Versions page for version requirements.

What is the Figure API in PyGMT?

It is the object-oriented way to build a map: you create a pygmt.Figure, call methods such as basemap, coast and text on it to add layers with a projection, a region and styling, then call show to display the result.

Does PyGMT work with xarray?

Yes. The packaging metadata registers an entry point under xarray.backends mapping the name gmt to pygmt.xarray, so PyGMT is usable as an xarray backend alongside the other formats xarray can open.

What licence is PyGMT released under?

The BSD 3-clause License, with a copy provided in the LICENSE.txt file in the repository. The README describes PyGMT as free software that you can redistribute or modify under those terms.

Official sources

  1. GenericMappingTools/pygmt on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/genericmappingtools-pygmt.svg)](https://hysenlabs.com/projects/genericmappingtools-pygmt)

Was this useful?