From faeebb3d7a76bd517beaf83e09762f9896188874 Mon Sep 17 00:00:00 2001 From: Megan Mason Date: Thu, 15 Aug 2024 20:27:38 +0000 Subject: [PATCH] fixed toc.yaml notebook 3 filename --- .../snowex-core/03_snowex_data_preview.ipynb | 822 ++++++++++++++++++ 1 file changed, 822 insertions(+) create mode 100644 book/tutorials/snowex-core/03_snowex_data_preview.ipynb diff --git a/book/tutorials/snowex-core/03_snowex_data_preview.ipynb b/book/tutorials/snowex-core/03_snowex_data_preview.ipynb new file mode 100644 index 0000000..bb6b802 --- /dev/null +++ b/book/tutorials/snowex-core/03_snowex_data_preview.ipynb @@ -0,0 +1,822 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "622d4e72-7cc0-4a52-91b4-9b643fef8e31", + "metadata": {}, + "source": [ + "# Data Exploration \n", + "(15 minutes)\n", + "\n", + "![](./content/03_snow-sculpture.jpg)\n", + "\n", + "Prerequisites: an EarthData Login " + ] + }, + { + "cell_type": "markdown", + "id": "7b34ac2f-82dc-4423-9c30-86f1cd737244", + "metadata": {}, + "source": [ + "```{admonition} Learning Objectives\n", + "- Experience a variety of SnowEx data across different spatial and temporal domains\n", + "- Preview code snippets to help you extract and prep data \n", + "- Get a first taste of the database! \n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "e7d2ed75-2386-4178-a03d-da4bc2509ec7", + "metadata": {}, + "source": [ + "## Spatial Focused Data\n", + "Let's take a look at data collected during the Intense Observation Periods (IOP) campaigns via EarthAcess data downloads. " + ] + }, + { + "cell_type": "markdown", + "id": "22cf11b1-e5c9-453b-8d23-d97df8f0bb03", + "metadata": {}, + "source": [ + "### I: 2017/2020 - Grand Mesa & Senator Beck, Colorado\n", + "Objective - Visualize SWE from Grand Mesa field campaigns.\\\n", + "Data description - SnowEx 2017 & 2020 IOP derived SWE from snow pits.\\\n", + "Datasets -\n", + "1. [SnowEx17 Community Snow Pit Measurements, Version 1](https://nsidc.org/data/snex17_snowpits/versions/1) (Grand Mesa + Senator Beck, CO)\n", + "2. [SnowEx20 Grand Mesa Intensive Observation Period Snow Pit Measurements, Version 1](https://nsidc.org/data/snex20_gm_sp/versions/1) (Grand Mesa, CO)" + ] + }, + { + "cell_type": "markdown", + "id": "2974712c-3555-4f56-bbd6-d71037a737d7", + "metadata": {}, + "source": [ + "We will begin by importing python packages we will need to explore data. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36ef0083-ff1f-4e49-a978-920e6e55912e", + "metadata": {}, + "outputs": [], + "source": [ + "# standard imports\n", + "import pandas as pd\n", + "import pyproj\n", + "\n", + "# plotting imports\n", + "import matplotlib.pyplot as plt\n", + "# from matplotlib import gridspec # do I use?\n", + "import matplotlib.dates as mdates\n", + "# import matplotlib.patches as patches # do I use?\n", + "import seaborn as sns\n", + "\n", + "# mapping imports\n", + "import folium\n", + "from pyproj import Transformer\n", + "import branca.colormap as cm\n", + "from folium import IFrame\n", + "from folium.plugins import MeasureControl\n", + "\n", + "# Earthaccess imports\n", + "import earthaccess" + ] + }, + { + "cell_type": "markdown", + "id": "bb8ff033-1080-4798-bc96-de83b60da6bc", + "metadata": {}, + "source": [ + "Now we continue by accessing data with our EarthData accounts" + ] + }, + { + "cell_type": "markdown", + "id": "824b209b-7f8a-4c43-9e6a-7d33d0766720", + "metadata": {}, + "source": [ + "### Download data from NASA's NSIDC DAAC " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd5a71dd-80d8-42d7-93a9-f662aa1eff16", + "metadata": {}, + "outputs": [], + "source": [ + "# connect to Earthaccess\n", + "auth = earthaccess.login()" + ] + }, + { + "cell_type": "markdown", + "id": "f4000c97-fc42-4171-8d95-5fb7bf94e4f0", + "metadata": {}, + "source": [ + "From [EarthData](https://search.earthdata.nasa.gov/search?fpj=SnowEx&fst0=cryosphere) we can glean information about the files we are interested in. For example, we learn that the SnowEx 2017 snow pit data are a multi-file granule, which will require one extra step to download. \n", + "![](./content/03_granules.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21d6145a-aada-4104-a787-44c33c7350a8", + "metadata": {}, + "outputs": [], + "source": [ + "# pull SnowEx 2017 snow pit data - Summary_SWE file\n", + "results_gm17 =earthaccess.search_data(\n", + " short_name='SNEX17_SNOWPITS',\n", + " granule_name = 'SnowEx17_SnowPits_GM')\n", + "\n", + "# some extra code to filter a multi-file granule (2017 IOP granules: 1). SnowEx17_SnowPits_GM, 2). SnowEx17_SnowPits_SBB\n", + "filtered_urls = []\n", + "\n", + "for granule in results_gm17:\n", + " links = granule.data_links()\n", + " for link in links:\n", + " if link == 'https://n5eil01u.ecs.nsidc.org/DP1/SNOWEX/SNEX17_SnowPits.001/2017.02.06/SnowEx17_SnowPits_GM_201702_v01.csv':\n", + " filtered_urls.append(link) # Knowing the name of the file I wanted helped here\n", + "\n", + "earthaccess.download(filtered_urls, \n", + " local_path='./Downloads')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "249a6f94-7f21-45cc-898b-28d40e0ba255", + "metadata": {}, + "outputs": [], + "source": [ + "# pull SnowEx 2020 snow pit data - Summary_SWE file\n", + "results_gm20 =earthaccess.search_data(\n", + " short_name='SNEX20_GM_SP',\n", + " granule_name = 'SnowEx20_SnowPits_GMIOP_Summary_SWE_2020_v01.csv')\n", + "\n", + "downloaded_file_gm20 = earthaccess.download(\n", + " results_gm20,\n", + " local_path='./Downloads',\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "96ab2d80-f1c8-4f51-90bf-c623eb98b0d6", + "metadata": {}, + "source": [ + "```{note}\n", + "The downside to this method is you have to know the specific filename you are interested in. That can require more time to familiarize yourself with the dataset. A great resource is to read the User Guide provided for most SnowEx data sets and accessed from the NSIDC data landing page. The User Guides provide information about filenames.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "6799a5ba-2e1a-4d60-8288-ff3fffa8c4e0", + "metadata": {}, + "source": [ + "Look over to the left in your files and see that we added a ***./Downloads*** folder to store the EarthData download.\n", + "\n", + "Next, let's use Python's pandas package to open the CSV file that contains Summary SWE data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d0282a3-29c0-489b-8fee-1d2a7d396338", + "metadata": {}, + "outputs": [], + "source": [ + "# open summary SWE files from our ./Downloads folder\n", + "s17 = pd.read_csv('./Downloads/SnowEx17_SnowPits_GM_201702_v01.csv')\n", + "s20 = pd.read_csv('./Downloads/SnowEx20_SnowPits_GMIOP_Summary_SWE_2020_v01.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae4e2225-78a3-4e32-9957-5282df384b3e", + "metadata": {}, + "outputs": [], + "source": [ + "print(s17.info())\n", + "s17.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1e9361d-abd6-4841-9ac0-5906f6302267", + "metadata": {}, + "outputs": [], + "source": [ + "# some dataframe clean up\n", + "s17 = s17[s17['#Location'] == 'GM-CO'] # keep the GM points only for now\n", + "s20 = s20[s20['Easting (m)'] < 750000] # removes point at GM lodge (n=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de618f73-1aa7-4343-a02b-5e4096d8d5ab", + "metadata": {}, + "outputs": [], + "source": [ + "# Convert UTM to Lat/Lon\n", + "transformer = pyproj.Transformer.from_crs(\"EPSG:32613\", \"EPSG:4326\") # UTM Zone 13N \n", + "s17['latitude'], s17['longitude'] = zip(*s17.apply(lambda row: transformer.transform(row['UTM13 Easting [m]'], row['UTM13 Northing [m]']), axis=1))\n", + "\n", + "transformer = pyproj.Transformer.from_crs(\"EPSG:32612\", \"EPSG:4326\") # UTM Zone 12N\n", + "s20['latitude'], s20['longitude'] = zip(*s20.apply(lambda row: transformer.transform(row['Easting (m)'], row['Northing (m)']), axis=1))" + ] + }, + { + "cell_type": "markdown", + "id": "43b66540-34cd-4705-9ae1-e3b2a4ba1aad", + "metadata": {}, + "source": [ + "Now that we have added Latitude and Longitude columns, let's look at the spatial extent of the data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ede844a-8d77-4a53-a5e6-dcad880325bd", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(8,4))\n", + "s17.plot.scatter('latitude', 'longitude', color='blueviolet', ax=ax, label='GrandMesa 2017')\n", + "s20.plot.scatter('latitude', 'longitude', color='orange', ax=ax, label='GrandMesa 2020')\n", + "plt.legend(loc='lower right')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "7b3e254e-f954-445f-998c-844d4233feb4", + "metadata": {}, + "source": [ + "We see that during the 2017 IOP the sampling area covered a greater extent. " + ] + }, + { + "cell_type": "markdown", + "id": "1bd5eb38-9758-4627-aee9-79c191251354", + "metadata": {}, + "source": [ + "### Let's add some context to these data points\n", + "By using an interactive map [(Folium)](https://autogis-site.readthedocs.io/en/2021/notebooks/L5/02_interactive-map-folium.html) we can move around the Mesa. Here we plot Latitude and Longitude on the y- and x-axes, respectively and add plot SWE as the 3rd dimension with the additional of a colorbar. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ca5ca23-5cb0-4bb6-b5f2-16adcfdee448", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a map using lat/lon mean\n", + "m = folium.Map(width=500, height=400,location=[s17['latitude'].mean(), s17['longitude'].mean()], zoom_start=10)\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "6e9e4f8a-4819-4760-b609-a67372a7f240", + "metadata": {}, + "source": [ + "I used the dataframe's lat/lon mean to center my map. I choose the 2017 dataframe because of the greater spatial extent we discovered above. " + ] + }, + { + "cell_type": "markdown", + "id": "df9b381e-ffef-4439-8b6a-3104e5c71b7a", + "metadata": {}, + "source": [ + "Let's now modify the map imagery " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f884b167-3858-4b0b-8880-628602c60f31", + "metadata": {}, + "outputs": [], + "source": [ + "# Add aerial imagery (ESRI World Imagery)\n", + "folium.TileLayer(\n", + " tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n", + " attr='Esri',\n", + " name='Esri Satellite',\n", + " overlay=False,\n", + " control=True,\n", + " opacity=0.9\n", + ").add_to(m)\n", + "\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "4aad9b7b-582a-4755-b4cd-aa41fe0f0433", + "metadata": {}, + "source": [ + "Oh goody, I can see the Mesa! Did you know this is the largest flat-topped mountain in the world? See for yourself [right here](https://en.wikipedia.org/wiki/Grand_Mesa)." + ] + }, + { + "cell_type": "markdown", + "id": "7fd319d0-13fc-4f9f-a2b8-9a1e3a0be67d", + "metadata": {}, + "source": [ + "Moving on, let's add the SWE values to the map!" + ] + }, + { + "cell_type": "markdown", + "id": "46d6a22a-5fc3-4e7a-bb43-5c269e674b17", + "metadata": {}, + "source": [ + "### Map + Imagery + Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f44baca-ea50-41ec-8b13-1a4b5f3155a8", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a Folium map \n", + "m = folium.Map(width=1000, height=600, location=[s17['latitude'].mean(), s17['longitude'].mean()], zoom_start=10)\n", + "\n", + "# Add aerial imagery (ESRI World Imagery)\n", + "folium.TileLayer(\n", + " tiles='https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n", + " attr='Esri',\n", + " name='Esri Satellite',\n", + " overlay=False,\n", + " control=True,\n", + " opacity=0.9\n", + ").add_to(m)\n", + "\n", + "# Create a colormap \n", + "colormap1 = cm.linear.Purples_09.to_step(12).scale(50,800)\n", + "colormap2 = cm.linear.YlOrBr_04.to_step(12).scale(50,800)\n", + "\n", + "# Plot the scatter plot for s17\n", + "for index, row in s17.iterrows():\n", + " folium.CircleMarker(location=[row['latitude'], row['longitude']], radius=3, fill=True, fill_opacity=1, color=colormap1(row['SWE [mm]'])).add_to(m)\n", + "\n", + "# Plot the scatter plot for s20\n", + "for index, row in s20.iterrows():\n", + " folium.CircleMarker(location=[row['latitude'], row['longitude']], radius=3, fill=True, fill_opacity=1, color=colormap2(row['SWE Mean (mm)'])).add_to(m)\n", + "\n", + "# Add colorbar legend to the map\n", + "colormap1.add_to(m)\n", + "colormap1.caption = '2017 SWE (mm)'\n", + "colormap1.stroke_color = '#ffffff' # White color for the text buffer\n", + "\n", + "colormap2.add_to(m)\n", + "colormap2.caption = '2020 SWE (mm)'\n", + "colormap2.stroke_color = '#ffffff' # White color for the text buffer\n", + "\n", + "# Define custom CSS for the colorbar legend\n", + "custom_css = \"\"\"\n", + "\n", + "\"\"\"\n", + "\n", + "m.add_child(MeasureControl(position='bottomleft', primary_length_unit='meters', secondary_length_unit='miles', primary_area_unit='sqmeters', secondary_area_unit='acres'))\n", + "\n", + "# Add the custom CSS to the map\n", + "m.get_root().html.add_child(folium.Element(custom_css))\n", + "\n", + "# Save the map as an HTML file or display it in Jupyter notebook\n", + "# m.save(path_out.joinpath('GMIOP_20_swe_map.html'))\n", + "\n", + "# Display the map\n", + "m" + ] + }, + { + "cell_type": "markdown", + "id": "8d145add-35d1-4e55-85ca-0940548f4b30", + "metadata": {}, + "source": [ + "```{note}\n", + "The Grand Mesa plateau splits the 12 & 13 UTM zone. That means the western portion of the Mesa is Zone 12 while the eastern portion is Zone 13. Due to the sampling design, the SnowEx 2017 data were collected as Zone 13 (majority of points were east of the divide) and SnowEx 2020 data were collected as Zone 12 (majority of points focused on the western portion of the plateau).\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "7b529c15-097d-4128-97da-acd2a0388145", + "metadata": {}, + "source": [ + "#### What variability is there during the different sampling years? " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3d95229-bb79-494a-b1b3-b46ef7663e8b", + "metadata": {}, + "outputs": [], + "source": [ + "# open again to reset (recall, we filtered out Senator Beck data before, let's keep that this time!)\n", + "s17 = pd.read_csv('./Downloads/SnowEx17_SnowPits_GM_201702_v01.csv')\n", + "s20 = pd.read_csv('./Downloads/SnowEx20_SnowPits_GMIOP_Summary_SWE_2020_v01.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3174d9e6-3109-43b9-b19c-1384dc2c73c1", + "metadata": {}, + "outputs": [], + "source": [ + "# subdataframes for GM and SB for 2017\n", + "s17_gm = s17[s17['#Location'] == 'GM-CO'] \n", + "s17_sb = s17[s17['#Location'] == 'SBB-CO'] " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f36125b4-f952-4731-88e3-bf1f17b3b2d9", + "metadata": {}, + "outputs": [], + "source": [ + "fig, axs = plt.subplots(1, 2, figsize=(12, 5))\n", + "\n", + "# ~~~~ Plot 1: Scatter plot of density and SWE for S17 and S20\n", + "\n", + "# Count the number of observations\n", + "n_s17_sb = s17_sb['SWE [mm]'].count()\n", + "n_s17_gm = s17_gm['SWE [mm]'].count()\n", + "n_s20 = s20['SWE Mean (mm)'].count()\n", + "\n", + "# Plot data for 2017 SBB\n", + "sns.scatterplot(data=s17_sb, x='Density Mean [kg/m^3]', y='Snow Depth [cm]', s=60, label=f'2017 SBB-CO (n={n_s17_sb})', marker='^', ax=axs[0])\n", + "\n", + "# Plot data for 2017 GM\n", + "sns.scatterplot(data=s17_gm, x='Density Mean [kg/m^3]', y='Snow Depth [cm]', s=60, label=f'2017 GM-CO (n={n_s17_gm})', marker='^', ax=axs[0])\n", + "\n", + "# Plot data for 2020 GM\n", + "sns.scatterplot(data=s20, x='Density Mean (kg/m^3)', y='Snow Depth (cm)', s=40, label=f'2020 GM-CO (n={n_s20})', ax=axs[0])\n", + "\n", + "# Adding labels and legends\n", + "axs[0].set_xlabel('Snow Density (kg/m$^3$)')\n", + "axs[0].set_ylabel('Snow Depth (cm)')\n", + "axs[0].legend()\n", + "axs[0].set_title('S17 and S20 Snow Pit Bulk Density and Depth')\n", + "axs[0].grid(True)\n", + "\n", + "\n", + "# ~~~~ Plot 2: PDF for S17 (Grand Mesa + Senator Beck) and S20 (Grand Mesa 2020)\n", + "\n", + "# Plot the PDF for 2017 SBB\n", + "sns.kdeplot(s17_sb['SWE [mm]'], label='2017 SBB-CO', linewidth=5, ax=axs[1])\n", + "\n", + "# Plot the PDF for 2017 GM\n", + "sns.kdeplot(s17_gm['SWE [mm]'], label='2017 GM-CO', linewidth=5, ax=axs[1])\n", + "\n", + "# Plot the PDF for 2020 GM\n", + "sns.kdeplot(s20['SWE Mean (mm)'], label='2020 GM-CO', linewidth=5, ax=axs[1])\n", + "\n", + "# Add title and labels\n", + "axs[1].set_title('S17 and S20 Snow Pit SWE')\n", + "axs[1].set_xlabel('SWE (mm)')\n", + "axs[1].set_ylabel('PDF')\n", + "axs[1].legend()\n", + "\n", + "# Save figure if needed\n", + "# plt.savefig(path_fig.joinpath('S17_n_S20_GMIOP_pdf.jpg'), bbox_inches='tight', pad_inches=0.1)\n", + "\n", + "# Show the plot\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "94cf4d8b-043b-4680-9286-6f47614f407f", + "metadata": {}, + "source": [ + "There is so much more we could dig into. Just ask HP, he'll say you could spend a lifetime studying snow on Grand Mesa :)" + ] + }, + { + "cell_type": "markdown", + "id": "b8c94689-8366-4b22-aca2-3e94ca08775c", + "metadata": {}, + "source": [ + "Alas, let us continue our spatial exploration but move it up to Alaska." + ] + }, + { + "cell_type": "markdown", + "id": "a950c906-c8e8-4d68-86ef-d896a2d7466c", + "metadata": {}, + "source": [ + "### II: 2023 Arctic Tundra and Boreal Forest, Alaska\n", + "Objective - Compare snow depth, density and SWE data from the Adirondack snow sampler (n=84) and snow pits (n=170)\\\n", + "Data description - SnowEx 2023 March 2023 IOP Snow Water Equivalent and Snow Pit Measurements\\\n", + "Datasets -\n", + "1. [SnowEx23 Snow Water Equivalent, Version 1](https://nsidc.org/data/snex23_swe/versions/1) (2-days of Adirondack snow sampler measurements North Slope (tundra) and Fairbanks (boreal forest))\n", + "2. SnowEx23 Snow Pit Measurements, Version 1 (in prep., available on the `snowexsql` database)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "494e1616-3015-4dc9-88b4-75eefcde36f2", + "metadata": {}, + "outputs": [], + "source": [ + "# Adirondack SWE download\n", + "results_swe = earthaccess.search_data(\n", + " short_name='SNEX23_SWE')\n", + "\n", + "downloaded_files_swe = earthaccess.download(\n", + " results_swe,\n", + " local_path='./Downloads',\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11ca7ed6-b6bc-49c4-9e8b-69b08bcf5429", + "metadata": {}, + "outputs": [], + "source": [ + "# datasets from Alaska contain more header rows. skipping 42 rows for now and dropping the numbered row under the columns names\n", + "s23 = pd.read_csv('./Downloads/SNEX23_SWE_Mar23IOP_AK_20230313_20230316_v01.0.csv', header=42, na_values=-9999)\n", + "s23 = s23.iloc[1:] # selects the row below the header number cols(1, 2, 3, ... etc.)\n", + "s23 = s23.reset_index(drop=True)\n", + "s23.head()" + ] + }, + { + "cell_type": "markdown", + "id": "721743ab-8ff5-4e2c-bf2c-2241fed86d21", + "metadata": {}, + "source": [ + "At each coordinate pair, the Adirondack snow sampler (i.e a large SWE tube, cross-sectional area A = 35.7 cm2) is used to collect 3 samples each of depth (cm) and mass (g). Bulk snow density and SWE are then computed afterwards using the equations from [Stuefer et al., 2020](https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2019WR025621). Here is the device being used on the North Slope in Alaska. \n", + "\n", + "![](./content/03_adirondack-sampler.jpg)\n" + ] + }, + { + "cell_type": "markdown", + "id": "e7d6142e-3429-4180-9c2a-61bdf2b98252", + "metadata": {}, + "source": [ + "Okay, back to some analysis. We need to get the mean of all three samples (containted in three different columns)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75ea9c55-66f8-41eb-acae-04059f706b49", + "metadata": {}, + "outputs": [], + "source": [ + "# CREATE DEPTH, DENSITY, and SWE Boxplots with the SWE Adirondack snow sampler\n", + "\n", + "# Combine the SWE, Depth, and Density columns for plotting\n", + "df_melted = pd.melt(s23, id_vars=['State', 'County'], value_vars=['SWE1', 'SWE2', 'SWE3', 'Depth1', 'Depth2', 'Depth3', 'Density1', 'Density2', 'Density3'],\n", + " var_name='Measurement', value_name='Value')\n", + "\n", + "# Create sub-dataframes for SWE, Depth, and Density\n", + "swe_df = df_melted[df_melted['Measurement'].str.contains('SWE')]\n", + "depth_df = df_melted[df_melted['Measurement'].str.contains('Depth')]\n", + "density_df = df_melted[df_melted['Measurement'].str.contains('Density')]\n", + "\n", + "# Initialize the figure and axes\n", + "fig, axs = plt.subplots(1, 3, figsize=(14, 6))\n", + "\n", + "# Define the custom order and labels\n", + "custom_order = ['Fairbanks', 'North Slope']\n", + "\n", + "# Plot the SWE boxplot\n", + "sns.boxplot(data=swe_df, x='County', y='Value', ax=axs[0], color='gray', order=custom_order)\n", + "axs[0].set_title('SWE')\n", + "axs[0].set_ylabel('SWE (mm)')\n", + "\n", + "# Plot the Depth boxplot\n", + "sns.boxplot(data=depth_df, x='County', y='Value', ax=axs[1], color='gray', order=custom_order)\n", + "axs[1].set_title('Depth')\n", + "axs[1].set_ylabel('Depth (cm)')\n", + "\n", + "# Plot the Density boxplot\n", + "sns.boxplot(data=density_df, x='County', y='Value', ax=axs[2], color='gray', order=custom_order)\n", + "axs[2].set_title('Density')\n", + "axs[2].set_ylabel('Density (kg/m$^3$)')\n", + "\n", + "# Adjust the layout\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "97c7d3d2-ed6a-415c-b352-0ab1e7d7d9ba", + "metadata": {}, + "source": [ + "We can compare our Adirondack snow sampler results to the snow pit measurement. The boxplots below were generated during the review and data submission preparation work for the March 2023 snow pits. Notice, the snow pit trends match those of the snow sampler tube. The median SWE is higher in the boreal forest (Fairbanks sites) as a result of the deeper snow. Overall, the tundra (North Slope sites) has greater density.\n", + "\n", + "![](./content/03_ak-pits-boxplots.png)\n" + ] + }, + { + "cell_type": "markdown", + "id": "1dd0e2f5-1289-4972-b433-99d43e86522d", + "metadata": {}, + "source": [ + "What are other ways to look at the data? Recall that the Boreal Forest has a land cover classification enbedded in the plot name. Why not look at SWE, depth, and density by land cover type? Recall, the Land Classification information is embedded in the pitID name (e.g. WB241 the 'W' stands for wetland, or EA221 the 'E' stands for Evergreen). \n", + "\n", + "![](./content/03_ak-pits-landcov-boxplots.png)\n", + "\n", + "Does this mean that all Evergreen sites have more snow!?\n", + "\n", + "Careful now, there is a lot to consider when interpreting results. This plot alone looks like we have deeper, denser snow in the Evergreen forests, but keep in mind you may not know the other environmental and terrain factors that might cause you to jump to this conclusion. Keep in mind relative location and elevation when looking at data. The Alaska study sites are all relativily flat compared to traditional complex terrain areas, but the majority of our Evergreen sites were sampled in the Caribou-Poker Creek Research Watershed, which is higher in elevation that the sites closer to Fairbanks. " + ] + }, + { + "cell_type": "markdown", + "id": "c7ef28f8-5632-4c02-8c96-2770e5ba6eb0", + "metadata": {}, + "source": [ + "Alaska was the last stop for SnowEx field campaigns, that means the data collection was easy-breezy. \n", + "\n", + "WRONG. \n", + "\n", + "Here are some challenges we encountered daily:\n", + "1. Ground vegetation - where is 0?? Often, the bottom of the snowpack varied more than the snow surface! \n", + "2. Tussocks, what are they and why are there so many? (NOTE - tussocks were better quantified during the October sampling periods when snow was low.\n", + "3. Snow Voids - snowpack bottoms were not always flush to the ground surface and could be overestimated. Grassy vegetation mats, downed brush and shrubs, or other vegetation creates air pockets or vegetation gaps near the ground surface. Sometimes, the snow was suspended by 10-25 cm depending on the site. " + ] + }, + { + "cell_type": "markdown", + "id": "835c7b48-a5d2-469d-bda5-9d94ff5ee128", + "metadata": {}, + "source": [ + "These data are really exiting to look at because it's the newest in the SnowEx collection following the Alaska campaign. \n", + "\n", + "Let's make sure we cover some of the Time Series data as that has matured since the last SnowEx Hackweek event. " + ] + }, + { + "cell_type": "markdown", + "id": "32a2a1d5-1b04-40d2-b58a-fa78bc6eca73", + "metadata": {}, + "source": [ + "_____\n", + "\n", + "![](https://ugokawaii.com/wp-content/uploads/2023/02/gears.gif)\n", + "## Temporal Focused Data\n", + "Let's take a look at data collected during the weekly Time Series (TS) campaigns using the `snowexsql` database for data access." + ] + }, + { + "cell_type": "markdown", + "id": "fa05e6a4-51b0-4a1a-aed0-02c1fa880b6c", + "metadata": {}, + "source": [ + "### III: 2020/2021 Western U.S Time Series \n", + "Objective - Explore data within the `snowexsql` database\\\n", + "Data description - [specify here] \\\n", + "Datasets -\n", + "1. [SnowEx20 Time Series Snow Pit Measurements, Version 2 ](https://nsidc.org/data/snex20_ts_sp/versions/2)\n", + "2. [SnowEx21 Time Series Snow Pit Measurements, Version 1](https://nsidc.org/data/snex21_ts_sp/versions/1)" + ] + }, + { + "cell_type": "markdown", + "id": "d539b2c9-454a-48b5-8ac2-cb2d090ec93b", + "metadata": {}, + "source": [ + "Let me start by sharing a teaser of what's we can do with weekly snow pit observations from multiple sites around the Western U.S. \n", + "\n", + "![](./content/03_pitprogression-BogusBasin.png)\n", + "\n", + "**Figure X** (cap here)" + ] + }, + { + "cell_type": "markdown", + "id": "f1483c77-fc80-4f38-8ad3-d458f85446bc", + "metadata": {}, + "source": [ + "To do this, we are going to use the snowexsql database. Here are the imports we need to gain access. \n", + "#### Set Up Computing Environment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0982d0cc-1950-44e6-9cb0-b033bc5eb6f4", + "metadata": {}, + "outputs": [], + "source": [ + "#database imports\n", + "from snowexsql.db import get_db\n", + "from snowexsql.data import PointData, LayerData, ImageData, SiteData\n", + "from snowexsql.conversions import query_to_geopandas" + ] + }, + { + "cell_type": "markdown", + "id": "c8347590-f21f-4482-9ad8-746cb8a91496", + "metadata": {}, + "source": [ + "### The Basics\n", + "#### How are the data contained?\n", + "![](./content/03_db-layers.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3f7e310-368d-499b-bcbb-65d8972da711", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89d66b97-fff0-4bb9-802d-43777dff7e79", + "metadata": {}, + "outputs": [], + "source": [ + "# decide how much to use from 2022 tutorial\n", + "\n", + "# mini leadup examples (1a, 1b, 1c, 1d - mini queries, very helpful to introduce!)\n", + "\n", + "# plot snow temp profiles\n", + "# find where we have liquid water content (LWC) data " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee8f7b32-5a0f-4c63-b268-534290b2d1bb", + "metadata": {}, + "outputs": [], + "source": [ + "# wrap it all up nicely!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46aab5fd-ba59-4cd2-8e5c-e6d6974471a3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}