diff --git a/docs/history.rst b/docs/history.rst index 8a90bc912..f2940ff08 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -10,6 +10,7 @@ Latest - REF: use regex to process PROJ strings in :meth:`.CRS.to_dict` (pull #1086) - BUG: :class:`.MercatorAConversion` defined only for lat_0 = 0 (issue #1089) - BUG: Add support for `PROJ_DATA` environment variable (issue #1097) +- BUG: Ensure numpy masked arrays stay masked after projection (issue #1102) 3.3.1 ------- diff --git a/pyproj/utils.py b/pyproj/utils.py index efafa329d..5f500af8e 100644 --- a/pyproj/utils.py +++ b/pyproj/utils.py @@ -108,6 +108,11 @@ def _copytobuffer(xxx: Any, inplace: bool = False) -> Tuple[Any, DataType]: Tuple[Any, DataType] The copy of the data prepared for the PROJ API & Python Buffer API. """ + # handle numpy masked Arrays; note that pandas.Series also has a "mask" + # attribute, hence checking for simply the "mask" attr isn't sufficient + if hasattr(xxx, "hardmask"): + return xxx, DataType.ARRAY + # check for pandas.Series, xarray.DataArray or dask.array.Array if hasattr(xxx, "__array__") and callable(xxx.__array__): xxx = xxx.__array__() diff --git a/test/test_utils.py b/test/test_utils.py index ae5eaff20..2d9d7cf05 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -42,6 +42,13 @@ def test__copytobuffer__numpy_array(in_arr): ) +def test__copytobuffer__numpy_masked_array(): + in_arr = numpy.ma.array([1]) + out_arr, dtype = _copytobuffer(in_arr) + + assert isinstance(out_arr, numpy.ma.MaskedArray) + + def test__copytobuffer__fortran_order(): data = numpy.ones((2, 4), dtype=numpy.float64, order="F") converted_data, dtype = _copytobuffer(data)