Hyrax 1.18.0 is now available.
Read the release notes →

  •  Icon
  •  Icon
  •  Icon
  •  Icon

What OPeNDAP data is needed to create an Xarray Dataset? Single URL case

What OPeNDAP data is needed to create an Xarray Dataset? Single URL case
Only 2 requests are made per remote file: one for all metadata and another for all dimension data. In contrast, when using only PyDAP to access a remote file, only the metadata is fetched. This difference will be very useful when scaling to the many granules case.

It is often said that when creating an Xarray Dataset, no data is downloaded and the data representation is lazy. That is not technically true. When creating a dataset, two things are “eagerly downloaded“:

  • All the metadata (variable names, attributes, description, etc)
  • All dimension data (time, longitude, latitude, etc)

This information is fetched via separate requests. You can inspect that when using PyDAP as an Xarray engine, since PyDAP can make use of Cached sessions. Below, we demonstrate this.

Tutorial

This tutorial will demonstrate:

  1. How to install the necessary libraries.
  2. How to discover OPeNDAP urls from NASA’s Earthdata Cloud.
  3. How to Authenticate in order to stream data.
  4. How to create an Xarray Dataset.
  5. How to verify the requests made to the remote OPeNDAP server.

Create an isolated environment

Here, we open a terminal and create an isolated containerized environment, to ensure all the work below is reproducible. We will use Python 3.12, and available libraries for such environment. And we will use a jupyterlab environment as our working station.

Terminal
$ mamba create -n opendap_env -c conda-forge python=3.12 ipython pydap jupyterlab earthaccess netCDF4 xarray
$ mamba activate opendap_env
$ jupyter lab

Once on a jupyter notebook, we begin by importing the necessary libraries and methods

Python
import xarray as xr
import datetime as dt
import earthaccess

# import pydap-specific tools
from pydap.net import create_session
from pydap.client import get_cmr_urls

Lets get some data URLs

For this scenario, we search for remote data files (granules) from NASA's TEMPO. The following snippet uses NASA's Common Metadata Repository to search for OPeNDAP URLs

Python
TEMPO_O3TOT_L3_V03_ccid = "C2930764281-LARC_CLOUD"
time_range = [dt.datetime(2025, 9, 1), dt.datetime(2025, 9, 30)] # One month of data

cmr_urls = get_cmr_urls(ccid=TEMPO_O3TOT_L3_V03_ccid, time_range=time_range, limit=1000) # you can incread the limit of results

print("################################################ \n We found a total of ", len(cmr_urls), "OPeNDAP URLS!!!\n################################################")

The above code snippet should produce about 200 OPeNDAP URLs!

How to search and discover OPeNDAP URLs from NASA's Earthdata Cloud
To better understand how to search and discover OPeNDAP URLs from NASA's Earthdata Cloud, follow this link to check an entire tutorial!

Authenticate

To access data from NASA's Earthdata Cloud, you need to have an Earthdata Login (EDL) account and, importantly, a token. The next snippet of code helps with authentication, and will generate a requests session object with the necessary credentials to access data from a remote NASA server.

Python
from earthaccess.exceptions import LoginStrategyUnavailable
try:
    auth = earthaccess.login(strategy="netrc", persist=True) # you will be prompted to add your EDL credentials
except LoginStrategyUnavailable:
    auth = earthaccess.login(strategy="interactive", persist=True)

# pass Token Authorization to a new Session.
my_session = create_session(session=auth.get_session(),use_cache=True, cache_kwargs={"cache_name":'debug_case'})
my_session.cache.clear()

The snippet above shows that earthaccess was used to authenticate. It will store the credentials in your local machine in a standard netrc file for later reuse. Then PyDAP's create_session extracts the credentials from earthaccess to generate a requests_cache session. This is usually done to debug a session as it allows to inspects the requests done to the server! (There will be a sqlite object created in your local machine called debug.sqlite. This can be reused for later.)

At last, we create an Xarray Dataset from one of the OPeNDAP URLs as follow

Python
url = cmr_urls[0].replace("https", "dap4")
ds = xr.open_dataset(url, engine='pydap', session=my_session)
ds
DAP4 or HTTPS?
The DAP4 protocol is NOT an alternative protocol for HTTPS. Replacing https with dap4 is only done to instruct Xarray (and pydap) which dap protocol to use. The URLs sent to the server will begin with https (you will verify this later).

Finally, we verify the requests sent to the server via our Cached session

Because we used PyDAP as the Xarray engine, and we used a Cached session (the my_session), we can inspect all the requests sent to the remote server

Python
[url.replace("%2F","/").replace("%5B", "[").replace("%5D","]").replace("%3A",":").replace("%3B",";") for url in my_session.cache.urls()]
Jupyter Cell Output

['https://opendap.earthdata.nasa.gov/collections/C2930764281-LARC_CLOUD/granules/TEMPO_O3TOT_L3_V03_20250831T232841Z_S016.nc.dap?dap4.ce=/longitude[0:1:7749];/time[0:1:0];/latitude[0:1:2949]&dap4.checksum=true',
 'https://opendap.earthdata.nasa.gov/collections/C2930764281-LARC_CLOUD/granules/TEMPO_O3TOT_L3_V03_20250831T232841Z_S016.nc.dmr']

NOTE: There is no dap4 scheme in the URL.

The example shows that there are 2 requests per granule, one for all the dimensions (the first element in the list above) and the other request is the DMR of the remote granule, i.e. the Dataset Metadata Response that the DAP4 protocol produces.

What about aggregating multiple remote granules?

Things get a little complicated and potentially messy! This is the subject for another post.