Skip to content

Commit 4fa1f7a

Browse files
authored
Merge pull request #1047 from UXARRAY/rajeeja/from_file_notebook
User Guide for `Grid.from_file()`
2 parents 7c104fa + 027ad5d commit 4fa1f7a

File tree

6 files changed

+262
-2
lines changed

6 files changed

+262
-2
lines changed

docs/user-guide/from_file.ipynb

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "4a432a8bf95d9cdb",
6+
"metadata": {},
7+
"source": [
8+
"# Reading & Working with Geometry Files\n",
9+
"\n",
10+
"This notebooks demonstrates how to use the `Grid.from_file()` class method to load in geometry files such as:\n",
11+
"\n",
12+
"1. Shapefile\n",
13+
"2. GeoJSON\n",
14+
"\n",
15+
"Highlighted is a workflow showcasing how to remap a variable from an unstructured grid to a Shapefile."
16+
]
17+
},
18+
{
19+
"cell_type": "code",
20+
"execution_count": null,
21+
"id": "b35ba4a2c30750e4",
22+
"metadata": {
23+
"ExecuteTime": {
24+
"end_time": "2024-10-09T17:50:50.244285Z",
25+
"start_time": "2024-10-09T17:50:50.239653Z"
26+
}
27+
},
28+
"outputs": [],
29+
"source": [
30+
"import uxarray as ux\n",
31+
"import warnings\n",
32+
"import geocat.datafiles as geodf\n",
33+
"\n",
34+
"warnings.filterwarnings(\"ignore\")"
35+
]
36+
},
37+
{
38+
"cell_type": "markdown",
39+
"id": "395a3db7-495c-4cff-b733-06bbe522a604",
40+
"metadata": {},
41+
"source": [
42+
"## Load a shapefile and plot \n",
43+
"\n",
44+
"* This section demonstrates how to load a shapefile using uxarray's Grid.from_file() function\n",
45+
"* The shapefile used in this example is the US national boundary file from the US Census Bureau. It is a 20m resolution shapefile that represents the national boundary of the United States. \n",
46+
"* The data plotted is subset to a specific bounding box, which is defined by the latitude and longitude bounds. The result is plotted using the matplotlib backend."
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": null,
52+
"id": "b4160275c09fe6b0",
53+
"metadata": {
54+
"ExecuteTime": {
55+
"end_time": "2024-10-09T17:50:51.217211Z",
56+
"start_time": "2024-10-09T17:50:50.540946Z"
57+
}
58+
},
59+
"outputs": [],
60+
"source": [
61+
"shp_filename = (\n",
62+
" \"../../test/meshfiles/shp/cb_2018_us_nation_20m/cb_2018_us_nation_20m.shp\"\n",
63+
")\n",
64+
"uxds = ux.Grid.from_file(shp_filename)\n",
65+
"lat_bounds = [-90, -70]\n",
66+
"lon_bounds = [20, 55]\n",
67+
"uxds = uxds.subset.bounding_box(lon_bounds, lat_bounds)\n",
68+
"uxds.plot(\n",
69+
" title=\"US 20m Focus on Mainland (cb_2018_us_nation_20m.shp)\",\n",
70+
" backend=\"matplotlib\",\n",
71+
" width=500,\n",
72+
")"
73+
]
74+
},
75+
{
76+
"cell_type": "markdown",
77+
"id": "9808189d",
78+
"metadata": {},
79+
"source": [
80+
"## Load a Geojson file and plot\n",
81+
"\n",
82+
" * This section demonstrates how to load a Geojson file using uxarray's Grid.from_file() function\n",
83+
" * The Geojson file used in this example is a few buildings around downtown Chicago. The plot is shown using the \"matplotlib\" backend for bounds specific to the region.\n",
84+
"\n"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"id": "31d92527",
91+
"metadata": {},
92+
"outputs": [],
93+
"source": [
94+
"geojson_filename = \"../../test/meshfiles/geojson/sample_chicago_buildings.geojson\"\n",
95+
"uxgeojson = ux.Grid.from_file(geojson_filename)\n",
96+
"lat_bounds = [41.6, 42.1]\n",
97+
"lon_bounds = [-87.7, -87.5]\n",
98+
"uxgeojson.subset.bounding_box(lon_bounds, lat_bounds).plot(backend=\"matplotlib\")"
99+
]
100+
},
101+
{
102+
"cell_type": "markdown",
103+
"id": "f2f14b3a",
104+
"metadata": {},
105+
"source": [
106+
"## Open NetCDF mesh file using the Grid.from_file() function\n",
107+
"\n",
108+
"* Regular NetCDF files can also be opened using this function. Backend options available are:\n",
109+
" * xarray\n",
110+
" * geopandas (default for opening shapefile, geojson file and other file formats supported by geopandas read_file function)\n",
111+
"* In the following code, we load a NetCDF mesh file: scrip/outCSne8/outCSne8.nc and print out the grid contents."
112+
]
113+
},
114+
{
115+
"cell_type": "code",
116+
"execution_count": null,
117+
"id": "aba5d650",
118+
"metadata": {},
119+
"outputs": [],
120+
"source": [
121+
"nc_filename = \"../../test/meshfiles/scrip/outCSne8/outCSne8.nc\"\n",
122+
"uxgrid = ux.Grid.from_file(nc_filename, backend=\"xarray\")\n",
123+
"uxgrid"
124+
]
125+
},
126+
{
127+
"cell_type": "markdown",
128+
"id": "f27481e2-5c1c-4189-b0c7-39737c4e47f8",
129+
"metadata": {},
130+
"source": [
131+
"## Remapping from Shapefile\n",
132+
"\n",
133+
"The following steps are needed for Remapping Global Relative Humidity Data on to a specific region defined by Shapefile using UXarray\n",
134+
"\n",
135+
"1. **Read the shapefile** (uxds)\n"
136+
]
137+
},
138+
{
139+
"cell_type": "code",
140+
"execution_count": null,
141+
"id": "002b3f66-11ed-4f3d-905f-967802b9fff2",
142+
"metadata": {},
143+
"outputs": [],
144+
"source": [
145+
"shp_filename = (\n",
146+
" \"../../test/meshfiles/shp/chicago_neighborhoods/chicago_neighborhoods.shp\"\n",
147+
")\n",
148+
"uxds = ux.Grid.from_file(shp_filename)\n",
149+
"lat_bounds = [41, 43]\n",
150+
"lon_bounds = [-89, -90]\n",
151+
"uxds = uxds.subset.bounding_box(lon_bounds, lat_bounds)\n",
152+
"uxds.plot(\n",
153+
" title=\"Chicago Neighborhoods\",\n",
154+
" backend=\"bokeh\",\n",
155+
")"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"id": "c9447221-aaba-4155-868d-f88b791e559e",
161+
"metadata": {},
162+
"source": [
163+
"\n",
164+
"2. **Initialize Input Data Files**\n",
165+
" - The input datasets consist of NetCDF files that include global relative humidity data.\n",
166+
" - The `datafiles` variable points to two NetCDF files using the `geodf.get` function, specifying the paths:\n",
167+
" - The first file contains meteorological diagnostic data: \n",
168+
" `netcdf_files/MPAS/FalkoJudt/dyamond_1/30km/diag.2016-08-20_00.00.00_subset.nc`.\n",
169+
" - The second file provides the MPAS grid specification: \n",
170+
" `netcdf_files/MPAS/FalkoJudt/dyamond_1/30km/x1.655362.grid_subset.nc`.\n",
171+
"\n",
172+
"2. **Open the Datasets with UXarray**\n",
173+
" - The `ux.open_dataset()` function is used to load these files, making them accessible as a UXarray Dataset.\n",
174+
" - `uxds_source` is the opened dataset that holds the meteorological data, such as relative humidity, structured over the MPAS grid."
175+
]
176+
},
177+
{
178+
"cell_type": "code",
179+
"execution_count": null,
180+
"id": "9b629686-8286-4336-b188-8a1b12c0fcd2",
181+
"metadata": {},
182+
"outputs": [],
183+
"source": [
184+
"datafiles = (\n",
185+
" geodf.get(\n",
186+
" \"netcdf_files/MPAS/FalkoJudt/dyamond_1/30km/diag.2016-08-20_00.00.00_subset.nc\"\n",
187+
" ),\n",
188+
" geodf.get(\"netcdf_files/MPAS/FalkoJudt/dyamond_1/30km/x1.655362.grid_subset.nc\"),\n",
189+
")\n",
190+
"\n",
191+
"uxds_source = ux.open_dataset(datafiles[1], datafiles[0])"
192+
]
193+
},
194+
{
195+
"cell_type": "markdown",
196+
"id": "ab2f5f8c",
197+
"metadata": {},
198+
"source": [
199+
"4. **Remap Relative Humidity Data**\n",
200+
" - The `relhum_200hPa` variable is accessed from `uxds_source` to extract relative humidity data at 200 hPa pressure level.\n",
201+
" - **Inverse Distance Weighted Remapping**:\n",
202+
" - The data is remapped using UXarray’s `inverse_distance_weighted` method.\n",
203+
" - The remapping is done to \"face centers,\" adapting the data from its original grid to align with a new shape or structure.\n",
204+
"\n",
205+
"5. **Plot the Remapped Data**\n",
206+
" - The remapped data for Chicago neighborhoods is plotted using UXarray's plotting utilities.\n",
207+
" - The plot uses the `sequential_blue` colormap and is rendered with the `bokeh` backend.\n",
208+
" - The title of the plot is \"Chicago Neighborhoods Relative Humidity,\" giving a clear representation of how relative humidity varies spatially."
209+
]
210+
},
211+
{
212+
"cell_type": "code",
213+
"execution_count": null,
214+
"id": "af78a1ed-e9e4-4dd0-a58f-87640e7d5f11",
215+
"metadata": {},
216+
"outputs": [],
217+
"source": [
218+
"chicago_relative_humidty = uxds_source[\"relhum_200hPa\"].remap.inverse_distance_weighted(\n",
219+
" uxds, remap_to=\"face centers\"\n",
220+
")\n",
221+
"\n",
222+
"chicago_relative_humidty[0].plot(\n",
223+
" cmap=ux.cmaps.sequential_blue,\n",
224+
" title=\"Chicago Neighborhoods Relative Humidty\",\n",
225+
" backend=\"bokeh\",\n",
226+
")"
227+
]
228+
}
229+
],
230+
"metadata": {
231+
"kernelspec": {
232+
"display_name": "Python 3 (ipykernel)",
233+
"language": "python",
234+
"name": "python3"
235+
},
236+
"language_info": {
237+
"codemirror_mode": {
238+
"name": "ipython",
239+
"version": 3
240+
},
241+
"file_extension": ".py",
242+
"mimetype": "text/x-python",
243+
"name": "python",
244+
"nbconvert_exporter": "python",
245+
"pygments_lexer": "ipython3",
246+
"version": "3.11.9"
247+
}
248+
},
249+
"nbformat": 4,
250+
"nbformat_minor": 5
251+
}

docs/userguide.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ These user guides provide additional details about specific features in UXarray.
8282
`Compatibility with HoloViz Tools <user-guide/holoviz.ipynb>`_
8383
Use UXarray with HoloViz tools
8484

85-
85+
`Reading & Working with Geometry Files <user-guide/from_file.ipynb>`_
86+
Load and work with geometry files (i.e. Shapefile, GeoJSON)
8687

8788
.. toctree::
8889
:hidden:
@@ -106,3 +107,4 @@ These user guides provide additional details about specific features in UXarray.
106107
user-guide/structured.ipynb
107108
user-guide/from-points.ipynb
108109
user-guide/holoviz.ipynb
110+
user-guide/from_file.ipynb
Binary file not shown.
884 Bytes
Binary file not shown.

test/test_geopandas.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
shp_filename_5poly = current_path / "meshfiles" / "shp" / "5poly/5poly.shp"
1010
shp_filename_multi = current_path / "meshfiles" / "shp" / "multipoly/multipoly.shp"
1111
geojson_filename = current_path / "meshfiles" / "geojson" / "sample_chicago_buildings.geojson"
12+
nc_filename = current_path / "meshfiles" / "scrip" / "outCSne8" / "outCSne8.nc"
1213

1314
def test_read_shpfile():
1415
"""Read a shapefile."""
@@ -43,3 +44,8 @@ def test_read_geojson():
4344
uxgrid = ux.Grid.from_file(geojson_filename)
4445
assert uxgrid.n_face == 10
4546
assert uxgrid.n_max_face_nodes == 36
47+
48+
def test_load_xarray_with_from_file():
49+
""" Use backend xarray to call the from_file method."""
50+
uxgrid = ux.Grid.from_file(nc_filename, backend="xarray")
51+
uxgrid.validate()

uxarray/grid/grid.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,8 @@ def from_file(
365365
grid_ds, source_dims_dict = _read_geodataframe(filename)
366366

367367
elif backend == "xarray":
368-
grid_ds, source_dims_dict = cls.from_dataset(filename)
368+
dataset = xr.open_dataset(filename, **kwargs)
369+
return cls.from_dataset(dataset)
369370

370371
else:
371372
raise ValueError("Backend not supported")

0 commit comments

Comments
 (0)