{ "cells": [ { "cell_type": "markdown", "id": "d5886a2c-ebd2-4e80-8aa7-b111d74c76fb", "metadata": {}, "source": [ "<img src=\"https://raw.githubusercontent.com/UXARRAY/uxarray/main/docs/_static/images/logos/uxarray_logo_h_dark.svg\"\n", " width=\"30%\"\n", " alt=\"UXarray logo\"\n", " align=\"right\"\n", "/>\n", "\n", "# Spatial Selection Operators\n", "\n", "### In this tutorial, you'll learn:\n", "\n", "* Using UXarray to select specific regions from an unstructured grid\n", "\n", "\n", "### Related Documentation\n", "\n", "* [UXarray Subsetting Documentation](https://uxarray.readthedocs.io/en/latest/user-guide/subset.html)\n", "* [UXarray Cross-Section Documentation](https://uxarray.readthedocs.io/en/latest/user-guide/cross-sections.html)\n", "\n", "### Prerequisites\n", "\n", "| Concepts | Importance | Notes |\n", "|-----------------------------------------------| --- | --- |\n", "| [UXDataset & UxDataArray Notebook](uxds-uxda) | Necessary | |\n", "\n", "**Time to learn**: 10 minutes\n", "\n", "-----\n" ] }, { "cell_type": "markdown", "id": "ba50a82c-0c16-4704-bab5-13446f550d82", "metadata": {}, "source": [ "## Overview\n", "\n", "When working with unstructured grids, a region or zone rather than the entire global grid might be of interest for data analysis and visualization. Such spatial selection of the grid/data might help with not only analyzing/plotting a specific region/zone, but also reducing the data size and increasing the performance as well as allowing the entire plots to be effectively displayed on the screen.\n", "\n", "This notebook showcases how to spatially subset a grid and take a cross-section of the grid at a constant latitude and longitude." ] }, { "cell_type": "markdown", "id": "95356e7a-bbba-4648-bbac-10d609855ce4", "metadata": {}, "source": [ "## Subsetting\n", "\n", "UXarray provides functionality for subsetting the grid into a **bounding box**, **bounding circle**, or **K-nearest neighbors**. \n", "\n", "Before demonstrating them, let us load some global data first:" ] }, { "cell_type": "markdown", "id": "6815426b-ab86-41c4-b04f-e7546c5e6e7e", "metadata": {}, "source": [ "### Load Data" ] }, { "cell_type": "code", "id": "b619a6a6-eaaa-4e5b-b15f-98502b8f4b28", "metadata": { "scrolled": true }, "source": [ "# Import\n", "import cartopy.crs as ccrs\n", "import geoviews.feature as gf\n", "import uxarray as ux\n", "\n", "grid_path = \"../../meshfiles/x1.655362.grid.nc\"\n", "data_path = \"../../meshfiles/x1.655362.data.nc\"\n", "\n", "# Open dataset and grab a data variable of interest\n", "uxds = ux.open_dataset(grid_path, data_path)\n", "uxda = uxds[\"relhum_200hPa\"][0]" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "71695b1f-e0b6-4e6d-b6ff-3b0b927e4f0f", "metadata": {}, "source": [ "### Plot The Global Data" ] }, { "cell_type": "markdown", "id": "43ae12eb-92cb-4b55-9d49-14774dcefb7c", "metadata": {}, "source": [ "<div class=\"admonition alert alert-info\">\n", " <p class=\"admonition-title\" style=\"font-weight:bold\">Note!</p>\n", " The visualizations throughout this tutorial are only for demonstrating the results of the subsetting and cross-sections versus the global grid. Since the details of plotting with UXarray will be covered in the next chapter, we will not go over any details of the plots here.\n", "</div>" ] }, { "cell_type": "code", "id": "e623aac7-6177-497e-852b-31d7224906e6", "metadata": {}, "source": [ "plot_opts = {\"width\": 700, \"height\": 350}\n", "\n", "features = gf.coastline(\n", " projection=ccrs.PlateCarree(), line_width=0.4, scale=\"50m\"\n", ") * gf.states(projection=ccrs.PlateCarree(), line_width=0.4, scale=\"50m\")\n", "\n", "clim = (uxda.values.min(), uxda.values.max())\n", "\n", "uxda.plot(\n", " rasterize=True, periodic_elements=\"exclude\", title=\"Global Grid\", **plot_opts\n", ") * features" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "f53848bf-7630-4b4e-979a-99c48628c464", "metadata": {}, "source": [ "### Generate Various Subsets" ] }, { "cell_type": "code", "id": "ead0c311-d3b7-41aa-8523-7260ce829d6f", "metadata": {}, "source": [ "# Bounding box around Boulder, CO\n", "ref_lon = -105.2705\n", "ref_lat = 40.0150\n", "ref_offset = 1\n", "\n", "lon_bounds = (ref_lon - ref_offset, ref_lon + ref_offset)\n", "lat_bounds = (ref_lat - ref_offset, ref_lat + ref_offset)\n", "\n", "# Subset the global data variable and its grid using the bounding box\n", "uxda_bbox = uxda.subset.bounding_box(lon_bounds, lat_bounds, element=\"nodes\")" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "id": "2fcb49ce-4c9f-473a-9c93-8d0a0b42a7b1", "metadata": {}, "source": [ "# Now use a bounding circle subsetting\n", "ref_center = [ref_lon, ref_lat]\n", "\n", "uxda_bcircle = uxda.subset.bounding_circle(ref_center, ref_offset)" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "id": "1de8acc4-5b2f-4cdd-ad02-a6f4017cafa9", "metadata": {}, "source": [ "# Now use a K-nearest neighbor subsetting\n", "k_nn = 60\n", "\n", "uxda_nn = uxda.subset.nearest_neighbor(ref_center, k=k_nn, element=\"nodes\")" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "31b8019b-a965-49b8-9490-6481f50bddcd", "metadata": {}, "source": [ "### Plot The Subsets" ] }, { "cell_type": "code", "id": "88d7c474-c762-43d0-917e-b282f7109a0c", "metadata": { "scrolled": true }, "source": [ "plot_bbox = (\n", " uxda_bbox.plot(\n", " rasterize=True,\n", " periodic_elements=\"exclude\",\n", " clim=clim,\n", " title=\"Bounding Box Subset around Boulder, CO (Corner Node Query)\",\n", " **plot_opts,\n", " )\n", " * features\n", ")\n", "\n", "plot_bcircle = (\n", " uxda_bcircle.plot(\n", " rasterize=True,\n", " periodic_elements=\"exclude\",\n", " clim=clim,\n", " title=\"Bounding Circle Subset around Boulder, CO (Corner Node Query)\",\n", " **plot_opts,\n", " )\n", " * features\n", ")\n", "\n", "plot_nn = (\n", " uxda_nn.plot(\n", " rasterize=True,\n", " periodic_elements=\"exclude\",\n", " clim=clim,\n", " title=\"K-Nearest Neighbor Subset around Boulder, CO (Corner Node Query)\",\n", " **plot_opts,\n", " )\n", " * features\n", ")\n", "\n", "(plot_bbox + plot_bcircle + plot_nn).cols(1)" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "125509b9-3b8e-46dc-8523-38ceeb01beee", "metadata": {}, "source": [ "## Cross-sections\n", "\n", "Similarly, UXarray provides functionality for taking cross-sections of a grid/data at constant **latitudes** and **longitudes**. " ] }, { "cell_type": "markdown", "id": "fc734a30-5fa9-4157-bda4-731a902c89ba", "metadata": {}, "source": [ "### Load Data" ] }, { "cell_type": "code", "id": "78b774d6-db3d-4d4a-aefa-1293a13e33a7", "metadata": { "scrolled": true }, "source": [ "# Data paths\n", "grid_path = \"../../meshfiles/outCSne30.grid.ug\"\n", "data_path = \"../../meshfiles/outCSne30.data.nc\"\n", "\n", "# Open dataset and grab a data variable of interest\n", "uxds = ux.open_dataset(grid_path, data_path)\n", "uxda = uxds[\"psi\"]" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "193e9dce-55b0-4900-9312-14480a2e76ac", "metadata": {}, "source": [ "### Plot The Global Data" ] }, { "cell_type": "code", "id": "21a7e180-8afa-461a-a976-4a9370290b2e", "metadata": {}, "source": [ "projection = ccrs.Robinson()\n", "\n", "features_2 = gf.coastline(\n", " projection=projection, line_width=0.4, scale=\"50m\"\n", ") * gf.states(projection=projection, line_width=0.4, scale=\"50m\")\n", "\n", "uxda.plot(\n", " cmap=\"inferno\",\n", " periodic_elements=\"split\",\n", " projection=projection,\n", " title=\"Global Plot\",\n", ") * features_2" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "ded07a82-7a7a-4a55-8e74-9c1d71fe5154", "metadata": {}, "source": [ "### Generate Cross-Sections" ] }, { "cell_type": "code", "id": "e869e010-86f9-4eaa-b1f1-8568fb4907ed", "metadata": {}, "source": [ "# Cross-section at the latitude of Boulder, CO\n", "cross_lat = 40.0150\n", "\n", "uxda_cross_lat = uxda.cross_section.constant_latitude(cross_lat)" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "id": "9f629337-21f9-4448-a181-612c038fa92a", "metadata": {}, "source": [ "# Now cross-section at the longitude of Boulder, CO\n", "cross_lon = -105.2705\n", "\n", "uxda_cross_lon = uxda.cross_section.constant_longitude(cross_lon)" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "8ef8af94-c6f4-468d-95ea-534d6130cfdb", "metadata": {}, "source": [ "### Plot The Cross-Sections" ] }, { "cell_type": "code", "id": "53e0f8dc-b51f-473e-b184-8ddc5203e7e9", "metadata": {}, "source": [ "plot_cross_lat = (\n", " uxda_cross_lat.plot(\n", " rasterize=False,\n", " backend=\"bokeh\",\n", " cmap=\"inferno\",\n", " projection=projection,\n", " global_extent=True,\n", " coastline=True,\n", " title=f\"Cross-section at ({cross_lat}) degrees latitude around Boulder, CO\",\n", " )\n", " * features_2\n", ")\n", "\n", "plot_cross_lon = (\n", " uxda_cross_lon.plot(\n", " rasterize=False,\n", " backend=\"bokeh\",\n", " cmap=\"inferno\",\n", " projection=projection,\n", " global_extent=True,\n", " coastline=True,\n", " title=f\"Cross-section at ({cross_lon}) degrees longitude around Boulder, CO\",\n", " )\n", " * features_2\n", ")\n", "\n", "(plot_cross_lat + plot_cross_lon).cols(1)" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "id": "977a1608-cf7e-4342-967e-a088523e7630", "metadata": {}, "source": [ "## What is next?\n", "With this section, we have wrapped up this chapter, move on to the next chapter!" ] } ], "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.12.8" } }, "nbformat": 4, "nbformat_minor": 5 }