or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

coordinate-systems.mdcore-data-structures.mdfile-io.mdgeometric-operations.mdindex.mdspatial-relationships.mdtesting-utilities.mdvisualization.md

spatial-relationships.mddocs/

0

# Spatial Relationships

1

2

GeoPandas provides comprehensive spatial relationship operations including spatial joins, overlays, and geometric predicates. These operations enable complex spatial analysis by testing relationships between geometries and combining datasets based on spatial criteria.

3

4

## Capabilities

5

6

### Spatial Predicates

7

8

Binary spatial predicates that test relationships between geometries.

9

10

```python { .api }

11

class GeoSeries:

12

def contains(self, other, align=True):

13

"""

14

Test whether each geometry contains the other geometry.

15

16

Parameters:

17

- other: GeoSeries or single geometry

18

- align: Whether to align indices before operation

19

20

Returns:

21

- pandas.Series: Boolean values indicating containment

22

"""

23

...

24

25

def within(self, other, align=True):

26

"""

27

Test whether each geometry is within the other geometry.

28

29

Parameters:

30

- other: GeoSeries or single geometry

31

- align: Whether to align indices before operation

32

33

Returns:

34

- pandas.Series: Boolean values indicating within relationship

35

"""

36

...

37

38

def intersects(self, other, align=True):

39

"""

40

Test whether each geometry intersects the other geometry.

41

42

Parameters:

43

- other: GeoSeries or single geometry

44

- align: Whether to align indices before operation

45

46

Returns:

47

- pandas.Series: Boolean values indicating intersection

48

"""

49

...

50

51

def touches(self, other, align=True):

52

"""

53

Test whether each geometry touches the other geometry.

54

55

Parameters:

56

- other: GeoSeries or single geometry

57

- align: Whether to align indices before operation

58

59

Returns:

60

- pandas.Series: Boolean values indicating touch relationship

61

"""

62

...

63

64

def crosses(self, other, align=True):

65

"""

66

Test whether each geometry crosses the other geometry.

67

68

Parameters:

69

- other: GeoSeries or single geometry

70

- align: Whether to align indices before operation

71

72

Returns:

73

- pandas.Series: Boolean values indicating crossing

74

"""

75

...

76

77

def disjoint(self, other, align=True):

78

"""

79

Test whether each geometry is disjoint from the other geometry.

80

81

Parameters:

82

- other: GeoSeries or single geometry

83

- align: Whether to align indices before operation

84

85

Returns:

86

- pandas.Series: Boolean values indicating disjoint relationship

87

"""

88

...

89

90

def overlaps(self, other, align=True):

91

"""

92

Test whether each geometry overlaps the other geometry.

93

94

Parameters:

95

- other: GeoSeries or single geometry

96

- align: Whether to align indices before operation

97

98

Returns:

99

- pandas.Series: Boolean values indicating overlap

100

"""

101

...

102

103

def covers(self, other, align=True):

104

"""

105

Test whether each geometry covers the other geometry.

106

107

Parameters:

108

- other: GeoSeries or single geometry

109

- align: Whether to align indices before operation

110

111

Returns:

112

- pandas.Series: Boolean values indicating coverage

113

"""

114

...

115

116

def covered_by(self, other, align=True):

117

"""

118

Test whether each geometry is covered by the other geometry.

119

120

Parameters:

121

- other: GeoSeries or single geometry

122

- align: Whether to align indices before operation

123

124

Returns:

125

- pandas.Series: Boolean values indicating covered_by relationship

126

"""

127

...

128

129

def contains_properly(self, other, align=True):

130

"""

131

Test whether each geometry properly contains the other geometry.

132

133

Parameters:

134

- other: GeoSeries or single geometry

135

- align: Whether to align indices before operation

136

137

Returns:

138

- pandas.Series: Boolean values indicating proper containment

139

"""

140

...

141

142

def geom_equals(self, other, align=True):

143

"""

144

Test whether each geometry is geometrically equal to the other.

145

146

Parameters:

147

- other: GeoSeries or single geometry

148

- align: Whether to align indices before operation

149

150

Returns:

151

- pandas.Series: Boolean values indicating geometric equality

152

"""

153

...

154

155

def geom_equals_exact(self, other, tolerance, align=True):

156

"""

157

Test whether each geometry is exactly equal to the other within tolerance.

158

159

Parameters:

160

- other: GeoSeries or single geometry

161

- tolerance: Coordinate tolerance for comparison

162

- align: Whether to align indices before operation

163

164

Returns:

165

- pandas.Series: Boolean values indicating exact equality

166

"""

167

...

168

169

def dwithin(self, other, distance, align=True):

170

"""

171

Test whether each geometry is within specified distance of the other.

172

173

Parameters:

174

- other: GeoSeries or single geometry

175

- distance: Maximum distance threshold

176

- align: Whether to align indices before operation

177

178

Returns:

179

- pandas.Series: Boolean values indicating within-distance relationship

180

"""

181

...

182

183

def covered_by(self, other, align=True):

184

"""

185

Test whether each geometry is covered by the other geometry.

186

187

Parameters:

188

- other: GeoSeries or single geometry

189

- align: Whether to align indices before operation

190

191

Returns:

192

- pandas.Series: Boolean values indicating covered relationship

193

"""

194

...

195

```

