Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

While it is recommended to import data into Vapor using session.LoadDataset(), Vapor also supports importing data from XArray datasets.

The following cell will download sample data from NCAR’s Research Data Archives.

import os
import requests
import zipfile
url = 'https://data.rda.ucar.edu/ds897.7/Katrina.zip'
extract_to = './data'
zip_name = "Katrina.zip"
data_file = './data/wrfout_d02_2005-08-29_02.nc'

# Check if the data file already exists
if not os.path.exists(data_file):
    # Download zip
    with requests.get(url, stream=True) as r:
        r.raise_for_status()
        with open(zip_name, 'wb') as f:
            for chunk in r.iter_content(chunk_size=8192):
                f.write(chunk)
    # Extract the file
    with zipfile.ZipFile(zip_name, 'r') as zip_ref:
        zip_ref.extractall(extract_to)

    # Clean up the zip file
    os.remove(zip_name)

    print(f"Data downloaded and extracted to {data_file}")
else:
    print(f"Data file already exists at {data_file}, skipping download and extraction.")
---------------------------------------------------------------------------
SSLCertVerificationError                  Traceback (most recent call last)
File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:464, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    463 try:
--> 464     self._validate_conn(conn)
    465 except (SocketTimeout, BaseSSLError) as e:

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:1106, in HTTPSConnectionPool._validate_conn(self, conn)
   1105 if conn.is_closed:
-> 1106     conn.connect()
   1108 # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connection.py:796, in HTTPSConnection.connect(self)
    794 server_hostname_rm_dot = server_hostname.rstrip(".")
--> 796 sock_and_verified = _ssl_wrap_socket_and_match_hostname(
    797     sock=sock,
    798     cert_reqs=self.cert_reqs,
    799     ssl_version=self.ssl_version,
    800     ssl_minimum_version=self.ssl_minimum_version,
    801     ssl_maximum_version=self.ssl_maximum_version,
    802     ca_certs=self.ca_certs,
    803     ca_cert_dir=self.ca_cert_dir,
    804     ca_cert_data=self.ca_cert_data,
    805     cert_file=self.cert_file,
    806     key_file=self.key_file,
    807     key_password=self.key_password,
    808     server_hostname=server_hostname_rm_dot,
    809     ssl_context=self.ssl_context,
    810     tls_in_tls=tls_in_tls,
    811     assert_hostname=self.assert_hostname,
    812     assert_fingerprint=self.assert_fingerprint,
    813 )
    814 self.sock = sock_and_verified.socket

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connection.py:975, in _ssl_wrap_socket_and_match_hostname(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)
    973         server_hostname = normalized
--> 975 ssl_sock = ssl_wrap_socket(
    976     sock=sock,
    977     keyfile=key_file,
    978     certfile=cert_file,
    979     key_password=key_password,
    980     ca_certs=ca_certs,
    981     ca_cert_dir=ca_cert_dir,
    982     ca_cert_data=ca_cert_data,
    983     server_hostname=server_hostname,
    984     ssl_context=context,
    985     tls_in_tls=tls_in_tls,
    986 )
    988 try:

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/ssl_.py:433, in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)
    431 context.set_alpn_protocols(ALPN_PROTOCOLS)
--> 433 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
    434 return ssl_sock

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/ssl_.py:477, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
    475     return SSLTransport(sock, ssl_context, server_hostname)
--> 477 return ssl_context.wrap_socket(sock, server_hostname=server_hostname)

File ~/micromamba/envs/cookbook-dev/lib/python3.14/ssl.py:455, in SSLContext.wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
    449 def wrap_socket(self, sock, server_side=False,
    450                 do_handshake_on_connect=True,
    451                 suppress_ragged_eofs=True,
    452                 server_hostname=None, session=None):
    453     # SSLSocket class handles server_hostname encoding before it calls
    454     # ctx._wrap_socket()
--> 455     return self.sslsocket_class._create(
    456         sock=sock,
    457         server_side=server_side,
    458         do_handshake_on_connect=do_handshake_on_connect,
    459         suppress_ragged_eofs=suppress_ragged_eofs,
    460         server_hostname=server_hostname,
    461         context=self,
    462         session=session
    463     )

File ~/micromamba/envs/cookbook-dev/lib/python3.14/ssl.py:1076, in SSLSocket._create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)
   1075                 raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
-> 1076             self.do_handshake()
   1077 except:

File ~/micromamba/envs/cookbook-dev/lib/python3.14/ssl.py:1372, in SSLSocket.do_handshake(self, block)
   1371         self.settimeout(None)
-> 1372     self._sslobj.do_handshake()
   1373 finally:

SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082)

During handling of the above exception, another exception occurred:

SSLError                                  Traceback (most recent call last)
File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:788, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    787 # Make the request on the HTTPConnection object
--> 788 response = self._make_request(
    789     conn,
    790     method,
    791     url,
    792     timeout=timeout_obj,
    793     body=body,
    794     headers=headers,
    795     chunked=chunked,
    796     retries=retries,
    797     response_conn=response_conn,
    798     preload_content=preload_content,
    799     decode_content=decode_content,
    800     **response_kw,
    801 )
    803 # Everything went great!

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:488, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    487         new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 488     raise new_e
    490 # conn.request() calls http.client.*.request, not the method in
    491 # urllib3.request. It also calls makefile (recv) on the socket.

SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082)

