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:470, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    469 try:
--> 470     self._validate_conn(conn)
    471 except (SocketTimeout, BaseSSLError) as e:

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

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connection.py:878, in HTTPSConnection.connect(self)
    877 else:
--> 878     wrapped_socket, is_verified = _ssl_wrap_socket_and_match_hostname(
    879         sock=sock,
    880         cert_reqs=self.cert_reqs,
    881         ssl_version=self.ssl_version,
    882         ssl_minimum_version=self.ssl_minimum_version,
    883         ssl_maximum_version=self.ssl_maximum_version,
    884         ca_certs=self.ca_certs,
    885         ca_cert_dir=self.ca_cert_dir,
    886         ca_cert_data=self.ca_cert_data,
    887         cert_file=self.cert_file,
    888         key_file=self.key_file,
    889         key_password=self.key_password,
    890         server_hostname=server_hostname_rm_dot,
    891         ssl_context=self.ssl_context,
    892         tls_in_tls=tls_in_tls,
    893         assert_hostname=self.assert_hostname,
    894         assert_fingerprint=self.assert_fingerprint,
    895     )
    896 self.sock = wrapped_socket

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connection.py:1080, 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)
   1078         server_hostname = normalized
-> 1080 ssl_sock = ssl_wrap_socket(
   1081     sock=sock,
   1082     keyfile=key_file,
   1083     certfile=cert_file,
   1084     key_password=key_password,
   1085     ca_certs=ca_certs,
   1086     ca_cert_dir=ca_cert_dir,
   1087     ca_cert_data=ca_cert_data,
   1088     server_hostname=server_hostname,
   1089     ssl_context=context,
   1090     tls_in_tls=tls_in_tls,
   1091 )
   1093 try:

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/ssl_.py:437, 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)
    435 context.set_alpn_protocols(ALPN_PROTOCOLS)
--> 437 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
    438 return ssl_sock

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/ssl_.py:481, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
    479     return SSLTransport(sock, ssl_context, server_hostname)
--> 481 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:793, 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)
    792 # Make the request on the HTTPConnection object
--> 793 response = self._make_request(
    794     conn,
    795     method,
    796     url,
    797     timeout=timeout_obj,
    798     body=body,
    799     headers=headers,
    800     chunked=chunked,
    801     retries=retries,
    802     response_conn=response_conn,
    803     preload_content=preload_content,
    804     decode_content=decode_content,
    805     **response_kw,
    806 )
    808 # Everything went great!

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/connectionpool.py:494, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    493         new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 494     raise new_e
    496 # conn.request() calls http.client.*.request, not the method in
    497 # 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:847, 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)
    845     new_e = ProtocolError("Connection aborted.", new_e)
--> 847 retries = retries.increment(
    848     method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    849 )
    850 retries.sleep()

File ~/micromamba/envs/cookbook-dev/lib/python3.14/site-packages/urllib3/util/retry.py:555, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    554     reason = error or ResponseError(cause)
--> 555     raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
    557 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()