# Incompatible differences between versions 1.x and 2.x

For those familiar with the cf-python API at version 1.x, some important, backwards incompatible changes were introduced at version 2.0.

Some of these changes could break code written at version 1.x, causing an exception to be raised. For others, those marked with a warning, version 1.x may work but could produce scientifically different results.

All of the changes have been designed to make the interface more consistent and intuitive to use and were introduced at version 2.0 to coincide with the updated CF data model structure.

## attributes

Note

At version 2.x `cf.Field.attributes` is callable and allows the attributes to be updated inplace.

    >>> cf.__version__
    2.0
    >>> f.attributes()
    {'ncvar': 'tas'}

At version 1.x it wasn’t callable and returned a `dict` copy of the attributes.

## axes

Note

At version 2.x `cf.Field.axes` returns, by default, a `dict`. If the `ordered` parameter is `True` then it returns an `OrderedDict`.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> f.axes()
    {'dim0': <CF DomainAxis: 12>,
     'dim1': <CF DomainAxis: 64>,
     'dim2': <CF DomainAxis: 128>,
     'dim3': <CF DomainAxis: 1>}
    >>> f.axes(ordered=True)
    OrderedDict([('dim3', <CF DomainAxis: 1>),
                 ('dim0', <CF DomainAxis: 12>),
                 ('dim1', <CF DomainAxis: 64>),
                 ('dim2', <CF DomainAxis: 128>)])

At version 1.x it returned a `set` by default or, if the `ordered` parameter was `True`, it returned a `list`.

## axis

Note

At version 2.x `cf.Field.axis` returns, by default, a `cf.DomainAxis` object. A domain axis identifier (such as “dim2”) may be returned by setting the `key` parameter to `True`.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> f.axis('X')
    <CF DomainAxis: 128>
    >>> f.axis('X', key=True)
    'dim2'

At version 1.x it always returned a domain axis identifier.

## bounds

Warning

Running code written at version 1.x with the version 2.x library could produce scientifically different results.

Note

At version 2.x performing arithmetic on coordinates also modifies the coordinate bounds, if present.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> t = f.coord('T')
    >>> print t.array[0], t.bounds.array[0]
    164569.0 [ 164554.  164584.]
    >>> t -= 1000000
    >>> print t.array[0], t.bounds.array[0]
    -835431.0 [-835446. -835416.]

If the bounds are not to be changed, just the coordinate values, then the arithmetic may be applied to the coordinate object’s data array.

    >>> t.data += 1000000
    >>> print t.array[0], t.bounds.array[0]
    164569.0 [-835446. -835416.]

At version 1.x performing arithmetic on coordinates did not modify the coordinate bounds - they had to be modified seperately.

## collapse

Warning

Running code written at version 1.x with the version 2.x library could produce scientifically different results.

Note

At version 2.x `cf.Field.collapse` does not, by default, weight the calculations, i.e. the `weights` parameter defaults to `None`.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> g = f.collapse('mean')
    >>> g.datum()
    279.1922
    >>> g = f.collapse('mean', weights=None)
    >>> g.datum()
    279.1922

Non-equal weighting has to be specifically requested with the `weights` parameter.

    >>> h = f.collapse('mean', axes=['X', 'Y', 'T'], weights=['T', 'area'])
    >>> h.datum()
    288.6733

At version 1.x the `weights` parameter defaulted to `'auto'`, meaning that calculations were were weighted according to metadata present in the field.

## dump

Note

At version 2.x the output of `cf.Field.dump` has been reformatted.

## FieldList

Warning

Running code written at version 1.x with the version 2.x library could produce scientifically different results.

Note

At version 2.x `cf.FieldList` is not a subclass of `cf.Field`, therefore `cf.FieldList` does not inherit any methods from `cf.Field`.

    >>> cf.__version__
    2.0
    >>> fl
    [<CF Field: specific_humidity(latitude(73), longitude(96)) K>,
     <CF Field: air_pressure(height(17), latitude(145), longitude(196)) K>]
    >>> isinstance(fl, cf.Field)
    False
    >>> gl = fl.collapse('mean')
    DeprecationError: collapse method has been removed from a field list. Use on individual fields.
    >>> gl = cf.FieldList([f.collapse('mean') for f in fl])

At version 1.x `cf.FieldList` was a subclass of `cf.Field` and inherited all of the methods that returned a `cf.Field` when used on a field (such as `collapse` and `squeeze`).

## read

Note

