Skip to article frontmatterSkip to article content

Microsoft Planetary Computer


The Planetary Computer includes a vast amount of ECMWF open data available via Azure Storage.

The earthkit and ecmwf-opendata package

When using the ecmwf-opendata Python library, we set source to azure and data hosted on Microsoft’s Azure will be accessed.

# !pip3 install ecmwf-opendata
from ecmwf.opendata import Client

client = Client(source="azure")
request = {
    "time": 12,
    "type": "fc",
    "step": 0,
    "param": "2t",
}
# client.retrieve(request, "azure_2t_data.grib2")
# dm_2t = ekd.from_source("file", "azure_2t_data.grib2")
# dm_2t.ls()
from ecmwf.opendata import Client
import earthkit.data

client = Client(source="https://ai4edataeuwest.blob.core.windows.net/ecmwf/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.grib2?st=2025-07-01T09%3A54%3A00Z&se=2025-07-02T10%3A39%3A00Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-07-02T02%3A32%3A03Z&ske=2025-07-09T02%3A32%3A03Z&sks=b&skv=2024-05-04&sig=qcG7eWdtC7/lhamMO1x8UwyA8A45tGFXAE55Xu5UQKg%3D")
request = {
    "date": "2025-06-25 12:00:00",
    "time": 12,
    "type": "fc",
    "step": 0,
    "stream": "oper",
    "param": "2t",
}
client.retrieve(request, "azure_2t_data.grib2")
dm_2t = ekd.from_source("file", "azure_2t_data.grib2")

ds = earthkit.data.from_source(
    "ecmwf-open-data",
    source="https://ai4edataeuwest.blob.core.windows.net/ecmwf/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.grib2?st=2025-07-01T09%3A54%3A00Z&se=2025-07-02T10%3A39%3A00Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-07-02T02%3A32%3A03Z&ske=2025-07-09T02%3A32%3A03Z&sks=b&skv=2024-05-04&sig=qcG7eWdtC7/lhamMO1x8UwyA8A45tGFXAE55Xu5UQKg%3D",
    model="ifs",
    date="20250625",
    time=12,
    stream="oper",
    type="fc",
    #param="2t",
    target="azure_2t_data.grib2",
)
ds.ls()
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
Cell In[13], line 13
      4 client = Client(source="https://ai4edataeuwest.blob.core.windows.net/ecmwf/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.grib2?st=2025-07-01T09%3A54%3A00Z&se=2025-07-02T10%3A39%3A00Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-07-02T02%3A32%3A03Z&ske=2025-07-09T02%3A32%3A03Z&sks=b&skv=2024-05-04&sig=qcG7eWdtC7/lhamMO1x8UwyA8A45tGFXAE55Xu5UQKg%3D")
      5 request = {
      6     "date": "2025-06-25 12:00:00",
      7     "time": 12,
   (...)     11     "param": "2t",
     12 }
---> 13 client.retrieve(request, "azure_2t_data.grib2")
     15 ds = earthkit.data.from_source(
     16     "ecmwf-open-data",
     17     source="https://ai4edataeuwest.blob.core.windows.net/ecmwf/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.grib2?st=2025-07-01T09%3A54%3A00Z&se=2025-07-02T10%3A39%3A00Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-07-02T02%3A32%3A03Z&ske=2025-07-09T02%3A32%3A03Z&sks=b&skv=2024-05-04&sig=qcG7eWdtC7/lhamMO1x8UwyA8A45tGFXAE55Xu5UQKg%3D",
   (...)     24     target="azure_2t_data.grib2",
     25 )
     28 #client.retrieve(request, "azure_2t_data.grib2")
     29 #dm_2t = ekd.from_source("file", "azure_2t_data.grib2")

File ~/Alenka/Code4Earth_2025/python-dev/lib/python3.12/site-packages/ecmwf/opendata/client.py:147, in Client.retrieve(self, request, target, **kwargs)
    146 def retrieve(self, request=None, target=None, **kwargs):
--> 147     result = self._get_urls(request, target=target, use_index=True, **kwargs)
    148     result.size = download(
    149         result.urls,
    150         target=result.target,
    151         verify=self.verify,
    152         session=self.session,
    153     )
    154     return result

File ~/Alenka/Code4Earth_2025/python-dev/lib/python3.12/site-packages/ecmwf/opendata/client.py:247, in Client._get_urls(self, request, use_index, target, **kwargs)
    244         seen.add(url)
    246 if for_index and use_index:
