diff --git a/_preview/12/.buildinfo b/_preview/12/.buildinfo
new file mode 100644
index 00000000..8be0bd88
--- /dev/null
+++ b/_preview/12/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: ad0edbdeb265f9d9d6dc4619922a3ebc
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/_preview/12/README.html b/_preview/12/README.html
new file mode 100644
index 00000000..9be97ec5
--- /dev/null
+++ b/_preview/12/README.html
@@ -0,0 +1,869 @@
+
+
+
+
+
+
+
This Cookbook is a comprehensive showcase of workflows & techniques for visualizing Unstructured Grids using UXarray.
+
+
Motivation
+
The ability to natively visualize unstructured grids is a much-needed ability within the Scientific Python Ecosystem,
+which poses multiple challenges and needs to:
+
+
Not regrid the source unstructured grid to structure
+
Take advantage of grid information, such as connectivity variables
+
Limit the amount of pre-processing needed to prepare the data for Python visualization tools
+
+
UXarray enables such visualization methods that operate directly on unstructured grid data,
+providing Xarray-styled functionality to better read in
+and use unstructured grid datasets that follow standard conventions.
+UXarray supports a variety of unstructured grid formats including UGRID, MPAS, SCRIP, and Exodus,
+and is extendable for other formats.
+
This cookbook covers an introduction to unstructured grids and UXarray,
+provides an overview of the visualization methods and libraries, and showcases several UXarray visualization functions.
This cookbook is split up into a few chapters that provide a detailed overview of how to use UXarray to work with and visualize unstructured grid datasets:
+
1. Introduction to UXarray & Unstructured Grids
+
Here we cover what unstructured grids are and how they are different than structured grids as well as whay UXarray could play a significant role in unstructured grid visualization.
+
2. Methods & Libraries for Unstructured Grid Visualization
+
In this chapter, we briefly introduce plotting libraries and their specific technologies as well as rendering techniques that could be used for unstructured grid plotting and are used as part of UXarray.
+
3. UXarray Visualization
+
Several visualization cases and examples that can be realized using UXarray are provided in this chapter; grid topology plots, polygons, points, to name a few. Also in this section, the usage of UXarray plotting API and a discussion of visualization at scale are also provided.
+
+
+
Running the Notebooks
+
You can either run the notebook using Binder or on your local machine.
+
+
Running on Binder
+
The simplest way to interact with a Jupyter Notebook is through
+Binder, which enables the execution of a
+Jupyter Book in the cloud. The details of how this works are not
+important for now. All you need to know is how to launch a Pythia
+Cookbooks chapter via Binder. Simply navigate your mouse to
+the top right corner of the book chapter you are viewing and click
+on the rocket ship icon, (see figure below), and be sure to select
+“launch Binder”. After a moment you should be presented with a
+notebook that you can interact with. I.e. you’ll be able to execute
+and even change the example programs. You’ll see that the code cells
+have no output at first, until you execute them by pressing
+Shift+Enter. Complete details on how to interact with
+a live Jupyter notebook are described in Getting Started with
+Jupyter.
+
+
+
Running on Your Own Machine
+
If you are interested in running this material locally on your computer, you will need to follow this workflow:
+
+
Clone the https://github.com/ProjectPythia/unstructured-grid-viz-cookbook repository:
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/_preview/12/_images/0eaeb0fbc25505828c457df778435770e9d57a35b7cebf85e181b3846a32952d.png b/_preview/12/_images/0eaeb0fbc25505828c457df778435770e9d57a35b7cebf85e181b3846a32952d.png
new file mode 100644
index 00000000..09bd6b90
Binary files /dev/null and b/_preview/12/_images/0eaeb0fbc25505828c457df778435770e9d57a35b7cebf85e181b3846a32952d.png differ
diff --git a/_preview/12/_images/NSF-NCAR_Lockup-UCAR-Dark_102523.svg b/_preview/12/_images/NSF-NCAR_Lockup-UCAR-Dark_102523.svg
new file mode 100644
index 00000000..4eb4ded5
--- /dev/null
+++ b/_preview/12/_images/NSF-NCAR_Lockup-UCAR-Dark_102523.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/_preview/12/_images/UAlbany-A2-logo-purple-gold.svg b/_preview/12/_images/UAlbany-A2-logo-purple-gold.svg
new file mode 100644
index 00000000..4fdfe3a8
--- /dev/null
+++ b/_preview/12/_images/UAlbany-A2-logo-purple-gold.svg
@@ -0,0 +1,1125 @@
+
+
diff --git a/_preview/12/_images/Unidata_logo_horizontal_1200x300.svg b/_preview/12/_images/Unidata_logo_horizontal_1200x300.svg
new file mode 100644
index 00000000..0d9fd70f
--- /dev/null
+++ b/_preview/12/_images/Unidata_logo_horizontal_1200x300.svg
@@ -0,0 +1,891 @@
+
+
diff --git a/_preview/12/_images/ae3f003a659249c7440ab94a10d42ba5d8d3e43fed7b2045b1c99ade774d64be.png b/_preview/12/_images/ae3f003a659249c7440ab94a10d42ba5d8d3e43fed7b2045b1c99ade774d64be.png
new file mode 100644
index 00000000..a7bba626
Binary files /dev/null and b/_preview/12/_images/ae3f003a659249c7440ab94a10d42ba5d8d3e43fed7b2045b1c99ade774d64be.png differ
diff --git a/_preview/12/_images/b59189f0e60db4a3be15f84866b53e452d6c1bc08fb949c8219e7a7b906aa4cf.png b/_preview/12/_images/b59189f0e60db4a3be15f84866b53e452d6c1bc08fb949c8219e7a7b906aa4cf.png
new file mode 100644
index 00000000..64963003
Binary files /dev/null and b/_preview/12/_images/b59189f0e60db4a3be15f84866b53e452d6c1bc08fb949c8219e7a7b906aa4cf.png differ
diff --git a/_preview/12/_images/c8cb2fb60dc227795c53f15c61d619c428c81882889a8bd722eac6e592bd0c5d.svg b/_preview/12/_images/c8cb2fb60dc227795c53f15c61d619c428c81882889a8bd722eac6e592bd0c5d.svg
new file mode 100644
index 00000000..7a9687fa
--- /dev/null
+++ b/_preview/12/_images/c8cb2fb60dc227795c53f15c61d619c428c81882889a8bd722eac6e592bd0c5d.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/_preview/12/_images/contients.jpg b/_preview/12/_images/contients.jpg
new file mode 100644
index 00000000..9c06d21d
Binary files /dev/null and b/_preview/12/_images/contients.jpg differ
diff --git a/_preview/12/_images/d336d74b0f648898540478ff42c3a9a5220570c8396152668d5dcbcc2c2554f6.svg b/_preview/12/_images/d336d74b0f648898540478ff42c3a9a5220570c8396152668d5dcbcc2c2554f6.svg
new file mode 100644
index 00000000..51c150bc
--- /dev/null
+++ b/_preview/12/_images/d336d74b0f648898540478ff42c3a9a5220570c8396152668d5dcbcc2c2554f6.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/_preview/12/_images/dd51adb0ffc0c19fb50c16824c1baefd0e7a54e1f3c02de42e241b9fd1831020.png b/_preview/12/_images/dd51adb0ffc0c19fb50c16824c1baefd0e7a54e1f3c02de42e241b9fd1831020.png
new file mode 100644
index 00000000..c1b95836
Binary files /dev/null and b/_preview/12/_images/dd51adb0ffc0c19fb50c16824c1baefd0e7a54e1f3c02de42e241b9fd1831020.png differ
diff --git a/_preview/12/_images/e120dfbe3180ec0345469c8ced263bfd043a3403e3bb430e6fee5e98554c50aa.svg b/_preview/12/_images/e120dfbe3180ec0345469c8ced263bfd043a3403e3bb430e6fee5e98554c50aa.svg
new file mode 100644
index 00000000..32f0806b
--- /dev/null
+++ b/_preview/12/_images/e120dfbe3180ec0345469c8ced263bfd043a3403e3bb430e6fee5e98554c50aa.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/_preview/12/_images/edges.jpg b/_preview/12/_images/edges.jpg
new file mode 100644
index 00000000..846add04
Binary files /dev/null and b/_preview/12/_images/edges.jpg differ
diff --git a/_preview/12/_images/faces.png b/_preview/12/_images/faces.png
new file mode 100644
index 00000000..9809bc95
Binary files /dev/null and b/_preview/12/_images/faces.png differ
diff --git a/_preview/12/_images/global_point_raster.png b/_preview/12/_images/global_point_raster.png
new file mode 100644
index 00000000..047a9079
Binary files /dev/null and b/_preview/12/_images/global_point_raster.png differ
diff --git a/_preview/12/_images/global_polygon_raster.png b/_preview/12/_images/global_polygon_raster.png
new file mode 100644
index 00000000..23d44f77
Binary files /dev/null and b/_preview/12/_images/global_polygon_raster.png differ
diff --git a/_preview/12/_images/nodes.png b/_preview/12/_images/nodes.png
new file mode 100644
index 00000000..511532a3
Binary files /dev/null and b/_preview/12/_images/nodes.png differ
diff --git a/_preview/12/_images/point_raster_global_no_proj.png b/_preview/12/_images/point_raster_global_no_proj.png
new file mode 100644
index 00000000..f4a13fcf
Binary files /dev/null and b/_preview/12/_images/point_raster_global_no_proj.png differ
diff --git a/_preview/12/_images/point_raster_orthographic.png b/_preview/12/_images/point_raster_orthographic.png
new file mode 100644
index 00000000..e6264dd6
Binary files /dev/null and b/_preview/12/_images/point_raster_orthographic.png differ
diff --git a/_preview/12/_images/polygon_raster_regional_dyn_zoomed.png b/_preview/12/_images/polygon_raster_regional_dyn_zoomed.png
new file mode 100644
index 00000000..0738b22b
Binary files /dev/null and b/_preview/12/_images/polygon_raster_regional_dyn_zoomed.png differ
diff --git a/_preview/12/_images/polygons.png b/_preview/12/_images/polygons.png
new file mode 100644
index 00000000..9cb27698
Binary files /dev/null and b/_preview/12/_images/polygons.png differ
diff --git a/_preview/12/_images/raster-vs-vector.png b/_preview/12/_images/raster-vs-vector.png
new file mode 100644
index 00000000..924fcc2e
Binary files /dev/null and b/_preview/12/_images/raster-vs-vector.png differ
diff --git a/_preview/12/_images/raster_example.png b/_preview/12/_images/raster_example.png
new file mode 100644
index 00000000..b4350d59
Binary files /dev/null and b/_preview/12/_images/raster_example.png differ
diff --git a/_preview/12/_images/regional_point_raster.png b/_preview/12/_images/regional_point_raster.png
new file mode 100644
index 00000000..3d232163
Binary files /dev/null and b/_preview/12/_images/regional_point_raster.png differ
diff --git a/_preview/12/_images/regional_point_raster_dyn.png b/_preview/12/_images/regional_point_raster_dyn.png
new file mode 100644
index 00000000..9d2f3906
Binary files /dev/null and b/_preview/12/_images/regional_point_raster_dyn.png differ
diff --git a/_preview/12/_images/regional_polygon_raster.png b/_preview/12/_images/regional_polygon_raster.png
new file mode 100644
index 00000000..522db07d
Binary files /dev/null and b/_preview/12/_images/regional_polygon_raster.png differ
diff --git a/_preview/12/_images/regional_polygon_raster_dyn.png b/_preview/12/_images/regional_polygon_raster_dyn.png
new file mode 100644
index 00000000..27d3405f
Binary files /dev/null and b/_preview/12/_images/regional_polygon_raster_dyn.png differ
diff --git a/_preview/12/_images/sample_mesh.png b/_preview/12/_images/sample_mesh.png
new file mode 100644
index 00000000..704f2208
Binary files /dev/null and b/_preview/12/_images/sample_mesh.png differ
diff --git a/_preview/12/_images/uxarray-plot-api-design.png b/_preview/12/_images/uxarray-plot-api-design.png
new file mode 100644
index 00000000..75468c75
Binary files /dev/null and b/_preview/12/_images/uxarray-plot-api-design.png differ
diff --git a/_preview/12/_sources/README.md b/_preview/12/_sources/README.md
new file mode 100644
index 00000000..128d7c3b
--- /dev/null
+++ b/_preview/12/_sources/README.md
@@ -0,0 +1,108 @@
+
+
+
+
+
+# Unstructured Grid Visualization Cookbook
+
+[![nightly-build](https://github.com/ProjectPythia/unstructured-grid-viz-cookbook/actions/workflows/nightly-build.yaml/badge.svg)](https://github.com/ProjectPythia/unstructured-grid-viz-cookbook/actions/workflows/nightly-build.yaml)
+[![Binder](https://binder.projectpythia.org/badge_logo.svg)](https://binder.projectpythia.org/v2/gh/ProjectPythia/unstructured-grid-viz-cookbook.git/main?labpath=notebooks)
+[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.10403389.svg)](https://doi.org/10.5281/zenodo.10403389)
+
+This Cookbook is a comprehensive showcase of workflows & techniques for visualizing Unstructured Grids using [UXarray](https://uxarray.readthedocs.io/).
+
+## Motivation
+
+The ability to natively visualize unstructured grids is a much-needed ability within the Scientific Python Ecosystem,
+which poses multiple challenges and needs to:
+
+- Not regrid the source unstructured grid to structure
+- Take advantage of grid information, such as connectivity variables
+- Limit the amount of pre-processing needed to prepare the data for Python visualization tools
+
+UXarray enables such visualization methods that operate directly on unstructured grid data,
+providing Xarray-styled functionality to better read in
+and use unstructured grid datasets that follow standard conventions.
+UXarray supports a variety of unstructured grid formats including UGRID, MPAS, SCRIP, and Exodus,
+and is extendable for other formats.
+
+This cookbook covers an introduction to unstructured grids and UXarray,
+provides an overview of the visualization methods and libraries, and showcases several UXarray visualization functions.
+
+## Authors
+
+[Philip Chmielowiec (NSF NCAR)](https://github.com/philipc2)
+
+[Orhan Eroglu (NSF NCAR)](https://github.com/erogluorhan)
+
+[Rajeev Jain (Argonne National Laboratory)](https://github.com/rajeeja)
+
+[Ian Franda (University of Wisconsin-Madison)](https://github.com/ifranda)
+
+### Contributors
+
+
+
+
+
+## Structure
+
+This cookbook is split up into a few chapters that provide a detailed overview of how to use UXarray to work with and visualize unstructured grid datasets:
+
+**1. Introduction to UXarray & Unstructured Grids**
+
+Here we cover what unstructured grids are and how they are different than structured grids as well as whay UXarray could play a significant role in unstructured grid visualization.
+
+**2. Methods & Libraries for Unstructured Grid Visualization**
+
+In this chapter, we briefly introduce plotting libraries and their specific technologies as well as rendering techniques that could be used for unstructured grid plotting and are used as part of UXarray.
+
+**3. UXarray Visualization**
+
+Several visualization cases and examples that can be realized using UXarray are provided in this chapter; grid topology plots, polygons, points, to name a few. Also in this section, the usage of UXarray plotting API and a discussion of visualization at scale are also provided.
+
+## Running the Notebooks
+
+You can either run the notebook using [Binder](https://binder.projectpythia.org/) or on your local machine.
+
+### Running on Binder
+
+The simplest way to interact with a Jupyter Notebook is through
+[Binder](https://binder.projectpythia.org/), which enables the execution of a
+[Jupyter Book](https://jupyterbook.org) in the cloud. The details of how this works are not
+important for now. All you need to know is how to launch a Pythia
+Cookbooks chapter via Binder. Simply navigate your mouse to
+the top right corner of the book chapter you are viewing and click
+on the rocket ship icon, (see figure below), and be sure to select
+“launch Binder”. After a moment you should be presented with a
+notebook that you can interact with. I.e. you’ll be able to execute
+and even change the example programs. You’ll see that the code cells
+have no output at first, until you execute them by pressing
+{kbd}`Shift`\+{kbd}`Enter`. Complete details on how to interact with
+a live Jupyter notebook are described in [Getting Started with
+Jupyter](https://foundations.projectpythia.org/foundations/getting-started-jupyter.html).
+
+### Running on Your Own Machine
+
+If you are interested in running this material locally on your computer, you will need to follow this workflow:
+
+1. Clone the `https://github.com/ProjectPythia/unstructured-grid-viz-cookbook` repository:
+
+ ```bash
+ git clone https://github.com/ProjectPythia/unstructured-grid-viz-cookbook.git
+ ```
+
+1. Move into the `unstructured-grid-viz-cookbook` directory
+ ```bash
+ cd unstructured-grid-viz-cookbook
+ ```
+1. Create and activate your conda environment from the `environment.yml` file
+ ```bash
+ conda env create -f environment.yml
+ conda activate unstructured-grid-viz-cookbook-dev
+ ```
+1. Move into the `notebooks` directory and start up Jupyterlab
+ ```bash
+ cd notebooks/
+ jupyter lab
+ ```
diff --git a/_preview/12/_sources/meshfiles/catalog.md b/_preview/12/_sources/meshfiles/catalog.md
new file mode 100644
index 00000000..c037ef90
--- /dev/null
+++ b/_preview/12/_sources/meshfiles/catalog.md
@@ -0,0 +1,13 @@
+# Sample Unstructured Grid Datasets
+
+## Geoflow
+
+Source: TODO
+
+## oU120
+
+Source: TODO
+
+## CSne30
+
+Source: E3SM Output
diff --git a/_preview/12/_sources/notebooks/01-intro/01-unstructured-grid-overview.ipynb b/_preview/12/_sources/notebooks/01-intro/01-unstructured-grid-overview.ipynb
new file mode 100644
index 00000000..58538852
--- /dev/null
+++ b/_preview/12/_sources/notebooks/01-intro/01-unstructured-grid-overview.ipynb
@@ -0,0 +1,372 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Unstructured Grids Overview"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "---"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The goal of this notebook is to provide a brief overview of unstructured grids and provide a teaser of plotting with the [UXarray](https://uxarray.readthedocs.io/) package.\n",
+ "\n",
+ "Contents:\n",
+ "1. Structured vs. Unstructured Grids\n",
+ "2. Structured Grids\n",
+ "3. Unstructured Grids\n",
+ "4. Why UXarrary for unstructured grids?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Structured vs Unstructured Grids\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "It is important to understand this difference, before diving into unstructured grid:\n",
+ "\n",
+ "A structured grid is well-ordered, with a simple scheme used to label elements and identify neighbors, while an unstructured grid allows elements to be joined in any manner, requiring special lists to identify neighboring elements.\n",
+ "\n",
+ "Note that the focus here is on two dimensional grids in the climate and weather context, but the same concepts apply to three dimensional grids."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Structured Grids\n",
+ "A few advantages of structured grids are:\n",
+ "- Uniform Representation: Simplifies numerical methods and enhances result interpretation.\n",
+ " \n",
+ "- Efficient Numerics: Well-suited for finite-difference schemes, ensuring computational efficiency.\n",
+ " \n",
+ "- Simplified Interpolation: Straightforward interpolation facilitates integration of observational data and model outputs.\n",
+ " \n",
+ "- Boundary Handling: Ideal for regular boundaries, easing implementation of boundary conditions.\n",
+ " \n",
+ "- Optimized Parallel Computing: Regular structure supports efficient parallel computing for scalability."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This code below shows a structured mesh example over 2D earth geometry and plots random temperature data. \n",
+ "\n",
+ "Given the number of points in longitude and latitude direction, the code uses Numpy's meshgrid to generates a structured grid. The temperature data is then interpolated onto this grid, creating a smooth representation. Xarray is leveraged to organize the gridded data into a dataset, facilitating easy manipulation and visualization. The resulting plot showcases the data on this structure mesh, providing a clearer understanding of temperature variations across defined longitude and latitude ranges. Plotting the structured grid and the temperature data is done using Cartopy, a cartographic plotting library. \n",
+ "\n",
+ "There are many other libraries and ways to create a structured grids."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import cartopy.crs as ccrs\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import xarray as xr\n",
+ "\n",
+ "# Define the global domain\n",
+ "lat_range = [-90.0, 90.0]\n",
+ "lon_range = [-180.0, 180.0]\n",
+ "\n",
+ "# Create a structured grid. Note the number of points in each dimension\n",
+ "# There is not need to store the grid points in a separate array\n",
+ "# Also note that the grid points are evenly spaced and not connectivity information is needed\n",
+ "\n",
+ "num_lat_points = 20\n",
+ "num_lon_points = 30\n",
+ "\n",
+ "lats = np.linspace(lat_range[0], lat_range[1], num_lat_points)\n",
+ "lons = np.linspace(lon_range[0], lon_range[1], num_lon_points)\n",
+ "\n",
+ "lons_grid, lats_grid = np.meshgrid(lons, lats)\n",
+ "\n",
+ "# Generate random temperature data for each grid point\n",
+ "temperature_data = np.random.uniform(\n",
+ " low=20, high=30, size=(num_lat_points, num_lon_points)\n",
+ ")\n",
+ "\n",
+ "# Create xarray Dataset\n",
+ "ds = xr.Dataset()\n",
+ "ds[\"temperature\"] = ([\"lat\", \"lon\"], temperature_data)\n",
+ "ds[\"lon\"] = lons\n",
+ "ds[\"lat\"] = lats\n",
+ "\n",
+ "# Plot the structured grid using xarray\n",
+ "fig, ax = plt.subplots(subplot_kw={\"projection\": ccrs.PlateCarree()})\n",
+ "ax.set_global()\n",
+ "\n",
+ "# Plot world map lines\n",
+ "ax.coastlines()\n",
+ "ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False)\n",
+ "\n",
+ "# Plot the structured grid\n",
+ "cs = ax.pcolormesh(\n",
+ " ds[\"lon\"], ds[\"lat\"], ds[\"temperature\"], cmap=\"coolwarm\", shading=\"auto\"\n",
+ ")\n",
+ "\n",
+ "# Colorbar\n",
+ "cbar = plt.colorbar(cs, ax=ax, label=\"Temperature (°C)\")\n",
+ "\n",
+ "ax.set_title(\"Structured Grid Example\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Unstructured Grids"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Characteristic features of unstructured grids are:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "- Adaptability to complex geometries: Fits intricate shapes and boundaries\n",
+ "\n",
+ "- Often runs faster than structured grids: Requires fewer elements to achieve similar accuracy\n",
+ " \n",
+ "- Local refinement: Concentrates resolution on areas of interest\n",
+ " \n",
+ "- Flexibility in element types: Accommodates various element shapes\n",
+ " \n",
+ "- Efficient parallelization: Scales well to multiple processors\n",
+ " \n",
+ "- Suitability for dynamic simulations: Adapts to changing conditions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "There are a variety of libraries and conventions for creating unstructured grids. Here we use a very basic standard python approach to showcase an unstructured grid: \n",
+ "\n",
+ "The code generates an unstructured grid over a rectangular domain defined by latitude and longitude ranges. It creates a set of points using matplotlib.tri.Triangulation. The resulting triangulation is then plotted using cartopy and matplotlib.\n",
+ "\n",
+ "The are many other types of elements that can be used to create unstructured grids. Polygonal elements are often used to represent complex geometries. Meshes often contain mixed elements with different types of elements used in different areas of the domain."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import cartopy.crs as ccrs\n",
+ "import matplotlib.pyplot as plt\n",
+ "import matplotlib.tri as mtri\n",
+ "import numpy as np\n",
+ "import xarray as xr\n",
+ "\n",
+ "# Generate random temperature data\n",
+ "np.random.seed(42)\n",
+ "num_points = 600\n",
+ "latitudes = np.random.uniform(low=-90, high=90, size=num_points)\n",
+ "longitudes = np.random.uniform(low=-180, high=180, size=num_points)\n",
+ "temperatures = np.random.uniform(low=-30, high=30, size=num_points)\n",
+ "\n",
+ "# Create xarray DataArray for temperature data\n",
+ "temperature_data = xr.DataArray(\n",
+ " temperatures, dims=\"points\", coords={\"points\": range(num_points)}\n",
+ ")\n",
+ "\n",
+ "# Perform Delaunay triangulation\n",
+ "triang = mtri.Triangulation(longitudes, latitudes)\n",
+ "\n",
+ "# Create xarray DataArray for triangulation coordinates\n",
+ "triang_data = xr.DataArray(\n",
+ " np.column_stack([triang.x, triang.y]), dims=(\"points\", \"coords\")\n",
+ ")\n",
+ "\n",
+ "# Plot the globe with unstructured mesh using xarray\n",
+ "fig, ax = plt.subplots(subplot_kw={\"projection\": ccrs.PlateCarree()})\n",
+ "ax.set_global()\n",
+ "\n",
+ "# Plot world map lines with prominent gridlines\n",
+ "ax.coastlines(linewidth=0.5)\n",
+ "# ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False, linewidth=0.5)\n",
+ "\n",
+ "# Plot unstructured mesh with bold lines\n",
+ "ax.triplot(\n",
+ " triang, \"ko-\", markersize=0.1, linewidth=0.5, alpha=0.5\n",
+ ") # Increase linewidth to see the triangles\n",
+ "\n",
+ "# Scatter plot with temperature data\n",
+ "sc = ax.scatter(\n",
+ " longitudes,\n",
+ " latitudes,\n",
+ " c=temperature_data,\n",
+ " cmap=\"coolwarm\",\n",
+ " s=10,\n",
+ " transform=ccrs.PlateCarree(),\n",
+ ")\n",
+ "\n",
+ "# Colorbar\n",
+ "cbar = plt.colorbar(sc, ax=ax, label=\"Temperature (°C)\")\n",
+ "\n",
+ "ax.set_title(\"Unstructured Grid Example\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note:
\n",
+ " This is a very basic example of an unstructured grid with triangles. There are very specialized libraries to create\n",
+ " unstructured grids. Often the region of interest is meshed with a finer resolution. The mesh is then coarsened in\n",
+ " areas where the resolution is not needed. This is done to reduce the number of elements and improve computational\n",
+ " efficiency.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Why UXarray for Unstructured Grids?\n",
+ "\n",
+ "UXarray, which stands for \"Unstructured-Xarray\", is a Python package that provides Xarray-styled functionality for working with unstructured grids built around the UGRID conventions. UXarray can simplify working with unstructured grids because it:\n",
+ "\n",
+ "- Enables significant data analysis and visualization functionality to be executed directly on unstructured grids\n",
+ "\n",
+ "- Inherits from Xarray, providing simplified data using familiar (Xarray-like) data structures and operations\n",
+ " \n",
+ "- Brings standardization to unstructured mesh support for climate data analysis and visualization\n",
+ "\n",
+ "- Adheres to the UGRID specifications for compatibility across a variety of mesh formats\n",
+ "\n",
+ "- Builds on optimized data structures and algorithms for handling large and complex unstructured datasets\n",
+ "\n",
+ "- Supports enhanced interoperability and community collaboration\n",
+ "\n",
+ "- Provides a single interface for supporting a variety of unstructured grid formats including UGRID, MPAS, SCRIP, and Exodus"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note:
\n",
+ " This notebook serves as an introduction to unstructured grids and UXarray. For more information, please visit the\n",
+ " UXarray documentation and specifically see the \n",
+ " Usage examples section.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## What is next?\n",
+ "The next sections will start with basic building blocks of UXarray and then slowly dive into more advanced features."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "nbdime-conflicts": {
+ "local_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python 3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ],
+ "remote_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ]
+ },
+ "toc-autonumbering": false
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_preview/12/_sources/notebooks/01-intro/02-data-structures.ipynb b/_preview/12/_sources/notebooks/01-intro/02-data-structures.ipynb
new file mode 100644
index 00000000..d48f6178
--- /dev/null
+++ b/_preview/12/_sources/notebooks/01-intro/02-data-structures.ipynb
@@ -0,0 +1,328 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Data Structures\n",
+ "---"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "UXarray extends upon Xarray's core data structures (i.e. Dataset and DataArray) and provides functionality for operating on unstructured (a.k.a. non-regular) grids. \n",
+ "\n",
+ "This notebook will showcase the core UXarray data structures and how to interact with them"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import uxarray as ux"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "First, lets specify the paths to our Grid and Data files. As mentioned in the previous notebook, unstructured grids are typically separated into two files: one containing the grid topology and one containing data variables that reside on that grid."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "file_dir = \"../../meshfiles/\"\n",
+ "grid_filename = file_dir + \"oQU480.grid.nc\"\n",
+ "data_filename = file_dir + \"oQU480.data.nc\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## `Grid` Data Structure\n",
+ "\n",
+ "An unstructured grid file can be opened standalone using the `ux.open_grid` method, which is a catch-all method that parses the provided input and returns a `Grid` object with grid coordinate and connectivity variables represented in the UGRID conventions.\n",
+ "\n",
+ "Printing our `Grid` instance shows all available grid variables and original grid type.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid = ux.open_grid(grid_filename)\n",
+ "grid"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "We can access our coordinate, connectivity, and other descriptor variables as attributes through this `Grid` instance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid.node_lon"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid.face_node_connectivity"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## `UxDataset` & `UxDataArray` Data Structures\n",
+ "\n",
+ "UXarray inherits from Xarray's two core data structures `Dataset` & `DataArray` to provide a grid-informed implementation through the `UxDataset` & `UxDataArray` data structures. \n",
+ "\n",
+ "The major difference between them is that UXarray's implementation is paired with a `Grid` object, accessed through the `.uxgrid` property.\n",
+ "\n",
+ "UXarray also provides an overloaded `ux.open_dataset` method, which takes in both a Grid and Data file path to construct a `UxDataset`\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds = ux.open_dataset(grid_filename, data_filename)\n",
+ "uxds"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "We can see that our `UxDataset` has a single data variable ``bottomDepth``, which is mapped to each face (as specified by the ``n_face`` dimension).\n",
+ "\n",
+ "We can access this variable by indexing our `UxDataset` to obtain a `UxDataArray`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds[\"bottomDepth\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "You can access the `Grid` instance using the `.uxgrid` attribute, which is linked to every `UxDataset` and `UxDataArray`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds.uxgrid"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "Each `UxDataArray` under a `UxDataset` is linked to the same `Grid` object"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds.uxgrid == uxds[\"bottomDepth\"].uxgrid"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "nbdime-conflicts": {
+ "local_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python 3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ],
+ "remote_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ]
+ },
+ "toc-autonumbering": false
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_preview/12/_sources/notebooks/01-intro/03-data-mapping.ipynb b/_preview/12/_sources/notebooks/01-intro/03-data-mapping.ipynb
new file mode 100644
index 00000000..04c5d261
--- /dev/null
+++ b/_preview/12/_sources/notebooks/01-intro/03-data-mapping.ipynb
@@ -0,0 +1,272 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Data Mapping\n",
+ "---\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "When attempting to visualize a data variable that resides on an unstructured grid, it's important to identify what element it is mapped to, since that will dictate what visualization to choose.\n",
+ "\n",
+ "This notebook provides a quick overview of how data is commonly mapped to unstructured grid elements."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import uxarray as ux"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "is_executing": true,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Sample Mesh\n",
+ "\n",
+ "As described in the previous sections, an Unstructured Grid is composed of Nodes, Edges, and Faces.\n",
+ "\n",
+ "Below is a basic example of an Unstructured Grid, containing 13 Nodes, 15 Edges, and 3 Faces.\n",
+ "\n",
+ "![Sample Mesh](../images/sample/sample_mesh.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Face-Centered Data\n",
+ "\n",
+ "Face-Centered data is mapped to the area that each face covers. \n",
+ "\n",
+ "![Faces](../images/sample/faces.png)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Node-Centered Data\n",
+ "\n",
+ "Node-Centered data is assigned to the corners of each face.\n",
+ "\n",
+ "\n",
+ "![Faces](../images/sample/nodes.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Edge-Centered Data\n",
+ "\n",
+ "Edge-Centered data is assigned to the edge that connects each pair of modes.\n",
+ "\n",
+ "![Edges](../images/sample/edges.jpg)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Identifying Data Mappings with UXarray\n",
+ "\n",
+ "We can identify what element a data variable is mapped to by looking at the final dimensions of a `UxDataArray` or `UxDataset`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "file_dir = \"../../meshfiles/\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid_filename_mpas = file_dir + \"oQU480.grid.nc\"\n",
+ "data_filename_mpas = file_dir + \"oQU480.data.nc\"\n",
+ "uxds_mpas = ux.open_dataset(grid_filename_mpas, data_filename_mpas)\n",
+ "\n",
+ "uxds_mpas[\"bottomDepth\"].dims"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "The variable ``bottomDepth`` has a dimension of ``n_face``, which means that it is mapped to faces."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid_filename_geoflow = file_dir + \"geoflow.grid.nc\"\n",
+ "data_filename_geoflow = file_dir + \"geoflow.data.nc\"\n",
+ "uxds_geoflow = ux.open_dataset(grid_filename_geoflow, data_filename_geoflow)\n",
+ "\n",
+ "uxds_geoflow[\"v1\"].dims"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "The variable ``v1`` has a final dimension of ``n_node``, which means that it is mapped to the corner nodes of each face. However, it also has additional dimensions, ``time`` and ``meshLayers``. These additional dimensions describe the dimensionality of the data outside the unstructured grid, representing the temporal and vertical dimensions."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "nbdime-conflicts": {
+ "local_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python 3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ],
+ "remote_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ]
+ },
+ "toc-autonumbering": false
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_preview/12/_sources/notebooks/02-methods/01-plotting-libraries.ipynb b/_preview/12/_sources/notebooks/02-methods/01-plotting-libraries.ipynb
new file mode 100644
index 00000000..dab9cff9
--- /dev/null
+++ b/_preview/12/_sources/notebooks/02-methods/01-plotting-libraries.ipynb
@@ -0,0 +1,327 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Plotting Libraries\n",
+ "---\n",
+ "\n",
+ "We will introduce functionality from two visualization libraries and how they are being utilized by UXarray for unstructured grids visualization purposes. \n",
+ "\n",
+ "Before diving deep into these, looking into the current snapshot of the UXarray visualization design through a simple Unified Modelling Language (UML)-like diagram could be helpful to better understand UXarray's relation with such libraries. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note:
\n",
+ " The following design diagram is actually provided in the Plotting\n",
+ " API section along with key takeaways about it. We highly recommend to check them out as well.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## UXarray Plotting API Design"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now, let us look into the visualization libraries that UXarray relies upon or provides an interface with."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## HoloViz"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "[HoloViz](https://holoviz.org/) is a stack of tools (such as Holoviews, Datashader, Geoviews, SpatialPandas, hvPlot etc.) that provide high-level functionality to visualize even the very large datasets efficiently in Python. HoloViz packages are well-suited for unstructured grid visualization because:\n",
+ "\n",
+ "1. They provide rendering functionality for both vector geometries and rasterization, which will be detailed in the [next section](02-rendering-techniques). Such functionality is much needed for UXarray's grid topology and data visualization purposes.\n",
+ "2. Unlike Matplotlib, they support using the connectivity information that comes from the unstructured grids\n",
+ "3. They are designed to be scalable for even the largest datasets that'd be generated as result of kilometer-scale analyses"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Important!
\n",
+ " UXarray takes care of the vital tasks such as recognizing unstructured grids from various formats (such as UGRID,\n",
+ " MPAS, Scrip, Exodus, etc.) and representing them in a unified UGRID-like format, providing the data structures and\n",
+ " functionality necessary for convenient preprocessing of the grid, and wrapping up HoloViz packages' functionality to\n",
+ " enable unstructured grids-specialized, high-level visualization functions.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let us look at the HoloViz packages that we utilize under the hood of UXarray to provide high-level, scalable visualization functions."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### HoloViews\n",
+ "\n",
+ "[Holoviews](https://holoviews.org/about.html) houses several elements (e.g. `Path()`, `Points()`) that we wrap up in the UXarray plotting accessors to enable visualization of grid geometries such as nodes and edges. Similarly, other elements of this package (e.g. `Polygons()`) are used by UXarray for various polygon vector visulization purposes."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note:
\n",
+ " UXarray allows both Matplotlib and Bokeh backends to be chosen in visualization functions as they are provided by Holoviews (in addition to Plotly).\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Datashader"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "[Datashader](https://datashader.org/about.html) is the graphics pipeline system of the HoloViz tool stack for creating meaningful representations of large datasets quickly and flexibly. We utilize Datashader rasterization methods, transfer functions, and other shading operators in our polyon rasterization code."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### GeoViews"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Actually, we do not wrap [GeoViews](https://geoviews.org/index.html) functionality in UXarray. Instead, we leave it up to the user's preferences to explore and visualize geographical, meteorological, and oceanographic datasets and features using the visulization outputs from our UXarray plotting functions. However, we love to enrich the plots in our documentation and examples with addition of a lot of Geoviews features such as ocean, land, coastlines, etc."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Spatialpandas"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Spatialpandas is a package that provides Pandas extension arrays for spatial/geometric operations. This package has an element called `GeoDataFrame`, which can be used directly by packages from the HoloViz stack such as hvPlot, Datashader, Holoviews, and Geoviews. Therefore, UXarray provides Grid conversions to `GeoDataFrame` to allow the user to perform visualizations direclty in HoloViz packages rather than needing to use our UXarray plotting functions. \n",
+ "\n",
+ "Because this cookbook's main goal is to showcase UXarray's own visulization capabilities, we will not detail this conversion here but provide a link to a [UXarray usage example](https://uxarray.readthedocs.io/en/latest/examples/005-to-geodataframe-for-holoviz.html) that demonstrates this."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Matplotlib"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Matplotlib is the workhorse of Python visualization needs, for both general and geoscientific purposes. However, when it \n",
+ "comes to visualizing unstructured grids, Matplotlib's:\n",
+ "\n",
+ "1. Functionality is limited such that there is no way to use the connectivity information that comes with the unstructured grid \n",
+ "2. Scalability especially for kilometer-scale (e.g. individual storm-reoslving) resolutions is limited. \n",
+ "\n",
+ "We still support Matplotlib as a backend option in our visualization functionality, which will be covered in the next chapter. \n",
+ "\n",
+ "Moreover, just like conversion to `Spatialpandas.GeoDataFrame`, we provide conversion functions from UXarray to Matplotlib data structures such as collections, which can be utilized for visualizations directly in Matplotlib after the conversion."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Collections \n",
+ "Detailed information about Matplotlib's Collections API can be found [here](https://matplotlib.org/stable/api/collections_api.html). In Uxarray, conversions to `LineCollection` and `PolyCollection` are provided for visualizing Grid Geometries and data variables, respectively. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Warning!
\n",
+ " While these conversion functions have already been released, we have observed some issues with the resulting Matplotlib plots after the exceution of\n",
+ " these functions, and the bug-fixing of that is WIP. Hence, we don't have an officially released documentation/example about these functions yet.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Cartopy"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "Cartopy is originally a Python library for cartographic visualizations with Matplotlib; however, they provide a number of features such as `crs`, i.e. Coordinate Reference Systems (a.k.a. projections), that are significant for cartographic visualizations.\n",
+ "\n",
+ "While UXarray does not rely upon Cartopy, we support projections through our visualization functions with the help of `Cartopy.crs`. The use of such projections in the UXarray functions will be showcased in the next chapter; thus, let us stop at this point."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "nbdime-conflicts": {
+ "local_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python 3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ],
+ "remote_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ]
+ },
+ "toc-autonumbering": false
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_preview/12/_sources/notebooks/02-methods/02-rendering-techniques.ipynb b/_preview/12/_sources/notebooks/02-methods/02-rendering-techniques.ipynb
new file mode 100644
index 00000000..375e6b36
--- /dev/null
+++ b/_preview/12/_sources/notebooks/02-methods/02-rendering-techniques.ipynb
@@ -0,0 +1,338 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Rendering Techniques\n",
+ "---\n",
+ "\n",
+ "Since Unstructured Grids require significantly more overhead to represent compared to Structured (a.k.a. Regular) grids, the choice of rendering technique plays an important in obtaining high-resolution, accurate, and scalable visualuations. \n",
+ "\n",
+ "\n",
+ "This notebook introduces relevant concepts and techniques that will be mentioned and used throughout this Cookbook."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Vector (Shape) Geometries\n",
+ "\n",
+ "The nodes, edges, and faces that make up an Unstructured Grid can each be converted into a geometric shape for visualization. These geometric shapes can often be referred to as vector graphics, since each geometry is mathematically represented when rendering.\n",
+ "\n",
+ "For example, in the UXarray Visualization section, we will showcase how we can convert the faces in our Unstructured Grid into Polygons.\n",
+ "\n",
+ "When constructing our visualization, we can render each face using directly onto the screen. \n",
+ "\n",
+ "Rendering each face as a polygon will lead to visuals that look like this, which are extremely high-quality and represent the exact geometry of each face.\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "Another example of Vector Geometries is encountered when adding features to a visualization, such as Contents or Borders. The geometries of these features are drawn onto our screen.\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Shapely Example"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "One Python package which is used for representing and manipulating geometries is [Shapely](https://shapely.readthedocs.io/en/stable/manual.html).\n",
+ "\n",
+ "UXarray uses Shapely paired with SpatialPandas and other packages to represent unstructured grid elements (nodes, edges, faces) as geometries for visualization.\n",
+ "\n",
+ "The following code snippets are basic examples of how these elements can be represented as geometries.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import shapely as sp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "A node is represented as a pair of longitude and latitude coordinates"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "sp.Point([0.0, 0.0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "An edge is represented as a pair of nodes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "sp.LineString([[0.0, 0.0], [180, -90]])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "A face is represented as a counter-clockwise set of nodes, with the first and final nodes in the set being equivalent (form a closed face)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "sp.Polygon([[100, 40], [100, 50], [90, 50], [90, 40], [100, 40]])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Rasterization\n",
+ "\n",
+ "While there is definitely merit in rendering each geometric shape directly, this operation is extremely computationally expensive for large datasets.\n",
+ "\n",
+ "Rasterization is a technique in computer graphics that converts vector (a.k.a geometric shapes) graphics into a raster image, which can be thought of as a regularly-sampled array of pixel values used for rendering.\n",
+ "\n",
+ "The figure below shows a simplified example of how rasterization \"approximates\" the geometry of different elements.\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "For unstructured grids, rasterization looks something like the following.\n",
+ "\n",
+ " \n",
+ "\n",
+ "\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "The black edges outline the expected geometry of each face (a.k.a polygon).\n",
+ "\n",
+ "We can observe the jaggedness in the shading, which is the product of rasterization approximating each face."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "
\n",
+ "
See also:
\n",
+ " A more comprehensive showcase of rasterization can be found here\n",
+ "
\n",
+ " This notebook is currently under development! Please refer to the Holoviews Documentation \n",
+ "
"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/_preview/12/_sources/notebooks/03-uxarray-vis/01-plot-api.ipynb b/_preview/12/_sources/notebooks/03-uxarray-vis/01-plot-api.ipynb
new file mode 100644
index 00000000..f8733eb2
--- /dev/null
+++ b/_preview/12/_sources/notebooks/03-uxarray-vis/01-plot-api.ipynb
@@ -0,0 +1,438 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Plotting API\n",
+ "---\n",
+ "\n",
+ "UXarray provides a feature-rich plotting API for visualizing unstructured grids, with or without data variables.\n",
+ "\n",
+ "This notebook introduces how to interface with the plotting methods through UXarray's core data structures and provides an introduction to methods that are covered in detail in the next sections."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "
\n",
+ "
See also:
\n",
+ " This notebook acts as an introduction into using the UXarray plotting API. Please refer to the following notebooks in this chapter for a detailed\n",
+ " overview of visualization techniques for different purposes (e.g. Grid Topology, Polygons)\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## UXarray Plotting API Design"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Before jumping into any code, let's take a look at a high-level snapshot of UXarray's API design from an Unifed Modeling Language (UML)-like standpoint.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Key takeaways from this design are that:\n",
+ "\n",
+ "- UXarray's unified grid representation (through the UGRID conventions) means that all visualization functionality is agnostic to the grid format initially provided by the user.\n",
+ "- Each Uxarray data structure (i.e. `Grid`, `UxDataset`, `UxDataArray`) has its own `.plot` accessor, which is used to call plotting routines.\n",
+ "- The visualization functionality through these `.plot` accessors use HoloViz packages' plotting functions, wrapping them in a way to exploit all the information that comes from unstructured grids (e.g. connectivity) and provide our unstructured grids-specific functions in the most convenient way for the user.\n",
+ "- `Grid` additionally provides conversion functions that generate `SpatialPandas.GeoDataFrame` as well as `Matplotlib.PolyCollection` and `Matplotlib.LineCollection` data structures to be visualized in HoloViz packages and Matplotlib, respectively, at the user's own convenience.\n",
+ "\n",
+ "Now, we can see the API in action on a sample dataset."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Imports"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import uxarray as ux"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Data\n",
+ "\n",
+ "The grid and data files used in this notebook are from 480km MPAS Ocean model output.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "base_path = \"../../meshfiles/\"\n",
+ "grid_filename = base_path + \"oQU480.grid.nc\"\n",
+ "data_filename = base_path + \"oQU480.data.nc\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid = ux.open_grid(grid_filename)\n",
+ "grid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds = ux.open_dataset(grid_filename, data_filename)\n",
+ "uxds"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Grid\n",
+ "\n",
+ "Since a `Grid` instance only contains information about the topology of an unstructured grid (a.k.a. no data variables), the visualizations generated from the `Grid` class only showcase the coordinates and connectivity.\n",
+ "\n",
+ "By default, the `Grid.plot` method renders the borders of each of the faces."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid.plot(title=\"Default Grid Plot\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "The UXarray plotting API is written with HoloViews, with the default backend used for generating plots being `bokeh`. This means that by default, all plots are enabled with interactive features such as panning and zooming. In addition to `bokeh`, UXarray also supports the `matplotlib` backend.\n",
+ "\n",
+ "For the remainder of this notebook, we will use the `matplotlib` backend to generate static plots."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid.plot(\n",
+ " title=\"Default Grid Plot with Matplotlib\",\n",
+ " backend=\"matplotlib\",\n",
+ " aspect=2,\n",
+ " fig_size=500,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "\n",
+ "\n",
+ "You can call specific plotting routines through the `plot` accessor"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "grid.plot.nodes(title=\"Grid Node Plot\", backend=\"matplotlib\", aspect=2, fig_size=500)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "Since each `UxDataset` and `UxDataArray` is always linked to a `Grid` instance through the `uxgrid` attribute, all of these grid-specific visualizations are accessible by using that attribute.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds.uxgrid.plot(\n",
+ " title=\"Grid plot through uxgrid attribute\",\n",
+ " backend=\"matplotlib\",\n",
+ " aspect=2,\n",
+ " fig_size=500,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## UxDataArray Plotting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "The default plotting method is a great starting point for visualizations. It selects what visualization method to use based on the grid element that the data is mapped to (nodes, edges, faces) and the number of elements in the mesh. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds[\"bottomDepth\"].plot(\n",
+ " title=\"Default UxDataArray Plot\", backend=\"matplotlib\", aspect=2, fig_size=500\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "We can also call other plotting methods through the `plot` accessor, as was the case with the `Grid` class.\n",
+ "\n",
+ "For example, if we wanted to rasterize the polygons and exclude the ones that cross the antimeridian, it would look something like the following."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "uxds[\"bottomDepth\"].plot.polygons(\n",
+ " exclude_antimeridian=False,\n",
+ " title=\"Vector Polygon Plot\",\n",
+ " backend=\"matplotlib\",\n",
+ " aspect=2,\n",
+ " fig_size=500,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## UxDataset Plotting\n",
+ "\n",
+ "As of the most recent release, UXarray does not support plotting functionality through a `ux.UxDataset`. For instance, if the following commented out code was executed, it would throw an exception.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# uxds.plot()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.5"
+ },
+ "nbdime-conflicts": {
+ "local_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python 3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ],
+ "remote_diff": [
+ {
+ "diff": [
+ {
+ "diff": [
+ {
+ "key": 0,
+ "op": "addrange",
+ "valuelist": [
+ "Python3"
+ ]
+ },
+ {
+ "key": 0,
+ "length": 1,
+ "op": "removerange"
+ }
+ ],
+ "key": "display_name",
+ "op": "patch"
+ }
+ ],
+ "key": "kernelspec",
+ "op": "patch"
+ }
+ ]
+ },
+ "toc-autonumbering": false
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/_preview/12/_sources/notebooks/03-uxarray-vis/02-grid-topology.ipynb b/_preview/12/_sources/notebooks/03-uxarray-vis/02-grid-topology.ipynb
new file mode 100644
index 00000000..8647ef39
--- /dev/null
+++ b/_preview/12/_sources/notebooks/03-uxarray-vis/02-grid-topology.ipynb
@@ -0,0 +1,422 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Grid Topology"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "No matter what analysis operations you are performing on the data, visualization of the geometric elements of an unstructured grid (i.e. nodes, edges) without any data mapped to them can always be useful for a number of reasons, including but not limited to understanding the mesh topology and diagnosing patterns or issues with or prior to data analysis (e.g. analyzing the mesh of a dynamical core prior to running a simulation).\n",
+ "\n",
+ "UXarray provides convenient functionality to visualize these elements of the `Grid` object. Below we will introduce those functions, but let us do the initial setup first:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "## Setup"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This setup handles the package imports and data loading."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Imports"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import cartopy.crs as ccrs\n",
+ "import geoviews.feature as gf\n",
+ "import holoviews as hv\n",
+ "import uxarray as ux"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "### Read in the data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# File paths\n",
+ "file_dir = \"../../meshfiles/\"\n",
+ "\n",
+ "# We use 480km dataset in this example but there is also 120km dataset\n",
+ "# in the file directory that can be further explored\n",
+ "grid_filename = \"oQU480.grid.nc\"\n",
+ "data_filename = \"oQU480.data.nc\"\n",
+ "\n",
+ "# A standalone grid can be opened for immediate visualization\n",
+ "ux_grid = ux.open_grid(file_dir + grid_filename)\n",
+ "\n",
+ "# Visualization through a `UxDataset`'s associated grid, `uxds.uxgrid` is also possible.\n",
+ "uxds = ux.open_dataset(file_dir + grid_filename, file_dir + data_filename)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Important!
\n",
+ " How to plot through `Grid`, `UxDataset`, or `UxDataArray`?\n",
+ " \n",
+ " \n",
+ " As the above `ux_grid` and `uxds` creation suggests, you may either have a `UxDataset` (or similarly \n",
+ " `UxDataArray`), or a standalone `Grid` object. Visualization of the geometric elements of an \n",
+ " unstructured grid is possible in all of these cases as follows (Through `uxgrid` accessor when it is \n",
+ " a `UxDataset` or `UxDataArray`):\n",
+ " \n",
+ " `uxarray.Grid.plot.plotting_function()` \n",
+ " `uxarray.UxDataset.uxgrid.plot.plotting_function()` \n",
+ " `uxarray.UxDataArray.uxgrid.plot.plotting_function()` \n",
+ " We will demonstrate plotting functions using the standalone `ux_grid` thorughout this notebook.\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plotting Edges"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plotting the edges of an Unstructured Grid gives us an immediate idea of what the actual mesh looks like since connected edges construct the faces of the grid. Because of this, edge visualization is considered as the default method for Grid topology visualization purposes, and the default plotting method `uxarray.Grid.plot()`, provides an edge plot as follows:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ux_grid.plot(\n",
+ " title=\"Default Grid Plot Method\",\n",
+ " width=700,\n",
+ " height=350,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip:
\n",
+ " See also `ux_grid.plot.mesh()` and `ux_grid.plot.edges()` that would both create the same plot.\n",
+ "
\n",
+ ""
+ ],
+ "text/plain": [
+ ":Layout\n",
+ " .Image.I :Image [lon,lat] (lon_lat var)\n",
+ " .Image.II :Image [lon,lat] (lon_lat var)"
+ ]
+ },
+ "execution_count": 117,
+ "metadata": {
+ "application/vnd.holoviews_exec.v0+json": {
+ "id": "p12127"
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(\n",
+ " uxds_480km[\"bottomDepth\"].plot.rasterize(\n",
+ " method=\"point\", width=900, height=400, title=\"480km Grid\"\n",
+ " )\n",
+ " + uxds_120km[\"bottomDepth\"].plot.rasterize(\n",
+ " method=\"point\", width=900, height=400, title=\"120km Grid\"\n",
+ " )\n",
+ ").cols(1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Pixel Ratio"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "source": [
+ "As the resolution of our grid increases, observe how there is a much higher density of points, to the point where we can start to observe the trends of the data variable. \n",
+ "\n",
+ "As was the case with the Polygon raster, we can specify a `pixel_ratio` value to control the bin sized used for rasterization. To summarize:\n",
+ "\n",
+ "* A high pixel ratio increases the number of bins by making each bin smaller, meaning that on average less points fall into each bin, leading to a sparsity\n",
+ "* A low pixel ratio decreases the number of bins by making each bin larger, meaning that on average more points fall into each bin, decreasing the sparsity\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 118,
+ "metadata": {
+ "collapsed": false,
+ "jupyter": {
+ "outputs_hidden": false
+ }
+ },
+ "outputs": [
+ {
+ "data": {},
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/vnd.holoviews_exec.v0+json": "",
+ "text/html": [
+ "