The above exception was the direct cause of the following exception:

MaxRetryError                             Traceback (most recent call last)
File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/adapters.py:696, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    695 try:
--> 696     resp = conn.urlopen(
    697         method=request.method,
    698         url=url,
    699         body=request.body,  # type: ignore[arg-type]  # urllib3 stubs don't accept Iterable[bytes | str]
    700         headers=request.headers,  # type: ignore[arg-type]  # urllib3#3072
    701         redirect=False,
    702         assert_same_host=False,
    703         preload_content=False,
    704         decode_content=False,
    705         retries=self.max_retries,
    706         timeout=resolved_timeout,
    707         chunked=chunked,
    708     )
    710 except (ProtocolError, OSError) as err:

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:842, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    840     new_e = ProtocolError("Connection aborted.", new_e)
--> 842 retries = retries.increment(
    843     method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    844 )
    845 retries.sleep()

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/retry.py:543, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    542     reason = error or ResponseError(cause)
--> 543     raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
    545 log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)

MaxRetryError: HTTPSConnectionPool(host='data.rda.ucar.edu', port=443): Max retries exceeded with url: /ds897.7/Katrina.zip (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082)')))

During handling of the above exception, another exception occurred:

SSLError                                  Traceback (most recent call last)
Cell In[1], line 12
      8 
      9 # Check if the data file already exists
     10 if not os.path.exists(data_file):
     11     # Download zip
---> 12     with requests.get(url, stream=True) as r:
     13         r.raise_for_status()
     14         with open(zip_name, 'wb') as f:
     15             for chunk in r.iter_content(chunk_size=8192):

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/api.py:87, in get(url, params, **kwargs)
     74 def get(
     75     url: _t.UriType, params: _t.ParamsType = None, **kwargs: Unpack[_t.GetKwargs]
     76 ) -> Response:
     77     r"""Sends a GET request.
     78 
     79     :param url: URL for the new :class:`Request` object.
   (...)     84     :rtype: requests.Response
     85     """
---> 87     return request("get", url, params=params, **kwargs)

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/api.py:71, in request(method, url, **kwargs)
     67 # By using the 'with' statement we are sure the session is closed, thus we
     68 # avoid leaving sockets open which can trigger a ResourceWarning in some
     69 # cases, and look like a memory leak in others.
     70 with sessions.Session() as session:
---> 71     return session.request(method=method, url=url, **kwargs)

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/sessions.py:651, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    646 send_kwargs = {
    647     "timeout": timeout,
    648     "allow_redirects": allow_redirects,
    649 }
    650 send_kwargs.update(settings)
--> 651 resp = self.send(prep, **send_kwargs)
    653 return resp

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/sessions.py:784, in Session.send(self, request, **kwargs)
    781 start = preferred_clock()
    783 # Send the request
--> 784 r = adapter.send(request, **kwargs)
    786 # Total elapsed time of the request (approximately)
    787 elapsed = preferred_clock() - start

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/requests/adapters.py:727, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    723         raise ProxyError(e, request=request)
    725     if isinstance(e.reason, _SSLError):
    726         # This branch is for urllib3 v1.22 and later.
--> 727         raise SSLError(e, request=request)
    729     raise ConnectionError(e, request=request)
    731 except ClosedPoolError as e:

SSLError: HTTPSConnectionPool(host='data.rda.ucar.edu', port=443): Max retries exceeded with url: /ds897.7/Katrina.zip (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1082)')))

In order to pass XArray data to Vapor, create a data set within your vapor session using Session.CreatePythonDataset().

from vapor import session, renderer, dataset, camera
import xarray as xr

ses = session.Session()
data = ses.CreatePythonDataset()

First we will load the dataset with XArray

ds = xr.open_dataset("data/wrfout_d02_2005-08-29_02.nc")
ds

We can add variables from our XArray dataset to our Vapor dataset using dataset.AddXarrayDataset(). We should be careful though -- once the data is loaded with XArray, Vapor cannot determine if a dimension is spatial or temporal. Because of this, we should make sure the data array we pass contains only spatial dimensions.

U10 = ds["U10"]
U10

In this case, U10 should be a two dimensional variable (longitude and latitude). But notice that in the DataArray we just created we still have a time dimension. Because of this, Vapor will incorrectly treat it as a 3 dimensional variable. Before passing the DataArray to Vapor, we should remove the temporal dimension.

U10 = ds["U10"].squeeze("Time")
U10

Now, we can add this variable to our Vapor dataset with dataset.AddXArrayData(). The first parameter will be the variable name that we want to appear in our Vapor dataset, while the second parameter is the XArray DataArray.

data.AddXArrayData("U10", U10)

Now, we can render our data using any of Vapor’s renderers.

# Create a renderer for the data
ren = data.NewRenderer(renderer.WireFrameRenderer)
ren.SetVariableName("U10")
# Show the rendering
ses.GetCamera().ViewAll()
ses.Show()
ses.DeleteRenderer(ren)

The same process can be used to render a 3D variable

data.AddXArrayData("U", ds["U"].squeeze("Time"))
ren = data.NewRenderer(renderer.WireFrameRenderer)
ren.SetVariableName("U")
ses.GetCamera().LookAt([ 138.64364963, -213.94716727,  293.46022828],
                       [157., 154.,   0.],
                       [0.04815987, 0.62133843, 0.78206086])
ses.Show()