import os
import xarray as xr
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 usingxarray
? - 🛰️ 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
Helper functions
print_gen_structure
This function helps us to retrieve and visualise the names for each of the stored groups inside a .zarr
product. As an output, it will print a general overview of elements inside the zarr
.
def print_gen_structure(node, indent=""):
print(f"{indent}{node.name}") #allows us access each node
for child_name, child_node in node.children.items(): #loops inside the selected nodes to extract naming
+ " ") # prints the name of the selected nodes print_gen_structure(child_node, indent
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
storeengine
:zarr
, as it is the encoding structure of the file.chunks
: loads the data withDask
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:
= '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'
url
# Opening the .zarr's data tree:
= xr.open_datatree(
s3_lst_zarr_sample="zarr") url, engine
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:
"measurements/orphan"] # Run it yourself for an inteactive overview s3_lst_zarr_sample[
<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.