Skip to content

Commit e812329

Browse files
authored
Merge branch 'main' into pandas-2.1
2 parents 6083058 + 189f376 commit e812329

File tree

8 files changed

+291
-43
lines changed

8 files changed

+291
-43
lines changed

.github/workflows/ci_docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ jobs:
115115
sphinx-copybutton
116116
sphinx-design
117117
sphinx-gallery
118-
sphinx_rtd_theme
118+
sphinx_rtd_theme<3.0
119119
120120
# Download cached remote files (artifacts) from GitHub
121121
- name: Download remote data from GitHub

ci/requirements/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ dependencies:
3030
- sphinx-copybutton
3131
- sphinx-design
3232
- sphinx-gallery
33-
- sphinx_rtd_theme
33+
- sphinx_rtd_theme<3.0

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ dependencies:
4242
- sphinx-copybutton
4343
- sphinx-design
4444
- sphinx-gallery>=0.17.0
45-
- sphinx_rtd_theme
45+
- sphinx_rtd_theme<3.0
4646
# Dev dependencies (type hints)
4747
- mypy
4848
- pandas-stubs

pygmt/tests/baseline/test_figure_shift_origin.png.dvc

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: 39b241fdd879271cf1e8cf1f73454706
3+
size: 9910
4+
hash: md5
5+
path: test_shift_origin.png