196

197

### Distance Operations

198

199

Functions for calculating distances between geometries.

200

201

```python { .api }

202

class GeoSeries:

203

def distance(self, other, align=True):

204

"""

205

Calculate distance to other geometry.

206

207

Parameters:

208

- other: GeoSeries or single geometry

209

- align: Whether to align indices before operation

210

211

Returns:

212

- pandas.Series: Distance values (units depend on CRS)

213

"""

214

...

215

```

216

217

### Set Operations

218

219

Geometric set operations that combine geometries.

220

221

```python { .api }

222

class GeoSeries:

223

def intersection(self, other, align=True):

224

"""

225

Calculate intersection with other geometry.

226

227

Parameters:

228

- other: GeoSeries or single geometry

229

- align: Whether to align indices before operation

230

231

Returns:

232

- GeoSeries: Intersection geometries

233

"""

234

...

235

236

def union(self, other, align=True):

237

"""

238

Calculate union with other geometry.

239

240

Parameters:

241

- other: GeoSeries or single geometry

242

- align: Whether to align indices before operation

243

244

Returns:

245

- GeoSeries: Union geometries

246

"""

247

...

248

249

def difference(self, other, align=True):

250

"""

251

Calculate difference from other geometry.

252

253

Parameters:

254

- other: GeoSeries or single geometry

255

- align: Whether to align indices before operation

256

257

Returns:

258

- GeoSeries: Difference geometries

259

"""

260

...

261

262

def symmetric_difference(self, other, align=True):

263

"""

264

Calculate symmetric difference with other geometry.

265

266

Parameters:

267

- other: GeoSeries or single geometry

268

- align: Whether to align indices before operation

269

270

Returns:

271

- GeoSeries: Symmetric difference geometries

272

"""

273

...

274

275

def unary_union(self):

276

"""

277

Calculate union of all geometries in the series.

278

279

Returns:

280

- shapely.geometry: Single unified geometry

281

"""

282

...

283

```

284

285

### Spatial Joins

286

287

Functions for joining datasets based on spatial relationships.

288

289

```python { .api }

290

def sjoin(left_df, right_df, how='inner', predicate='intersects', lsuffix='left', rsuffix='right', **kwargs):

291

"""

292

Spatial join of two GeoDataFrames.

293

294

Parameters:

295

- left_df: Left GeoDataFrame

296

- right_df: Right GeoDataFrame

297

- how: Type of join ('left', 'right', 'outer', 'inner')

298

- predicate: Spatial predicate ('intersects', 'within', 'contains', 'overlaps', 'crosses', 'touches')

299

- lsuffix: Suffix for left DataFrame column conflicts

300

- rsuffix: Suffix for right DataFrame column conflicts

301

- **kwargs: Additional parameters

302

303

Returns:

304

- GeoDataFrame: Spatially joined data

305

"""

306

...

307

308

def sjoin_nearest(left_df, right_df, how='inner', max_distance=None, lsuffix='left', rsuffix='right', distance_col=None, **kwargs):

309

"""

310

Spatial join to nearest geometries.

311

312

Parameters:

313

- left_df: Left GeoDataFrame

314

- right_df: Right GeoDataFrame

315

- how: Type of join ('left', 'right', 'outer', 'inner')

316

- max_distance: Maximum distance for nearest neighbor search

317

- lsuffix: Suffix for left DataFrame column conflicts

318

- rsuffix: Suffix for right DataFrame column conflicts

319

- distance_col: Name for distance column in result

320

- **kwargs: Additional parameters

321

322

Returns:

323

- GeoDataFrame: Spatially joined data with nearest neighbors

324

"""

325

...

326

```

327

328

### Overlay Operations

329

330

Functions for geometric overlay operations between datasets.

331

332

```python { .api }

333

def overlay(df1, df2, how='intersection', keep_geom_type=None, make_valid=True):

334

"""

335

Perform geometric overlay operation between two GeoDataFrames.

336

337

Parameters:

338

- df1: First GeoDataFrame

339

- df2: Second GeoDataFrame

340

- how: Overlay operation ('intersection', 'union', 'identity', 'symmetric_difference', 'difference')

341

- keep_geom_type: Whether to keep only original geometry types

342

- make_valid: Whether to make invalid geometries valid before operation

343

344

Returns:

345

- GeoDataFrame: Result of overlay operation

346

"""

347

...

348

```

