The ESA Climate Change Initative Sea Surface Temperature data¶

  • Funding: ESA and AWS Public Dataset Program

Credits: Tutorial development¶

  • Niall McCarroll
  • Dr. Chelle Gentemann - Twitter - Farallon Institute

Credits: Creating of the Zarr CCI SST dataset.¶

  • Niall McCarroll
  • Dr. Chris Merchant

Tutorial 1 - Getting Started¶

This tutorial helps you get started with the Sea Surface Temperature Daily Analysis dataset: European Space Agency Climate Change Initiative product version 2.1, hosted by AWS opendata.

1.0 Importing packages¶

In [11]:
import fsspec
import matplotlib.pyplot as plt
import s3fs
import xarray as xr
import numpy as np

1.1 Opening the dataset¶

The following code will load the metadata for the dataset. It is really fast because it uses 'lazy loading'. Data is only loaded when it is needed, and only the chunks that are needed are accessed.

In [2]:
# if you are running on AWS cloud you can use the line below and it will be faster to read and access the data
#ds = xr.open_zarr(fsspec.get_mapper("s3://surftemp-sst/data/sst.zarr"),consolidated=True)

# if you are running anywhere other than AWS cloud (eg. your local computer or mybinder.org) this is the line that will work
ds = xr.open_zarr('https://surftemp-sst.s3.us-west-2.amazonaws.com/data/sst.zarr')

1.2 Inspecting the dataset¶

Xarray will print out all the variables in the dataset so you can explore them. Click on the icons to the right of the data to examine the data variable attributes and see some values for the data variable. At the bottom you can explore the global attributes for the dataset. This dataset contains:

Variable name Description Units
analysed_sst Analysed sea surface temperature (Kelvin) kelvin
analysis_uncertainty Estimated error standard deviation of analysed_sst kelvin
sea_ice_fraction The estimated fraction of the area covered by sea ice -
mask Bit mask (bit0:sea,bit1:land:bit2:lake,bit3:ice) -
In [3]:
ds
Out[3]:
<xarray.Dataset>
Dimensions:                   (time: 14367, lat: 3600, lon: 7200, bnds: 2)
Coordinates:
  * lat                       (lat) float32 -89.97 -89.93 -89.88 ... 89.93 89.97
  * lon                       (lon) float32 -180.0 -179.9 -179.9 ... 179.9 180.0
  * time                      (time) datetime64[ns] 1981-09-01T12:00:00 ... 2...
Dimensions without coordinates: bnds
Data variables:
    analysed_sst              (time, lat, lon) float32 dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
    analysed_sst_uncertainty  (time, lat, lon) float32 dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
    lat_bnds                  (lat, bnds) float32 dask.array<chunksize=(360, 2), meta=np.ndarray>
    lon_bnds                  (lon, bnds) float32 dask.array<chunksize=(720, 2), meta=np.ndarray>
    mask                      (time, lat, lon) float32 dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
    sea_ice_fraction          (time, lat, lon) float32 dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
Attributes: (12/61)
    Conventions:                     CF-1.5, Unidata Observation Dataset v1.0
    Metadata_Conventions:            Unidata Dataset Discovery v1.0
    acknowledgment:                  Funded by the Copernicus Climate Change ...
    cdm_data_type:                   grid
    comment:                         These data were produced by the Met Offi...
    contact:                         http://copernicus-support.ecmwf.int
    ...                              ...
    time_coverage_resolution:        P1D
    time_coverage_start:             20201215T000000Z
    title:                           C3S SST L4 product
    tracking_id:                     7fdf2639-26e5-4d4f-a60e-0bcfc9744204
    uuid:                            7fdf2639-26e5-4d4f-a60e-0bcfc9744204
    westernmost_longitude:           -180.0
