NOAA OISST: one day, and 45 years of one day

netCDF
multidim VRT
/vsizip/
/vsicurl/
/vsis3/
Daily netCDF over HTTPS and S3, and a zipped multidim VRT spanning the whole record.

NOAA’s Optimum Interpolation SST v2.1 is a quarter-degree daily analysis from September 1981, one netCDF file per day. It is served by NCEI over HTTPS and mirrored on AWS Open Data.

One day over HTTPS

  • Address: /vsicurl/https://www.ncei.noaa.gov/data/sea-surface-temperature-optimum-interpolation/v2.1/access/avhrr/202501/oisst-avhrr-v02r01.20250103.nc
  • Provider: NOAA NCEI
  • Permanent: an archive the provider commits to keeping.
  • Status: answered the store check at 2026-11-01 09:15 UTC.
dsn = ("/vsicurl/https://www.ncei.noaa.gov/data/sea-surface-temperature-optimum-interpolation/"
       "v2.1/access/avhrr/202501/oisst-avhrr-v02r01.20250103.nc")
if live("oisst-ncei"):
    day = xr.open_dataset(dsn, engine="gdalxarray")
    print(day)
<xarray.Dataset> Size: 33MB
Dimensions:  (time: 1, zlev: 1, lat: 720, lon: 1440)
Coordinates:
  * time     (time) datetime64[ns] 8B 2025-01-03T12:00:00
  * zlev     (zlev) float32 4B 0.0
  * lat      (lat) float32 3kB -89.88 -89.62 -89.38 -89.12 ... 89.38 89.62 89.88
  * lon      (lon) float32 6kB 0.125 0.375 0.625 0.875 ... 359.4 359.6 359.9
Data variables:
    anom     (time, zlev, lat, lon) float64 8MB ...
    err      (time, zlev, lat, lon) float64 8MB ...
    ice      (time, zlev, lat, lon) float64 8MB ...
    sst      (time, zlev, lat, lon) float64 8MB ...
Attributes: (12/37)
    Conventions:                CF-1.6, ACDD-1.3
    title:                      NOAA/NCEI 1/4 Degree Daily Optimum Interpolat...
    references:                 Reynolds, et al.(2007) Daily High-Resolution-...
    source:                     ICOADS, NCEP_GTS, GSFC_ICE, NCEP_ICE, Pathfin...
    id:                         oisst-avhrr-v02r01.20250103.nc
    naming_authority:           gov.noaa.ncei
    ...                         ...
    time_coverage_start:        2025-01-03T00:00:00Z
    time_coverage_end:          2025-01-03T23:59:59Z
    metadata_link:              https://doi.org/10.25921/RE9P-PT57
    ncei_template_version:      NCEI_NetCDF_Grid_Template_v2.0
    comment:                    Data was converted from NetCDF-3 to NetCDF-4 ...
    sensor:                     Thermometer, AVHRR
if live("oisst-ncei"):
    fig, ax = plt.subplots(figsize=(10, 4.5))
    day["sst"].isel(time=0, zlev=0).plot(ax=ax, cmap="RdYlBu_r", vmin=-2, vmax=32)
    ax.set_title(str(day.time.values[0])[:10])
    plt.show()

OISST v2.1 for one day, read from NCEI over /vsicurl/.

The same product on S3

The AWS mirror is a public bucket, read anonymously. config_options= applies GDAL settings around the open and again around every later lazy read, so they do not need to be set process-wide:

  • Address: /vsis3/noaa-cdr-sea-surface-temp-optimum-interpolation-pds/data/v2.1/avhrr/198109/oisst-avhrr-v02r01.19810930.nc
  • Provider: NOAA Open Data Dissemination
  • Permanent: an archive the provider commits to keeping.
  • Status: answered the store check at 2026-11-01 09:15 UTC.
dsn = ("/vsis3/noaa-cdr-sea-surface-temp-optimum-interpolation-pds/"
       "data/v2.1/avhrr/198109/oisst-avhrr-v02r01.19810930.nc")
if live("oisst-aws"):
    first = xr.open_dataset(dsn, engine="gdalxarray",
                            config_options={"AWS_NO_SIGN_REQUEST": "YES", "AWS_REGION": "us-east-1"})
    print(first["sst"].sel(lat=-42.875, lon=148.125, method="nearest").values.ravel())
[11.61999974]

Forty-five years of one day

A multidimensional VRT can stitch every daily file into one (time, zlev, lat, lon) array. Zipped, the whole record is one small file on a GitHub release; the VRT refers to the daily files on AWS, so the composition is /vsizip/ over /vsicurl/ for the recipe and /vsis3/ for the data.

  • Address: /vsizip//vsicurl/https://github.com/mdsumner/xrdbi/releases/download/latest/oisst-mdim.vrt.zip/oisst-mdim.vrt
  • Provider: mdsumner/xrdbi GitHub release tag latest
  • Rolling: the address is stable, the contents change over time.
  • Status: answered the store check at 2026-11-01 09:15 UTC.
dsn = ("/vsizip//vsicurl/https://github.com/mdsumner/xrdbi/releases/download/latest/"
       "oisst-mdim.vrt.zip/oisst-mdim.vrt")
if live("oisst-mdim-zip"):
    rec = xr.open_dataset(dsn, engine="gdalxarray", config_options={"AWS_NO_SIGN_REQUEST": "YES"})
    print(dict(rec.sizes), str(rec.time.values[0])[:10], str(rec.time.values[-1])[:10])
{'time': 16382, 'zlev': 1, 'lat': 720, 'lon': 1440} 1981-09-01 2026-07-08

Each 27 June, in a one-degree box off eastern Tasmania. The boolean selection reaches gdalxarray as a list of days, and it reads just those days (45 small reads), not the span from the first to the last:

if live("oisst-mdim-zip"):
    t = rec.time.dt
    box = (rec["sst"].sel(lat=slice(-44, -43), lon=slice(147, 148))
           .isel(time=(t.month == 6) & (t.day == 27)))
    series = box.mean(["zlev", "lat", "lon"]).load()
    fig, ax = plt.subplots(figsize=(9, 3.5))
    series.plot(ax=ax, marker="o")
    ax.set_ylabel("SST (degrees C)"); ax.set_title("27 June, each year of the record")
    plt.show()

Mean SST on 27 June each year, 43-44S 147-148E, off eastern Tasmania.

Rendered with GDAL 3.13.3, xarray 2026.4.1.dev32+g71cfb13ac, numpy 2.5.4, gdalxarray 0.5.1, rasterix 0.2.4.