Skip to content

Commit 3ed8618

Browse files
authored
Add Figure.choropleth to plot choropleth maps (#2798)
1 parent 95256f7 commit 3ed8618

File tree

8 files changed

+119
-14
lines changed

8 files changed

+119
-14
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Plotting map elements
2525
:toctree: generated
2626

2727
Figure.basemap
28+
Figure.choropleth
2829
Figure.coast
2930
Figure.colorbar
3031
Figure.directional_rose

examples/gallery/maps/choropleth_map.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
Choropleth map
33
==============
44
5-
The :meth:`pygmt.Figure.plot` method allows us to plot geographical data such as
6-
polygons which are stored in a :class:`geopandas.GeoDataFrame` object. Use
7-
:func:`geopandas.read_file` to load data from any supported OGR format such as a
8-
shapefile (.shp), GeoJSON (.geojson), geopackage (.gpkg), etc. You can also use a full
9-
URL pointing to your desired data source. Then, pass the :class:`geopandas.GeoDataFrame`
10-
as an argument to the ``data`` parameter of :meth:`pygmt.Figure.plot`, and style the
11-
geometry using the ``pen`` parameter. To fill the polygons based on a corresponding
12-
column you need to set ``fill="+z"`` as well as select the appropriate column using the
13-
``aspatial`` parameter as shown in the example below.
5+
The :meth:`pygmt.Figure.choropleth` method allows us to plot geographical data such as
6+
polygons which are stored in a :class:`geopandas.GeoDataFrame` object or an OGR_GMT
7+
file. Use :func:`geopandas.read_file` to load data from any supported OGR formats such
8+
as a shapefile (.shp), GeoJSON (.geojson), geopackage (.gpkg), etc. You can also use a
9+
full URL pointing to your desired data source. Then, pass the
10+
:class:`geopandas.GeoDataFrame` as an argument to the ``data`` parameter of
11+
:meth:`pygmt.Figure.choropleth`, and style the geometry using the ``pen`` parameter. To
12+
fill the polygons based on a corresponding column you need to specify the column name to
13+
the ``column`` parameter.
1414
"""
1515

1616
# %%
@@ -34,7 +34,7 @@
3434

3535
# Next, we plot the polygons and fill them using the defined colormap. The target column
3636
# is defined by the aspatial parameter.
37-
fig.plot(data=africa, pen="0.8p,gray50", fill="+z", cmap=True, aspatial="Z=POP_EST")
37+
fig.choropleth(data=africa, column="POP_EST", pen="0.8p,gray50")
3838

3939
# Add colorbar legend.
4040
fig.colorbar(
@@ -45,5 +45,4 @@
4545
triangle_height=0.2,
4646
move_text="label",
4747
)
48-
4948
fig.show()

pygmt/_typing.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@
2020
with contextlib.suppress(ImportError):
2121
StringArrayTypes |= importlib.import_module(name="pyarrow").StringArray
2222

23-
# PathLike and TableLike types
23+
# PathLike, GeoLike, and TableLike types
2424
PathLike = str | os.PathLike
2525
TableLike = dict | np.ndarray | pd.DataFrame | xr.Dataset
26-
with contextlib.suppress(ImportError):
27-
TableLike |= importlib.import_module(name="geopandas").GeoDataFrame
26+
try:
27+
import geopandas
28+
29+
GeoLike = geopandas.GeoDataFrame
30+
except ImportError:
31+
GeoLike = None
32+
if GeoLike is not None:
33+
TableLike |= GeoLike

pygmt/figure.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ def _repr_html_(self) -> str:
410410

411411
from pygmt.src import ( # type: ignore[misc] # noqa: PLC0415
412412
basemap,
413+
choropleth,
413414
coast,
414415
colorbar,
415416
contour,

pygmt/src/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from pygmt.src.basemap import basemap
66
from pygmt.src.binstats import binstats
77
from pygmt.src.blockm import blockmean, blockmedian, blockmode
8+
from pygmt.src.choropleth import choropleth
89
from pygmt.src.coast import coast
910
from pygmt.src.colorbar import colorbar
1011
from pygmt.src.config import config

pygmt/src/choropleth.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
choropleth - Plot a choropleth map.
3+
"""
4+
5+
from pygmt._typing import GeoLike, PathLike
6+
7+
__doctest_skip__ = ["choropleth"]
8+
9+
10+
def choropleth(
11+
self,
12+
data: GeoLike | PathLike,
13+
column: str,
14+
cmap: str | bool = True,
15+
**kwargs,
16+
):
17+
"""
18+
Plot a choropleth map.
19+
20+
This method is a thin wrapper around :meth:`pygmt.Figure.plot` that sets the
21+
appropriate parameters for creating a choropleth map by filling polygons based on
22+
values in a specified data column. It requires the input data to be a geo-like
23+
Python object that implements ``__geo_interface__`` (e.g. a
24+
:class:`geopandas.GeoDataFrame`), or an OGR_GMT file containing the geometry and
25+
data to plot.
26+
27+
Parameters
28+
----------
29+
data
30+
A geo-like Python object which implements ``__geo_interface__`` (e.g. a
31+
:class:`geopandas.GeoDataFrame` or :class:`shapely.geometry`), or an OGR_GMT
32+
file containing the geometry and data to plot.
33+
column
34+
The name of the data column to use for the fill.
35+
cmap
36+
The CPT to use for filling the polygons. If set to ``True``, the current CPT
37+
will be used.
38+
**kwargs
39+
Additional keyword arguments passed to :meth:`pygmt.Figure.plot`.
40+
41+
Examples
42+
--------
43+
>>> import geopandas as gpd
44+
>>> import pygmt
45+
>>> world = gpd.read_file(
46+
... "https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
47+
... )
48+
>>> world["POP_EST"] *= 1e-6 # Population in millions
49+
50+
>>> fig = pygmt.Figure()
51+
>>> fig.basemap(region=[-19.5, 53, -38, 37.5], projection="M15c", frame=True)
52+
>>> pygmt.makecpt(cmap="bilbao", series=(0, 270, 10), reverse=True)
53+
>>> fig.choropleth(world, column="POP_EST", pen="0.3p,gray10")
54+
>>> fig.colorbar(frame=True)
55+
>>> fig.show()
56+
"""
57+
self.plot(
58+
data=data, close=True, fill="+z", cmap=cmap, aspatial=f"Z={column}", **kwargs
59+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: ed720d3682b43c4474cd21f49e788a98
3+
size: 155020
4+
hash: md5
5+
path: test_choropleth.png

pygmt/tests/test_choropleth.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Test Figure.choropleth.
3+
"""
4+
5+
import pytest
6+
from pygmt import Figure, makecpt
7+
8+
gpd = pytest.importorskip("geopandas")
9+
10+
11+
@pytest.fixture(scope="module", name="world")
12+
def fixture_world():
13+
"""
14+
Download and cache the Natural Earth countries dataset for testing.
15+
"""
16+
return gpd.read_file(
17+
"https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
18+
)
19+
20+
21+
@pytest.mark.mpl_image_compare
22+
def test_choropleth(world):
23+
"""
24+
Test Figure.choropleth method.
25+
"""
26+
world["POP_EST"] *= 1e-6 # Population in millions
27+
28+
fig = Figure()
29+
fig.basemap(region=[-19.5, 53, -38, 37.5], projection="M15c", frame=True)
30+
makecpt(cmap="bilbao", series=(0, 270, 10), reverse=True)
31+
fig.choropleth(world, column="POP_EST", pen="0.3p,gray10")
32+
fig.colorbar(frame=True)
33+
return fig

0 commit comments

Comments
 (0)