Field structure

A field (stored in a Field object) is a container for a data array (stored in a Data object) and metadata comprising properties to describe the physical nature of the data and a coordinate system (called a space, stored in a Space object), which describes the positions of each element of the data array.

It is structured in exactly the same way as a field construct defined by the CF data model.

The field’s space may contain coordinates and cell measures (which themselves contain data arrays and properties to describe them; and are stored in Coordinate and CellMeasure objects respectively) and transforms (stored in Transform objects) to describe how other auxiliary coordinates may be computed.

As in the CF data model, all components of a field are optional.

Example

The structure is exposed by printing out a full dump of a field, followed by descriptions of some of the output sections:

>>> type(f)
<class 'cf.field.Field'>
>>> cf.dump(f)
field summary
-------------
Data            : air_temperature(time, latitude, longitude)
Cell methods    : time: mean
Dimensions      : time(12) = [15, ..., 345] days since 1860-1-1
                : latitude(73) = [-90, ..., 90] degrees_north
                : longitude(96) = [0, ..., 356.25] degrees_east
                : height(1) = [2] m
Auxiliary coords:

air_temperature field
---------------------
Field.shape = (12, 73, 96)
Field.first_datum = 245.965759277
Field.last_datum  = 238.590637207
Field._FillValue = 1e+20
Field.Units = <CF Units: K>
Field.cell_methods = <CF CellMethods: time: mean>

Field.Conventions = 'CF-1.5'
Field.experiment_id = 'climate of the 20th Century experiment (20C3M)'
Field.long_name = 'Surface Air Temperature'
Field.standard_name = 'air_temperature'
Field.title = 'model output prepared for IPCC AR4'

space
-----
Field.space.dimension_sizes = {'dim2': 96, 'dim3': 1, 'dim0': 12, 'dim1': 73}

Field.space.dimensions['data'] = ['dim0', 'dim1', 'dim2']
Field.space.dimensions['dim0'] = ['dim0']
Field.space.dimensions['dim1'] = ['dim1']
Field.space.dimensions['dim2'] = ['dim2']
Field.space.dimensions['dim3'] = ['dim3']

time coordinate
---------------
Field.space['dim0'].shape = (12,)
Field.space['dim0'].first_datum = 15.0
Field.space['dim0'].last_datum  = 345.0
Field.space['dim0']._FillValue = None
Field.space['dim0'].Units = <CF Units: days since 1860-1-1 calendar=360_day>

Field.space['dim0'].axis = 'T'
Field.space['dim0'].long_name = 'time'
Field.space['dim0'].standard_name = 'time'

Field.space['dim0'].bounds.shape = (12, 2)
Field.space['dim0'].bounds.first_datum = 0.0
Field.space['dim0'].bounds.last_datum  = 360.0
Field.space['dim0'].bounds._FillValue = None
Field.space['dim0'].bounds.Units = <CF Units: days since 1860-1-1 calendar=360_day>

latitude coordinate
-------------------
Field.space['dim1'].shape = (73,)
Field.space['dim1'].first_datum = -90.0
Field.space['dim1'].last_datum  = 90.0
Field.space['dim1']._FillValue = None
Field.space['dim1'].Units = <CF Units: degrees_north>

Field.space['dim1'].axis = 'Y'
Field.space['dim1'].long_name = 'latitude'
Field.space['dim1'].standard_name = 'latitude'

Field.space['dim1'].bounds.shape = (73, 2)
Field.space['dim1'].bounds.first_datum = -90.0
Field.space['dim1'].bounds.last_datum  = 90.0
Field.space['dim1'].bounds._FillValue = None
Field.space['dim1'].bounds.Units = <CF Units: degrees_north>

longitude coordinate
--------------------
Field.space['dim2'].shape = (96,)
Field.space['dim2'].first_datum = 0.0
Field.space['dim2'].last_datum  = 356.25
Field.space['dim2']._FillValue = None
Field.space['dim2'].Units = <CF Units: degrees_east>

Field.space['dim2'].axis = 'X'
Field.space['dim2'].long_name = 'longitude'
Field.space['dim2'].standard_name = 'longitude'

