{ "cells": [ { "cell_type": "markdown", "id": "8fdce2ee", "metadata": { "execution": {} }, "source": [ "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/neuromatch/climate-course-content/blob/main/tutorials/W1D1_ClimateSystemOverview/student/W1D1_Tutorial9.ipynb)   \"Open" ] }, { "cell_type": "markdown", "id": "GJtN30QLJnet", "metadata": { "execution": {} }, "source": [ "# Bonus Tutorial 9: Masking with Multiple Conditions\n", "\n", "**Week 1, Day 1, Climate System Overview**\n", "\n", "**Content creators:** Sloane Garelick, Julia Kent\n", "\n", "**Content reviewers:** Katrina Dobson, Younkap Nina Duplex, Danika Gupta, Maria Gonzalez, Will Gregory, Nahid Hasan, Paul Heubel, Sherry Mi, Beatriz Cosenza Muralles, Jenna Pearson, Agustina Pesce, Chi Zhang, Ohad Zivan\n", "\n", "**Content editors:** Paul Heubel, Jenna Pearson, Chi Zhang, Ohad Zivan\n", "\n", "**Production editors:** Wesley Banfield, Paul Heubel, Jenna Pearson, Konstantine Tsafatinos, Chi Zhang, Ohad Zivan\n", "\n", "**Our 2024 Sponsors:** CMIP, NFDI4Earth" ] }, { "cell_type": "markdown", "id": "8b65d43f-6bcb-443c-ba90-95749702309d", "metadata": { "execution": {} }, "source": [ "## ![project pythia](https://projectpythia.org/_static/images/logos/pythia_logo-blue-rtext.svg)\n", "\n", "Pythia credit: Rose, B. E. J., Kent, J., Tyle, K., Clyne, J., Banihirwe, A., Camron, D., May, R., Grover, M., Ford, R. R., Paul, K., Morley, J., Eroglu, O., Kailyn, L., & Zacharias, A. (2023). Pythia Foundations (Version v2023.05.01) https://zenodo.org/record/8065851\n", "\n", "## ![CMIP.png](https://github.com/ClimateMatchAcademy/course-content/blob/main/tutorials/Art/CMIP.png?raw=true)\n" ] }, { "cell_type": "markdown", "id": "0KwcJyrEmsww", "metadata": { "execution": {} }, "source": [ "# Tutorial Objectives\n", "\n", "*Estimated timing of tutorial:* 15 minutes\n", "\n", "In the previous Tutorial 8, you masked data using one condition (areas where SST was above 0ºC). You can also mask data using multiple conditions. For example, you can mask data from regions outside a certain spatial area by providing constraints on the latitude and longitude. \n", "\n", "In this tutorial, you will practice masking data using multiple conditions in order to interpret SST in the tropical Pacific Ocean in the context of the El Niño Southern Oscillation (ENSO)." ] }, { "cell_type": "markdown", "id": "0af7bee1-3de3-453a-8ae8-bcd7910b4266", "metadata": { "execution": {}, "tags": [] }, "source": [ "# Setup\n" ] }, { "cell_type": "code", "execution_count": null, "id": "a3d3f235-a5bf-4445-be5b-0aba0c3c1f7e", "metadata": { "execution": {} }, "outputs": [], "source": [ "# installations ( uncomment and run this cell ONLY when using google colab or kaggle )\n", "#!pip install pythia_datasets" ] }, { "cell_type": "code", "execution_count": null, "id": "06073287-7bdb-45b5-9cec-8cdf123adb49", "metadata": { "execution": {}, "executionInfo": { "elapsed": 521, "status": "ok", "timestamp": 1681573817272, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "# imports\n", "import xarray as xr\n", "from pythia_datasets import DATASETS\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install and import feedback gadget\n" ] }, { "cell_type": "code", "execution_count": null, "id": "07974de6-0957-45b3-9e77-895af3c459c8", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Install and import feedback gadget\n", "\n", "!pip3 install vibecheck datatops --quiet\n", "\n", "from vibecheck import DatatopsContentReviewContainer\n", "def content_review(notebook_section: str):\n", " return DatatopsContentReviewContainer(\n", " \"\", # No text prompt\n", " notebook_section,\n", " {\n", " \"url\": \"https://pmyvdlilci.execute-api.us-east-1.amazonaws.com/klab\",\n", " \"name\": \"comptools_4clim\",\n", " \"user_key\": \"l5jpxuee\",\n", " },\n", " ).render()\n", "\n", "\n", "feedback_prefix = \"W1D1_T9\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Figure Settings\n" ] }, { "cell_type": "code", "execution_count": null, "id": "b389f92a-2998-494d-a58c-f582a91c6b95", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Figure Settings\n", "import ipywidgets as widgets # interactive display\n", "\n", "%config InlineBackend.figure_format = 'retina'\n", "plt.style.use(\n", " \"https://raw.githubusercontent.com/neuromatch/climate-course-content/main/cma.mplstyle\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Video 1: Past, Present, and Future Climate\n" ] }, { "cell_type": "code", "execution_count": null, "id": "51f0a30a-35f7-4b29-a1d6-5d242f6aefa7", "metadata": { "cellView": "form", "execution": {}, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "# @title Video 1: Past, Present, and Future Climate\n", "\n", "from ipywidgets import widgets\n", "from IPython.display import YouTubeVideo\n", "from IPython.display import IFrame\n", "from IPython.display import display\n", "\n", "\n", "class PlayVideo(IFrame):\n", " def __init__(self, id, source, page=1, width=400, height=300, **kwargs):\n", " self.id = id\n", " if source == 'Bilibili':\n", " src = f'https://player.bilibili.com/player.html?bvid={id}&page={page}'\n", " elif source == 'Osf':\n", " src = f'https://mfr.ca-1.osf.io/render?url=https://osf.io/download/{id}/?direct%26mode=render'\n", " super(PlayVideo, self).__init__(src, width, height, **kwargs)\n", "\n", "\n", "def display_videos(video_ids, W=400, H=300, fs=1):\n", " tab_contents = []\n", " for i, video_id in enumerate(video_ids):\n", " out = widgets.Output()\n", " with out:\n", " if video_ids[i][0] == 'Youtube':\n", " video = YouTubeVideo(id=video_ids[i][1], width=W,\n", " height=H, fs=fs, rel=0)\n", " print(f'Video available at https://youtube.com/watch?v={video.id}')\n", " else:\n", " video = PlayVideo(id=video_ids[i][1], source=video_ids[i][0], width=W,\n", " height=H, fs=fs, autoplay=False)\n", " if video_ids[i][0] == 'Bilibili':\n", " print(f'Video available at https://www.bilibili.com/video/{video.id}')\n", " elif video_ids[i][0] == 'Osf':\n", " print(f'Video available at https://osf.io/{video.id}')\n", " display(video)\n", " tab_contents.append(out)\n", " return tab_contents\n", "\n", "\n", "video_ids = [('Youtube', 'I9X4XymeO4A'), ('Bilibili', 'BV1QF411X7rg')]\n", "tab_contents = display_videos(video_ids, W=730, H=410)\n", "tabs = widgets.Tab()\n", "tabs.children = tab_contents\n", "for i in range(len(tab_contents)):\n", " tabs.set_title(i, video_ids[i][0])\n", "display(tabs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "id": "bf18fa96-f99f-420c-95aa-5b18704fac8a", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Past_Present_Future_Climate_Video\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "af18aad1-ddc6-404c-bf27-978471fe2b70", "metadata": { "cellView": "form", "execution": {}, "pycharm": { "name": "#%%\n" }, "tags": [ "remove-input" ] }, "outputs": [], "source": [ "# @markdown\n", "from ipywidgets import widgets\n", "from IPython.display import IFrame\n", "\n", "link_id = \"dtgax\"\n", "\n", "print(f\"If you want to download the slides: https://osf.io/download/{link_id}/\")\n", "IFrame(src=f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/{link_id}/?direct%26mode=render%26action=download%26mode=render\", width=854, height=480)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "id": "6a5f6a63-2185-448e-9a94-104977794bb0", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Past_Present_Future_Climate_Slides\")" ] }, { "cell_type": "markdown", "id": "4dd6b000-b079-461c-9a0e-8fd2bced814b", "metadata": { "execution": {}, "tags": [] }, "source": [ "# Section 1: Using `.where()` with multiple conditions" ] }, { "cell_type": "markdown", "id": "9719db5b-e645-4815-b8df-d454fa7703e7", "metadata": { "execution": {} }, "source": [ "First, let's load the same data that we used in the previous tutorials (monthly sea surface temperature (SST) data from the climate model CESM2):" ] }, { "cell_type": "code", "execution_count": null, "id": "7837f8bd-da89-4718-ab02-d5107576d2d6", "metadata": { "execution": {}, "executionInfo": { "elapsed": 4331, "status": "ok", "timestamp": 1681573823172, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "filepath = DATASETS.fetch(\"CESM2_sst_data.nc\")\n", "ds = xr.open_dataset(filepath)\n", "ds" ] }, { "cell_type": "markdown", "id": "538bd497-3059-4f6e-9c48-5104958f8528", "metadata": { "execution": {} }, "source": [ "The `.where()` method allows us to mask using multiple conditions. To do this, we need to make sure each conditional expression is enclosed in `()`. To combine conditions, we use the `bit-wise and` (`&`) operator and/or the `bit-wise or` (`|`). Let's use `.where()` to isolate locations with temperature values **greater than 25 and less than 30**:" ] }, { "cell_type": "code", "execution_count": null, "id": "c9bf1c46-e7ed-43c1-8a45-e03d22295da1", "metadata": { "execution": {}, "executionInfo": { "elapsed": 624, "status": "ok", "timestamp": 1681573874480, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "# take the last time step as our data\n", "sample = ds.tos.isel(time=-1)\n", "\n", "# just keep data between 25 and 30 degC\n", "sample.where((sample > 25) & (sample < 30)).plot(size=6)" ] }, { "cell_type": "markdown", "id": "e1047138", "metadata": { "execution": {} }, "source": [ "# Section 2: Using `.where()` with a Custom Fill Value" ] }, { "cell_type": "markdown", "id": "74960d46", "metadata": { "execution": {} }, "source": [ "`.where()` can take a second argument, which, if supplied, defines a fill value for the masked region. Below we fill masked regions with a constant `0`:" ] }, { "cell_type": "code", "execution_count": null, "id": "505bbd2d", "metadata": { "execution": {}, "tags": [] }, "outputs": [], "source": [ "sample.where((sample > 25) & (sample < 30), 0).plot(size=6)" ] }, { "cell_type": "markdown", "id": "d016a386", "metadata": { "execution": {} }, "source": [ "# Section 3: Using `.where()` with Specific Coordinates" ] }, { "cell_type": "markdown", "id": "d1796fc8-039b-4c40-a6f4-b3a00c130770", "metadata": { "execution": {} }, "source": [ "We can use coordinates to apply a mask as well. For example, we can use a mask to assess tropical Pacific SST associated with the El Niño Southern Oscillation (ENSO). As we learned in the video, ENSO is a climate phenomenon that originates in the tropical Pacific Ocean but has global impacts on atmospheric circulation, temperature, and precipitation. The two phases of ENSO are El Niño (warmer than average SSTs in the central and eastern tropical Pacific Ocean) and La Niña (cooler than average SSTs in the central and eastern tropical Pacific Ocean). The Niño 3.4 region is an area in the centeral and eastern Pacific Ocean that is often used for determining the phase of ENSO. Below, we will use the `latitude` and `longitude` coordinates to mask everywhere outside of the [Niño 3.4 region](https://www.ncdc.noaa.gov/teleconnections/enso/indicators/sst/). Note in our data that we are in degrees East, so the values we input for `longitude` will be shifted compared to the figure below.\n", "\n", "![](https://www.ncdc.noaa.gov/monitoring-content/teleconnections/nino-regions.gif)\n" ] }, { "cell_type": "code", "execution_count": null, "id": "090f1997-8dea-4eed-aa55-ab3a180ecdd5", "metadata": { "execution": {}, "executionInfo": { "elapsed": 728, "status": "ok", "timestamp": 1681573881072, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 }, "tags": [] }, "outputs": [], "source": [ "# input the conditions for the latitude and longitude values we wish to preserve\n", "sample.where(\n", " (sample.lat < 5) & (sample.lat > -5) & (sample.lon > 190) & (sample.lon < 240)\n", ").plot(size=6)" ] }, { "cell_type": "markdown", "id": "b3dab758", "metadata": { "execution": {} }, "source": [ "Now let's look at a time series of the data from this masked region. Rather than specifying a certain time period, we can mask all areas outside of the Niño 3.4 region and then take the spatial mean to assess changes in Niño 3.4 SST over this time period." ] }, { "cell_type": "code", "execution_count": null, "id": "aae12476-4802-42a2-993b-29da6c383535", "metadata": { "execution": {}, "executionInfo": { "elapsed": 567, "status": "ok", "timestamp": 1681573884614, "user": { "displayName": "Sloane Garelick", "userId": "04706287370408131987" }, "user_tz": 240 } }, "outputs": [], "source": [ "nino = ds.tos.where(\n", " (sample.lat < 5) & (sample.lat > -5) & (sample.lon > 190) & (sample.lon < 240)\n", ")\n", "# create a time series of the spatial mean\n", "nino_mean = nino.mean(dim=[\"lat\", \"lon\"])\n", "nino_mean" ] }, { "cell_type": "code", "execution_count": null, "id": "c12ef69c-b730-486c-9300-286cc2e338ae", "metadata": { "execution": {} }, "outputs": [], "source": [ "nino_mean.plot()" ] }, { "cell_type": "markdown", "id": "4ee8f111-7662-496b-8493-7b08f9bfee2d", "metadata": { "execution": {} }, "source": [ "## Questions 3: Climate Connection" ] }, { "cell_type": "markdown", "id": "c2468980", "metadata": { "execution": {} }, "source": [ "1. What patterns (e.g. cycles, trends) do you observe in this SST time series for the Niño 3.4 region?\n", "2. What do you think might be responsible for the patterns you observe? What about any trends?\n", "3. Notice that we did not use a weighted mean. Do you think the results would be very different if we did weight the mean?" ] }, { "cell_type": "markdown", "id": "c8986c67", "metadata": { "colab_type": "text", "execution": {}, "tags": [] }, "source": [ "[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D1_ClimateSystemOverview/solutions/W1D1_Tutorial9_Solution_ffe2e77d.py)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Submit your feedback\n" ] }, { "cell_type": "code", "execution_count": null, "id": "601b5358-8df2-4b1e-9576-bb5323d6b9ce", "metadata": { "cellView": "form", "execution": {}, "tags": [ "hide-input" ] }, "outputs": [], "source": [ "# @title Submit your feedback\n", "content_review(f\"{feedback_prefix}_Questions_3\")" ] }, { "cell_type": "markdown", "id": "5f6c15ba-b7d3-4ef9-a100-44057a2cefce", "metadata": { "execution": {} }, "source": [ "# Summary\n", "\n", "- Similar to NumPy, arithmetic operations are vectorized over a DataArray\n", "- Xarray provides aggregation methods like `.sum()` and `.mean()`, with the option to specify which dimension over which the operation will be done\n", "- `.groupby()` enables the convenient split-apply-combine workflow\n", "- The `.where()` method allows for filtering or replacing of data based on one or more provided conditions" ] }, { "cell_type": "markdown", "id": "2f1d8229-d6c0-49ac-bc34-06949ef71c3f", "metadata": { "execution": {} }, "source": [ "# Resources" ] }, { "cell_type": "markdown", "id": "8b7b578b-11fd-4cfa-b430-6f019194b73a", "metadata": { "execution": {} }, "source": [ "Code and data for this tutorial is based on existing content from [Project Pythia](https://foundations.projectpythia.org/core/xarray/computation-masking.html)." ] } ], "metadata": { "colab": { "collapsed_sections": [], "include_colab_link": true, "name": "W1D1_Tutorial9", "provenance": [], "toc_visible": true }, "kernel": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.9.19" } }, "nbformat": 4, "nbformat_minor": 5 }