pygmt/tests/test_clib_to_numpy.py

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
"""
2+
Tests for the _to_numpy function in the clib.conversion module.
3+
"""
4+
5+
import sys
6+
7+
import numpy as np
8+
import numpy.testing as npt
9+
import pandas as pd
10+
import pytest
11+
from packaging.version import Version
12+
from pygmt.clib.conversion import _to_numpy
13+
14+
try:
15+
import pyarrow as pa
16+
17+
_HAS_PYARROW = True
18+
except ImportError:
19+
_HAS_PYARROW = False
20+
21+
22+
def _check_result(result, expected_dtype):
23+
"""
24+
A helper function to check if the result of the _to_numpy function is a C-contiguous
25+
NumPy array with the expected dtype.
26+
"""
27+
assert isinstance(result, np.ndarray)
28+
assert result.flags.c_contiguous
29+
assert result.dtype.type == expected_dtype
30+
31+
32+
########################################################################################
33+
# Test the _to_numpy function with Python built-in types.
34+
########################################################################################
35+
@pytest.mark.parametrize(
36+
("data", "expected_dtype"),
37+
[
38+
pytest.param(
39+
[1, 2, 3],
40+
np.int32
41+
if sys.platform == "win32" and Version(np.__version__) < Version("2.0")
42+
else np.int64,
43+
id="int",
44+
),
45+
pytest.param([1.0, 2.0, 3.0], np.float64, id="float"),
46+
pytest.param(
47+
[complex(+1), complex(-2j), complex("-Infinity+NaNj")],
48+
np.complex128,
49+
id="complex",
50+
),
51+
],
52+
)
53+
def test_to_numpy_python_types_numeric(data, expected_dtype):
54+
"""
55+
Test the _to_numpy function with Python built-in numeric types.
56+
"""
57+
result = _to_numpy(data)
58+
_check_result(result, expected_dtype)
59+
npt.assert_array_equal(result, data)
60+
61+
62+
########################################################################################
63+
# Test the _to_numpy function with NumPy arrays.
64+
#
65+
# There are 24 fundamental dtypes in NumPy. Not all of them are supported by PyGMT.
66+
#
67+
# - Numeric dtypes:
68+
# - int8, int16, int32, int64, longlong
69+
# - uint8, uint16, uint32, uint64, ulonglong
70+
# - float16, float32, float64, longdouble
71+
# - complex64, complex128, clongdouble
72+
# - bool
73+
# - datetime64, timedelta64
74+
# - str_
75+
# - bytes_
76+
# - object_
77+
# - void
78+
#
79+
# Reference: https://numpy.org/doc/2.1/reference/arrays.scalars.html
80+
########################################################################################
81+
np_dtype_params = [
82+
pytest.param(np.int8, np.int8, id="int8"),
83+
pytest.param(np.int16, np.int16, id="int16"),
84+
pytest.param(np.int32, np.int32, id="int32"),
85+
pytest.param(np.int64, np.int64, id="int64"),
86+
pytest.param(np.longlong, np.longlong, id="longlong"),
87+
pytest.param(np.uint8, np.uint8, id="uint8"),
88+
pytest.param(np.uint16, np.uint16, id="uint16"),
89+
pytest.param(np.uint32, np.uint32, id="uint32"),
90+
pytest.param(np.uint64, np.uint64, id="uint64"),
91+
pytest.param(np.ulonglong, np.ulonglong, id="ulonglong"),
92+
pytest.param(np.float16, np.float16, id="float16"),
93+
pytest.param(np.float32, np.float32, id="float32"),
94+
pytest.param(np.float64, np.float64, id="float64"),
95+
pytest.param(np.longdouble, np.longdouble, id="longdouble"),
96+
pytest.param(np.complex64, np.complex64, id="complex64"),
97+
pytest.param(np.complex128, np.complex128, id="complex128"),
98+
pytest.param(np.clongdouble, np.clongdouble, id="clongdouble"),
99+
]
100+
101+
102+
@pytest.mark.parametrize(("dtype", "expected_dtype"), np_dtype_params)
103+
def test_to_numpy_ndarray_numpy_dtypes_numeric(dtype, expected_dtype):
104+
"""
105+
Test the _to_numpy function with NumPy arrays of NumPy numeric dtypes.
106+
107+
Test both 1-D and 2-D arrays which are not C-contiguous.
108+
"""
109+
# 1-D array that is not C-contiguous
110+
array = np.array([1, 2, 3, 4, 5, 6], dtype=dtype)[::2]
111+
assert array.flags.c_contiguous is False
112+
result = _to_numpy(array)
113+
_check_result(result, expected_dtype)
114+
npt.assert_array_equal(result, array, strict=True)
115+
116+
# 2-D array that is not C-contiguous
117+
array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=dtype)[::2, ::2]
118+
assert array.flags.c_contiguous is False
119+
result = _to_numpy(array)
120+
_check_result(result, expected_dtype)
121+
npt.assert_array_equal(result, array, strict=True)
122+
123+
124+
########################################################################################
125+
# Test the _to_numpy function with pandas.Series.
126+
#
127+
# In pandas, dtype can be specified by
128+
#
129+
# 1. NumPy dtypes (see above)
130+
# 2. pandas dtypes
131+
# 3. PyArrow types (see below)
132+
#
133+
# pandas provides following dtypes:
134+
#
135+
# - Numeric dtypes:
136+
# - Int8, Int16, Int32, Int64
137+
# - UInt8, UInt16, UInt32, UInt64
138+
# - Float32, Float64
139+
# - DatetimeTZDtype
140+
# - PeriodDtype
141+
# - IntervalDtype
142+
# - StringDtype
143+
# - CategoricalDtype
144+
# - SparseDtype
145+
# - BooleanDtype
146+
# - ArrowDtype: a special dtype used to store data in the PyArrow format.
147+
#
148+
# References:
149+
# 1. https://pandas.pydata.org/docs/reference/arrays.html
150+
# 2. https://pandas.pydata.org/docs/user_guide/basics.html#basics-dtypes
151+
# 3. https://pandas.pydata.org/docs/user_guide/pyarrow.html
152+
########################################################################################
153+
@pytest.mark.parametrize(("dtype", "expected_dtype"), np_dtype_params)
154+
def test_to_numpy_pandas_series_numpy_dtypes_numeric(dtype, expected_dtype):
155+
"""
156+
Test the _to_numpy function with pandas.Series of NumPy numeric dtypes.
157+
"""
158+
series = pd.Series([1, 2, 3, 4, 5, 6], dtype=dtype)[::2] # Not C-contiguous
159+
result = _to_numpy(series)
160+
_check_result(result, expected_dtype)
161+
npt.assert_array_equal(result, series)
162+
163+
164+
########################################################################################
165+
# Test the _to_numpy function with PyArrow arrays.
166+
#
167+
# PyArrow provides the following types:
168+
#
169+
# - Numeric types:
170+
# - int8, int16, int32, int64
171+
# - uint8, uint16, uint32, uint64
172+
# - float16, float32, float64
173+
#
174+
# In PyArrow, array types can be specified in two ways:
175+
#
176+
# - Using string aliases (e.g., "int8")
177+
# - Using pyarrow.DataType (e.g., ``pa.int8()``)
178+
#
179+
# Reference: https://arrow.apache.org/docs/python/api/datatypes.html
180+
########################################################################################
181+
@pytest.mark.skipif(not _HAS_PYARROW, reason="pyarrow is not installed")
182+
@pytest.mark.parametrize(
183+
("dtype", "expected_dtype"),
184+
[
185+
pytest.param("int8", np.int8, id="int8"),
186+
pytest.param("int16", np.int16, id="int16"),
187+
pytest.param("int32", np.int32, id="int32"),
188+
pytest.param("int64", np.int64, id="int64"),
189+
pytest.param("uint8", np.uint8, id="uint8"),
190+
pytest.param("uint16", np.uint16, id="uint16"),
191+
pytest.param("uint32", np.uint32, id="uint32"),
192+
pytest.param("uint64", np.uint64, id="uint64"),
193+
pytest.param("float16", np.float16, id="float16"),
194+
pytest.param("float32", np.float32, id="float32"),
195+
pytest.param("float64", np.float64, id="float64"),
196+
],
197+
)
198+
def test_to_numpy_pyarrow_array_pyarrow_dtypes_numeric(dtype, expected_dtype):
199+
"""
200+
Test the _to_numpy function with PyArrow arrays of PyArrow numeric types.
201+
"""
202+
data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
203+
if dtype == "float16": # float16 needs special handling
204+
# Example from https://arrow.apache.org/docs/python/generated/pyarrow.float16.html
205+
data = np.array(data, dtype=np.float16)
206+
array = pa.array(data, type=dtype)[::2]
207+
result = _to_numpy(array)
208+
_check_result(result, expected_dtype)
209+
npt.assert_array_equal(result, array)
210+
211+
212+
@pytest.mark.skipif(not _HAS_PYARROW, reason="pyarrow is not installed")
213+
@pytest.mark.parametrize(
214+
("dtype", "expected_dtype"),
215+
[
216+
pytest.param("int8", np.float64, id="int8"),
217+
pytest.param("int16", np.float64, id="int16"),
218+
pytest.param("int32", np.float64, id="int32"),
219+
pytest.param("int64", np.float64, id="int64"),
220+
pytest.param("uint8", np.float64, id="uint8"),
221+
pytest.param("uint16", np.float64, id="uint16"),
222+
pytest.param("uint32", np.float64, id="uint32"),
223+
pytest.param("uint64", np.float64, id="uint64"),
224+
pytest.param("float16", np.float16, id="float16"),
225+
pytest.param("float32", np.float32, id="float32"),
226+
pytest.param("float64", np.float64, id="float64"),
227+
],
228+
)
229+
def test_to_numpy_pyarrow_array_pyarrow_dtypes_numeric_with_na(dtype, expected_dtype):
230+
"""
231+
Test the _to_numpy function with PyArrow arrays of PyArrow numeric types and NA.
232+
"""
233+
data = [1.0, 2.0, None, 4.0, 5.0, 6.0]
234+
if dtype == "float16": # float16 needs special handling
235+
# Example from https://arrow.apache.org/docs/python/generated/pyarrow.float16.html
236+
data = np.array(data, dtype=np.float16)
237+
array = pa.array(data, type=dtype)[::2]
238+
result = _to_numpy(array)
239+
_check_result(result, expected_dtype)
240+
npt.assert_array_equal(result, array)