xarray.Dataset
    • time: 14367
    • lat: 3600
    • lon: 7200
    • bnds: 2
    • lat
      (lat)
      float32
      -89.97 -89.93 ... 89.93 89.97
      axis :
      Y
      bounds :
      lat_bnds
      comment :
      Latitude geographical coordinates,WGS84 projection
      long_name :
      Latitude
      reference_datum :
      geographical coordinates, WGS84 projection
      standard_name :
      latitude
      units :
      degrees_north
      valid_max :
      90.0
      valid_min :
      -90.0
      array([-89.975, -89.925, -89.875, ...,  89.875,  89.925,  89.975],
            dtype=float32)
    • lon
      (lon)
      float32
      -180.0 -179.9 ... 179.9 180.0
      axis :
      X
      bounds :
      lon_bnds
      comment :
      Longitude geographical coordinates,WGS84 projection
      long_name :
      Longitude
      reference_datum :
      geographical coordinates, WGS84 projection
      standard_name :
      longitude
      units :
      degrees_east
      valid_max :
      180.0
      valid_min :
      -180.0
      array([-179.975, -179.925, -179.875, ...,  179.875,  179.925,  179.975],
            dtype=float32)
    • time
      (time)
      datetime64[ns]
      1981-09-01T12:00:00 ... 2020-12-...
      axis :
      T
      bounds :
      time_bnds
      comment :
      long_name :
      reference time of sst field
      standard_name :
      time
      array(['1981-09-01T12:00:00.000000000', '1981-09-02T12:00:00.000000000',
             '1981-09-03T12:00:00.000000000', ..., '2020-12-29T12:00:00.000000000',
             '2020-12-30T12:00:00.000000000', '2020-12-31T12:00:00.000000000'],
            dtype='datetime64[ns]')
    • analysed_sst
      (time, lat, lon)
      float32
      dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
      depth :
      20 cm
      long_name :
      analysed sea surface temperature
      source :
      ATSR<1,2>-ESACCI-L3U-v2.0, AATSR-ESACCI-L3U-v2.0, AVHRR<07,09,11,12,14,15,16,17,18,19>_G-ESACCI-L3U-v2.0, AVHRRMTA_G-ESACCI-L3U-v2.0
      standard_name :
      sea_water_temperature
      units :
      kelvin
      valid_max :
      4500
      valid_min :
      -300
      Array Chunk
      Bytes 1.35 TiB 49.44 MiB
      Shape (14367, 3600, 7200) (50, 360, 720)
      Count 28801 Tasks 28800 Chunks
      Type float32 numpy.ndarray
      7200 3600 14367
    • analysed_sst_uncertainty
      (time, lat, lon)
      float32
      dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
      long_name :
      estimated error standard deviation of analysed_sst
      standard_name :
      sea_water_temperature standard_error
      units :
      kelvin
      valid_max :
      32767
      valid_min :
      0
      Array Chunk
      Bytes 1.35 TiB 49.44 MiB
      Shape (14367, 3600, 7200) (50, 360, 720)
      Count 28801 Tasks 28800 Chunks
      Type float32 numpy.ndarray
      7200 3600 14367
    • lat_bnds
      (lat, bnds)
      float32
      dask.array<chunksize=(360, 2), meta=np.ndarray>
      comment :
      Contains the northern and southern boundaries of the grid cells.
      long_name :
      Latitude cell boundaries
      reference_datum :
      geographical coordinates, WGS84 projection
      valid_max :
      90.0
      valid_min :
      -90.0
      Array Chunk
      Bytes 28.12 kiB 2.81 kiB
      Shape (3600, 2) (360, 2)
      Count 11 Tasks 10 Chunks
      Type float32 numpy.ndarray
      2 3600
    • lon_bnds
      (lon, bnds)
      float32
      dask.array<chunksize=(720, 2), meta=np.ndarray>
      comment :
      Contains the eastern and western boundaries of the grid cells.
      long_name :
      Longitude cell boundaries
      reference_datum :
      geographical coordinates, WGS84 projection
      valid_max :
      180.0
      valid_min :
      -180.0
      Array Chunk
      Bytes 56.25 kiB 5.62 kiB
      Shape (7200, 2) (720, 2)
      Count 11 Tasks 10 Chunks
      Type float32 numpy.ndarray
      2 7200
    • mask
      (time, lat, lon)
      float32
      dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
      comment :
      b0: 1=grid cell is open sea water b1: 1=grid cell is land b2: 1=grid cell is lake surface b3: 1=grid cell is sea ice b4-b7: reserved for future grid mask data
      flag_masks :
      [1, 2, 4, 8, 16]
      flag_meanings :
      water land optional_lake_surface sea_ice optional_river_surface
      long_name :
      sea/land/lake/ice field composite mask
      source :
      NAVOCEANO_landmask_v1.0 EUMETSAT_OSI-SAF_icemask ARCLake_lakemask
      valid_max :
      31
      valid_min :
      1
      Array Chunk
      Bytes 1.35 TiB 49.44 MiB
      Shape (14367, 3600, 7200) (50, 360, 720)
      Count 28801 Tasks 28800 Chunks
      Type float32 numpy.ndarray
      7200 3600 14367
    • sea_ice_fraction
      (time, lat, lon)
      float32
      dask.array<chunksize=(50, 360, 720), meta=np.ndarray>
      comment :
      Sea ice area fraction
      long_name :
      sea ice area fraction
      source :
      EUMETSAT_OSI-SAF-ICE-OSI-450-v2.0, EUMETSAT_OSI-SAF-ICE-OSI-430-v1.2
      standard_name :
      sea_ice_area_fraction
      units :
      1
      valid_max :
      100
      valid_min :
      0
      Array Chunk
      Bytes 1.35 TiB 49.44 MiB
      Shape (14367, 3600, 7200) (50, 360, 720)
      Count 28801 Tasks 28800 Chunks
      Type float32 numpy.ndarray
      7200 3600 14367
  • Conventions :
    CF-1.5, Unidata Observation Dataset v1.0
    Metadata_Conventions :
    Unidata Dataset Discovery v1.0
    acknowledgment :
    Funded by the Copernicus Climate Change Service. Use of these data should acknowledge the Copernicus Climate Change Service
    cdm_data_type :
    grid
    comment :
    These data were produced by the Met Office as part of the C3S project. WARNING Some applications are unable to properly handle signed byte values. If values are encountered > 127, please subtract 256 from this reported value
    contact :
    http://copernicus-support.ecmwf.int
    corrections :
    Post-hoc corrections have been applied from Merchant and Embury (2020) https://doi.org/10.3390/rs12162554
    creation_date :
    2021-02-10T10:53:38Z
    creator_email :
    science.leader@esa-sst-cci.org
    creator_name :
    Copernicus Climate Change Service (C3S)
    creator_processing_institution :
    These data were produced on the JASMIN infrastructure at STFC as part of the C3S project
    creator_url :
    https://climate.copernicus.eu/
    date_created :
    20210210T105338Z
    easternmost_longitude :
    180.00001525878906
    file_quality_level :
    3
    gds_version_id :
    2.0
    geospatial_lat_max :
    90.0
    geospatial_lat_min :
    -90.0
    geospatial_lat_resolution :
    0.05000000074505806
    geospatial_lat_units :
    degrees_north
    geospatial_lon_max :
    180.0
    geospatial_lon_min :
    -180.0
    geospatial_lon_resolution :
    0.05000000074505806
    geospatial_lon_units :
    degrees_east
    geospatial_vertical_max :
    -0.20000000298023224
    geospatial_vertical_min :
    -0.20000000298023224
    history :
    Created using OSTIA reanalysis system v3.0
    id :
    OSTIA-C3S-L4-GLOB-v2.0
    institution :
    C3S
    keywords :
    Oceans > Ocean Temperature > Sea Surface Temperature
    keywords_vocabulary :
    NASA Global Change Master Directory (GCMD) Science Keywords
    license :
    Creative Commons Licence by attribution (https://creativecommons.org/licenses/by/4.0/)
    metadata_link :
    http://www.esa-cci.org
    naming_authority :
    org.ghrsst
    netcdf_version_id :
    4.2.1.1 of Oct 19 2012 14:25:16
    northernmost_latitude :
    90.0
    platform :
    NOAA-19, MetOpA, Sentinel-3A
    processing_level :
    L4
    product_specification_version :
    SST_CCI-PSD-UKMO-201-Issue-H
    product_version :
    2.0
    project :
    Copernicus Climate Change Service (C3S)
    publisher_email :
    copernicus-support@ecmwf.int
    publisher_name :
    Copernicus Climate Data Store
    publisher_url :
    https://climate.copernicus.eu/
    references :
    http://www.esa-sst-cci.org
    sensor :
    AVHRR_GAC, SLSTR
    source :
    AVHRR19_G-C3S-L3U-ICDR-v2.0 AVHRRMTA_G-C3S-L3U-ICDR-v2.0 SLSTRA-C3S-L3U-ICDR-v2.0, OSI-430
    southernmost_latitude :
    -90.0
    spatial_resolution :
    0.05 degree
    standard_name_vocabulary :
    NetCDF Climate and Forecast (CF) Metadata Convention
    start_time :
    20201215T000000Z
    stop_time :
    20201216T000000Z
    summary :
    OSTIA L4 product from the C3S project, produced using OSTIA reanalysis sytem v3.0
    time_coverage_duration :
    P1D
    time_coverage_end :
    20201216T000000Z
    time_coverage_resolution :
    P1D
    time_coverage_start :
    20201215T000000Z
    title :
    C3S SST L4 product
    tracking_id :
    7fdf2639-26e5-4d4f-a60e-0bcfc9744204
    uuid :
    7fdf2639-26e5-4d4f-a60e-0bcfc9744204
    westernmost_longitude :
    -180.0

1.3 Plot a timeseries of the analyzed_sst over a specific time range¶

The data covers the earth's surface at a resolution of 0.05 degrees. If you are interested in temperatures at a single location, extract a timeseries at a specific location. This is easiest to do with two .sel calls. First we select our time range. Next we select the latitude and longitude specifing method="nearest" to find the nearest point.

In [4]:
ds["analysed_sst"] \
    .sel(time=slice("1982-01-01", "1985-12-31")) \
    .sel(lat=51, lon=-38, method="nearest") \
    .plot(figsize=(10, 5))
Out[4]:
[<matplotlib.lines.Line2D at 0x7fa80901af10>]

1.4 Plot data for a specific region¶

it is easy to select a subset of the data for given range of latitudes and longitudes. For example, to see the data for a region at a single point in time:

In [5]:
ds["analysed_sst"] \
    .sel(time="2006-02-23") \
    .sel(lat=slice(30, 45), lon=slice(115, 140)) \
    .plot(cmap="coolwarm", figsize=(5, 5))
Out[5]:
<matplotlib.collections.QuadMesh at 0x7fa809405050>

1.5 Plotting global sea surface temperatures at a point in time¶

In [6]:
ds["analysed_sst"].sel(time="1983-01-01").plot(cmap="coolwarm", figsize=(10, 5))
Out[6]:
<matplotlib.collections.QuadMesh at 0x7fa808e7b310>

1.6 Inspecting other variables in the dataset¶

In this dataset, the uncertainty is calculated for each pixel and included as another data variable. This can be useful when you are trying to understand how accurate the data is or how to blend it with other data or inject into a model. Here we plot the SST uncertainty data for a region (the gulf of guinea) at a single point in time:

In [7]:
ds["analysed_sst_uncertainty"] \
    .sel(time="2006-02-23")    \
    .sel(lat=slice(30, 45), lon=slice(115, 140)) \
    .plot(vmin=0, vmax=1)
Out[7]:
<matplotlib.collections.QuadMesh at 0x7fa75125e350>

This dataset calculates SST for all ocean pixels, including areas covered by sea ice. In those regions the SST relaxes back to -2 C (271.15 K). For some science applications, it is important to remove data covered by sea ice. This dataset has a variable for sea ice fraction that can be used to mask the data. Here we plot the sea ice fraction for 01 Jan 1983.

In [8]:
ds["sea_ice_fraction"] \
    .sel(time="1983-01-01") \
    .plot(vmin=0, vmax=1, figsize=(10, 5))
Out[8]:
<matplotlib.collections.QuadMesh at 0x7fa755a1eb90>

There is also a mask in the data. To see what the different values of the mask means, you can print out the attributes.

In [9]:
ds["mask"].attrs
Out[9]:
{'comment': 'b0: 1=grid cell is open sea water b1: 1=grid cell is land b2: 1=grid cell is lake surface b3: 1=grid cell is sea ice b4-b7: reserved for future grid mask data',
 'flag_masks': [1, 2, 4, 8, 16],
 'flag_meanings': 'water land optional_lake_surface sea_ice optional_river_surface',
 'long_name': 'sea/land/lake/ice field composite mask',
 'source': 'NAVOCEANO_landmask_v1.0 EUMETSAT_OSI-SAF_icemask ARCLake_lakemask',
 'valid_max': 31,
 'valid_min': 1}

Note in the attributes that this is a bit mask flag. The bits are given in the comments. Below we set up the bit flags and then plot each bit to show the different masks individually over Scandanavia

In [10]:
sea_bit,land_bit,lake_bit,seaice_bit = 0,1,2,3
bits = [sea_bit,land_bit,lake_bit,seaice_bit]
bitstr = ['Sea','Land','Lake','Sea Ice']

fig, axes = plt.subplots(ncols=4, figsize=(15, 5))

subset = (
    ds["mask"]
    .sel(time="2006-01-18")
    .sel(lon=slice(2, 42), lat=slice(53, 72))
)

for ib,bit in enumerate(bits):
    print(bitstr[bit])
    subset_mask = np.bitwise_and(subset.astype('uint8'), int(2**bit)) > 0
    subset_mask.plot(ax=axes[bit],add_colorbar=False)
    axes[bit].set_title(bitstr[bit])
Sea
Land
Lake
Sea Ice
In [ ]: