0
# Coordinate Reference Systems
1
2
Comprehensive CRS handling including creation from various formats (EPSG, WKT, PROJ), conversion between formats, and validation. The CRS system is essential for proper geospatial data processing, ensuring that coordinates are interpreted correctly and can be transformed between different projections and datums.
3
4
## Capabilities
5
6
### CRS Class
7
8
The main interface for working with coordinate reference systems. Supports creation from and conversion to multiple formats including EPSG codes, WKT strings, and PROJ parameter dictionaries.
9
10
```python { .api }
11
class CRS:
12
def __init__(self, initialdata=None, **kwargs):
13
"""
14
Create a CRS from PROJ parameters or other CRS data.
15
16
Parameters:
17
- initialdata: dict or CRS, initial CRS data
18
- kwargs: dict, additional PROJ parameters
19
"""
20
21
@classmethod
22
def from_epsg(cls, code):
23
"""
24
Create CRS from EPSG authority code.
25
26
Parameters:
27
- code: int, EPSG code (e.g., 4326 for WGS84)
28
29
Returns:
30
CRS instance
31
32
Raises:
33
- CRSError: If EPSG code is invalid or not found
34
"""
35
36
@classmethod
37
def from_wkt(cls, wkt, morph_from_esri_dialect=False):
38
"""
39
Create CRS from Well-Known Text string.
40
41
Parameters:
42
- wkt: str, WKT representation of CRS
43
- morph_from_esri_dialect: bool, convert from ESRI WKT format
44
45
Returns:
46
CRS instance
47
48
Raises:
49
- CRSError: If WKT string is invalid
50
"""
51
52
@classmethod
53
def from_dict(cls, initialdata=None, **kwargs):
54
"""
55
Create CRS from PROJ parameter dictionary.
56
57
Parameters:
58
- initialdata: dict, PROJ parameters
59
- kwargs: dict, additional PROJ parameters
60
61
Returns:
62
CRS instance
63
"""
64
65
@classmethod
66
def from_string(cls, value, morph_from_esri_dialect=False):
67
"""
68
Create CRS from various string formats.
69
70
Parameters:
71
- value: str, CRS string (PROJ4, WKT, EPSG:code, etc.)
72
- morph_from_esri_dialect: bool, convert from ESRI format
73
74
Returns:
75
CRS instance
76
77
Raises:
78
- CRSError: If string format is not recognized
79
"""
80
81
@classmethod
82
def from_user_input(cls, value, morph_from_esri_dialect=False):
83
"""
84
Create CRS from flexible user input.
85
86
Parameters:
87
- value: str, dict, or CRS, various input formats
88
- morph_from_esri_dialect: bool, convert from ESRI format
89
90
Returns:
91
CRS instance
92
"""
93
94
@classmethod
95
def from_authority(cls, auth_name, code):
96
"""
97
Create CRS from authority name and code.
98
99
Parameters:
100
- auth_name: str, authority name (e.g., 'EPSG', 'ESRI')
101
- code: str or int, authority code
102
103
Returns:
104
CRS instance
105
"""
106
107
def to_dict(self, projjson=False):
108
"""
109
Convert CRS to PROJ parameter dictionary.
110
111
Parameters:
112
- projjson: bool, return PROJJSON format if True
113
114
Returns:
115
dict: PROJ parameters or PROJJSON
116
"""
117
118
def to_wkt(self, morph_to_esri_dialect=False, version=None):
119
"""
120
Convert CRS to Well-Known Text string.
121
122
Parameters:
123
- morph_to_esri_dialect: bool, convert to ESRI WKT format
124
- version: WktVersion, WKT format version
125
126
Returns:
127
str: WKT representation
128
"""
129
130
def to_epsg(self, confidence_threshold=70):
131
"""
132
Convert CRS to EPSG code if possible.
133
134
Parameters:
135
- confidence_threshold: int, minimum confidence for match (0-100)
136
137
Returns:
138
int or None: EPSG code if found
139
"""
140
141
def to_authority(self, confidence_threshold=70):
142
"""
143
Convert CRS to authority name and code.
144
145
Parameters:
146
- confidence_threshold: int, minimum confidence for match
147
148
Returns:
149
tuple or None: (authority_name, code) if found
150
"""
151
152
def to_string(self):
153
"""
154
Convert CRS to string representation.
155
156
Returns:
157
str: PROJ4 or WKT string representation
158
"""
159
160
@property
161
def data(self):
162
"""Get PROJ4 dictionary representation."""
163
164
@property
165
def wkt(self):
166
"""Get OGC WKT representation."""
167
168
@property
169
def is_valid(self):
170
"""Test if CRS is valid."""
171
172
@property
173
def is_geographic(self):
174
"""Test if CRS is geographic (lat/lon)."""
175
176
@property
177
def is_projected(self):
178
"""Test if CRS is projected."""
179
180
@property
181
def is_epsg_code(self):
182
"""Test if CRS is defined by an EPSG code."""
183
184
@property
185
def linear_units(self):
186
"""Get short name for linear units."""
187
188
@property
189
def linear_units_factor(self):
190
"""Get linear units and conversion factor to meters."""
191
```
192
193
#### Usage Examples
194
195
```python
196
from fiona.crs import CRS
197
198
# Create CRS from EPSG code (most common)
199
wgs84 = CRS.from_epsg(4326) # WGS84 geographic
200
utm_zone_10n = CRS.from_epsg(32610) # UTM Zone 10N
201
web_mercator = CRS.from_epsg(3857) # Web Mercator
202
203
print(f"WGS84 is geographic: {wgs84.is_geographic}")
204
print(f"UTM is projected: {utm_zone_10n.is_projected}")
205
206
# Create from PROJ4 dictionary
207
proj_dict = {
208
'proj': 'lcc', # Lambert Conformal Conic
209
'lat_1': 33, # Standard parallel 1
210
'lat_2': 45, # Standard parallel 2
211
'lat_0': 39, # Latitude of origin
212
'lon_0': -96, # Central meridian
213
'x_0': 0, # False easting
214
'y_0': 0, # False northing
215
'datum': 'NAD83',
216
'units': 'm',
217
'no_defs': True
218
}
219
lcc_crs = CRS.from_dict(proj_dict)
220
221
# Create from WKT string
222
wkt_string = '''
223
GEOGCS["WGS 84",
224
DATUM["WGS_1984",
225
SPHEROID["WGS 84",6378137,298.257223563]],
226
PRIMEM["Greenwich",0],
227
UNIT["degree",0.0174532925199433]]
228
'''
229
wkt_crs = CRS.from_wkt(wkt_string)
230
231
# Create from various string formats
232
epsg_string_crs = CRS.from_string('EPSG:4326')
233
proj4_string_crs = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs')
234
235
# Flexible user input (automatically detects format)
236
user_crs = CRS.from_user_input('EPSG:4326') # EPSG code
237
user_crs2 = CRS.from_user_input(wgs84) # Existing CRS object
238
user_crs3 = CRS.from_user_input(proj_dict) # PROJ dict
239
240
# Convert between formats
241
crs = CRS.from_epsg(4326)
242
243
# Convert to different representations
244
proj_dict = crs.to_dict()
245
wkt_repr = crs.to_wkt()
246
epsg_code = crs.to_epsg()
247
authority = crs.to_authority()
248
249
print(f"PROJ dict: {proj_dict}")
250
print(f"WKT: {wkt_repr}")
251
print(f"EPSG: {epsg_code}")
252
print(f"Authority: {authority}")
253
254
# Check CRS properties
255
print(f"Linear units: {utm_zone_10n.linear_units}")
256
print(f"Units factor: {utm_zone_10n.linear_units_factor}")
257
print(f"Is valid: {crs.is_valid}")
258
```
259
260
### CRS Utility Functions
261
262
Helper functions for working with coordinate reference systems and coordinate order conventions.
263
264
```python { .api }
265
def epsg_treats_as_latlong(input_crs):
266
"""
267
Test if CRS should use latitude/longitude coordinate order.
268
269
Parameters:
270
- input_crs: CRS or CRS-like object
271
272
Returns:
273
bool: True if lat/lon order should be used
274
"""
275
276
def epsg_treats_as_northingeasting(input_crs):
277
"""
278
Test if CRS should use northing/easting coordinate order.
279
280
Parameters:
281
- input_crs: CRS or CRS-like object
282
283
Returns:
284
bool: True if northing/easting order should be used
285
"""
286
```
287
288
#### Usage Examples
289
290
```python
291
from fiona.crs import CRS, epsg_treats_as_latlong, epsg_treats_as_northingeasting
292
293
# Check coordinate order conventions
294
wgs84 = CRS.from_epsg(4326)
295
utm = CRS.from_epsg(32610)
296
297
print(f"WGS84 uses lat/lon order: {epsg_treats_as_latlong(wgs84)}")
298
print(f"UTM uses northing/easting: {epsg_treats_as_northingeasting(utm)}")
299
300
# This affects how you should interpret coordinates
301
if epsg_treats_as_latlong(wgs84):
302
# Coordinates should be interpreted as (latitude, longitude)
303
coords = (37.7749, -122.4194) # San Francisco
304
else:
305
# Coordinates should be interpreted as (longitude, latitude)
306
coords = (-122.4194, 37.7749)
307
```
308
309
## Common CRS Examples
310
311
### Geographic Coordinate Systems
312
313
```python
314
# World Geodetic System 1984 (most common for GPS data)
315
wgs84 = CRS.from_epsg(4326)
316
317
# North American Datum 1983
318
nad83 = CRS.from_epsg(4269)
319
320
# European Terrestrial Reference System 1989
321
etrs89 = CRS.from_epsg(4258)
322
```
323
324
### Projected Coordinate Systems
325
326
```python
327
# Web Mercator (used by Google Maps, OpenStreetMap)
328
web_mercator = CRS.from_epsg(3857)
329
330
# UTM zones (Universal Transverse Mercator)
331
utm_zone_10n = CRS.from_epsg(32610) # UTM Zone 10N (California)
332
utm_zone_18n = CRS.from_epsg(32618) # UTM Zone 18N (New York)
333
334
# State Plane systems (US)
335
ca_state_plane = CRS.from_epsg(2227) # California Zone III
336
337
# National grids
338
british_national_grid = CRS.from_epsg(27700) # UK
339
```
340
341
### Custom Projections
342
343
```python
344
# Custom Lambert Conformal Conic
345
custom_lcc = CRS.from_dict({
346
'proj': 'lcc',
347
'lat_1': 33,
348
'lat_2': 45,
349
'lat_0': 39,
350
'lon_0': -96,
351
'x_0': 0,
352
'y_0': 0,
353
'datum': 'NAD83',
354
'units': 'm'
355
})
356
357
# Custom Albers Equal Area
358
custom_albers = CRS.from_dict({
359
'proj': 'aea',
360
'lat_1': 29.5,
361
'lat_2': 45.5,
362
'lat_0': 37.5,
363
'lon_0': -96,
364
'x_0': 0,
365
'y_0': 0,
366
'datum': 'NAD83',
367
'units': 'm'
368
})
369
```
370
371
## Integration with Collections
372
373
CRS objects integrate seamlessly with Fiona collections for reading and writing geospatial data:
374
375
```python
376
import fiona
377
from fiona.crs import CRS
378
379
# Reading: CRS is automatically parsed from data file
380
with fiona.open('input.shp', 'r') as collection:
381
crs = collection.crs
382
print(f"Input CRS: {crs}")
383
print(f"Is geographic: {crs.is_geographic}")
384
385
# Writing: Specify CRS for output file
386
output_crs = CRS.from_epsg(4326)
387
schema = {
388
'geometry': 'Point',
389
'properties': {'name': 'str'}
390
}
391
392
with fiona.open('output.geojson', 'w', driver='GeoJSON',
393
crs=output_crs, schema=schema) as collection:
394
feature = {
395
'geometry': {'type': 'Point', 'coordinates': [-122.4, 37.8]},
396
'properties': {'name': 'San Francisco'}
397
}
398
collection.write(feature)
399
400
# CRS reprojection (requires separate transform step)
401
with fiona.open('input_utm.shp', 'r') as input_col:
402
input_crs = input_col.crs
403
output_crs = CRS.from_epsg(4326) # Convert to WGS84
404
405
with fiona.open('output_wgs84.geojson', 'w',
406
driver='GeoJSON', crs=output_crs,
407
schema=input_col.schema) as output_col:
408
409
for feature in input_col:
410
# Transform coordinates (see transforms.md for details)
411
transformed_feature = transform_feature(feature, input_crs, output_crs)
412
output_col.write(transformed_feature)
413
```
414
415
## Error Handling
416
417
CRS operations can encounter various errors that should be handled appropriately:
418
419
```python
420
from fiona.errors import CRSError
421
422
try:
423
# Invalid EPSG code
424
invalid_crs = CRS.from_epsg(99999)
425
except CRSError as e:
426
print(f"Invalid EPSG code: {e}")
427
428
try:
429
# Invalid WKT string
430
invalid_wkt = CRS.from_wkt("INVALID WKT STRING")
431
except CRSError as e:
432
print(f"Invalid WKT: {e}")
433
434
try:
435
# CRS that cannot be converted to EPSG
436
custom_crs = CRS.from_dict({'proj': 'custom_projection'})
437
epsg_code = custom_crs.to_epsg()
438
if epsg_code is None:
439
print("CRS cannot be matched to an EPSG code")
440
except CRSError as e:
441
print(f"CRS conversion error: {e}")
442
```