Hyrax 1.18.0 is now available.
Read the release notes →
What OPeNDAP data is needed to create an Xarray Dataset? Single URL 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:
- How to install the necessary libraries.
- How to discover OPeNDAP urls from NASA’s Earthdata Cloud.
- How to Authenticate in order to stream data.
- How to create an Xarray Dataset.
- 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.
$ 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
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
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!
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.
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
url = cmr_urls[0].replace("https", "dap4")
ds = xr.open_dataset(url, engine='pydap', session=my_session)
ds
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
[url.replace("%2F","/").replace("%5B", "[").replace("%5D","]").replace("%3A",":").replace("%3B",";") for url in my_session.cache.urls()]
['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.