At version 2.x `cf.read` always returns a `cf.FieldList`.

    >>> cf.__version__
    2.0
    >>> fl = cf.read('file[12].nc')
    >>> fl
    [<CF Field: specific_humidity(latitude(73), longitude(96)) K>,
     <CF Field: air_pressure(height(17), latitude(145), longitude(196)) K>]
    >>> fl = cf.read('file3.nc')
    >>> fl
    [<CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>]

The new function `cf.read_field` will always return a `cf.Field` if there is only one identified in the input file(s).

    >>> f = cf.read_field('file3.nc')
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>

At version 1.x `cf.read` returned a `cf.Field` if only one field was found in the input files(s), otherwise it returned a `cf.FieldList`.

## regridc

Note

At version 2.x `cf.Field.regridc` the regridding method must be specified. The `method` parameter does not have an `'auto'` option.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> g
    <CF Field: specific_humidity(time(360), latitude(73), longitude(96)) K>
    >>> h = f.regridc(g, 'time', 'nearest_stod')
    >>> h
    <CF Field: air_temperature(time(360), latitude(64), longitude(128)) K>

At version 1.x the regridding method defaulted to `'auto'`, meaning that the method was inferred according to metadata present in the field.

## regrids

Note

At version 2.x `cf.Field.regrids` the regridding method must be specified. The `method` parameter does not have an `'auto'` option.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> g
    <CF Field: specific_humidity(time(360), latitude(73), longitude(96)) K>
    >>> h = f.regrids(g, 'conservative')
    >>> h
    <CF Field: air_temperature(time(12), latitude(73), longitude(96)) K>

At version 1.x the regridding method defaulted to `'auto'`, meaning that the method was inferred according to metadata present in the field.

## properties

Note

At version 2.x `cf.Field.properties` is callable and allows the CF properties to be updated inplace.

    >>> cf.__version__
    2.0
    >>> f.properties()
    {'Conventions': 'CF-1.6',
     'experiment_id': 'pre-industrial control experiment',
     'project_id': 'IPCC Fourth Assessment',
     'realization': 1,
     'standard_name': 'air_temperature',
     'title': 'model output prepared for IPCC AR4'}

At version 1.x it wasn’t callable and returned a `dict` copy of the CF properties.

## select

Note

At version 2.x `cf.Field.select` has been removed. Use `cf.Field.match` to see if an individual field meets given criteria.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> f.match('air_temperature')
    True

`cf.FieldList.select` always returns another field list.

    >>> fl
    [<CF Field: specific_humidity(latitude(73), longitude(96)) K>,
     <CF Field: air_pressure(height(17), latitude(145), longitude(196)) K>]
    >>> fl.select('specific_humidity|air_pressure')
    [<CF Field: specific_humidity(latitude(73), longitude(96)) K>,
     <CF Field: air_pressure(height(17), latitude(145), longitude(196)) K>]
    >>> fl.select('specific_humidity')
    [<CF Field: specific_humidity(latitude(73), longitude(96)) K>]
    >>> fl.select('ocean_meridional_overturning_streamfunction')
    []

The new method `cf.FieldList.select_field` will always return a `cf.Field` if there is only one identified in the field list.

    >>> fl.select_field('specific_humidity')
    <CF Field: specific_humidity(latitude(73), longitude(96)) K>

At version 1.x `cf.FieldList.select` returned a `cf.Field` if only one field element was found in the field list, otherwise it returned a `cf.FieldList`. `cf.Field.select` either returned the field itself or an empty `cf.FieldList`.

## Indexing a field

Warning

Running code written at version 1.x with the version 2.x library could produce scientifically different results.

Note

At version 2.x indexing on a field object returns a subspace of the field, in exactly the way that indexing the `cf.Field.subspace` attribute does.

    >>> cf.__version__
    2.0
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> g = f[::-2, 0, 28:]
    >>> g
    <CF Field: air_temperature(time(6), latitude(1), longitude(100)) K>
    >>> h = f.subspace[::-2, 0, 28:]
    >>> h
    <CF Field: air_temperature(time(6), latitude(1), longitude(100)) K>
    >>> g.equals(h)
    True
    >>> f.equals(f[0])
    False

Assignment to a subspace of the data array may either be done to a subspace defined by direct indexing or to one defined by indexing the `cf.Field.subspace` attribute.

    >>> g = f.copy()
    >>> g[0] = -99
    >>> h = f.copy()
    >>> h.subspace[0] = -99
    >>> g.equals(h)
    True

At version 1.x direct indexing on a field returned the field itself, with no subspacing.

    >>> cf.__version__
    1.5
    >>> f
    <CF Field: air_temperature(time(12), latitude(64), longitude(128)) K>
    >>> f.equals(f[0])
    True