349

350

### Clipping Operations

351

352

Functions for clipping geometries by masks.

353

354

```python { .api }

355

def clip(gdf, mask, keep_geom_type=False, sort=False):

356

"""

357

Clip geometries to the boundary of another geometry.

358

359

Parameters:

360

- gdf: GeoDataFrame to clip

361

- mask: Geometry or GeoDataFrame to use as clipping mask

362

- keep_geom_type: Whether to keep only original geometry types

363

- sort: Whether to sort the result by index

364

365

Returns:

366

- GeoDataFrame: Clipped geometries

367

"""

368

...

369

```

370

371

### Geocoding Operations

372

373

Functions for converting between addresses and coordinates.

374

375

```python { .api }

376

def geocode(strings, provider=None, **kwargs):

377

"""

378

Geocode addresses to coordinates.

379

380

Parameters:

381

- strings: List or Series of address strings

382

- provider: Geocoding provider name

383

- **kwargs: Provider-specific parameters

384

385

Returns:

386

- GeoDataFrame: Geocoded addresses with geometry points

387

"""

388

...

389

390

def reverse_geocode(points, provider=None, **kwargs):

391

"""

392

Reverse geocode coordinates to addresses.

393

394

Parameters:

395

- points: GeoSeries of Point geometries or array-like coordinates

396

- provider: Geocoding provider name

397

- **kwargs: Provider-specific parameters

398

399

Returns:

400

- GeoDataFrame: Reverse geocoded coordinates with address information

401

"""

402

...

403

```

404

405

### Geometry Utilities

406

407

Utility functions for working with collections of geometries.

408

409

```python { .api }

410

def collect(x, multi=False):

411

"""

412

Collect geometries into a GeometryCollection or Multi-geometry.

413

414

Parameters:

415

- x: Array-like of geometries

416

- multi: Whether to create Multi-geometry instead of GeometryCollection

417

418

Returns:

419

- shapely.geometry: GeometryCollection or Multi-geometry

420

"""

421

...

422

```

423

424

## Usage Examples

425

426

### Spatial Predicates

427

428

```python

429

import geopandas as gpd

430

from shapely.geometry import Point, Polygon

431

432

# Create sample data

433

points = gpd.GeoDataFrame({

434

'id': [1, 2, 3, 4],

435

'geometry': [Point(1, 1), Point(3, 3), Point(5, 1), Point(2, 4)]

436

})

437

438

polygons = gpd.GeoDataFrame({

439

'name': ['A', 'B'],

440

'geometry': [

441

Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]), # Square A

442

Polygon([(3, 2), (5, 2), (5, 4), (3, 4)]) # Square B

443

]

444

})

445

446

# Test spatial relationships

447

polygon_a = polygons.geometry.iloc[0]

448

449

# Points within polygon A

450

within_a = points.geometry.within(polygon_a)

451

print(f"Points within A: {points[within_a]['id'].tolist()}")

452

453

# Points intersecting polygon A

454

intersect_a = points.geometry.intersects(polygon_a)

455

print(f"Points intersecting A: {points[intersect_a]['id'].tolist()}")

456

457

# Test between all combinations

458

for i, poly in polygons.iterrows():

459

contained = points.geometry.within(poly['geometry'])

460

print(f"Points in {poly['name']}: {points[contained]['id'].tolist()}")

461

```

462

463

### Distance Calculations

464

465

```python

466

# Calculate distances between points and polygons

467

distances_to_a = points.geometry.distance(polygons.geometry.iloc[0])

468

print(f"Distances to polygon A: {distances_to_a}")

469

470

# Find nearest polygon for each point

471

distances_to_all = []

472

for _, poly in polygons.iterrows():

473

dist = points.geometry.distance(poly['geometry'])

474

distances_to_all.append(dist)

475

476

# Create distance matrix

477

import pandas as pd

478

distance_matrix = pd.DataFrame(distances_to_all,

479

index=polygons['name'],

480

columns=points['id']).T

481

print("Distance matrix:")

482

print(distance_matrix)

483

484

# Find nearest polygon for each point

485

nearest_polygon = distance_matrix.idxmin(axis=1)

486

print(f"Nearest polygon for each point: {nearest_polygon}")

487

```

488

489

### Spatial Joins

490

491

