0
# Attributes and Metadata
1
2
Attributes provide metadata for files, groups, and variables in netCDF4 files. They store descriptive information such as units, descriptions, valid ranges, and processing history, enabling self-documenting data files.
3
4
## Capabilities
5
6
### Attribute Management
7
8
Dictionary-like interface for managing attributes on netCDF objects.
9
10
```python { .api }
11
class Attributes(MutableMapping):
12
def __getitem__(self, key: str):
13
"""
14
Get attribute value by name.
15
16
Args:
17
key (str): Attribute name
18
19
Returns:
20
Attribute value (type depends on stored data)
21
"""
22
...
23
24
def __setitem__(self, key: str, value) -> None:
25
"""
26
Set attribute value.
27
28
Args:
29
key (str): Attribute name
30
value: Attribute value (scalar, string, or array)
31
"""
32
...
33
34
def __delitem__(self, key: str) -> None:
35
"""
36
Delete attribute.
37
38
Args:
39
key (str): Attribute name to delete
40
"""
41
...
42
43
def __contains__(self, key: str) -> bool:
44
"""Check if attribute exists."""
45
...
46
47
def __iter__(self):
48
"""Iterate over attribute names."""
49
...
50
51
def __len__(self) -> int:
52
"""Number of attributes."""
53
...
54
55
def keys(self):
56
"""Attribute names."""
57
...
58
59
def values(self):
60
"""Attribute values."""
61
...
62
63
def items(self):
64
"""(name, value) pairs."""
65
...
66
```
67
68
### Attribute Access
69
70
All netCDF objects (File, Group, Variable) have an attrs property.
71
72
```python { .api }
73
# Available on File, Group, and Variable classes
74
@property
75
def attrs(self) -> Attributes:
76
"""Dictionary-like access to attributes."""
77
...
78
```
79
80
## Usage Examples
81
82
### Variable Attributes
83
84
```python
85
import h5netcdf
86
import numpy as np
87
88
with h5netcdf.File('attributes.nc', 'w') as f:
89
# Create dimensions and variable
90
f.dimensions['time'] = 100
91
f.dimensions['lat'] = 180
92
f.dimensions['lon'] = 360
93
94
temp = f.create_variable('temperature', ('time', 'lat', 'lon'), dtype='f4')
95
96
# Set common variable attributes
97
temp.attrs['units'] = 'K'
98
temp.attrs['long_name'] = 'Air Temperature'
99
temp.attrs['standard_name'] = 'air_temperature'
100
temp.attrs['valid_range'] = [200.0, 350.0]
101
temp.attrs['missing_value'] = -999.0
102
temp.attrs['_FillValue'] = -999.0
103
104
# Set processing attributes
105
temp.attrs['source'] = 'ERA5 Reanalysis'
106
temp.attrs['processing_level'] = 'Level 3'
107
temp.attrs['creation_date'] = '2023-11-15'
108
109
# Numeric attributes
110
temp.attrs['scale_factor'] = 1.0
111
temp.attrs['add_offset'] = 0.0
112
temp.attrs['calibration_factor'] = 0.98
113
114
# Array attributes
115
temp.attrs['flag_values'] = np.array([0, 1, 2, 3], dtype='i1')
116
temp.attrs['flag_meanings'] = 'good questionable bad missing'
117
```
118
119
### Global Attributes (File Level)
120
121
```python
122
with h5netcdf.File('global_attrs.nc', 'w') as f:
123
# Set global (file-level) attributes
124
f.attrs['title'] = 'Global Temperature Analysis'
125
f.attrs['institution'] = 'Climate Research Center'
126
f.attrs['contact'] = 'data@climate.org'
127
f.attrs['Conventions'] = 'CF-1.8'
128
f.attrs['history'] = 'Created on 2023-11-15 using h5netcdf'
129
f.attrs['source'] = 'Satellite observations and model data'
130
f.attrs['references'] = 'Smith et al. (2023), Journal of Climate'
131
132
# Geospatial attributes
133
f.attrs['geospatial_lat_min'] = -90.0
134
f.attrs['geospatial_lat_max'] = 90.0
135
f.attrs['geospatial_lon_min'] = -180.0
136
f.attrs['geospatial_lon_max'] = 180.0
137
f.attrs['geospatial_lat_units'] = 'degrees_north'
138
f.attrs['geospatial_lon_units'] = 'degrees_east'
139
140
# Temporal attributes
141
f.attrs['time_coverage_start'] = '2023-01-01T00:00:00Z'
142
f.attrs['time_coverage_end'] = '2023-12-31T23:59:59Z'
143
144
# Technical attributes
145
f.attrs['processing_software'] = 'h5netcdf v1.6.4'
146
f.attrs['format_version'] = 'netCDF-4'
147
f.attrs['compression'] = 'gzip level 6'
148
```
149
150
### Group Attributes
151
152
```python
153
with h5netcdf.File('group_attrs.nc', 'w') as f:
154
# Create groups with attributes
155
observations = f.create_group('observations')
156
observations.attrs['description'] = 'Raw observational data'
157
observations.attrs['quality_control'] = 'Level 1'
158
observations.attrs['instrument'] = 'AVHRR'
159
160
model = f.create_group('model')
161
model.attrs['description'] = 'Model simulation results'
162
model.attrs['model_name'] = 'WRF v4.3'
163
model.attrs['grid_resolution'] = '25km'
164
model.attrs['physics_scheme'] = 'YSU PBL, WSM6 microphysics'
165
```
166
167
### Coordinate Variable Attributes
168
169
```python
170
with h5netcdf.File('coordinates.nc', 'w') as f:
171
f.dimensions['time'] = 12
172
f.dimensions['lat'] = 180
173
f.dimensions['lon'] = 360
174
175
# Time coordinate
176
time = f.create_variable('time', ('time',), dtype='f8')
177
time.attrs['units'] = 'days since 2023-01-01 00:00:00'
178
time.attrs['calendar'] = 'standard'
179
time.attrs['long_name'] = 'Time'
180
time.attrs['standard_name'] = 'time'
181
time.attrs['axis'] = 'T'
182
183
# Latitude coordinate
184
lat = f.create_variable('lat', ('lat',), dtype='f4')
185
lat.attrs['units'] = 'degrees_north'
186
lat.attrs['long_name'] = 'Latitude'
187
lat.attrs['standard_name'] = 'latitude'
188
lat.attrs['axis'] = 'Y'
189
lat.attrs['valid_range'] = [-90.0, 90.0]
190
191
# Longitude coordinate
192
lon = f.create_variable('lon', ('lon',), dtype='f4')
193
lon.attrs['units'] = 'degrees_east'
194
lon.attrs['long_name'] = 'Longitude'
195
lon.attrs['standard_name'] = 'longitude'
196
lon.attrs['axis'] = 'X'
197
lon.attrs['valid_range'] = [-180.0, 180.0]
198
```
199
200
### Reading and Inspecting Attributes
201
202
```python
203
with h5netcdf.File('inspect_attrs.nc', 'r') as f:
204
# Inspect global attributes
205
print("Global attributes:")
206
for name, value in f.attrs.items():
207
print(f" {name}: {value}")
208
209
# Inspect variable attributes
210
for var_name, variable in f.variables.items():
211
print(f"\nVariable '{var_name}' attributes:")
212
for attr_name, attr_value in variable.attrs.items():
213
print(f" {attr_name}: {attr_value}")
214
215
# Check for specific attributes
216
if 'temperature' in f.variables:
217
temp = f.variables['temperature']
218
219
if 'units' in temp.attrs:
220
print(f"Temperature units: {temp.attrs['units']}")
221
222
if 'valid_range' in temp.attrs:
223
vmin, vmax = temp.attrs['valid_range']
224
print(f"Valid range: {vmin} to {vmax}")
225
226
# Check for fill value
227
fill_value = temp.attrs.get('_FillValue', None)
228
if fill_value is not None:
229
print(f"Fill value: {fill_value}")
230
```
231
232
### Attribute Data Types
233
234
```python
235
with h5netcdf.File('attr_types.nc', 'w') as f:
236
f.dimensions['x'] = 10
237
var = f.create_variable('data', ('x',), dtype='f4')
238
239
# String attributes
240
var.attrs['string_attr'] = 'This is a string'
241
var.attrs['unicode_attr'] = 'Unicode: αβγ'
242
243
# Numeric attributes
244
var.attrs['int_attr'] = 42
245
var.attrs['float_attr'] = 3.14159
246
var.attrs['double_attr'] = np.float64(2.718281828)
247
248
# Array attributes
249
var.attrs['int_array'] = np.array([1, 2, 3, 4, 5])
250
var.attrs['float_array'] = np.array([1.1, 2.2, 3.3])
251
var.attrs['string_array'] = ['option1', 'option2', 'option3']
252
253
# Boolean-like (stored as integers)
254
var.attrs['flag'] = np.int8(1) # True
255
var.attrs['enabled'] = np.int8(0) # False
256
257
# Special values
258
var.attrs['nan_value'] = np.nan
259
var.attrs['inf_value'] = np.inf
260
```
261
262
### CF Convention Attributes
263
264
```python
265
# Following Climate and Forecast (CF) conventions
266
with h5netcdf.File('cf_compliant.nc', 'w') as f:
267
# Global CF attributes
268
f.attrs['Conventions'] = 'CF-1.8'
269
f.attrs['title'] = 'Monthly Global Temperature Anomalies'
270
f.attrs['institution'] = 'Climate Data Center'
271
f.attrs['source'] = 'Reanalysis'
272
f.attrs['history'] = 'Created 2023-11-15'
273
f.attrs['comment'] = 'Temperature anomalies relative to 1981-2010 base period'
274
275
# Create dimensions
276
f.dimensions['time'] = None
277
f.dimensions['lat'] = 180
278
f.dimensions['lon'] = 360
279
280
# Time with CF-compliant attributes
281
time = f.create_variable('time', ('time',), dtype='f8')
282
time.attrs['standard_name'] = 'time'
283
time.attrs['long_name'] = 'time'
284
time.attrs['units'] = 'days since 1850-01-01 00:00:00'
285
time.attrs['calendar'] = 'standard'
286
time.attrs['axis'] = 'T'
287
288
# Temperature with full CF metadata
289
temp = f.create_variable('temperature_anomaly', ('time', 'lat', 'lon'), dtype='f4')
290
temp.attrs['standard_name'] = 'air_temperature_anomaly'
291
temp.attrs['long_name'] = 'Near-Surface Air Temperature Anomaly'
292
temp.attrs['units'] = 'K'
293
temp.attrs['cell_methods'] = 'time: mean'
294
temp.attrs['grid_mapping'] = 'crs'
295
temp.attrs['coordinates'] = 'lon lat'
296
temp.attrs['valid_range'] = [-50.0, 50.0]
297
temp.attrs['_FillValue'] = -9999.0
298
```
299
300
### Modifying Attributes
301
302
```python
303
with h5netcdf.File('modify_attrs.nc', 'r+') as f: # Note: 'r+' mode for modification
304
if 'temperature' in f.variables:
305
temp = f.variables['temperature']
306
307
# Modify existing attribute
308
if 'processing_level' in temp.attrs:
309
temp.attrs['processing_level'] = 'Level 2B'
310
311
# Add new attribute
312
temp.attrs['last_modified'] = '2023-11-15T14:30:00Z'
313
314
# Delete attribute
315
if 'obsolete_attr' in temp.attrs:
316
del temp.attrs['obsolete_attr']
317
318
# Update global attributes
319
f.attrs['history'] += f"; Modified {datetime.now().isoformat()}"
320
```
321
322
### Attribute Validation and Standards
323
324
```python
325
def validate_cf_attributes(variable):
326
"""Validate CF convention compliance."""
327
required_attrs = ['standard_name', 'units']
328
recommended_attrs = ['long_name', 'valid_range']
329
330
missing_required = [attr for attr in required_attrs
331
if attr not in variable.attrs]
332
missing_recommended = [attr for attr in recommended_attrs
333
if attr not in variable.attrs]
334
335
if missing_required:
336
print(f"Missing required attributes: {missing_required}")
337
338
if missing_recommended:
339
print(f"Missing recommended attributes: {missing_recommended}")
340
341
# Check units format
342
if 'units' in variable.attrs:
343
units = variable.attrs['units']
344
if not isinstance(units, str):
345
print("Units should be a string")
346
347
# Usage
348
with h5netcdf.File('validate.nc', 'r') as f:
349
for var_name, variable in f.variables.items():
350
print(f"Validating {var_name}:")
351
validate_cf_attributes(variable)
352
```
353
354
## Standard Attribute Names
355
356
### Variable Attributes
357
- **units**: Physical units (e.g., 'K', 'm/s', 'kg m-2 s-1')
358
- **long_name**: Descriptive name
359
- **standard_name**: CF standard name
360
- **valid_range**: [min, max] valid values
361
- **_FillValue**: Fill value for missing data
362
- **missing_value**: Alternative missing value indicator
363
- **scale_factor**: Scaling factor for packed data
364
- **add_offset**: Offset for packed data
365
366
### Coordinate Attributes
367
- **axis**: 'X', 'Y', 'Z', or 'T' for spatial/temporal axes
368
- **positive**: 'up' or 'down' for vertical coordinates
369
- **calendar**: Calendar type for time coordinates
370
- **bounds**: Variable containing cell boundaries
371
372
### Global Attributes
373
- **Conventions**: Metadata convention (e.g., 'CF-1.8')
374
- **title**: Dataset title
375
- **institution**: Data producing institution
376
- **source**: Data source description
377
- **history**: Processing history
378
- **comment**: Additional information