pygmt/tests/test_figure.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -292,26 +292,6 @@ def test_figure_show():
292292
fig.show()
293293

294294

295-
@pytest.mark.mpl_image_compare
296-
def test_figure_shift_origin():
297-
"""
298-
Test if fig.shift_origin works.
299-
"""
300-
kwargs = {"region": [0, 3, 0, 5], "projection": "X3c/5c", "frame": 0}
301-
fig = Figure()
302-
# First call shift_origin without projection and region.
303-
# Test issue https://github.com/GenericMappingTools/pygmt/issues/514
304-
fig.shift_origin(xshift="2c", yshift="3c")
305-
fig.basemap(**kwargs)
306-
fig.shift_origin(xshift="4c")
307-
fig.basemap(**kwargs)
308-
fig.shift_origin(yshift="6c")
309-
fig.basemap(**kwargs)
310-
fig.shift_origin(xshift="-4c", yshift="6c")
311-
fig.basemap(**kwargs)
312-
return fig
313-
314-
315295
def test_figure_show_invalid_method():
316296
"""
317297
Test to check if an error is raised when an invalid method is passed to show.
@@ -407,22 +387,6 @@ def test_invalid_method(self):
407387
set_display(method="invalid")
408388

409389

410-
def test_figure_unsupported_xshift_yshift():
411-
"""
412-
Raise an exception if X/Y/xshift/yshift is used.
413-
"""
414-
fig = Figure()
415-
fig.basemap(region=[0, 1, 0, 1], projection="X1c/1c", frame=True)
416-
with pytest.raises(GMTInvalidInput):
417-
fig.plot(x=1, y=1, style="c3c", xshift="3c")
418-
with pytest.raises(GMTInvalidInput):
419-
fig.plot(x=1, y=1, style="c3c", X="3c")
420-
with pytest.raises(GMTInvalidInput):
421-
fig.plot(x=1, y=1, style="c3c", yshift="3c")
422-
with pytest.raises(GMTInvalidInput):
423-
fig.plot(x=1, y=1, style="c3c", Y="3c")
424-
425-
426390
class TestGetDefaultDisplayMethod:
427391
"""
428392
Test the _get_default_display_method function.

