Skip to content

Commit

Permalink
geopandas: Mapping int/int64 to int32 for OGR_GMT format (#2592)
Browse files Browse the repository at this point in the history
Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com>
  • Loading branch information
seisman and weiji14 authored Aug 21, 2023
1 parent 14b045a commit 5b05b6a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
16 changes: 14 additions & 2 deletions pygmt/helpers/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,30 @@ def tempfile_from_geojson(geojson):
E.g. '1a2b3c4d5e6.gmt'.
"""
with GMTTempFile(suffix=".gmt") as tmpfile:
# pylint: disable=import-outside-toplevel
import geopandas as gpd

os.remove(tmpfile.name) # ensure file is deleted first
ogrgmt_kwargs = {"filename": tmpfile.name, "driver": "OGR_GMT", "mode": "w"}
try:
# Map int/int64 to int32 since OGR_GMT only supports 32-bit integer
# https://github.com/geopandas/geopandas/issues/967#issuecomment-842877704
# https://github.com/GenericMappingTools/pygmt/issues/2497
if geojson.index.name is None:
geojson.index.name = "index"
geojson = geojson.reset_index(drop=False)
schema = gpd.io.file.infer_schema(geojson)
for col, dtype in schema["properties"].items():
if dtype in ("int", "int64"):
schema["properties"][col] = "int32"
ogrgmt_kwargs["schema"] = schema
# Using geopandas.to_file to directly export to OGR_GMT format
geojson.to_file(**ogrgmt_kwargs)
except AttributeError:
# pylint: disable=import-outside-toplevel
# Other 'geo' formats which implement __geo_interface__
import json

import fiona
import geopandas as gpd

with fiona.Env():
jsontext = json.dumps(geojson.__geo_interface__)
Expand Down
4 changes: 4 additions & 0 deletions pygmt/tests/baseline/test_geopandas_plot_int_dtypes.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
outs:
- md5: c1c6eda2a88adf4d96f18f4e0c5db4d5
size: 43582
path: test_geopandas_plot_int_dtypes.png
53 changes: 52 additions & 1 deletion pygmt/tests/test_geopandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import numpy.testing as npt
import pytest
from pygmt import Figure, info
from pygmt import Figure, info, makecpt, which

gpd = pytest.importorskip("geopandas")
shapely = pytest.importorskip("shapely")
Expand Down Expand Up @@ -131,3 +131,54 @@ def test_geopandas_plot3d_non_default_circle():
style="c0.2c",
)
return fig


@pytest.mark.parametrize(
"dtype",
[
"int32",
"int64",
# Enable Int32/Int64 dtypes when geopandas>=0.13.3 is released with
# patch https://github.com/geopandas/geopandas/pull/2950
# pd.Int32Dtype(),
# pd.Int64Dtype(),
],
)
@pytest.mark.mpl_image_compare(filename="test_geopandas_plot_int_dtypes.png")
def test_geopandas_plot_int_dtypes(dtype):
"""
Check that plotting a geopandas GeoDataFrame with integer columns works,
including int32 and int64 (non-nullable), Int32 and Int64 (nullable).
This is a regression test for
https://github.com/GenericMappingTools/pygmt/issues/2497
"""
# Read shapefile in geopandas.GeoDataFrame
shapefile = which(
fname="@RidgeTest.shp @RidgeTest.shx @RidgeTest.dbf @RidgeTest.prj",
download="c",
)
gdf = gpd.read_file(shapefile[0])

# Reproject geometry and change dtype of NPOINTS column
gdf["geometry"] = (
gdf.to_crs(crs="EPSG:3857")
.buffer(distance=100000)
.to_crs(crs="OGC:CRS84") # convert to lon/lat to prevent @null in PROJ CRS
)
gdf["NPOINTS"] = gdf.NPOINTS.astype(dtype=dtype)

# Plot figure with three polygons colored based on NPOINTS value
fig = Figure()
makecpt(cmap="lisbon", series=[10, 60, 10], continuous=True)
fig.plot(
data=gdf,
frame=True,
pen="1p,black",
close=True,
fill="+z",
cmap=True,
aspatial="Z=NPOINTS",
)
fig.colorbar()
return fig

0 comments on commit 5b05b6a

Please sign in to comment.