{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"[](https://colab.research.google.com/github/neuromatch/climate-course-content/blob/main/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere/student/W1D3_Tutorial5.ipynb)
"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Tutorial 5: Calculating Anomalies Using Precipitation Data\n",
"\n",
"**Week 1, Day 3, Remote Sensing**\n",
"\n",
"**Content creators:** Douglas Rao\n",
"\n",
"**Content reviewers:** Katrina Dobson, Younkap Nina Duplex, Maria Gonzalez, Will Gregory, Nahid Hasan, Sherry Mi, Beatriz Cosenza Muralles, Jenna Pearson, Agustina Pesce, Chi Zhang, Ohad Zivan\n",
"\n",
"**Content editors:** Jenna Pearson, Chi Zhang, Ohad Zivan\n",
"\n",
"**Production editors:** Wesley Banfield, Jenna Pearson, Chi Zhang, Ohad Zivan\n",
"\n",
"**Our 2023 Sponsors:** NASA TOPS and Google DeepMind"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Tutorial Objectives\n",
"\n",
"In this tutorial, you will learn how to calculate climate anomalies using satellite climate data records.\n",
"\n",
"By the end of this tutorial you will be able to:\n",
"\n",
"* Calculate an anomaly to a climatology.\n",
"* Calculate the rolling mean of the anomaly data to smooth the time series and extract long-term signals/patterns.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {},
"tags": [
"colab"
]
},
"outputs": [],
"source": [
"# installations ( uncomment and run this cell ONLY when using google colab or kaggle )\n",
"\n",
"# !pip install s3fs --quiet\n",
"\n",
"# # properly install cartopy in colab to avoid session crash\n",
"# !apt-get install libproj-dev proj-data proj-bin --quiet\n",
"# !apt-get install libgeos-dev --quiet\n",
"# !pip install cython --quiet\n",
"# !pip install cartopy --quiet\n",
"# !pip install geoviews\n",
"\n",
"# !apt-get -qq install python-cartopy python3-cartopy --quiet\n",
"# !pip uninstall -y shapely --quiet\n",
"# !pip install shapely --no-binary shapely --quiet\n",
"\n",
"# !pip install boto3 --quiet\n",
"\n",
"# you may need to restart the runtime after running this cell and that is ok"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# imports\n",
"import s3fs\n",
"import xarray as xr\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cartopy\n",
"import cartopy.crs as ccrs\n",
"import boto3\n",
"import botocore\n",
"import os\n",
"import pooch\n",
"import tempfile\n",
"import holoviews\n",
"from geoviews import Dataset as gvDataset\n",
"import geoviews.feature as gf\n",
"from geoviews import Image as gvImage"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Figure Settings\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"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/ClimateMatchAcademy/course-content/main/cma.mplstyle\"\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Helper functions\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"hide-input"
]
},
"outputs": [],
"source": [
"# @title Helper functions\n",
"\n",
"def pooch_load(filelocation=None, filename=None, processor=None):\n",
" shared_location = \"/home/jovyan/shared/data/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere\" # this is different for each day\n",
" user_temp_cache = tempfile.gettempdir()\n",
"\n",
" if os.path.exists(os.path.join(shared_location, filename)):\n",
" file = os.path.join(shared_location, filename)\n",
" else:\n",
" file = pooch.retrieve(\n",
" filelocation,\n",
" known_hash=None,\n",
" fname=os.path.join(user_temp_cache, filename),\n",
" processor=processor,\n",
" )\n",
"\n",
" return file"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Video 1: Calculating Anomaly\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"execution": {},
"tags": [
"remove-input"
]
},
"outputs": [],
"source": [
"# @title Video 1: Calculating Anomaly\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', 'CYaS35CBCB0'), ('Bilibili', 'BV1NX4y1v72r')]\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": "code",
"execution_count": null,
"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 = \"kvdgr\"\n",
"\n",
"download_link = f\"https://osf.io/download/{link_id}/\"\n",
"render_link = f\"https://mfr.ca-1.osf.io/render?url=https://osf.io/{link_id}/?direct%26mode=render%26action=download%26mode=render\"\n",
"# @markdown\n",
"out = widgets.Output()\n",
"with out:\n",
" print(f\"If you want to download the slides: {download_link}\")\n",
" display(IFrame(src=f\"{render_link}\", width=730, height=410))\n",
"display(out)"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Section 1: From Climatology to Anomaly\n",
"\n",
"Building upon your knowledge of climatology from the last tutorial, you will now calculate the anomalies from this climatology. An **anomaly**, in the context of climate studies, represents a departure from standard climatological conditions. For example, if the normal January temperature of the city that you live in is 10 °C and the January temperature of this year is 15 °C. We usually say the temperature anomaly of January this year is 5 °C above normal/ the climatology. The anomaly is an essential tool in detecting changes in climate patterns and is frequently utilized in critical climate reports such as those generated by the [Intergovernmental Panel on Climate Change (IPCC)](https://www.ipcc.ch/).\n",
"\n",
"To calculate an anomaly, we first establish a reference period, usually a 30-year window, to define our climatology. In this process, it is crucial to use high-quality data and aggregate it to the desired spatial resolution and temporal frequency, such as weekly or monthly. The anomaly is then determined by subtracting this long-term average from a given observation, thus creating a useful metric for further climate analysis such as trend analysis.\n",
"\n",
"In this tutorial, we will employ the [CPCP monthly precipitation Climate Data Record (CDR)](https://disc.gsfc.nasa.gov/datasets/GPCPMON_3.2/summary) to compute a monthly anomaly time series. Furthermore, we will learn to calculate the rolling mean of the generated precipitation anomaly time series. This knowledge will be invaluable for our upcoming tutorial on climate variability."
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Section 1.1: Calculating the Monthly Anomaly\n",
"\n",
"To calculate anomaly, you first need to calculate the monthly climatology. Since you already learned how to do this during last tutorial, we will fast forward this step. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# connect to the AWS S3 bucket for the GPCP Monthly Precipitation CDR data\n",
"fs = s3fs.S3FileSystem(anon=True)\n",
"\n",
"# get the list of all data files in the AWS S3 bucket\n",
"file_pattern = \"noaa-cdr-precip-gpcp-monthly-pds/data/*/gpcp_v02r03_monthly_*.nc\"\n",
"file_location = fs.glob(file_pattern)\n",
"\n",
"# open connection to all data files\n",
"client = boto3.client(\n",
" \"s3\", config=botocore.client.Config(signature_version=botocore.UNSIGNED)\n",
") # initialize aws s3 bucket client\n",
"file_ob = [\n",
" pooch_load(filelocation=\"http://s3.amazonaws.com/\" + file, filename=file)\n",
" for file in file_location\n",
"]\n",
"\n",
"# open all the monthly data files and concatenate them along the time dimension\n",
"# this process will take ~ 1 minute to complete due to the number of data files\n",
"ds = xr.open_mfdataset(file_ob, combine=\"nested\", concat_dim=\"time\")\n",
"\n",
"# comment for colab users only: this could toss an error message for you.\n",
"# you should still be able to use the dataset with this error just not print ds\n",
"# you can try uncommenting the following line to avoid the error\n",
"# ds.attrs['history']='' # the history attribute have unique chars that cause a crash on Google colab.\n",
"ds"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate climatology using `.sel()` and `.groupby()` directly.\n",
"precip_clim = (\n",
" ds.precip.sel(time=slice(\"1981-01-01\", \"2010-12-01\"))\n",
" .groupby(\"time.month\")\n",
" .mean(dim=\"time\")\n",
")\n",
"precip_clim"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Now we have the monthly precipitation climatology. How can we calculate the monthly anomaly?\n",
"\n",
"As we learned before - let's use `.groupby()` from `xarray`. We can split the entire time period based on the month of the year and then subtract the climatology of that specific month from the monthly value and recombine the value together."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# use `.groupby()` to calculate the monthly anomaly\n",
"precip_anom = ds.precip.groupby(\"time.month\") - precip_clim\n",
"precip_anom"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"You may have noticed that there is an additional coordinate in the anomaly dataset. The additional coordinate is `month` which is a direct outcome because of the `.groupby()` action we just performed.\n",
"\n",
"If you want to save the data for future use, you can write the data out to a netCDF file using `.to_netcdf()`. It will automatically carry all the coordinates, dimensions, and relevant information into the netCDF file."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# an example of how to export the GPCP monthly anomaly data comparing to the climatology period of 1981-2010.\n",
"# precip_anom.to_netcdf('t5_gpcp-monthly-anomaly_1981-2010.nc')"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Section 1.2: Examining the Anomaly\n",
"\n",
"First, let's take a look at the geospatial pattern of the monthly anomaly of a selected month – January of 1979."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# initate plot\n",
"fig = plt.figure(figsize=(9, 6))\n",
"\n",
"# set map projection\n",
"ax = plt.axes(projection=ccrs.Robinson())\n",
"\n",
"# add coastal lines to indicate land/ocean\n",
"ax.coastlines()\n",
"\n",
"# add grid lines for latitude and longitude\n",
"ax.gridlines()\n",
"\n",
"# add the precipitation data for\n",
"precip_anom.sel(time=\"1979-01-01\").plot(\n",
" ax=ax,\n",
" transform=ccrs.PlateCarree(),\n",
" vmin=-8,\n",
" vmax=8,\n",
" cmap=\"BrBG\",\n",
" cbar_kwargs=dict(shrink=0.5, label=\"Monthly Anomaly \\n(mm/day)\"),\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {},
"tags": []
},
"source": [
"From the map of this monthly anomaly, we can see the spatial pattern of how precipitation for the January of 1979 has departed from the 30-year normal. Part of the Amazon saw notable increase of precipitation during this month as well as the northeast coast of the United States. "
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Interactive Demo 1.2\n",
"\n",
"In the interactive demo below (make sure to run the code) you will be able to scroll through the anomaly for a few months in 1979 to see how it changes from month to month during this year."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {},
"tags": []
},
"outputs": [],
"source": [
"holoviews.extension(\"bokeh\")\n",
"dataset_plot = gvDataset(\n",
" precip_anom.isel(time=slice(0, 10))\n",
") # only the first 10, as it is a time consuming task\n",
"images = dataset_plot.to(gvImage, [\"longitude\", \"latitude\"], [\"precip\"], \"time\")\n",
"images.opts(\n",
" cmap=\"BrBG\",\n",
" colorbar=True,\n",
" width=600,\n",
" height=400,\n",
" projection=ccrs.Robinson(),\n",
" clim=(-8, 8),\n",
" clabel=\"Monthly Anomaly \\n(mm/day)\",\n",
") * gf.coastline"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"To visualize the changes in the precipitation anomaly over many months, we can also take a look at the time series of a selected grid. We will use the same point (0°N, 0°E) that we used as an example in the last tutorial."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# set up two subplots that share the x-axis to compare monthly precipitation and monthly anomaly\n",
"fig, axs = plt.subplots(2, sharex=True)\n",
"fig.suptitle(\"GPCP Monthly Precipitaion v.s. Monthly Anomaly\")\n",
"axs[0].plot(ds.time, ds.precip.sel(latitude=0, longitude=0, method=\"nearest\"))\n",
"axs[0].set_ylabel(\"Precip (mm/day)\")\n",
"axs[1].plot(\n",
" precip_anom.time, precip_anom.sel(latitude=0, longitude=0, method=\"nearest\")\n",
")\n",
"axs[1].set_ylabel(\"Anomaly (mm/day)\")\n",
"axs[1].set_xlabel(\"Time\")\n",
"\n",
"# add horizontal line of y=0 for the anomaly subplot\n",
"axs[1].axhline(y=0, color=\"k\", linestyle=\"-\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Note that, unlike the upper panel showing precipitation values, the lower panel displaying the monthly anomaly not exhibit distinct seasonal cycles. This discrepancy highlights one of the advantages of utilizing anomaly data for climate analysis. By removing the repetitive patterns induced by seasonality or other stable factors, we can effectively isolate the specific signals in the data that are of interest, such as climate variability or climate trends. This approach allows for a clearer focus on the desired climate-related patterns without the interference of predictable seasonal variations."
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Section 2: Anomaly Analysis\n",
"\n",
"In this section, we are going to explore a few different analyses on the anomaly data: \n",
"\n",
"- Calculating rolling mean\n",
"- Calculating global mean\n",
"\n",
"You have already practiced using these tools during the last two days or material, here we will focus on applying them to a much longer satellite data record than you have encountered previously."
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Section 2.1: Rolling Mean\n",
"\n",
"The monthly anomaly time series often contains noisy data that may obscure the patterns associated with large-scale climate variability. To mitigate this noise and enhance the visibility of underlying patterns, we can apply a rolling mean technique using the `.rolling()` function. This approach involves smoothing the monthly time series to facilitate the identification of climate variability."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate 12-month rolling mean for the selected location\n",
"grid_month = precip_anom.sel(latitude=0, longitude=0, method=\"nearest\")\n",
"grid_rolling = grid_month.rolling(time=12, center=True).mean()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# create the time series plot of monthly anomaly\n",
"fig, ax = plt.subplots(figsize=(12, 6))\n",
"grid_month.plot(label=\"Monthly Anomaly\", ax=ax)\n",
"grid_rolling.plot(color=\"k\", label=\"12-mon rolling mean\", ax=ax)\n",
"ax.axhline(y=0, color=\"y\", linestyle=\"-\")\n",
"ax.set_ylabel(\"Precipitation Anomaly (mm/day)\")\n",
"ax.legend()\n",
"ax.set_xlabel(\"Time\")\n",
"# remove the automatically generated title\n",
"ax.set_title(\"\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"As you can see, the 12-month rolling mean removes the high-frequency variations of monthly precipitation anomaly data, allowing the slower-changing patterns of precipitation to become more apparent."
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Coding Exercises 2.1\n",
"\n",
"1. Calculate the 24-month rolling mean for the same grid and compare the three different time series (monthly anomaly, 12-month rolling mean, 24-month rolling mean)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate 24-month rolling mean\n",
"# grid_rolling_24m = ...\n",
"\n",
"# plot all three time series together with different colors\n",
"# fig, ax = ..."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere/solutions/W1D3_Tutorial5_Solution_ebd7c176.py)\n",
"\n",
"*Example output:*\n",
"\n",
"
\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Questions 2.1\n",
"\n",
"1. What are the major differences you notice between the 12 and 24 month rolling averages?\n",
"2. What would generally dictate the window size to use in a rolling average of a satellite derived climate variable such as precipitation anomalies?"
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {},
"tags": []
},
"source": [
"[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere/solutions/W1D3_Tutorial5_Solution_25e66bca.py)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"## Section 2.2: Global Mean\n",
"\n",
"When examining global-scale changes, it is common to aggregate global mean values from all grid cells. However, it is important to note that despite each grid having the same resolution of `2.5°×2.5°`, they represent different areas on the Earth's surface. Specifically, the same grid covers larger spatial areas in the tropics compared to the polar regions as discussed in the climate system overview day.\n",
"\n",
"To address this issue, it is necessary to weight the values based on their respective surface areas. Unlink the model data you used previously, where you had the grid cell area available as a variable, for our gridded observations we will use weights based on the cosine of the latitude as this function takes into account the decreasing area towards the poles."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate the weights using the latitude coordinates\n",
"weights = np.cos(np.deg2rad(precip_anom.latitude))\n",
"weights.name = \"weights\"\n",
"weights"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate weighted global monthly mean\n",
"anom_weighted = precip_anom.weighted(weights)\n",
"global_weighted_mean = anom_weighted.mean((\"latitude\", \"longitude\"))\n",
"global_weighted_mean"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# create the time series plot of global weighted monthly anomaly\n",
"fig, ax = plt.subplots(figsize=(12, 6))\n",
"global_weighted_mean.plot(label=\"Monthly anomaly\", ax=ax)\n",
"global_weighted_mean.rolling(time=12, center=True).mean((\"latitude\", \"longitude\")).plot(\n",
" color=\"k\", label=\"12-mon rolling mean\", ax=ax\n",
")\n",
"ax.axhline(y=0, color=\"y\", linestyle=\"-\")\n",
"ax.set_ylabel(\"Precipitation Anomaly (mm/day)\")\n",
"ax.legend()"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Coding Exercises 2.2\n",
"\n",
"1. Plot the 12-month rolling average of the difference between the global weighted and unweighted mean time series.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"execution": {}
},
"outputs": [],
"source": [
"# calculate unweighted global mean\n",
"global_unweighted_mean = ...\n",
"\n",
"# calculate different between weighted and unweighted global mean\n",
"# global_diff = global_weighted_mean - global_unweighted_mean\n",
"\n",
"# plot the time series of the difference\n",
"# fig, ax = ..."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {}
},
"source": [
"[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere/solutions/W1D3_Tutorial5_Solution_15f88aa8.py)\n",
"\n",
"*Example output:*\n",
"\n",
"
\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"### Questions 2.2\n",
"\n",
"1. Give one example of why the weighted mean might be *higher* than the unweighted mean, as in the 2000-2004 period."
]
},
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"execution": {},
"tags": []
},
"source": [
"[*Click for solution*](https://github.com/neuromatch/climate-course-content/tree/main/tutorials/W1D3_RemoteSensingLandOceanandAtmosphere/solutions/W1D3_Tutorial5_Solution_7c6157c7.py)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Summary\n",
"\n",
"In this tutorial, you learned how to calculate a climate anomaly using satellite derived precipitation data. \n",
"\n",
"* The anomaly allows us to look at the signals that may be covered by the seasonal cycle pattern (e.g., temperature/precipitation seasonal cycle).\n",
"* The anomaly data can be further smoothed using rolling mean to reveal longer-term signals at annual or decade time scale.\n",
"\n",
"We will use the anomaly concept to study climate variability in the next tutorial.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"# Resources"
]
},
{
"cell_type": "markdown",
"metadata": {
"execution": {}
},
"source": [
"Data from this tutorial can be accessed [here](https://noaa-cdr-precip-gpcp-monthly-pds.s3.amazonaws.com/index.html#data/)."
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"include_colab_link": true,
"name": "W1D3_Tutorial5",
"provenance": [],
"toc_visible": true
},
"kernel": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"kernelspec": {
"display_name": "climatematch",
"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": 4
}