```python

492

# Join points to polygons they fall within

493

joined = gpd.sjoin(points, polygons, how='left', predicate='within')

494

print("Points joined to containing polygons:")

495

print(joined[['id', 'name']])

496

497

# Join points to all intersecting polygons

498

joined_intersects = gpd.sjoin(points, polygons, how='left', predicate='intersects')

499

print("Points joined to intersecting polygons:")

500

print(joined_intersects[['id', 'name']])

501

502

# Join to nearest polygon regardless of containment

503

joined_nearest = gpd.sjoin_nearest(points, polygons, how='left')

504

print("Points joined to nearest polygons:")

505

print(joined_nearest[['id', 'name']])

506

507

# Join with distance threshold

508

joined_near = gpd.sjoin_nearest(points, polygons, how='left',

509

max_distance=1.0, distance_col='distance')

510

print("Points within 1.0 unit of polygons:")

511

print(joined_near[['id', 'name', 'distance']].dropna())

512

```

513

514

### Set Operations

515

516

```python

517

# Create overlapping polygons

518

poly1 = gpd.GeoDataFrame({

519

'id': [1],

520

'geometry': [Polygon([(0, 0), (3, 0), (3, 3), (0, 3)])]

521

})

522

523

poly2 = gpd.GeoDataFrame({

524

'id': [2],

525

'geometry': [Polygon([(2, 2), (5, 2), (5, 5), (2, 5)])]

526

})

527

528

# Calculate geometric intersections

529

intersection = poly1.geometry.intersection(poly2.geometry.iloc[0])

530

union = poly1.geometry.union(poly2.geometry.iloc[0])

531

difference = poly1.geometry.difference(poly2.geometry.iloc[0])

532

sym_diff = poly1.geometry.symmetric_difference(poly2.geometry.iloc[0])

533

534

print(f"Intersection area: {intersection.iloc[0].area}")

535

print(f"Union area: {union.iloc[0].area}")

536

print(f"Difference area: {difference.iloc[0].area}")

537

print(f"Symmetric difference area: {sym_diff.iloc[0].area}")

538

```

539

540

### Overlay Operations

541

542

```python

543

# Perform overlay operations

544

intersection_overlay = gpd.overlay(poly1, poly2, how='intersection')

545

union_overlay = gpd.overlay(poly1, poly2, how='union')

546

difference_overlay = gpd.overlay(poly1, poly2, how='difference')

547

548

print("Intersection overlay:")

549

print(intersection_overlay[['id_1', 'id_2', 'geometry']])

550

551

print("Union overlay:")

552

print(union_overlay[['id_1', 'id_2', 'geometry']])

553

554

# Identity overlay (keeps all of first dataset)

555

identity_overlay = gpd.overlay(poly1, poly2, how='identity')

556

print("Identity overlay:")

557

print(identity_overlay)

558

```

559

560

### Clipping Operations

561

562

```python

563

# Create data to clip

564

lines = gpd.GeoDataFrame({

565

'id': [1, 2, 3],

566

'geometry': [

567

LineString([(0, 1), (4, 1)]), # Crosses polygon

568

LineString([(1, 0), (1, 4)]), # Crosses polygon

569

LineString([(6, 0), (6, 4)]) # Outside polygon

570

]

571

})

572

573

# Clip lines to polygon boundary

574

clipping_polygon = Polygon([(0.5, 0.5), (3.5, 0.5), (3.5, 3.5), (0.5, 3.5)])

575

clipped_lines = gpd.clip(lines, clipping_polygon)

576

577

print("Original lines:", len(lines))

578

print("Clipped lines:", len(clipped_lines))

579

print("Clipped geometries:")

580

for i, geom in enumerate(clipped_lines.geometry):

581

print(f" Line {i+1}: {geom}")

582

```

583

584

### Complex Spatial Analysis

585

586

```python

587

# Load real world data

588

world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))

589

cities = gpd.read_file(gpd.datasets.get_path('naturalearth_cities'))

590

591

# Find cities within each country

592

cities_in_countries = gpd.sjoin(cities, world, how='left', predicate='within')

593

594

# Count cities per country

595

cities_per_country = (cities_in_countries

596

.groupby('name_right')

597

.size()

598

.sort_values(ascending=False))

599

print("Top 10 countries by number of cities:")

600

print(cities_per_country.head(10))

601

602

# Find countries that border the ocean (simplified)

603

# Create buffer around all land

604

land_union = world.geometry.unary_union

605

ocean_buffer = land_union.buffer(0.1) # Small buffer

606

607

# Countries touching the buffer are coastal

608

coastal_countries = world[world.geometry.touches(ocean_buffer)]

609

print(f"Number of coastal countries: {len(coastal_countries)}")

610

611

# Calculate distance from each city to nearest country border

612

country_boundaries = world.geometry.boundary

613

cities['dist_to_border'] = cities.geometry.apply(

614

lambda city: min(city.distance(boundary) for boundary in country_boundaries)

615

)

616

print("Cities farthest from any border:")

617

print(cities.nlargest(5, 'dist_to_border')[['name', 'dist_to_border']])

618

```