Reading or creating features

feature objects inherit from the main Feature base class which itself is particular type of Dataset (and derives from it). As such they can be created exactly in the same way as a Dataset object. They can also be created from other instances of dataset classes. Feature is an abstract base class and only objects from other classes in feature package can be instantiated.

A feature object can therefore be created, as any Dataset object, but it has to match the expected requirements on dimensions and coordinates of the instantiated feature class (see creating_datasets). In addition, it can be created from (and saved to) any cerbere object of dataset class. Examples are provided in the following sections.

Reading a feature from a file

Knowing the feature type of an object stored in a file, and dataset reader class corresponding to the file format, one can directly read the content from this file as a fully formed feature object.

In the following example, let’s open a CMEMS In Situ TAC drifter file, which is a Trajectory feature, for which there is a special CMEMSInsituDataset dataset reader class in cerberecontrib_marineinsitu cerbere contrib package.

>>> import cerbere
>>> traj = cerbere.open_as_feature(
... 'Trajectory',
... './tests/data/CMEMSInsituDataset/GL_TS_DB_6401811_20200517.nc',
... 'CMEMSInsituDataset')
>>> print(traj)

Creating a feature from or like a xarray Dataset object

Features can be created from a xarray xarray.Dataset object or using the same arguments as the ones used for creating a xarray.Dataset object. The definition of the xarray.Dataset object must match the requirements of the feature to be instantiated, in terms of dimensions and coordinate variables.

For instance to create a CylindricalGrid feature from a xarray.Dataset object, the later must have:

  • lat, lon, time dimensions. time dimension must have a length equal to 1.

  • a lat coordinate variable with dimension lat.

  • a lon coordinate variable with dimension lon.

  • a time coordinate variable with dimension time.

  • data variables with spatial dimensions (lat, lon,). Extra dimensions are allowed (except time).

    >>> import xarray as xr
    >>> import numpy as np
    >>> from datetime import datetime
    >>> from cerbere.feature.grid import CylindricalGrid
    >>>
    >>> # create an xarray Dataset with the structure of a cylindrical grid
    >>> lat = xr.DataArray(data=np.arange(-80, 80, 1), dims=['lat'])
    >>> lon = xr.DataArray(data=np.arange(-180, 180, 1), dims=['lon'])
    >>> time = xr.DataArray([datetime(2018, 1, 1)], dims='time')
    >>> var = xr.DataArray(
    ...             data=np.ones(shape=(160, 360)),
    ...             dims=['lat', 'lon'],
    ...             attrs={'myattr': 'test_attr_val'}
    ...         )
    >>> xrdataset = xr.Dataset(
    ...             coords={'lat': lat, 'lon': lon, 'time': time},
    ...             data_vars={'myvar': var},
    ...             attrs={'gattr1': 'gattr1_val', 'gattr2': 'gattr2_val'}
    ...         )
    >>>
    >>> # create the cylindrical grid feature from the xarray dataset object
    >>> grid = CylindricalGrid(xrdataset)
    

We can also pass directly the arguments for creating the xarray.Dataset to the CylindricalGrid constructor:

>>> grid = CylindricalGrid({
...     'coords': {
...         'time': {'dims': ('time'), 'data': [datetime(2018, 1, 1)]},
...         'lat': {'dims': ('lat'), 'data': np.arange(-80, 80, 1)},
...         'lon': {'dims': ('lon',), 'data': np.arange(-180, 180, 1)}},
...     'attrs': {'gattr1': 'gattr_val'},
...     'data_vars': {'myvar': {'dims': ('lat', 'lon',), 'data': np.ones(shape=(160, 360))}}
...  })
>>> grid = CylindricalGrid(
...     {'myvar': (['lat', 'lon'], np.ones(shape=(160, 360)))},
...     coords={
...         'time': (['time'], [datetime(2018, 1, 1)], {
...                      'units': 'seconds since 2001-01-01 00:00:00'}),
...         'lat': (['lat'], np.arange(-80, 80, 1)),
...         'lon': (['lon'], np.arange(-180, 180, 1))
...      },
...     attrs={'gattr1': 'gattr_val'}
... )

… or any other way described in creating_datasets.

Saving a feature to disk

A feature object can be saved to disk using a class object from dataset package provided it implements the save() method. Select the class corresponding to the format in which the feature must be saved.

For instance to save a feature to a CF compliant NetCDF4 file, the NCDataset can be used.

from cerbere.dataset.ncdataset import NCDataset

# instantiate a NCDataset object in write mode
ncf = NCDataset(dataset='test.nc', mode='w')

# save above cylindrical grid feature into a CF NetCDF4 file
grid.save(ncf)