0
# XArray Integration
1
2
MetPy provides seamless integration with xarray through custom accessors that make data arrays and datasets meteorology-aware. The `.metpy` accessor automatically handles coordinate identification, unit management, coordinate reference systems, and meteorological coordinate transformations.
3
4
## Capabilities
5
6
### DataArray Accessor
7
8
The MetPy DataArray accessor provides meteorological functionality directly on xarray DataArrays through the `.metpy` attribute.
9
10
```python { .api }
11
@property
12
def units:
13
"""
14
Get or set units of the DataArray as a pint.Unit.
15
16
Returns:
17
pint.Unit object representing the data units
18
"""
19
20
@property
21
def magnitude:
22
"""
23
Return magnitude of data values without units.
24
25
Returns:
26
Data array values without units attached
27
"""
28
29
@property
30
def unit_array:
31
"""
32
Return data values as a pint.Quantity.
33
34
Returns:
35
pint.Quantity with data and units
36
"""
37
38
def convert_units(units):
39
"""
40
Convert DataArray to different units.
41
42
Parameters:
43
- units: target units for conversion
44
45
Returns:
46
New DataArray with converted units
47
"""
48
49
def convert_to_base_units():
50
"""
51
Convert DataArray to base SI units.
52
53
Returns:
54
New DataArray with base units
55
"""
56
57
def convert_coordinate_units(coord, units):
58
"""
59
Convert coordinate to different units.
60
61
Parameters:
62
- coord: coordinate name to convert
63
- units: target units
64
65
Returns:
66
New DataArray with converted coordinate units
67
"""
68
69
def quantify():
70
"""
71
Convert data to pint.Quantity if not already quantified.
72
73
Returns:
74
DataArray with pint.Quantity data
75
"""
76
77
def dequantify():
78
"""
79
Convert pint.Quantity data to magnitude with units as attribute.
80
81
Returns:
82
DataArray with numeric data and units attribute
83
"""
84
```
85
86
### Coordinate System Properties
87
88
Automatic identification and access to meteorological coordinate axes.
89
90
```python { .api }
91
@property
92
def time:
93
"""
94
Return the time coordinate.
95
96
Returns:
97
Time coordinate DataArray
98
"""
99
100
@property
101
def vertical:
102
"""
103
Return the vertical coordinate (pressure, height, etc.).
104
105
Returns:
106
Vertical coordinate DataArray
107
"""
108
109
@property
110
def y:
111
"""
112
Return the y coordinate (latitude or projected y).
113
114
Returns:
115
Y coordinate DataArray
116
"""
117
118
@property
119
def latitude:
120
"""
121
Return the latitude coordinate.
122
123
Returns:
124
Latitude coordinate DataArray
125
"""
126
127
@property
128
def x:
129
"""
130
Return the x coordinate (longitude or projected x).
131
132
Returns:
133
X coordinate DataArray
134
"""
135
136
@property
137
def longitude:
138
"""
139
Return the longitude coordinate.
140
141
Returns:
142
Longitude coordinate DataArray
143
"""
144
145
def coordinates(*args):
146
"""
147
Return coordinate variables for specified axis types.
148
149
Parameters:
150
- args: axis type strings ('time', 'vertical', 'y', 'latitude', 'x', 'longitude')
151
152
Returns:
153
Generator yielding coordinate DataArrays
154
"""
155
156
def coordinates_identical(other):
157
"""
158
Check if coordinates match another DataArray.
159
160
Parameters:
161
- other: DataArray to compare coordinates with
162
163
Returns:
164
Boolean indicating coordinate match
165
"""
166
```
167
168
### Coordinate Reference System Support
169
170
Handle map projections and coordinate transformations for meteorological data.
171
172
```python { .api }
173
@property
174
def crs:
175
"""
176
Return coordinate reference system as CFProjection object.
177
178
Returns:
179
CFProjection object with CRS information
180
"""
181
182
@property
183
def cartopy_crs:
184
"""
185
Return CRS as cartopy projection object.
186
187
Returns:
188
cartopy CRS object for plotting
189
"""
190
191
@property
192
def cartopy_globe:
193
"""
194
Return globe associated with the CRS.
195
196
Returns:
197
cartopy Globe object
198
"""
199
200
@property
201
def cartopy_geodetic:
202
"""
203
Return cartopy geodetic CRS for the globe.
204
205
Returns:
206
cartopy Geodetic CRS
207
"""
208
209
@property
210
def pyproj_crs:
211
"""
212
Return CRS as pyproj object.
213
214
Returns:
215
pyproj CRS object
216
"""
217
218
@property
219
def pyproj_proj:
220
"""
221
Return Proj object for coordinate transformations.
222
223
Returns:
224
pyproj Proj object
225
"""
226
227
def assign_crs(cf_attributes=None, **kwargs):
228
"""
229
Assign coordinate reference system using CF conventions.
230
231
Parameters:
232
- cf_attributes: dictionary of CF projection attributes
233
- kwargs: CF attributes as keyword arguments
234
235
Returns:
236
New DataArray with CRS coordinate assigned
237
"""
238
239
def assign_latitude_longitude(force=False):
240
"""
241
Assign 2D latitude/longitude coordinates from y/x coordinates.
242
243
Parameters:
244
- force: overwrite existing lat/lon coordinates if True
245
246
Returns:
247
New DataArray with latitude/longitude coordinates
248
"""
249
250
def assign_y_x(force=False, tolerance=None):
251
"""
252
Assign 1D y/x coordinates from 2D latitude/longitude.
253
254
Parameters:
255
- force: overwrite existing y/x coordinates if True
256
- tolerance: maximum range tolerance for 2D to 1D collapse
257
258
Returns:
259
New DataArray with y/x dimension coordinates
260
"""
261
```
262
263
### Grid Analysis Properties
264
265
Meteorological grid analysis utilities for spatial derivatives and coordinate spacing.
266
267
```python { .api }
268
@property
269
def time_deltas:
270
"""
271
Return time differences in seconds.
272
273
Returns:
274
pint.Quantity with time differences
275
"""
276
277
@property
278
def grid_deltas:
279
"""
280
Return horizontal grid spacing for derivatives.
281
282
Returns:
283
Dictionary with 'dx' and 'dy' grid spacing arrays
284
"""
285
286
def find_axis_name(axis):
287
"""
288
Find coordinate name for given axis identifier.
289
290
Parameters:
291
- axis: axis identifier (int, string, or axis type)
292
293
Returns:
294
String name of the coordinate
295
"""
296
297
def find_axis_number(axis):
298
"""
299
Find dimension number for given axis identifier.
300
301
Parameters:
302
- axis: axis identifier (int, string, or axis type)
303
304
Returns:
305
Integer dimension number
306
"""
307
```
308
309
### Coordinate Management
310
311
Assign and manage meteorological coordinate metadata.
312
313
```python { .api }
314
def assign_coordinates(coordinates):
315
"""
316
Assign coordinates to specific MetPy axis types.
317
318
Parameters:
319
- coordinates: dict mapping axis types to coordinates, or None to clear
320
321
Returns:
322
New DataArray with assigned coordinate metadata
323
"""
324
```
325
326
### Advanced Indexing
327
328
Unit-aware and coordinate-type-aware data selection.
329
330
```python { .api }
331
@property
332
def loc:
333
"""
334
Unit-aware .loc indexer for DataArrays.
335
336
Returns:
337
Indexer object supporting units and coordinate types
338
"""
339
340
def sel(indexers=None, method=None, tolerance=None, drop=False, **indexers_kwargs):
341
"""
342
Unit-aware selection method.
343
344
Parameters:
345
- indexers: coordinate indexers (can include units)
346
- method: selection method for inexact matches
347
- tolerance: tolerance for inexact matches
348
- drop: drop scalar coordinates
349
- indexers_kwargs: indexers as keyword arguments
350
351
Returns:
352
Selected DataArray subset
353
"""
354
```
355
356
### Dataset Accessor
357
358
The MetPy Dataset accessor provides meteorological functionality for entire datasets.
359
360
```python { .api }
361
def parse_cf(varname=None, coordinates=None):
362
"""
363
Parse CF conventions for coordinate metadata.
364
365
Parameters:
366
- varname: variable name(s) to parse (default: all)
367
- coordinates: manual coordinate assignments
368
369
Returns:
370
DataArray or Dataset with parsed CF metadata
371
"""
372
373
@property
374
def loc:
375
"""
376
Unit-aware .loc indexer for Datasets.
377
378
Returns:
379
Indexer object supporting units
380
"""
381
382
def sel(indexers=None, method=None, tolerance=None, drop=False, **indexers_kwargs):
383
"""
384
Unit-aware Dataset selection.
385
386
Parameters:
387
- indexers: coordinate indexers
388
- method: selection method
389
- tolerance: selection tolerance
390
- drop: drop scalar coordinates
391
- indexers_kwargs: indexers as keywords
392
393
Returns:
394
Selected Dataset subset
395
"""
396
397
def assign_crs(cf_attributes=None, **kwargs):
398
"""
399
Assign CRS to Dataset variables.
400
401
Parameters:
402
- cf_attributes: CF projection attributes dictionary
403
- kwargs: CF attributes as keywords
404
405
Returns:
406
New Dataset with CRS coordinate
407
"""
408
409
def assign_latitude_longitude(force=False):
410
"""
411
Assign lat/lon coordinates to all applicable variables.
412
413
Parameters:
414
- force: overwrite existing coordinates
415
416
Returns:
417
New Dataset with latitude/longitude coordinates
418
"""
419
420
def assign_y_x(force=False, tolerance=None):
421
"""
422
Assign y/x coordinates to all applicable variables.
423
424
Parameters:
425
- force: overwrite existing coordinates
426
- tolerance: tolerance for coordinate collapse
427
428
Returns:
429
New Dataset with y/x coordinates
430
"""
431
432
def update_attribute(attribute, mapping):
433
"""
434
Update attribute across all Dataset variables.
435
436
Parameters:
437
- attribute: attribute name to update
438
- mapping: dict or callable for new attribute values
439
440
Returns:
441
New Dataset with updated attributes
442
"""
443
444
def quantify():
445
"""
446
Convert all numeric variables to pint.Quantities.
447
448
Returns:
449
New Dataset with quantified variables
450
"""
451
452
def dequantify():
453
"""
454
Convert pint.Quantities to magnitudes with units attributes.
455
456
Returns:
457
New Dataset with dequantified variables
458
"""
459
```
460
461
## Usage Examples
462
463
### Basic XArray Integration
464
465
```python
466
import xarray as xr
467
import metpy.xarray # Enables .metpy accessor
468
from metpy.units import units
469
470
# Load meteorological data
471
ds = xr.open_dataset('temperature_data.nc')
472
473
# Enable MetPy functionality
474
ds = ds.metpy.parse_cf()
475
476
# Access meteorological coordinates automatically
477
print("Time coordinate:", ds['temperature'].metpy.time)
478
print("Pressure levels:", ds['temperature'].metpy.vertical)
479
print("Spatial coordinates:", ds['temperature'].metpy.x, ds['temperature'].metpy.y)
480
481
# Check coordinate reference system
482
if hasattr(ds['temperature'].metpy, 'crs'):
483
print("Projection:", ds['temperature'].metpy.crs)
484
```
485
486
### Units and Conversions
487
488
```python
489
# Work with units automatically
490
temp = ds['temperature']
491
print("Original units:", temp.metpy.units)
492
493
# Convert units seamlessly
494
temp_celsius = temp.metpy.convert_units('celsius')
495
temp_kelvin = temp.metpy.convert_units('kelvin')
496
497
print(f"Temperature range: {temp_celsius.min().values:.1f} to {temp_celsius.max().values:.1f} °C")
498
499
# Convert coordinates
500
if 'height' in ds.coords:
501
# Convert height from meters to kilometers
502
ds_km = ds.metpy.convert_coordinate_units('height', 'km')
503
print("Height now in km:", ds_km.height.metpy.units)
504
```
505
506
### Coordinate System Operations
507
508
```python
509
# Assign coordinate reference system
510
import metpy.plots.mapping as mp
511
512
# For Lambert Conformal Conic projection
513
lcc_attrs = {
514
'grid_mapping_name': 'lambert_conformal_conic',
515
'standard_parallel': [25.0, 60.0],
516
'longitude_of_central_meridian': -100.0,
517
'latitude_of_projection_origin': 50.0
518
}
519
520
# Assign CRS to data
521
ds_proj = ds.metpy.assign_crs(lcc_attrs)
522
print("CRS assigned:", ds_proj.metpy.crs)
523
524
# Generate latitude/longitude coordinates from projection
525
ds_with_latlon = ds_proj.metpy.assign_latitude_longitude()
526
print("Latitude range:", ds_with_latlon.latitude.min().values, "to", ds_with_latlon.latitude.max().values)
527
```
528
529
### Advanced Selection and Indexing
530
531
```python
532
from metpy.units import units
533
534
# Unit-aware selection
535
temp_500mb = ds.sel(pressure=500 * units.hPa)
536
temp_region = ds.sel(
537
latitude=slice(30 * units.degrees_north, 50 * units.degrees_north),
538
longitude=slice(-120 * units.degrees_east, -90 * units.degrees_east)
539
)
540
541
# Select using coordinate types instead of names
542
temp_surface = ds.isel(vertical=0) # Surface level
543
temp_recent = ds.isel(time=-1) # Most recent time
544
545
# Advanced indexing with .loc
546
temp_point = ds.metpy.loc[{
547
'y': 40.0 * units.degrees_north,
548
'x': -105.0 * units.degrees_east,
549
'vertical': 850 * units.hPa
550
}]
551
```
552
553
### Grid Analysis
554
555
```python
556
# Calculate grid spacing for derivatives
557
temp = ds['temperature']
558
grid_info = temp.metpy.grid_deltas
559
560
print("Grid spacing dx:", grid_info['dx'])
561
print("Grid spacing dy:", grid_info['dy'])
562
563
# Use with MetPy calculation functions
564
import metpy.calc as mpcalc
565
566
# Calculate temperature advection
567
u_wind = ds['u_wind']
568
v_wind = ds['v_wind']
569
570
# Grid deltas automatically used by calculation functions
571
temp_advection = mpcalc.advection(temp, u_wind, v_wind)
572
print("Temperature advection calculated with automatic grid spacing")
573
```
574
575
### Working with Different Data Sources
576
577
```python
578
# GRIB data with CF conventions
579
grib_ds = xr.open_dataset('forecast.grib2', engine='cfgrib')
580
grib_ds = grib_ds.metpy.parse_cf()
581
582
# NetCDF data from THREDDS
583
netcdf_ds = xr.open_dataset('http://thredds.server.edu/data.nc')
584
netcdf_ds = netcdf_ds.metpy.parse_cf()
585
586
# Manual coordinate assignment when automatic parsing fails
587
coords_manual = {
588
'time': 'time',
589
'vertical': 'pressure',
590
'y': 'lat',
591
'x': 'lon'
592
}
593
ds_manual = ds.metpy.assign_coordinates(coords_manual)
594
```
595
596
### Integration with Calculations
597
598
```python
599
import metpy.calc as mpcalc
600
601
# Load upper-air data
602
sounding = xr.open_dataset('sounding.nc').metpy.parse_cf()
603
604
# Extract profiles - coordinates automatically identified
605
pressure = sounding['pressure'].metpy.vertical
606
temperature = sounding['temperature']
607
dewpoint = sounding['dewpoint']
608
609
# Calculations work seamlessly with xarray data
610
theta = mpcalc.potential_temperature(pressure, temperature)
611
rh = mpcalc.relative_humidity_from_dewpoint(temperature, dewpoint)
612
613
# Results maintain coordinate information
614
print("Potential temperature coordinates:", theta.coords)
615
print("Relative humidity range:", rh.min().values, "to", rh.max().values)
616
```
617
618
### Quantification and Dequantification
619
620
```python
621
# Convert to pint quantities for advanced unit operations
622
temp_quantity = ds['temperature'].metpy.quantify()
623
print("Temperature as quantity:", type(temp_quantity.data))
624
625
# Perform complex unit operations
626
temp_rankine = temp_quantity.metpy.convert_units('rankine')
627
temp_difference = temp_quantity - temp_quantity.mean()
628
629
# Convert back to normal xarray with units as attributes
630
temp_dequant = temp_quantity.metpy.dequantify()
631
print("Units attribute:", temp_dequant.attrs['units'])
632
```
633
634
## Coordinate Identification Criteria
635
636
MetPy uses multiple criteria to automatically identify coordinate types:
637
638
```python { .api }
639
# Coordinate axis types recognized by MetPy
640
metpy_axes = ['time', 'vertical', 'y', 'latitude', 'x', 'longitude']
641
642
# Identification criteria (examples)
643
coordinate_criteria = {
644
'standard_name': {
645
'time': 'time',
646
'vertical': {'air_pressure', 'height', 'geopotential_height'},
647
'latitude': 'latitude',
648
'longitude': 'longitude'
649
},
650
'axis': {
651
'time': 'T',
652
'vertical': 'Z',
653
'y': 'Y',
654
'x': 'X'
655
},
656
'units': {
657
'vertical': {'match': 'dimensionality', 'units': 'Pa'},
658
'latitude': {'match': 'name', 'units': {'degree_north', 'degrees_north'}},
659
'longitude': {'match': 'name', 'units': {'degree_east', 'degrees_east'}}
660
}
661
}
662
```
663
664
## Error Handling
665
666
```python
667
try:
668
# Attempt to access coordinate
669
time_coord = ds['temperature'].metpy.time
670
except AttributeError:
671
print("Time coordinate not found or not identifiable")
672
673
try:
674
# Attempt coordinate conversion
675
temp_kelvin = ds['temperature'].metpy.convert_units('kelvin')
676
except DimensionalityError:
677
print("Units are not compatible with temperature")
678
679
# Check for CRS before using projection methods
680
if hasattr(ds['temperature'].metpy, 'crs'):
681
cartopy_crs = ds['temperature'].metpy.cartopy_crs
682
else:
683
print("No CRS information available")
684
```
685
686
## Types
687
688
```python { .api }
689
from typing import Optional, Dict, Generator, Union
690
import xarray as xr
691
from pint import Quantity
692
693
# Accessor types
694
MetPyDataArrayAccessor = object
695
MetPyDatasetAccessor = object
696
697
# Coordinate types
698
CoordinateArray = xr.DataArray
699
CoordinateMapping = Dict[str, str]
700
701
# CRS types
702
CRS = object # CFProjection object
703
CartopyCRS = object
704
PyProjCRS = object
705
706
# Selection types
707
IndexerDict = Dict[str, Union[slice, Quantity, float, int]]
708
SelectionResult = Union[xr.DataArray, xr.Dataset]
709
```