0
# Testing Utilities
1
2
GeoPandas provides comprehensive testing utilities for validating geospatial data structures and operations. These utilities enable robust testing of spatial data processing workflows and ensure correctness of geometric operations.
3
4
## Capabilities
5
6
### Equality Assertions
7
8
Functions for testing equality between geospatial objects with appropriate tolerance handling.
9
10
```python { .api }
11
def assert_geoseries_equal(left, right, check_dtype=True, check_index_type=True, check_series_type=True, check_names=True, check_crs=True, check_geom_type=False, check_less_precise=False, normalize=False):
12
"""
13
Assert that two GeoSeries are equal.
14
15
Parameters:
16
- left: GeoSeries to compare
17
- right: GeoSeries to compare
18
- check_dtype: Whether to check dtype equivalence
19
- check_index_type: Whether to check index type equivalence
20
- check_series_type: Whether to check series type equivalence
21
- check_names: Whether to check names equivalence
22
- check_crs: Whether to check CRS equivalence
23
- check_geom_type: Whether to check geometry type consistency
24
- check_less_precise: Whether to use less precise comparison for coordinates
25
- normalize: Whether to normalize geometries before comparison
26
27
Raises:
28
- AssertionError: If GeoSeries are not equal according to criteria
29
"""
30
...
31
32
def assert_geodataframe_equal(left, right, check_dtype=True, check_index_type=True, check_frame_type=True, check_names=True, check_crs=True, check_geom_type=False, check_less_precise=False, normalize=False):
33
"""
34
Assert that two GeoDataFrames are equal.
35
36
Parameters:
37
- left: GeoDataFrame to compare
38
- right: GeoDataFrame to compare
39
- check_dtype: Whether to check dtype equivalence
40
- check_index_type: Whether to check index type equivalence
41
- check_frame_type: Whether to check frame type equivalence
42
- check_names: Whether to check names equivalence
43
- check_crs: Whether to check CRS equivalence
44
- check_geom_type: Whether to check geometry type consistency
45
- check_less_precise: Whether to use less precise comparison for coordinates
46
- normalize: Whether to normalize geometries before comparison
47
48
Raises:
49
- AssertionError: If GeoDataFrames are not equal according to criteria
50
"""
51
...
52
53
def assert_index_equal(left, right, exact='equiv', check_names=True, check_exact=True, check_categorical=True, check_order=True, rtol=1e-5, atol=1e-8, obj='Index'):
54
"""
55
Assert that two spatial indices are equal.
56
57
Parameters:
58
- left: Index to compare
59
- right: Index to compare
60
- exact: Whether to check index type exactly
61
- check_names: Whether to check names equivalence
62
- check_exact: Whether to compare exactly
63
- check_categorical: Whether to check categorical exactly
64
- check_order: Whether to check order
65
- rtol: Relative tolerance for numeric comparison
66
- atol: Absolute tolerance for numeric comparison
67
- obj: Object name for error messages
68
69
Raises:
70
- AssertionError: If indices are not equal according to criteria
71
"""
72
...
73
```
74
75
### Version Information
76
77
Function for displaying version information about GeoPandas and its dependencies.
78
79
```python { .api }
80
def show_versions():
81
"""
82
Print version information for GeoPandas and its dependencies.
83
84
This function displays version information for:
85
- GeoPandas itself
86
- Python interpreter
87
- Core dependencies (pandas, shapely, pyproj, etc.)
88
- Optional dependencies (matplotlib, etc.)
89
- System information
90
91
Useful for debugging and reporting issues.
92
"""
93
...
94
```
95
96
## Usage Examples
97
98
### Testing GeoSeries Equality
99
100
```python
101
import geopandas as gpd
102
from geopandas.testing import assert_geoseries_equal
103
from shapely.geometry import Point, Polygon
104
105
# Create test GeoSeries
106
gs1 = gpd.GeoSeries([Point(0, 0), Point(1, 1)], crs='EPSG:4326')
107
gs2 = gpd.GeoSeries([Point(0, 0), Point(1, 1)], crs='EPSG:4326')
108
109
# Test equality - should pass
110
assert_geoseries_equal(gs1, gs2)
111
112
# Test with different CRS - should fail unless check_crs=False
113
gs3 = gpd.GeoSeries([Point(0, 0), Point(1, 1)], crs='EPSG:3857')
114
try:
115
assert_geoseries_equal(gs1, gs3)
116
except AssertionError:
117
print("CRS mismatch detected")
118
119
# Ignore CRS differences
120
assert_geoseries_equal(gs1, gs3, check_crs=False)
121
```
122
123
### Testing GeoDataFrame Equality
124
125
```python
126
from geopandas.testing import assert_geodataframe_equal
127
128
# Create test GeoDataFrames
129
gdf1 = gpd.GeoDataFrame({
130
'name': ['A', 'B'],
131
'geometry': [Point(0, 0), Point(1, 1)]
132
}, crs='EPSG:4326')
133
134
gdf2 = gpd.GeoDataFrame({
135
'name': ['A', 'B'],
136
'geometry': [Point(0, 0), Point(1, 1)]
137
}, crs='EPSG:4326')
138
139
# Test equality
140
assert_geodataframe_equal(gdf1, gdf2)
141
142
# Test with different column order
143
gdf3 = gpd.GeoDataFrame({
144
'geometry': [Point(0, 0), Point(1, 1)],
145
'name': ['A', 'B']
146
}, crs='EPSG:4326')
147
148
# Should still be equal (column order doesn't matter by default)
149
assert_geodataframe_equal(gdf1, gdf3)
150
```
151
152
### Testing with Geometric Transformations
153
154
```python
155
# Test that geometric operations preserve expected properties
156
original = gpd.GeoSeries([
157
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
158
], crs='EPSG:4326')
159
160
# Buffer and then negative buffer should approximate original
161
buffered = original.buffer(0.1)
162
unbuffered = buffered.buffer(-0.1)
163
164
# Use less precise comparison due to floating point operations
165
assert_geoseries_equal(original, unbuffered, check_less_precise=True)
166
```
167
168
### Testing Coordinate Transformations
169
170
```python
171
# Test CRS transformations
172
gdf_wgs84 = gpd.GeoDataFrame({
173
'geometry': [Point(-74.0, 40.7)] # New York
174
}, crs='EPSG:4326')
175
176
# Transform to Web Mercator and back
177
gdf_mercator = gdf_wgs84.to_crs('EPSG:3857')
178
gdf_back = gdf_mercator.to_crs('EPSG:4326')
179
180
# Should be approximately equal (may have small precision differences)
181
assert_geodataframe_equal(gdf_wgs84, gdf_back, check_less_precise=True)
182
```
183
184
### Testing with Normalized Geometries
185
186
```python
187
from shapely.geometry import Polygon
188
189
# Create geometries that are topologically equal but with different coordinate order
190
poly1 = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
191
poly2 = Polygon([(1, 0), (1, 1), (0, 1), (0, 0)]) # Different starting point
192
193
gs1 = gpd.GeoSeries([poly1])
194
gs2 = gpd.GeoSeries([poly2])
195
196
# Direct comparison might fail due to coordinate ordering
197
try:
198
assert_geoseries_equal(gs1, gs2)
199
except AssertionError:
200
print("Coordinate order mismatch")
201
202
# Use normalize=True to handle coordinate ordering differences
203
assert_geoseries_equal(gs1, gs2, normalize=True)
204
```
205
206
### Testing Spatial Operations Results
207
208
```python
209
# Test that spatial operations produce expected results
210
circle = gpd.GeoSeries([Point(0, 0).buffer(1)])
211
square = gpd.GeoSeries([Polygon([(-1, -1), (1, -1), (1, 1), (-1, 1)])])
212
213
# Test intersection
214
intersection = gpd.overlay(
215
gpd.GeoDataFrame(geometry=circle),
216
gpd.GeoDataFrame(geometry=square),
217
how='intersection'
218
)
219
220
# Intersection should not be empty
221
assert not intersection.geometry.is_empty.any()
222
223
# Area should be less than both original geometries
224
assert (intersection.geometry.area < circle.area).all()
225
assert (intersection.geometry.area < square.area).all()
226
```
227
228
### Version Information for Debugging
229
230
```python
231
from geopandas.tools import show_versions
232
233
# Display comprehensive version information
234
show_versions()
235
236
# Example output:
237
# INSTALLED VERSIONS
238
# ------------------
239
# commit : None
240
# python : 3.9.7
241
# python-bits : 64
242
# OS : Linux
243
# OS-release : 5.4.0
244
# machine : x86_64
245
# processor : x86_64
246
# byteorder : little
247
# LC_ALL : None
248
# LANG : en_US.UTF-8
249
# LOCALE : en_US.UTF-8
250
#
251
# geopandas : 0.12.0
252
# pandas : 1.4.2
253
# fiona : 1.8.21
254
# numpy : 1.21.6
255
# shapely : 1.8.2
256
# pyproj : 3.3.1
257
# ...
258
```
259
260
### Custom Testing Workflows
261
262
```python
263
def test_spatial_workflow():
264
"""Example of testing a complete spatial analysis workflow."""
265
266
# 1. Create test data
267
points = gpd.GeoDataFrame({
268
'id': [1, 2, 3],
269
'geometry': [Point(0, 0), Point(1, 1), Point(2, 2)]
270
}, crs='EPSG:4326')
271
272
polygons = gpd.GeoDataFrame({
273
'zone': ['A', 'B'],
274
'geometry': [
275
Polygon([(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)]),
276
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)])
277
]
278
}, crs='EPSG:4326')
279
280
# 2. Perform spatial join
281
result = gpd.sjoin(points, polygons, how='left', predicate='within')
282
283
# 3. Test results
284
expected_zones = ['A', 'B', None] # Point 3 should be outside both zones
285
286
# Check that join produced expected zone assignments
287
for i, expected_zone in enumerate(expected_zones):
288
if expected_zone is None:
289
assert pd.isna(result.loc[i, 'zone'])
290
else:
291
assert result.loc[i, 'zone'] == expected_zone
292
293
# 4. Test geometric consistency
294
assert_geodataframe_equal(
295
result[['id', 'geometry']],
296
points[['id', 'geometry']]
297
)
298
299
print("Spatial workflow test passed!")
300
301
# Run the test
302
test_spatial_workflow()
303
```