0
# Geometric Operations
1
2
GeoPandas provides a comprehensive set of geometric operations for spatial analysis and geometric computations. These operations work on individual geometries and return new geometric objects or scalar values, enabling complex spatial analysis workflows.
3
4
## Capabilities
5
6
### Geometric Properties
7
8
Properties that return scalar values describing geometric characteristics.
9
10
```python { .api }
11
class GeoSeries:
12
@property
13
def area(self):
14
"""
15
Area of each geometry in the GeoSeries.
16
17
Returns:
18
- pandas.Series: Area values (units depend on CRS)
19
"""
20
...
21
22
@property
23
def length(self):
24
"""
25
Length of each geometry in the GeoSeries.
26
27
Returns:
28
- pandas.Series: Length values (units depend on CRS)
29
"""
30
...
31
32
@property
33
def geom_type(self):
34
"""
35
Geometry type of each geometry.
36
37
Returns:
38
- pandas.Series: Geometry type names ('Point', 'LineString', etc.)
39
"""
40
...
41
42
@property
43
def is_empty(self):
44
"""
45
Whether each geometry is empty.
46
47
Returns:
48
- pandas.Series: Boolean values indicating if geometry is empty
49
"""
50
...
51
52
@property
53
def is_ring(self):
54
"""
55
Whether each geometry is a closed ring.
56
57
Returns:
58
- pandas.Series: Boolean values indicating if geometry is a ring
59
"""
60
...
61
62
@property
63
def is_simple(self):
64
"""
65
Whether each geometry is simple (non-self-intersecting).
66
67
Returns:
68
- pandas.Series: Boolean values indicating if geometry is simple
69
"""
70
...
71
72
@property
73
def is_valid(self):
74
"""
75
Whether each geometry is valid.
76
77
Returns:
78
- pandas.Series: Boolean values indicating if geometry is valid
79
"""
80
...
81
82
@property
83
def is_closed(self):
84
"""
85
Whether each LinearRing or LineString geometry is closed.
86
87
Returns:
88
- pandas.Series: Boolean values indicating if geometry is closed
89
"""
90
...
91
92
@property
93
def is_ccw(self):
94
"""
95
Whether each LinearRing geometry has counter-clockwise orientation.
96
97
Returns:
98
- pandas.Series: Boolean values indicating counter-clockwise orientation
99
"""
100
...
101
102
@property
103
def has_z(self):
104
"""
105
Whether each geometry has Z (3D) coordinates.
106
107
Returns:
108
- pandas.Series: Boolean values indicating presence of Z coordinates
109
"""
110
...
111
112
@property
113
def has_m(self):
114
"""
115
Whether each geometry has M (measure) coordinates.
116
117
Returns:
118
- pandas.Series: Boolean values indicating presence of M coordinates
119
"""
120
...
121
```
122
123
### Geometric Constructors
124
125
Methods that create new geometries based on existing ones.
126
127
```python { .api }
128
class GeoSeries:
129
def buffer(self, distance, resolution=16, **kwargs):
130
"""
131
Buffer each geometry by given distance.
132
133
Parameters:
134
- distance: Buffer distance (units depend on CRS)
135
- resolution: Number of segments for circular arcs
136
- **kwargs: Additional parameters for shapely buffer
137
138
Returns:
139
- GeoSeries: Buffered geometries
140
"""
141
...
142
143
def boundary(self):
144
"""
145
Boundary of each geometry.
146
147
Returns:
148
- GeoSeries: Boundary geometries
149
"""
150
...
151
152
def centroid(self):
153
"""
154
Centroid of each geometry.
155
156
Returns:
157
- GeoSeries: Point geometries representing centroids
158
"""
159
...
160
161
def convex_hull(self):
162
"""
163
Convex hull of each geometry.
164
165
Returns:
166
- GeoSeries: Convex hull geometries
167
"""
168
...
169
170
def envelope(self):
171
"""
172
Envelope (bounding box) of each geometry.
173
174
Returns:
175
- GeoSeries: Rectangular envelope geometries
176
"""
177
...
178
179
def exterior(self):
180
"""
181
Exterior ring of each Polygon geometry.
182
183
Returns:
184
- GeoSeries: LinearRing geometries
185
"""
186
...
187
188
def interiors(self):
189
"""
190
Interior rings of each Polygon geometry.
191
192
Returns:
193
- pandas.Series: Lists of LinearRing geometries
194
"""
195
...
196
197
def representative_point(self):
198
"""
199
Representative point for each geometry (guaranteed to be within geometry).
200
201
Returns:
202
- GeoSeries: Point geometries within original geometries
203
"""
204
...
205
206
def simplify(self, tolerance, preserve_topology=True):
207
"""
208
Simplify geometries using Douglas-Peucker algorithm.
209
210
Parameters:
211
- tolerance: Simplification tolerance (units depend on CRS)
212
- preserve_topology: Whether to preserve topology
213
214
Returns:
215
- GeoSeries: Simplified geometries
216
"""
217
...
218
219
def minimum_rotated_rectangle(self):
220
"""
221
Minimum rotated bounding rectangle for each geometry.
222
223
Returns:
224
- GeoSeries: Rectangular geometries with minimum area enclosing original
225
"""
226
...
227
228
def minimum_bounding_circle(self):
229
"""
230
Minimum bounding circle for each geometry.
231
232
Returns:
233
- GeoSeries: Circular geometries with minimum area enclosing original
234
"""
235
...
236
237
def minimum_bounding_radius(self):
238
"""
239
Radius of minimum bounding circle for each geometry.
240
241
Returns:
242
- pandas.Series: Radius values for minimum bounding circles
243
"""
244
...
245
246
def concave_hull(self, ratio=0.0, allow_holes=False):
247
"""
248
Concave hull of each geometry using alpha shapes algorithm.
249
250
Parameters:
251
- ratio: Ratio parameter controlling concaveness (0.0 = convex hull, 1.0 = maximum concaveness)
252
- allow_holes: Whether to allow holes in the hull
253
254
Returns:
255
- GeoSeries: Concave hull geometries
256
"""
257
...
258
259
def delaunay_triangles(self, tolerance=0.0, only_edges=False):
260
"""
261
Delaunay triangulation of geometry coordinates.
262
263
Parameters:
264
- tolerance: Coordinate tolerance for triangulation
265
- only_edges: Return only triangle edges instead of filled triangles
266
267
Returns:
268
- GeoSeries: Triangle geometries or edge LineStrings
269
"""
270
...
271
272
def voronoi_polygons(self, tolerance=0.0, extend_to=None, only_edges=False):
273
"""
274
Voronoi diagram of Point geometries.
275
276
Parameters:
277
- tolerance: Coordinate tolerance for diagram generation
278
- extend_to: Geometry to extend diagram to (default: bounding box)
279
- only_edges: Return only diagram edges instead of filled polygons
280
281
Returns:
282
- GeoSeries: Voronoi polygon geometries or edge LineStrings
283
"""
284
...
285
286
def offset_curve(self, distance, quad_segs=8, join_style=1, mitre_limit=5.0):
287
"""
288
Create offset curve (parallel line) from LineString geometries.
289
290
Parameters:
291
- distance: Offset distance (positive for left, negative for right)
292
- quad_segs: Number of segments for quarter circle
293
- join_style: Join style (1=round, 2=mitre, 3=bevel)
294
- mitre_limit: Mitre ratio limit for mitre joins
295
296
Returns:
297
- GeoSeries: Offset curve geometries
298
"""
299
...
300
301
def line_merge(self, directed=False):
302
"""
303
Merge connected LineString geometries into continuous lines.
304
305
Parameters:
306
- directed: Whether to consider line direction in merging
307
308
Returns:
309
- GeoSeries: Merged LineString or MultiLineString geometries
310
"""
311
...
312
```
313
314
### Linear Referencing
315
316
Methods for working with linear geometries and distance-based positioning.
317
318
```python { .api }
319
class GeoSeries:
320
def project(self, other, normalized=False):
321
"""
322
Project point onto line geometry and return distance along line.
323
324
Parameters:
325
- other: Point geometry or GeoSeries of Points to project
326
- normalized: Return distance as fraction of line length (0.0 to 1.0)
327
328
Returns:
329
- pandas.Series: Distance values along the line
330
"""
331
...
332
333
def interpolate(self, distance, normalized=False):
334
"""
335
Return point at specified distance along line geometry.
336
337
Parameters:
338
- distance: Distance along line or array of distances
339
- normalized: Interpret distance as fraction of line length
340
341
Returns:
342
- GeoSeries: Point geometries at specified distances
343
"""
344
...
345
```
346
347
### Affine Transformations
348
349
Methods for applying affine transformations to geometries.
350
351
```python { .api }
352
class GeoSeries:
353
def translate(self, xoff=0.0, yoff=0.0, zoff=0.0):
354
"""
355
Translate geometries by given offsets.
356
357
Parameters:
358
- xoff: X offset
359
- yoff: Y offset
360
- zoff: Z offset
361
362
Returns:
363
- GeoSeries: Translated geometries
364
"""
365
...
366
367
def rotate(self, angle, origin='center', use_radians=False):
368
"""
369
Rotate geometries by given angle.
370
371
Parameters:
372
- angle: Rotation angle
373
- origin: Center of rotation ('center', 'centroid', or Point)
374
- use_radians: Whether angle is in radians (default: degrees)
375
376
Returns:
377
- GeoSeries: Rotated geometries
378
"""
379
...
380
381
def scale(self, xfact=1.0, yfact=1.0, zfact=1.0, origin='center'):
382
"""
383
Scale geometries by given factors.
384
385
Parameters:
386
- xfact: X scale factor
387
- yfact: Y scale factor
388
- zfact: Z scale factor
389
- origin: Center of scaling ('center', 'centroid', or Point)
390
391
Returns:
392
- GeoSeries: Scaled geometries
393
"""
394
...
395
396
def skew(self, xs=0.0, ys=0.0, origin='center', use_radians=False):
397
"""
398
Skew geometries by given angles.
399
400
Parameters:
401
- xs: X skew angle
402
- ys: Y skew angle
403
- origin: Center of skewing ('center', 'centroid', or Point)
404
- use_radians: Whether angles are in radians (default: degrees)
405
406
Returns:
407
- GeoSeries: Skewed geometries
408
"""
409
...
410
```
411
412
### Coordinate Access
413
414
Properties for accessing coordinate information from Point geometries.
415
416
```python { .api }
417
class GeoSeries:
418
@property
419
def x(self):
420
"""
421
X coordinates of Point geometries.
422
423
Returns:
424
- pandas.Series: X coordinate values (NaN for non-Point geometries)
425
"""
426
...
427
428
@property
429
def y(self):
430
"""
431
Y coordinates of Point geometries.
432
433
Returns:
434
- pandas.Series: Y coordinate values (NaN for non-Point geometries)
435
"""
436
...
437
438
@property
439
def z(self):
440
"""
441
Z coordinates of Point geometries.
442
443
Returns:
444
- pandas.Series: Z coordinate values (NaN for 2D or non-Point geometries)
445
"""
446
...
447
448
@property
449
def m(self):
450
"""
451
M coordinates of Point geometries.
452
453
Returns:
454
- pandas.Series: M coordinate values (NaN for non-M or non-Point geometries)
455
"""
456
...
457
458
@property
459
def bounds(self):
460
"""
461
Bounds of each geometry as (minx, miny, maxx, maxy).
462
463
Returns:
464
- pandas.DataFrame: DataFrame with minx, miny, maxx, maxy columns
465
"""
466
...
467
468
@property
469
def total_bounds(self):
470
"""
471
Total bounds of all geometries as (minx, miny, maxx, maxy).
472
473
Returns:
474
- numpy.ndarray: Array with [minx, miny, maxx, maxy]
475
"""
476
...
477
```
478
479
### Geometric Validation and Repair
480
481
Methods for validating and repairing geometries.
482
483
```python { .api }
484
class GeoSeries:
485
def make_valid(self, method='auto'):
486
"""
487
Make invalid geometries valid.
488
489
Parameters:
490
- method: Repair method ('auto', 'structure', 'linework')
491
492
Returns:
493
- GeoSeries: Valid geometries
494
"""
495
...
496
497
def normalize(self):
498
"""
499
Normalize geometries to canonical form.
500
501
Returns:
502
- GeoSeries: Normalized geometries
503
"""
504
...
505
506
def is_valid_reason(self):
507
"""
508
Return reason why each geometry is invalid.
509
510
Returns:
511
- pandas.Series: Text descriptions of invalidity reasons
512
"""
513
...
514
515
def clip_by_rect(self, xmin, ymin, xmax, ymax):
516
"""
517
Clip geometries to rectangular bounds.
518
519
Parameters:
520
- xmin: Minimum X coordinate
521
- ymin: Minimum Y coordinate
522
- xmax: Maximum X coordinate
523
- ymax: Maximum Y coordinate
524
525
Returns:
526
- GeoSeries: Clipped geometries
527
"""
528
...
529
530
def snap(self, other, tolerance):
531
"""
532
Snap vertices of geometries to reference geometries within tolerance.
533
534
Parameters:
535
- other: Reference geometry or GeoSeries to snap to
536
- tolerance: Snapping tolerance distance
537
538
Returns:
539
- GeoSeries: Snapped geometries
540
"""
541
...
542
543
def polygonize(self, node=True, full=False):
544
"""
545
Create polygons from collection of LineString geometries.
546
547
Parameters:
548
- node: Whether to node the lines first
549
- full: Return all polygonization products
550
551
Returns:
552
- GeoSeries: Polygonal geometries
553
"""
554
...
555
556
def unary_union(self):
557
"""
558
Union all geometries in the series into a single geometry.
559
560
Returns:
561
- Geometry: Single geometry representing union of all geometries
562
"""
563
...
564
565
def get_coordinates(self, include_z=None, ignore_index=False, index_parts=False):
566
"""
567
Extract coordinate arrays from geometries.
568
569
Parameters:
570
- include_z: Include Z coordinates if available
571
- ignore_index: Reset index in result
572
- index_parts: Include part indices for multi-part geometries
573
574
Returns:
575
- pandas.DataFrame: Coordinate arrays with x, y (and optionally z) columns
576
"""
577
...
578
```
579
580
## Usage Examples
581
582
### Basic Geometric Properties
583
584
```python
585
import geopandas as gpd
586
from shapely.geometry import Point, Polygon, LineString
587
588
# Create sample geometries
589
gdf = gpd.GeoDataFrame({
590
'name': ['Circle', 'Square', 'Line'],
591
'geometry': [
592
Point(0, 0).buffer(1), # Circle
593
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]), # Square
594
LineString([(0, 0), (1, 1), (2, 0)]) # Line
595
]
596
})
597
598
# Calculate geometric properties
599
print(f"Areas: {gdf.geometry.area}")
600
print(f"Lengths: {gdf.geometry.length}")
601
print(f"Types: {gdf.geometry.geom_type}")
602
print(f"Bounds: {gdf.geometry.bounds}")
603
print(f"Total bounds: {gdf.geometry.total_bounds}")
604
```
605
606
### Geometric Constructors
607
608
```python
609
# Create derived geometries
610
centroids = gdf.geometry.centroid
611
envelopes = gdf.geometry.envelope
612
convex_hulls = gdf.geometry.convex_hull
613
boundaries = gdf.geometry.boundary
614
615
# Buffer operations
616
buffered_small = gdf.geometry.buffer(0.5)
617
buffered_large = gdf.geometry.buffer(2.0, resolution=32)
618
619
# Simplification
620
complex_line = LineString([(i/10, (i/10)**2) for i in range(100)])
621
simplified = gpd.GeoSeries([complex_line]).simplify(0.1)
622
```
623
624
### Affine Transformations
625
626
```python
627
# Translation
628
translated = gdf.geometry.translate(xoff=10, yoff=5)
629
630
# Rotation (45 degrees counterclockwise)
631
rotated = gdf.geometry.rotate(45, origin='center')
632
633
# Scaling
634
scaled = gdf.geometry.scale(xfact=2.0, yfact=0.5, origin='center')
635
636
# Skewing
637
skewed = gdf.geometry.skew(xs=15, ys=0, origin='center')
638
639
# Combine transformations
640
transformed = (gdf.geometry
641
.translate(xoff=5, yoff=5)
642
.rotate(30, origin='center')
643
.scale(xfact=1.5, yfact=1.5, origin='center'))
644
```
645
646
### Coordinate Access
647
648
```python
649
# Create points
650
points = gpd.GeoSeries([
651
Point(1, 2),
652
Point(3, 4, 5), # 3D point
653
Point(6, 7)
654
])
655
656
# Access coordinates
657
print(f"X coordinates: {points.x}")
658
print(f"Y coordinates: {points.y}")
659
print(f"Z coordinates: {points.z}") # NaN for 2D points
660
661
# For non-Point geometries, coordinates are NaN
662
mixed_geoms = gpd.GeoSeries([
663
Point(1, 2),
664
LineString([(0, 0), (1, 1)]),
665
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
666
])
667
print(f"X coordinates: {mixed_geoms.x}") # Only Point has valid X
668
```
669
670
### Working with Complex Geometries
671
672
```python
673
# Polygon with holes
674
exterior = [(0, 0), (10, 0), (10, 10), (0, 10)]
675
hole1 = [(2, 2), (4, 2), (4, 4), (2, 4)]
676
hole2 = [(6, 6), (8, 6), (8, 8), (6, 8)]
677
polygon_with_holes = Polygon(exterior, [hole1, hole2])
678
679
gdf_complex = gpd.GeoDataFrame({'geometry': [polygon_with_holes]})
680
681
# Access polygon components
682
exterior_ring = gdf_complex.geometry.exterior
683
interior_rings = gdf_complex.geometry.interiors
684
685
print(f"Exterior: {exterior_ring.iloc[0]}")
686
print(f"Number of holes: {len(interior_rings.iloc[0])}")
687
```
688
689
### Geometric Validation and Repair
690
691
```python
692
from shapely.geometry import Polygon
693
694
# Create invalid geometry (self-intersecting polygon)
695
invalid_polygon = Polygon([(0, 0), (2, 2), (2, 0), (0, 2)])
696
gdf_invalid = gpd.GeoDataFrame({'geometry': [invalid_polygon]})
697
698
# Check validity
699
print(f"Is valid: {gdf_invalid.geometry.is_valid.iloc[0]}")
700
701
# Repair invalid geometry
702
gdf_repaired = gdf_invalid.copy()
703
gdf_repaired['geometry'] = gdf_repaired.geometry.make_valid()
704
print(f"Repaired is valid: {gdf_repaired.geometry.is_valid.iloc[0]}")
705
706
# Normalize geometries
707
normalized = gdf_repaired.geometry.normalize()
708
```
709
710
### Area and Distance Calculations
711
712
```python
713
# For accurate measurements, use projected CRS
714
gdf_geographic = gpd.read_file('world.shp') # WGS84
715
716
# Convert to appropriate UTM zone for accurate area calculation
717
utm_crs = gdf_geographic.estimate_utm_crs()
718
gdf_utm = gdf_geographic.to_crs(utm_crs)
719
720
# Calculate areas in square meters
721
areas_sqm = gdf_utm.geometry.area
722
723
# Calculate perimeters in meters
724
perimeters_m = gdf_utm.geometry.length
725
726
# Convert back to square kilometers for readability
727
areas_sqkm = areas_sqm / 1_000_000
728
729
print(f"Country areas (sq km): {areas_sqkm}")
730
```
731
732
### Representative Points
733
734
```python
735
# For complex polygons, centroids might fall outside the geometry
736
# Representative points are guaranteed to be inside
737
complex_polygon = gpd.read_file('complex_country.shp')
738
739
centroids = complex_polygon.geometry.centroid
740
rep_points = complex_polygon.geometry.representative_point()
741
742
# Check which centroids fall outside their polygons
743
centroids_outside = ~complex_polygon.geometry.contains(centroids)
744
print(f"Centroids outside polygon: {centroids_outside.sum()}")
745
746
# Representative points are always inside
747
rep_points_inside = complex_polygon.geometry.contains(rep_points)
748
print(f"Representative points inside: {rep_points_inside.all()}")
749
```