
Getting Started with Sea Ice CCI DataΒΆ
1. Import Necessary PackagesΒΆ
In this section, we import the required Python packages to work with ESA Climate Change Initiative (CCI) data. Most notably, we use the ESA Climate Toolbox which simplifies access, manipulation, and visualization of CCI datasets in Python.
These packages allow us to:
Access satellite-based climate data records from ESA.
Handle geospatial and temporal dimensions efficiently.
Visualize data with intuitive plotting tools.
π For a broader introduction to the toolbox and how to install it, visit:
π ESA CCI Climate Toolbox Quick Start
π ESA Climate Data Toolbox Website
from xcube.core.store import new_data_store
from esa_climate_toolbox.core import get_op
from esa_climate_toolbox.core import list_ecv_datasets
from esa_climate_toolbox.core import get_store
from esa_climate_toolbox.core import list_datasets
from esa_climate_toolbox.ops import plot
import xarray as xr
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import warnings
warnings.filterwarnings("ignore") # Suppressing warnings to keep notebook output clean
%matplotlib inlineStep 2: Connect to the ESA CCI Data StoreΒΆ
The ESA Climate Toolbox provides direct access to the ESA Climate Data Store, which hosts harmonized satellite-based climate data records produced under the ESA Climate Change Initiative (CCI).
In this step, we establish a connection to the data store so we can browse and open datasets. This connection allows us to access data without having to download files manually β a convenient way to explore and analyze large geospatial datasets in cloud-friendly formats such as Zarr or Kerchunk.
The data store includes a wide range of essential climate variables (ECVs), such as aerosols, land surface temperature, sea level, and soil moisture.
π Learn more about available datasets:
π ESA Climate Data Toolbox β Quick Start Guide
cci_store = new_data_store("esa-cci")
# List all available data sets of an ECV
# list_ecv_datasets("seaice")Step 3: Define the Dataset IDΒΆ
To work with a specific ESA CCI dataset, we need to specify its dataset ID. This unique identifier tells the toolbox which variable and product we want to access.
In this example, we are using a dataset from the Sea Ice CCI project that provides daily Level 4 sea ice concentration (SICONC) data derived from multiple satellite sensors over the Southern Hemisphere. Sea ice concentration is a key parameter for monitoring polar climate change, seasonal variability, and its interaction with the atmosphere and ocean.
For other ESA CCI projects (e.g., Ozone, Land Cover, Permafrost), simply replace the dataset ID accordingly.
We will use the following dataset ID:
data_id = 'esacci.SEAICE.day.L4.SICONC.multi-sensor.multi-platform.AMSR_25kmEASE2.2-1.SH'π A full list of dataset IDs can be retrieved from the store or found in the ESA CCI Climate Toolbox documentation.
Step 4: Describe Dataset (Check Available Variables and Metadata)ΒΆ
Before loading the full dataset, itβs helpful to inspect the metadata to understand its structure. This includes:
Available variables (e.g., sea ice concentration (ice_con), uncertainty estimates)
Temporal and spatial coverage
Data format and structure
This step ensures we know what the dataset contains and how to work with it. It also helps confirm that the variable we want to plot or analyze is actually included.
π οΈ Tip: You can use the description to verify variable names, dimensions (e.g., lat, lon, time), and time coverage.
π More on dataset structure:
π ESA Climate Toolbox β Data Access
cci_store.describe_data(data_id)Step 5: Check Open Parameters for the DatasetΒΆ
Before opening the dataset, we can inspect which parameters are supported by the Zarr opener (e.g., time_range, bbox, variable_names). This step helps ensure that we pass valid arguments when loading data and avoid errors.
The command below lists all expected input parameters and their allowed values for the selected dataset.
cci_store.get_open_data_params_schema(data_id=data_id, opener_id='dataset:zarr:cciodp')Step 6: Define Region, Time Range, and Variables of InterestΒΆ
Before opening the dataset, we define a few key parameters:
Time range: the date(s) we want to load
Variables: which data variable(s) to retrieve
(Optional) Bounding box: spatial region of interest β here we skip it to load the global dataset
variables = ['ice_conc'] # Variable to retrieve
start_date = '2016-09-21' # Start and end date (same for a single timestep)
end_date = '2016-09-21'
# bbox = (-10.0, 35.0, 30.0, 60.0) # Optional: restrict to a region like EuropeStep 7: Open the DatasetΒΆ
Now we open the dataset using the selected parameters.
The ESA Climate Toolbox will download only the necessary data (e.g., variable and time range).
You can always adjust the time range or variables to explore different slices of the dataset.
seaice_ds = cci_store.open_data(
data_id=data_id,
variable_names=variables,
time_range=[start_date, end_date]
# bbox=bbox # Uncomment if regional selection is needed
)Step 8: Display Dataset StructureΒΆ
We print a summary of the opened dataset to inspect its structure, dimensions, variables, and metadata.
This helps verify that the data was loaded correctly and shows what is available for analysis and visualization.
This step is useful to understand what the dataset contains before working with it further.
We will also inspect the unit of the data coordinates and have a look at the projection, in case we need to convert the coordinates to match them with geographical information in the plot.
print("\nOpened Dataset:\n", seaice_ds)
Opened Dataset:
<xarray.Dataset> Size: 1MB
Dimensions: (time: 1, yc: 432, xc: 432, bnds: 2)
Coordinates:
* time (time) datetime64[ns] 8B 2016-09-21T12:00:00
time_bnds (time, bnds) datetime64[ns] 16B dask.array<chunksize=(1, 2), meta=np.ndarray>
* xc (xc) float64 3kB -5.388e+03 -5.362e+03 ... 5.388e+03
* yc (yc) float64 3kB 5.388e+03 5.362e+03 ... -5.388e+03
Dimensions without coordinates: bnds
Data variables:
Lambert_Azimuthal_Grid float64 8B ...
ice_conc (time, yc, xc) float64 1MB dask.array<chunksize=(1, 432, 432), meta=np.ndarray>
Attributes:
Conventions: CF-1.7
title: esacci.SEAICE.day.L4.SICONC.multi-sensor.multi-p...
date_created: 2025-11-03T10:45:16.295359
processing_level: L4
time_coverage_start: 2016-09-21T00:00:00
time_coverage_end: 2016-09-22T00:00:00
time_coverage_duration: P1DT0H0M0S
history: [{'program': 'xcube_cci.chunkstore.CciChunkStore...
# First, let's inspect the grid mapping attributes
print("Northern Hemisphere grid mapping:")
print(seaice_ds["Lambert_Azimuthal_Grid"])
# Check the coordinate ranges
print(f"x range: {seaice_ds["xc"].values.min():.2f} to {seaice_ds["xc"].values.max():.2f}")
print(f"y range: {seaice_ds["yc"].values.min():.2f} to {seaice_ds["yc"].values.max():.2f}")Northern Hemisphere grid mapping:
<xarray.DataArray 'Lambert_Azimuthal_Grid' ()> Size: 8B
[1 values with dtype=float64]
Attributes: (12/17)
grid_mapping_name: lambert_azimuthal_equal_area
longitude_of_projection_origin: 0.0
latitude_of_projection_origin: -90.0
false_easting: 0.0
false_northing: 0.0
semi_major_axis: 6378137.0
... ...
shape: []
chunk_sizes: []
file_chunk_sizes: [1]
data_type: int64
dimensions: []
file_dimensions: []
x range: -5387.50 to 5387.50
y range: -5387.50 to 5387.50
Step 9: Visualize ResultsΒΆ
We now create a simple map plot of the selected variable.
This allows us to explore the spatial patterns of the data β in this case, the Sea Ice Concentration for the selected day.
For more interactive and advanced visualizations, check out the ESA Climate Toolbox or the Toolbox documentation.
From the output above, we learn that the projection is Lambert_Azimuthal_Grid and that the x- and y-values are given in km based on their dimensions.
In the next step, we will use this information to be able to combine our sea ice dataset with cartopy, so we can plot the coastlines as well.
We will start with defining all parameters we need for the plotting.
# Force eager loading by disabling chunks
seaice_ds_eager = seaice_ds.compute()
# Extract ice concentration
ice_conc = seaice_ds_eager["ice_conc"].isel(time=0).squeeze()
# Extract coordinates and convert from km to meters (see output above, where x and y range go from -5387 to + 5387)
x = seaice_ds_eager["xc"].values * 1000 # converting km to m
y = seaice_ds_eager["yc"].values * 1000
# Get date for the title
time_str = seaice_ds_eager['time'].isel(time=0).dt.strftime('%d %B %Y').item()
# Define projections matching the data's grid mapping
# The output above showed semi_major_axis = 6378137.0, the semi-major axis is the longest semidiameter of the globe, in this case 6378.137 km
globe = ccrs.Globe(semimajor_axis=6378137.0)
# The central longitude and latitude can also be found above
proj = ccrs.LambertAzimuthalEqualArea(
central_longitude=0.0,
central_latitude=-90.0,
globe=globe
)Now that we converted the x and y values and defned the projection, we can create a plot.
# Now we plot the figure using the information defined before
fig = plt.figure(figsize=(14, 7))
# --- Northern Hemisphere plot ---
ax = plt.subplot(1, 1, 1, projection=proj)
mesh = ax.pcolormesh(
x, y, ice_conc,
transform=proj,
cmap="Blues_r", vmin=0, vmax=100
)
ax.coastlines(resolution='50m')
ax.gridlines(draw_labels=False, linewidth=0.5, linestyle='--', alpha=0.5)
ax.set_title(f"Antarctic Sea Ice Concentration β {time_str}")
# Shared colorbar
cbar = fig.colorbar(mesh)#, cax=cbar_ax, orientation='horizontal')
cbar.set_label("Sea Ice Concentration (%)")
plt.tight_layout()
plt.show()