Skip to content

Commit

Permalink
Latitude & Longitude Interval Cross Section, Updated Bounding Box Sub…
Browse files Browse the repository at this point in the history
…set (#1115)

* update bounds subset, add latitude and longitude interval cross section

* update notebook and function sig

* docstrings, cleanup

* update test

* update TODO blurbs

* update notebook

---------

Co-authored-by: Rajeev Jain <[email protected]>
  • Loading branch information
philipc2 and rajeeja authored Jan 17, 2025
1 parent 17e84a4 commit 78dca67
Show file tree
Hide file tree
Showing 12 changed files with 648 additions and 272 deletions.
8 changes: 7 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ Grid

Grid.cross_section
Grid.cross_section.constant_latitude
Grid.cross_section.constant_longitude
Grid.cross_section.constant_latitude_interval
Grid.cross_section.constant_longitude_interval


UxDataArray
~~~~~~~~~~~
Expand All @@ -335,7 +339,9 @@ UxDataArray

UxDataArray.cross_section
UxDataArray.cross_section.constant_latitude

UxDataArray.cross_section.constant_longitude
UxDataArray.cross_section.constant_latitude_interval
UxDataArray.cross_section.constant_longitude_interval
Remapping
---------

Expand Down
142 changes: 97 additions & 45 deletions docs/user-guide/cross-sections.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,14 @@
"source": [
"# Cross-Sections\n",
"\n",
"This section demonstrates how to extract cross-sections from an unstructured grid using UXarray, which allows the analysis and visualization across slices of grids.\n"
"This section demonstrates how to extract cross-sections from an unstructured grid using UXarray, which allows the analysis and visualization across slices of grids. Cross-sections can be performed directly on a `ux.Grid` object or on a `ux.UxDataArray`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b35ba4a2c30750e4",
"metadata": {
"ExecuteTime": {
"start_time": "2024-10-14T16:39:35.957687Z"
},
"jupyter": {
"is_executing": true
}
},
"metadata": {},
"outputs": [],
"source": [
"import uxarray as ux\n",
Expand All @@ -33,24 +26,11 @@
"projection = ccrs.Robinson()"
]
},
{
"cell_type": "markdown",
"id": "395a3db7-495c-4cff-b733-06bbe522a604",
"metadata": {},
"source": [
"## Data"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b4160275c09fe6b0",
"metadata": {
"ExecuteTime": {
"end_time": "2024-10-09T17:50:51.217211Z",
"start_time": "2024-10-09T17:50:50.540946Z"
}
},
"metadata": {},
"outputs": [],
"source": [
"base_path = \"../../test/meshfiles/ugrid/outCSne30/\"\n",
Expand All @@ -66,44 +46,29 @@
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c844a3b5-ef71-41c8-a0ae-02ea937801d6",
"metadata": {},
"outputs": [],
"source": [
"uxds.uxgrid.normalize_cartesian_coordinates()"
]
},
{
"cell_type": "markdown",
"id": "a7a40958-0a4d-47e4-9e38-31925261a892",
"metadata": {},
"source": [
"## Constant Latitude\n",
"\n",
"Cross-sections along constant latitude lines can be obtained using the ``.cross_section.constant_latitude`` method, available for both ``ux.Grid`` and ``ux.DataArray`` objects. This functionality allows users to extract and analyze slices of data at specified latitudes, providing insights into variations along horizontal sections of the grid.\n"
"Cross-sections along constant latitude lines can be obtained by using the ``.cross_section.constant_latitude(lat)`` method. The sliced grid will be made up of the faces that contain at least one edge that intersects with a line of constant latitude.\n"
]
},
{
"cell_type": "markdown",
"id": "2fbe9f6e5bb59a17",
"metadata": {},
"source": [
"For example, we can obtain a cross-section at 30 degrees latitude by doing the following:"
"For example, we can obtain a cross-section at 0 degrees latitude by doing the following:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3775daa1-2f1d-4738-bab5-2b69ebd689d9",
"metadata": {
"ExecuteTime": {
"end_time": "2024-10-09T17:50:53.093314Z",
"start_time": "2024-10-09T17:50:53.077719Z"
}
},
"metadata": {},
"outputs": [],
"source": [
"lat = 0\n",
Expand Down Expand Up @@ -167,8 +132,7 @@
"## Constant Longitude\n",
"\n",
"\n",
"\n",
"Cross-sections along constant longitude lines can be obtained using the ``.cross_section.constant_longitude`` method, available for both ``ux.Grid`` and ``ux.DataArray`` objects. \n"
"Cross-sections along constant longitude lines can be obtained using the ``.cross_section.constant_longitude(lon)`` method. The sliced grid will be made up of the faces that contain at least one edge that intersects with a line of constant longitude.\n"
]
},
{
Expand Down Expand Up @@ -205,6 +169,94 @@
")"
]
},
{
"cell_type": "markdown",
"id": "5044b8680d514fdc",
"metadata": {},
"source": [
"## Constant Latitude Interval\n",
"\n",
"Cross-sections between two lines of latitudes can be obtained using the ``.cross_section.constant_lats_interval(lats)`` method. The sliced grid will contain faces that are strictly between the latitude interval."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fc84e47efe2edf96",
"metadata": {},
"outputs": [],
"source": [
"lats = [-20, 20]\n",
"\n",
"uxda_constant_lat_interval = uxds[\"psi\"].cross_section.constant_latitude_interval(lats)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "60232626ba6c74ad",
"metadata": {},
"outputs": [],
"source": [
"(\n",
" uxda_constant_lat_interval.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 between {lats[0]} and {lats[1]} degrees latitude\",\n",
" periodic_elements=\"split\",\n",
" )\n",
" * gf.grid(projection=projection)\n",
")"
]
},
{
"cell_type": "markdown",
"id": "4afa3d891a80c597",
"metadata": {},
"source": [
"## Constant Longitude Interval\n",
"\n",
"Cross-sections between two lines of longitude can be obtained using the ``.cross_section.constant_lons_interval(lons)`` method. The sliced grid will contain faces that are strictly between the longitude interval.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b183d15838aaf6bb",
"metadata": {},
"outputs": [],
"source": [
"lons = [-25, 25]\n",
"\n",
"uxda_constant_lon_interval = uxds[\"psi\"].cross_section.constant_longitude_interval(lats)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22793d56701504ce",
"metadata": {},
"outputs": [],
"source": [
"(\n",
" uxda_constant_lon_interval.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 between {lons[0]} and {lons[1]} degrees longitude\",\n",
" periodic_elements=\"split\",\n",
" )\n",
" * gf.grid(projection=projection)\n",
")"
]
},
{
"cell_type": "markdown",
"id": "54d9eff1-67f1-4691-a3b0-1ee0c874c98f",
Expand All @@ -219,7 +271,7 @@
"metadata": {},
"source": [
"```{warning}\n",
"Arbitrary great circle arc cross sections are not yet supported.\n",
"Arbitrary great circle arc cross sections are not yet implemented.\n",
"```"
]
}
Expand All @@ -240,7 +292,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
"version": "3.12.3"
}
},
"nbformat": 4,
Expand Down
69 changes: 2 additions & 67 deletions docs/user-guide/subset.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -256,20 +256,6 @@
"lat_bounds = (41.8781 - 2, 41.8781 + 2)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"Our bounding box ensures that the coordinates of our select element (`nodes`, `edge_centers`, or `face_centers`) are within the defined bounding box range.\n",
"\n",
"Below is an example using the corner nodes for our subset."
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -282,7 +268,8 @@
"outputs": [],
"source": [
"bbox_subset_nodes = uxds[\"relhum_200hPa\"][0].subset.bounding_box(\n",
" lon_bounds, lat_bounds, element=\"nodes\"\n",
" lon_bounds,\n",
" lat_bounds,\n",
")\n",
"\n",
"bbox_subset_nodes.plot(\n",
Expand All @@ -294,58 +281,6 @@
") * features"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"And similarly using the face center coordinates."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"bbox_subset_faces = uxds[\"relhum_200hPa\"][0].subset.bounding_box(\n",
" lon_bounds, lat_bounds, element=\"face centers\"\n",
")\n",
"\n",
"bbox_subset_faces.plot(\n",
" rasterize=True,\n",
" periodic_elements=\"exclude\",\n",
" clim=clim,\n",
" title=\"Bounding Box Subset (Face Center Query)\",\n",
" **plot_opts,\n",
") * features"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"While the bounding box is generally the same, you will notice differences along the border depending on which element is used to query.\n",
"\n",
":::{note}\n",
"Specifying which element to query (i.e. ``nodes``, ``edgecenters``, or ``face centers``) is supported by all subsetting methods.\n",
":::"
]
},
{
"cell_type": "markdown",
"metadata": {
Expand Down
Loading

0 comments on commit 78dca67

Please sign in to comment.