--> 247     data_urls = self.get_parts(data_urls, for_index)
    249 return Result(
    250     urls=data_urls,
    251     target=target,
   (...)    254     for_index=for_index,
    255 )

File ~/Alenka/Code4Earth_2025/python-dev/lib/python3.12/site-packages/ecmwf/opendata/client.py:268, in Client.get_parts(self, data_urls, for_index)
    266 index_url = f"{base}.index"
    267 r = robust(self.session.get)(index_url, verify=self.verify)
--> 268 r.raise_for_status()
    270 parts = []
    271 for line in r.iter_lines():

File ~/Alenka/Code4Earth_2025/python-dev/lib/python3.12/site-packages/requests/models.py:1026, in Response.raise_for_status(self)
   1021     http_error_msg = (
   1022         f"{self.status_code} Server Error: {reason} for url: {self.url}"
   1023     )
   1025 if http_error_msg:
-> 1026     raise HTTPError(http_error_msg, response=self)

HTTPError: 403 Client Error: Forbidden for url: https://ai4edataeuwest.blob.core.windows.net/ecmwf/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.grib2?st=2025-07-01T09%3A54%3A00Z&se=2025-07-02T10%3A39%3A00Z&sp=rl&sv=2024-05-04&sr=c&skoid=9c8ff44a-6a2c-4dfb-b298-1c9212f64d9a&sktid=72f988bf-86f1-41af-91ab-2d7cd011db47&skt=2025-07-02T02%3A32%3A03Z&ske=2025-07-09T02%3A32%3A03Z&sks=b&skv=2024-05-04&sig=qcG7eWdtC7/lhamMO1x8UwyA8A45tGFXAE55Xu5UQKg%3D/20250625/12z/ifs/0p25/oper/20250625120000-0h-oper-fc.index

The pystac_client and planetary_computer package

The example below shows how to download yesterday’s data.

!pip3 install pystac_client planetary_computer
!pip3 install xarray cfgrib
import pystac_client
import planetary_computer
import requests
import xarray as xr

catalog = pystac_client.Client.open(
    "https://planetarycomputer.microsoft.com/api/stac/v1",
    modifier=planetary_computer.sign_inplace,
)
search = catalog.search(
    collections=["ecmwf-forecast"],
    query={
        "ecmwf:stream": {"eq": "oper"},
        "ecmwf:type": {"eq": "fc"},
        "ecmwf:step": {"eq": "0h"},
    },
)
items = search.item_collection()

# select the most recent item
item = max(items, key=lambda item: item.datetime)

url = item.assets["data"].href
url_ecmwf = url.rpartition('?')[0]
filename = str(url_ecmwf.rpartition('oper/')[-1])

r = requests.get(url, stream=True)
with open(filename, mode="wb") as file:
    for chunk in r.iter_content(chunk_size=10 * 1024):
        file.write(chunk)

ds = xr.open_dataset(f'./{filename}', engine='cfgrib',
                     decode_timedelta=True,
                     backend_kwargs={'filter_by_keys': {'typeOfLevel': 'soilLayer'}})
ds
Loading...
Retrieve data for the date range of your interest
import pystac_client
import planetary_computer
import requests
import earthkit.data as ekd

catalog = pystac_client.Client.open(
    "https://planetarycomputer.microsoft.com/api/stac/v1",
    modifier=planetary_computer.sign_inplace,
)
# specify a date range
time_range = "2025-06-01/2025-06-01"

search = catalog.search(
    collections=["ecmwf-forecast"],
    query={
        "ecmwf:stream": {"eq": "oper"},
        "ecmwf:type": {"eq": "fc"},
        "ecmwf:step": {"eq": "0h"},
        },
    datetime=time_range)
items = search.item_collection()

list_of_files = []
for item in items:
    url = item.assets["data"].href
    url_ecmwf = url.rpartition('?')[0]
    filename = str(url_ecmwf.rpartition('oper/')[-1])
    
    r = requests.get(url, stream=True)
    with open(filename, mode="wb") as file:
        for chunk in r.iter_content(chunk_size=10 * 1024):
            file.write(chunk)
    list_of_files.append(filename)

for file_ in list_of_files:
    print(f'File: {file_}')
    ds = ekd.from_source("file", f'./{file_}')
    ds.ls()