Skip to content

Commit 9dbb8c3

Browse files
authored
Merge pull request #178 from aleaf/main
Update 11_xarray_mt_rainier...
2 parents fed1392 + 3cbf44c commit 9dbb8c3

2 files changed

Lines changed: 49 additions & 26 deletions

File tree

.github/workflows/test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,5 @@ jobs:
7676
shell: bash -l {0}
7777
run: |
7878
pytest tests/test_notebooks.py -v
79+
env:
80+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

notebooks/part0_python_intro/11_xarray_mt_rainier_precip.ipynb

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
"cell_type": "markdown",
6767
"metadata": {},
6868
"source": [
69-
"## Xarray"
69+
"## Xarray basics"
7070
]
7171
},
7272
{
@@ -163,7 +163,7 @@
163163
"cell_type": "markdown",
164164
"metadata": {},
165165
"source": [
166-
"## Datasets\n",
166+
"### Datasets\n",
167167
"A Dataset holds multiple DataArrays, analogous to a DataFrame in pandas housing multiple Series. Like in Pandas, the different DataArrays can share coordinates, and they can be assigned variable names (analogous to column names). The graphic at the beginning of this lesson shows a Dataset with precipitation, temperature, latitude and longitude DataArrays.\n",
168168
"\n",
169169
"A Dataset can be created from a DataArray with the `.to_dataset()` method:"
@@ -234,9 +234,9 @@
234234
"cell_type": "markdown",
235235
"metadata": {},
236236
"source": [
237-
"\n",
238-
"\n",
239-
"### inputs\n",
237+
"## The Mt. Rainer example\n",
238+
" \n",
239+
"### Inputs\n",
240240
"* [Daymet](https://daymet.ornl.gov/overview) gridded precipitation estimates for area around Mt. Rainier, 1980-2018. Obtained via the [Daymet Tile Selection Tool](https://daymet.ornl.gov/gridded/)\n",
241241
"* a [proj string](https://proj.org/usage/quickstart.html) for Daymet could be created from the [dataset description](https://daymet.ornl.gov/overview); however, it was easier to just copy it from [here](http://rpubs.com/tbiggs/GEOG576_EX3_DAYMET)\n",
242242
"* a 30 m DEM of elevations around Mt. Rainier, in geographic coordinates, created in the `gis_raster_mt_rainier_glaciers.ipynb` exercise"
@@ -329,7 +329,7 @@
329329
"source": [
330330
"### Let's add some topography for reference\n",
331331
"\n",
332-
"Load the elevation data with `rasterio`, get the bounding extent, and `rasterio.show` to quickly plot the data with its coordinates (instead of row, column locations)"
332+
"Load the elevation data into a Numpy array with `rasterio`, get the bounding extent, and `rasterio.show` to quickly plot the data with its coordinates (instead of row, column locations)"
333333
]
334334
},
335335
{
@@ -355,7 +355,7 @@
355355
"* use the `matplotlib` `LightSource.hillshade` method to convert the elevations to a shaded relief raster\n",
356356
" * assign `zorder=-1` to ensure that the data plot on the bottom\n",
357357
"* plot mean precip, but specify `alpha < 1` so that it has some transparency; the colorbar can be controlled with `cbar_kwargs` (arguments that are passed to the `matplotlib` colorbar constructor)\n",
358-
"* set the plot limits to the extent of the elevation raster (`*` unpacks list elevations into individual arguments)"
358+
"* set the plot limits to the extent of the elevation raster (`*` unpacks list elevations into individual arguments). This puts the elevation data in the correct geographic locations."
359359
]
360360
},
361361
{
@@ -385,7 +385,7 @@
385385
"### Getting data at point locations\n",
386386
"\n",
387387
"Say we want to get data for the mountain summit, and at the Paradise Visitor Center in Mt. Rainier National Park.\n",
388-
"We can easily get the lat, lon coordinates for these locations, but to get data from this dataset, we need to work in the [custom coordinate system for Daymet](https://daymet.ornl.gov/overview). Luckily, we found a PROJ string to define that, which we assigned to the variable `daymet_proj_string`. With the PROJ string, we can use `pyproj` to transform the coordinates to the Daymet CRS."
388+
"We can easily get the lat, lon coordinates for these locations, but to get data from this dataset, we need to work in the [custom coordinate system for Daymet](https://daymet.ornl.gov/overview). Luckily, we found a PROJ string to define that, which we assigned to the variable `daymet_proj_string`. With the PROJ string, we can use `pyproj` to transform (reproject) the lat/lon coordinates to the Daymet CRS."
389389
]
390390
},
391391
{
@@ -426,7 +426,7 @@
426426
"ax.set_xlim(*elev_extent[:2])\n",
427427
"for label, (y, x) in coords.items():\n",
428428
" ax.scatter(x, y, c='k')\n",
429-
" ax.text(x, y, label, transform=ax.transData)"
429+
" ax.text(x+.003, y+.003, label, transform=ax.transData, c='k')"
430430
]
431431
},
432432
{
@@ -566,7 +566,7 @@
566566
"metadata": {},
567567
"outputs": [],
568568
"source": [
569-
"prcp_subset = ds.prcp.loc[:].where(valid_lat&valid_lon)\n",
569+
"prcp_subset = ds.prcp.loc[:].where(valid_lat & valid_lon)\n",
570570
"prcp_subset = prcp_subset.dropna(dim='x', how='all').dropna(dim='y', how='all')\n",
571571
"prcp_subset.mean(axis=0).plot()"
572572
]
@@ -593,10 +593,10 @@
593593
"output_folder.mkdir(exist_ok=True)\n",
594594
"\n",
595595
"encoding={'prcp': {'zlib': True, # compression algorithm\n",
596-
" 'complevel': 4, # compression level\n",
597-
" 'dtype': 'float32',\n",
598-
" '_FillValue': -9999,\n",
599-
" }}\n",
596+
" 'complevel': 4, # compression level\n",
597+
" 'dtype': 'float32',\n",
598+
" '_FillValue': -9999,\n",
599+
" }}\n",
600600
"\n",
601601
"prcp_subset.to_netcdf(output_folder / 'rainier_prcp_subset.nc',\n",
602602
" encoding=encoding)"
@@ -840,7 +840,7 @@
840840
"for i, site in enumerate(sites):\n",
841841
" df = ds.prcp.sel(x=x[0], \n",
842842
" y=y[0],\n",
843-
" method='nearest').drop(['lat', 'lon', 'x', 'y']).to_dataframe()\n",
843+
" method='nearest').drop_vars(['lat', 'lon', 'x', 'y']).to_dataframe()\n",
844844
" df.columns = [site]\n",
845845
" dfs.append(df)\n",
846846
"\n",
@@ -937,9 +937,7 @@
937937
"metadata": {},
938938
"source": [
939939
"### Reprojecting the dataset\n",
940-
"Here we reproject the dataset into geographic coordinates (Lat/Lon). We can use the spatial reference ID 4269 (an [EPSG code](https://www.linkedin.com/pulse/whats-epsg-how-do-i-use-salina-morrow#:~:text=The%20EPSG%20number%20is%20a,that%20can%20display%20those%20files.)) to specify the destination coordinate reference system (geographic coordinates with the NAD83 datum).\n",
941-
"\n",
942-
"Note that this dataset already includes `lat`/`lon` coordinates. Because the x and y axes are in a projected coordinate reference system (Lambert Conformal Conic), the `lat`/`lon` coordinates are two dimensional (each point in the dataset has its own `lat`/`lon` coordinate). **`rioxarray`** doesn't like this for some reason-- as of version 0.15, it produces a `ValueError: IndexVariable objects must be 1-dimensional` when we try to reproject. To get around this, we can drop the `lat`/`lon` coordinates before calling `.rio.project()`."
940+
"Here we reproject the dataset into geographic coordinates (Lat/Lon). We can use the spatial reference ID 4269 (an [EPSG code](https://www.linkedin.com/pulse/whats-epsg-how-do-i-use-salina-morrow#:~:text=The%20EPSG%20number%20is%20a,that%20can%20display%20those%20files.)) to specify the destination coordinate reference system (geographic coordinates with the NAD83 datum)."
943941
]
944942
},
945943
{
@@ -948,7 +946,14 @@
948946
"metadata": {},
949947
"outputs": [],
950948
"source": [
951-
"ds_4269 = ds['prcp'].drop_vars(['lat', 'lon']).rio.reproject(4269)"
949+
"ds_4269 = ds['prcp'].rio.reproject(4269)"
950+
]
951+
},
952+
{
953+
"cell_type": "markdown",
954+
"metadata": {},
955+
"source": [
956+
"Note that this dataset already includes `lat`/`lon` coordinates. Because the x and y axes are in a projected coordinate reference system (Lambert Conformal Conic), the `lat`/`lon` coordinates are two dimensional (each point in the dataset has its own `lat`/`lon` coordinate). Earlier versions of **`rioxarray`** didn't like this for some reason-- as of version 0.15, it produced a `ValueError: IndexVariable objects must be 1-dimensional` when calling `rio.reproject()`. Droping the `lat`/`lon` coordinates before calling `.rio.project()` was a way to get around this. For example: ```ds_4269 = ds['prcp'].drop_vars(['lat', 'lon']).rio.reproject(4269)```"
952957
]
953958
},
954959
{
@@ -968,7 +973,7 @@
968973
"\n",
969974
"Write part of the dataset out to a GeoTIFF. \n",
970975
"\n",
971-
"Earlier versions of rioxarray require us to remove the `'grid_mapping'` attribute first (at least in version 0.15, you will get an error otherwise). `grid_mapping` is a variable from the original NetCDF dataset that specifies that coordinate reference information is contained in a variable called `'lambert_conformal_conic'` (we used it above to specify the coordinate reference information for **rioxarray**).\n",
976+
"Earlier versions of rioxarray required us to remove the `'grid_mapping'` attribute first (e.g. `del precip_slice.attrs['grid_mapping']`; at least in version 0.15, you would get an error otherwise). `grid_mapping` is a variable from the original NetCDF dataset that specifies that coordinate reference information is contained in a variable called `'lambert_conformal_conic'` (we used it above to specify the coordinate reference information for **rioxarray**).\n",
972977
"\n",
973978
"#### Write a single 2D timeslice to a raster"
974979
]
@@ -979,10 +984,7 @@
979984
"metadata": {},
980985
"outputs": [],
981986
"source": [
982-
"precip_slice = ds.sel(time='2018-12-30')['prcp']\n",
983-
"\n",
984-
"# remove grid_mapping if needed\n",
985-
"#del precip_slice.attrs['grid_mapping']"
987+
"precip_slice = ds.sel(time='2018-12-30')['prcp']"
986988
]
987989
},
988990
{
@@ -1046,7 +1048,7 @@
10461048
"metadata": {},
10471049
"outputs": [],
10481050
"source": [
1049-
"data = ds_4269.sel(time='2018')#.mean(axis=0)"
1051+
"data = ds_4269.sel(time='2018')"
10501052
]
10511053
},
10521054
{
@@ -1083,13 +1085,32 @@
10831085
"gdf.plot(ax=ax)\n",
10841086
"clipped.mean(axis=0).plot(ax=ax)"
10851087
]
1088+
},
1089+
{
1090+
"cell_type": "code",
1091+
"execution_count": null,
1092+
"metadata": {},
1093+
"outputs": [],
1094+
"source": []
10861095
}
10871096
],
10881097
"metadata": {
10891098
"kernelspec": {
1090-
"display_name": "Python 3 (ipykernel)",
1099+
"display_name": "pyclass",
10911100
"language": "python",
10921101
"name": "python3"
1102+
},
1103+
"language_info": {
1104+
"codemirror_mode": {
1105+
"name": "ipython",
1106+
"version": 3
1107+
},
1108+
"file_extension": ".py",
1109+
"mimetype": "text/x-python",
1110+
"name": "python",
1111+
"nbconvert_exporter": "python",
1112+
"pygments_lexer": "ipython3",
1113+
"version": "3.12.11"
10931114
}
10941115
},
10951116
"nbformat": 4,

0 commit comments

Comments
 (0)