pygmt/tests/test_shift_origin.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Test Figure.shift_origin.
3+
"""
4+
5+
import pytest
6+
from pygmt.exceptions import GMTInvalidInput
7+
from pygmt.figure import Figure
8+
9+
10+
@pytest.mark.mpl_image_compare
11+
def test_shift_origin():
12+
"""
13+
Test if fig.shift_origin works.
14+
"""
15+
kwargs = {"region": [0, 3, 0, 5], "projection": "X3c/5c", "frame": 0}
16+
fig = Figure()
17+
# First call shift_origin without projection and region.
18+
# Test issue https://github.com/GenericMappingTools/pygmt/issues/514
19+
fig.shift_origin(xshift="2c", yshift="3c")
20+
fig.basemap(**kwargs)
21+
fig.shift_origin(xshift="4c")
22+
fig.basemap(**kwargs)
23+
fig.shift_origin(yshift="6c")
24+
fig.basemap(**kwargs)
25+
fig.shift_origin(xshift="-4c", yshift="6c")
26+
fig.basemap(**kwargs)
27+
return fig
28+
29+
30+
def test_shift_origin_unsupported_xshift_yshift():
31+
"""
32+
Raise an exception if X/Y/xshift/yshift is used.
33+
"""
34+
fig = Figure()
35+
fig.basemap(region=[0, 1, 0, 1], projection="X1c/1c", frame=True)
36+
with pytest.raises(GMTInvalidInput):
37+
fig.plot(x=1, y=1, style="c3c", xshift="3c")
38+
with pytest.raises(GMTInvalidInput):
39+
fig.plot(x=1, y=1, style="c3c", X="3c")
40+
with pytest.raises(GMTInvalidInput):
41+
fig.plot(x=1, y=1, style="c3c", yshift="3c")
42+
with pytest.raises(GMTInvalidInput):
43+
fig.plot(x=1, y=1, style="c3c", Y="3c")

0 commit comments

Comments
 (0)