Discover EOPF Zarr - Sentinel-3 SLSTR Level-2 LST

Introduction

This tutorial introduces you to the structure of an EOPF Zarr product sample for Sentinel-3 SLSTR Level-2 Land Surface Temperature data. We will demonstrate how to access and open a .zarr product sample with xarray, how to visualise the zarr encoding structure, explore embedded information, and retrieve relevant metadata for further processing.

What we will learn

  • ⚙️ How to open a .zarr file using xarray?
  • 🛰️ The general structure of a Sentinel-3 SLSTR Level-2 LST item
  • 🔎 How to access metadata that describes the .zarr encoding?

Prerequisites

This tutorial uses a re-processed sample dataset from the EOPF Sentinel Zarr Samples Service STAC API that is available for direct access here.

The selected .zarr product is a Sentinel-3 SLSTR Level-2 LST tile from the 29th of May 2025:

  • File name: S3B_SL_2_LST____20250529T093001_20250529T093301_20250623T143718_0179_107_093_2340_ESA_O_NT_004.zarr.

Import libraries

import os
import xarray as xr

Helper functions

Open the zarr Store

In a first step, we use the open_datatree() function from the xarray library to open a .zarr store as a DataTree.
Inside, we need to define the following key word arguments:

  • filename_or_obj: path leading to a .zarr store
  • engine: zarr, as it is the encoding structure of the file.
  • chunks: loads the data with Dask using the engine’s preferred chunk size. If {} the loaded chunks are identical to the format’s original chunk size.

The final print of the DataTree object is commented out, as the display can be quite extensive, showing the entire content within the .zarr. An alternative is to apply a helper function that only displays the higher-level structure as shown in the next code cell.

# Defining the storage path:
url = 'https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:202505-s03slslst/29/products/cpm_v256/S3B_SL_2_LST____20250529T093001_20250529T093301_20250623T143718_0179_107_093_2340_ESA_O_NT_004.zarr'

# Opening the .zarr's data tree:
s3_lst_zarr_sample= xr.open_datatree(
    url, engine="zarr")

If we apply the helper function print_gen_structure on the root of the DataTree object, we will get a listing of the tree-like structure of the object. We can see all Zarr groups, such as measurements, quality and conditions, their sub-groups and content.

print("Zarr Sentinel-3 SLSTR Level-2 LST")
print_gen_structure(s3_lst_zarr_sample.root) 
print(' ', 'attributes', list(s3_lst_zarr_sample.attrs.keys()))
Zarr Sentinel-3 SLSTR Level-2 LST
None
  conditions
    auxiliary
      orphan
    geometry
    meteorology
    processing
      orphan
    time
  measurements
    orphan
  quality
    orphan
  attributes ['other_metadata', 'stac_discovery']

Extract information from Zarr groups

In the next step, we can explore the content of individual .zarr groups. By specifying the name of the group and subgroup and adding it into square brackets, we can extract the content of the relevant group. Let us extract the content of the subgroup orphan under measurements.

As a result, it is visible that Land Surface Temperature is stored as lst, with its respective coordinates in both x and y (EPSG: Respective to UTM zone) and latitude and longitude (EPSG:4326).

The xarray.DataTree structure allows the exploration of additional group-related metadata and information. For example, we can find the chunksize of each array and the coordinates.

# Retrieving the group where LST is stored:
s3_lst_zarr_sample["measurements/orphan"] # Run it yourself for an inteactive overview
<xarray.DatasetView> Size: 8MB
Dimensions:    (rows: 1200, columns: 1500, orphan_pixels: 187)
Coordinates:
    latitude   (rows, orphan_pixels) float64 2MB ...
    longitude  (rows, orphan_pixels) float64 2MB ...
    x          (rows, orphan_pixels) float64 2MB ...
    y          (rows, orphan_pixels) float64 2MB ...
Dimensions without coordinates: rows, columns, orphan_pixels
Data variables:
    lst        (rows, orphan_pixels) float32 898kB ...

Extract Zarr metadata on different levels

Through s3a_lst_zarr_sample.attrs[] we are able to visualise both the stac_discovery and other_metadata included in the zarr store.

For the properties inside stac_discovery for example we can get the parameters included:

# STAC metadata style:
print(list(s3_lst_zarr_sample.attrs["stac_discovery"].keys()))
['assets', 'bbox', 'collection', 'geometry', 'id', 'links', 'properties', 'stac_extensions', 'stac_version', 'type']

We are also, able to retrieve specific information by diving deep into the stac_discovery metadata, such as:

print('Date of Item Creation: ', s3_lst_zarr_sample.attrs['stac_discovery']['properties']['created'])
print('Item Bounding Box    : ', s3_lst_zarr_sample.attrs['stac_discovery']['bbox'])
print('Sentinel Platform    : ', s3_lst_zarr_sample.attrs['stac_discovery']['properties']['platform'])
print('Item Processing Level: ', s3_lst_zarr_sample.attrs['stac_discovery']['properties']['processing:level'])
print('Class ID.            : ', s3_lst_zarr_sample.attrs['stac_discovery']['properties']['product:timeliness_category'])
Date of Item Creation:  2025-06-23T14:37:18+00:00
Item Bounding Box    :  [20.6857, 28.6806, 1.68414, 41.9899]
Sentinel Platform    :  sentinel-3b
Item Processing Level:  L2
Class ID.            :  NT

And from other_metadata, we are able to retrieve the information specific to the instrument variables.

# Complementing metadata:
print(list(s3_lst_zarr_sample.attrs["other_metadata"].keys()))
['L0_offset_between_scan_index_and_ISP_scan_count_in', 'absolute_pass_number', 'band_description', 'cycle_number', 'data_information', 'eopf_category', 'ephemeris', 'history', 'i_nadir_first_acquired_pixel', 'i_oblique_first_acquired_pixel', 'in_scan_period_in_microseconds', 'meteo', 'phase_identifier', 'pixel_time_sampling_interval_along_scan_i_in_microseconds', 'product_unit', 'relative_pass_number', 'single_meteofield_synoptic_time_UTC_hours']

Some relevant information included:

print('i Nadir First Pixel   :', s3_lst_zarr_sample.attrs['other_metadata']['i_nadir_first_acquired_pixel'])
print('i Oblique First Pixel :',s3_lst_zarr_sample.attrs['other_metadata']['i_oblique_first_acquired_pixel'])
print('Phase Identifier      :',s3_lst_zarr_sample.attrs['other_metadata']['phase_identifier'])
i Nadir First Pixel   : 2469
i Oblique First Pixel : 1124
Phase Identifier      : 4

đź’Ş Now it is your turn

As we are able to retrieve several items from the EOPF Sentinel Zarr Samples Service STAC API, let us try the following:

Task

Go to the Sentinel-3 SLSTR Level-2 LST collection and:

  • Choose an item of interest.
  • Replicate the workflow and explore the item’s metadata. When was it retrieved?
  • What are the dimensions of the LST group?
  • What are the values of the bbox (location) of the item?

Conclusion

This tutorial provides an initial understanding of the .zarr structure for a Sentinel-3 SLSTR Level-2 LST product sample. By using the xarray library, we can effectively navigate and inspect the different components within the .zarr format, including its metadata and array organisation.

What’s next?

Now that you have been introduced to the .zarr encoding format, learned its core concepts, and understood the basics of how to explore it, you are prepared for the next step.
In the following chapter we will dive into the chunks concept for zarr and why is it relevant for EO.