Field.space['dim2'].bounds.shape = (96, 2)
Field.space['dim2'].bounds.first_datum = -1.875
Field.space['dim2'].bounds.last_datum  = 358.125
Field.space['dim2'].bounds._FillValue = None
Field.space['dim2'].bounds.Units = <CF Units: degrees_east>

height coordinate
-----------------
Field.space['dim3'].shape = (1,)
Field.space['dim3'].first_datum = 2.0
Field.space['dim3']._FillValue = None
Field.space['dim3'].Units = <CF Units: m>

Field.space['dim3'].axis = 'Z'
Field.space['dim3'].long_name = 'height'
Field.space['dim3'].positive = 'up'
Field.space['dim3'].standard_name = 'height'

field summary

Describes the field in terms of physical quantity of its data array (air_temperature), the identities of its dimensions (time, latitude, longitude and height) and the ranges of coordinate values along each axis.

air temperature field

Describes the field’s data array (array shape, first and last values, fill value, units and cell methods) and other descriptive CF properties (Conventions, experiment_id, long_name, standard_name and title)

space

Describes the coordinate system of the field by describing the coordinates, cell measures and transforms. See the space_structure section for more details.

time coordinate

Describes the coordinate’s data array (array shape, first and last values, fill value, and units), the coordinate’s cell bounds array (array shape, first and last values, fill value, and units) and other descriptive CF properties (axis, long_name and standard_name)

CF properties and attributes

Most CF properties are stored as familiar python objects (strings, numbers, tuples, numpy arrays, etc.):

>>> f.standard_name
'air_temperature'
>>> f._FillValue
1e+20
>>> f.valid_range
(-50.0, 50.0)
>>> f.flag_values
array([0, 1, 2, 4], dtype=int8)

There are some CF properties which require their own class:

Property Class Description
cell_methods CellMethods The characteristics that are is represented by cell values
>>> f.cell_methods
<CF CellMethods: time: mean (interval: 1.0 month)>

There are some attributes which store metadata other than CF properties which require their own class:

Attribute Class Description
Flags Flags The self describing CF flag values, meanings and masks
Units Units The units of the data array
space Space The field’s space
>>> f.Flags
<CF Flags: values=[0 1 2], masks=[0 2 2], meanings=['low' 'medium' 'high']>
>>> f.Units
<CF Units: days since 1860-1-1 calendar=360_day>
>>> f.space
<CF Space: (110, 106, 1, 19)>

The Units object may be accessed through the field’s units and calendar CF properties and the Flags object may be accessed through the field’s flag_values, flag_meanings and flag_masks CF properties:

>>> f.calendar = 'noleap'
>>> f.flag_values = ['a', 'b', 'c']

The Units and Flags objects may also be manipulated directly, which automatically adjusts the relevant CF properties:

>>> f.Units
<CF Units: 'm'>
>>> f.units
'm'
>>> f.Units *= 1000
>>> f.Units
<CF Units: '1000 m'>
>>> f.units
'1000 m'
>>> f.Units.units = '10 m'
>>> f.units
'10 m'

Other attributes used commonly (but not reserved) are:

Attribute Description
file The name of the file the field was read from
id An identifier for the field in the absence of a standard name. This may be used for ascertaining if two fields are aggregatable or combinable.
ncvar The netCDF variable name of the field
>>> f.file
'/home/me/file.nc'
>>> f.id
'field 8'
>>> f.ncvar
'tas'

Space structure

A space completely describes the field’s coordinate system.

It contains the dimension constructs, auxiliary coordinate constructs, transform constructs and cell measure constructs defined by the CF data model.

A field’s space is stored in its space attribute, the value of which is a Space object.

The space is a dictionary-like object whose key/value pairs identify and store the coordinate and cell measure constructs which describe it.

Dimensionality

The dimension sizes of the space are given by the space’s dimension_sizes attribute.

>>> f.space.dimension_sizes
{'dim1': 19, 'dim0': 12, 'dim2': 73, 'dim3': 96}

Components

The space’s key/value pairs identify and store its coordinate (Coordinate) and cell measure (CellMeasure) constructs.

Keys for dimension, auxiliary coordinate and cell measure constructs are prefixed “dim”, “aux” and “cm” respectively and followed by arbitrary, unique integers for discrimination:

>>> f.space['dim0']
<CF Coordinate: time(12)>
>>> f.space['dim2']
<CF Coordinate: latitude73)>
>>> f.space['aux0']
<CF Coordinate: forecast_time(12)>

The dimensions of each of these components, and of the field’s data array, are stored as ordered lists in the dimensions attribute:

>>> f.space.dimensions
{'data': ['dim0', 'dim1', 'dim2', 'dim3'],
 'aux0': ['dim0'],
 'dim0': ['dim0'],
 'dim1': ['dim1'],
 'dim2': ['dim2'],
 'dim3': ['dim3']}

Note

The field’s data array may contain fewer size 1 dimensions than its space.

Transform constructs are stored in the transforms attribute, which is a dictionary-like object containing Transform objects.

>>> f.space.transforms
{'trans0': <CF Transform: atmosphere_sigma_coordinate>}

Note

A single transform construct may be associated with any number of the space’s coordinates via their transform attributes

Field list

A FieldList object is an ordered sequence of fields analogous to a built-in python list.

It has all of the python list-like methods (__contains__, __getitem__, __setitem__, __len__, __delitem__, append, count, extend, index, insert, pop, remove, reverse), which behave as expected. For example:

>>> type(fl)
<class 'cf.field.FieldList'>
>>> fl
[<CF Field: eastward_wind(110, 106)>,
 <CF Field: air_temperature(12, 73, 96)>]
>>> len(fl)
2
>>> for f in fl:
...     print repr(f)
...
<CF Field: eastward_wind(110, 106)>,
<CF Field: air_temperature(12, 73, 96)>
>>> for f in fl[::-1]:
...     print repr(f)
...
<CF Field: air_temperature(12, 73, 96)>
<CF Field: eastward_wind(110, 106)>,
>>> f = fl[0]
>>> type(f)
<class 'cf.field.Field'>
>>> f in fl
True
>>> f = fl.pop()
>>> type(f)
<class 'cf.field.Field'>

Field versus field list

In some contexts, whether an object is a field or a field list is not known and does not matter. So to avoid ungainly type testing, some aspects of the FieldList interface are shared by a Field and vice versa.

Attributes and methods

Any attribute or method belonging to a field may be used on a field list and will be applied independently to each element:

>>> fl.ndim
[2, 3]
>>> fl.subspace[..., 0]
[<CF Field: eastward_wind(110, 1)>,
 <CF Field: air_temperature(12, 73, 1)>]
>>> fl **= 2
[<CF Field: eastward_wind**2(110, 106)>,
 <CF Field: air_temperature**2(12, 73, 1)>]
>>> fl.squeeze('longitude')
[<CF Field: eastward_wind**2(110, 1)>,
 <CF Field: air_temperature**2(12, 73)>]

CF properties may be changed to a common value with the setattr method:

>>> fl.setattr('comment', 'my data')
>>> fl.comment
['my data', 'my data']
>>> fl.setattr('foo', 'bar')
>>> fl.getattr('foo')
['bar', 'bar']

Changes tailored to each individual field in the list need to be carried out in a loop:

>>> for f in fl:
...     f.long_name = f.long_name.upper()
>>> long_names = ('square of eastward wind', 'square of temperature')
>>> for f, value in zip(fl, long_names):
...     f.long_name = value

Looping

Just as it is straight forward to iterate over the fields in a field list, a field will behave like a single element field list in iterative and indexing contexts:

>>> f
<CF Field: air_temperature(12, 73, 96)>
>>> f is f[0]
True
>>> f is f[-1]
True
>>> f is f[slice(0, 1)]
True
>>> f is f[slice(0, None, -1)]
True
>>> for g in f:
...     repr(g)
...
<CF Field: air_temperature(12, 73, 96)>

Table Of Contents

Previous topic

Reference manual

Next topic

Units

This Page