Homework 5: Xarray and CartoPy#


General:

  • Please submit your homework as a Jupyter notebook with well-commented code, plots, and your written summary

  • Make sure to submit other relevent file(s) required to run the main parts of your code

  • Late submission policy is same as Homework 3

  • Total 20 points



Install and import libraries#

#pip install nc-time-axis
#pip install netcdf4
#pip install h5netcdf
#pip install Pydap
import xarray as xr
import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import warnings
#  Suppress warnings issued by Cartopy when downloading data files
warnings.filterwarnings('ignore')

1. Problem Statement#

The aim is to study past precipitation data for North and South Florida and compare it with the Representative Concentration Pathway (RCP) 2.6, 4.5, and 8.5 simulations from the CMIP6 dataset. Research questions:

  • how do the precipitation trends in North and South Florida vary between historical data and the different RCP scenarios?

  • What are the potential implications of these future climate trends in Florida on water resources management and natural environment, with respect to strategies for conservation and adaptation?

2. Data Collection#

Global gridded monthly climate projection dataset underpinning the IPCC AR6 Interactive Atlas data for Florida were extracted and saved as:

  • pr_CORDEX-NAM_historical_mon_197001-200512_FL.nc

  • pr_CORDEX-NAM_rcp26_mon_200601-210012_FL.nc

  • pr_CORDEX-NAM_rcp45_mon_200601-210012_FL.nc

  • pr_CORDEX-NAM_rcp85_mon_200601-210012_FL.nc

In the context of climate data, the prefix ‘pr’ signifies precipitation data according to the CF conventions. The CORDEX-NAM dataset serves as a regional climate model intercomparison project focusing on North America. Each file contains data from an ensemble of 20 regional models. The historical data spans simulated records from January 1970 to December 2015, while the RCP26, RCP45, and RCP85 scenarios represent future emission trajectories with varying levels of greenhouse gas emissions, ranging from low (RCP26) to moderate (RCP45) to high (RCP85) emissions from January 2006 to December 2100. These files are stored in NetCDF format (.nc).

3. Data Exploration (10 points)#

Before we answer the questions above. Let us first understand our data by loading and plotting data for the historical simulations.

3.1 Load historical pr data for Florida#

2 points: Open file ‘pr_CORDEX-NAM_historical_mon_197001-200512_FL.nc’ as ds Dataset and display ds DataSet.

#Open dataset (change path as neeeded)
file = 'pr_CORDEX-NAM_historical_mon_197001-200512_FL.nc'
path = 'Data\\cmip6\\'
ds = xr.open_dataset(path + file, engine='netcdf4')

ds
<xarray.Dataset> Size: 10MB
Dimensions:          (lat: 16, bnds: 2, lon: 18, time: 432, member: 20)
Coordinates:
  * lat              (lat) float64 128B 24.25 24.75 25.25 ... 30.75 31.25 31.75
  * lon              (lon) float64 144B -87.75 -87.25 -86.75 ... -79.75 -79.25
  * time             (time) datetime64[ns] 3kB 1970-01-01 ... 2005-12-01
    member_id        (member) <U47 4kB ...
    gcm_institution  (member) <U12 960B ...
    gcm_model        (member) <U10 800B ...
    gcm_variant      (member) <U7 560B ...
    rcm_institution  (member) <U7 560B ...
    rcm_model        (member) <U8 640B ...
    rcm_variant      (member) <U8 640B ...
Dimensions without coordinates: bnds, member
Data variables:
    lat_bnds         (lat, bnds) float64 256B ...
    lon_bnds         (lon, bnds) float64 288B ...
    time_bnds        (time, bnds) datetime64[ns] 7kB ...
    pr               (member, time, lat, lon) float32 10MB ...
    crs              int32 4B ...
Attributes: (12/28)
    Conventions:                CF-1.9 ACDD-1.3
    title:                      IPCC-WGI AR6 Interactive Atlas Dataset
    summary:                    IPCC-WGI AR6 Interactive Atlas dataset: Month...
    keywords:                   CMIP5, CMIP6, CORDEX, IPCC, Interactive Atlas
    institution:                Instituto de Fisica de Cantabria (IFCA, CSIC-...
    contact:                    ipcc-ddc@ifca.unican.es
    ...                         ...
    geospatial_lon_min:         -172.0
    geospatial_lon_max:         -22.0
    geospatial_lon_resolution:  0.5
    geospatial_lon_units:       degrees_east
    date_created:               2022-10-26T00:00:00+00:00
    tracking_id:                c0aa48c5-d12b-4df9-89eb-3e5f8ac3dc70

3.2 Plot historical pr data for Florida#

Plot ‘pr’ data for the first member and first time step for all lat and lon values

def plot_pr(data_to_plot,member_number,timestep_number):
    """
    Plot precipitation data on a map.

    Parameters:
    data_to_plot (xarray.Dataset): Dataset containing precipitation data to be plotted.
    member_number (int): Member number for selecting data to plot.
    timestep_number (int): Timestep number for selecting data to plot.
    """
    

    # 1) Select plot extend: Lon_West, Lon_East, Lat_South, Lat_North in Degrees
    extent = [-79, -88, 24, 32] 
    
    # 2) Select projection
    projPC = ccrs.PlateCarree()
    
    # 3) Create figure
    fig = plt.figure(figsize=(7, 7))
    
    # 4) Plot variables 
    variable = 'pr'
    colormap = 'coolwarm'
    title= f"{ds.pr.attrs['long_name']} ({ds.attrs['experiment_id']})"
    
    # 5) Create Axes     
    ax = plt.subplot(1, 1, 1, projection=projPC)
    
    # 6) Setting the extent of the plot
    ax.set_extent(extent, crs=projPC)
    
    # 7) Add plot title 
    ax.set_title(title, fontsize=10, loc='left')
    
    # 8) Add gridlines
    gl = ax.gridlines(draw_labels=True, 
                      xlocs=np.arange(extent[1],extent[0], 1), 
                      ylocs= np.arange(extent[2], extent[3], 1),
                      linewidth=1, color='gray', alpha=0.5, linestyle='--',  zorder=40)
    gl.right_labels = False  # 
    gl.top_labels = False    # Set the font size for x-axis labels
    gl.xlabel_style = {'size': 10}  # Set the font size for x-axis labels
    gl.ylabel_style = {'size': 10}  # Set the font size for y-axis labels
    
    # 9) Adding Natural Earth features
    ## Pre-defined features
    ax.set_facecolor(cfeature.COLORS['water'])  #Blackgroundwater color for the ocean
    ax.add_feature(cfeature.LAKES.with_scale('10m'), color='aqua', zorder=21) 
    #ax.add_feature(cfeature.COASTLINE.with_scale('10m'), color='gray', zorder=21) 
    ax.add_feature(cfeature.STATES.with_scale('10m'),  zorder=21) 
    ax.add_feature(cfeature.BORDERS, edgecolor='red',facecolor='none', linewidth=2, zorder=22) 
    ax.stock_img()
    
    ## Adding names and locations of major cities
    locations_coordinates = {"Tampa": [27.9506, -82.4572], 
                         "Sarasota": [27.3364, -82.5307], 
                         "Fort Myers": [26.6406, -81.8723], 
                         "Naples": [26.142, -81.7948]}
    for location, coordinates in locations_coordinates.items():
        ax.plot(coordinates[1], coordinates[0],  
                transform=ccrs.PlateCarree(),  marker='o', color='black', markersize=3, zorder = 22)
        ax.text(coordinates[1] + 0.1, coordinates[0] + 0.1, 
                location, transform=ccrs.PlateCarree(), color='black', fontsize=8, zorder = 22)
    
    # 11) Adding raster data and colorbar for the first three subplots
    dataplot = ax.contourf(data_to_plot.lon, data_to_plot.lat, 
                           data_to_plot.pr[member_number,timestep_number,:,:], 
                           cmap=colormap, zorder=12, transform=ccrs.PlateCarree())
    colorbar = plt.colorbar(dataplot, orientation='horizontal', pad=0.1, shrink=0.8)  
    cb_label= f"{data_to_plot.pr.attrs['long_name']} ({data_to_plot.pr.attrs['units']})"
    colorbar.set_label(cb_label, fontsize=10)
# Call the function plot_pr to plot the content of your DataSet
# for the first member and first timestep
plot_pr(ds,0,0)
../../_images/70c5bbdbe2e0faf0a1af54807cc7d7002cfc881b16675a8802b061400d7767b8.png

3.3 Slice and plot historical pr data for North Florida#

For North Florida, extract a subset of the data where latitude ranges from 29.5 to 31 and longitude ranges from -88 to -81. Assign this subset to a new variable named ds_nf.

# Slice the dataset 'ds' to select data within the latitude range of 29.5 to 31 and longitude range of -88 to -81
# Create a copy of the sliced data and assign it to the variable 'ds_nf'
ds_nf = ds.sel(lat=slice(29.5, 31), lon=slice(-88, -81)).copy()

2 points: Plot that slice for the first member and first time step for all lat and lon values

# Call the function plot_pr to plot the content of your DataSet
# for the first member and first timestep

3.4 Slice and plot historical pr data for South Florida#

2 points: For South Florida, extract a subset of the data where latitude ranges from 24.6 to 27.5 and longitude ranges from -83 to -79.7. Assign this subset to a new variable named ds_sf.

# Slice the dataset 'ds' to select data within the latitude range of 24.6 to 27.5 and longitude range of -83 to -79.7
# Create a copy of the sliced data and assign it to the variable 'ds_sf'

2 points: Plot that slice for the first member and first time step for all lat and lon values

# Call the function plot_pr to plot the content of your DataSet
# for the first member and first timestep

3.5 Calculate and plot mean decadal pr of historical data#

2 points: Complete the code below.

# For North Florida, calculate the mean decadal precipitation over members, latitude, and longitude dimensions
# Resample the data annually and calculate the mean over time
# Plot the resulting data with the given label
plot_label=f"North Florida: {ds.attrs['experiment_id']}"
ds_nf.pr.mean(dim=('member','lat','lon')).resample(time='10Y').mean(dim='time').plot(label=plot_label,color='black',marker='o')
plt.ylabel('Precipitation (mm/day)')

# For South Florida, calculate the mean decadal precipitation over members, latitude, and longitude dimensions
# Resample the data annually and calculate the mean over time
# Plot the resulting data with the given label


# Add a legend outside of the plot
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left');
../../_images/3af868a5e8d7d9efa594f9481c0376a57281c63a7bb63f8620bae53d1bc184d8.png

3.6 Close file#

# Close the file after reading the data
ds.close()

4. Data analysis (10 points)#

Now, to address our research question, we will replicate the previous figure for historical data and include RCP2.6, RCP4.5, and RCP8.5 data. You should organize the codes for data loading, data slicing for North Florida, data slicing for South Florida, mean calculation in a for loop.

4.1 Plot historical, RCP4.5, and RCP8.5 data for North and South Florida#

Calculate and plot mean decadal pr for historical, RCP4.5, and RCP8.5 data for North and South Florida.

files =['pr_CORDEX-NAM_historical_mon_197001-200512_FL.nc',
        'pr_CORDEX-NAM_rcp45_mon_200601-210012_FL.nc',
        'pr_CORDEX-NAM_rcp85_mon_200601-210012_FL.nc']

line_colors= ['black','orange','red']

#Loop for all files 
for line_color,file in zip(line_colors,files):

    #Open dataset 
    ds = xr.open_dataset('Data\\cmip6\\' + file, engine='netcdf4')

    # Slice the dataset 'ds' to select data within the latitude range of 29.5 to 31 and longitude range of -88 to -81
    # Create a copy of the sliced data and assign it to the variable 'ds_nf'
    ds_nf = ds.sel(lat=slice(29.5, 31), lon=slice(-88, -81)).copy()

    # Slice the dataset 'ds' to select data within the latitude range of 24.6 to 27.5 and longitude range of -83 to -79.7
    # Create a copy of the sliced data and assign it to the variable 'ds_sf'
    ds_sf = ds.sel(lat=slice(24.6, 27.5), lon=slice(-83, -79.7)).copy()


    # For North Florida, calculate the mean precipitation over members, latitude, and longitude dimensions
    # Resample the data annually and calculate the mean over time
    # Plot the resulting data with the given label
    plot_label=f"North Florida: {ds.attrs['experiment_id']}"
    ds_nf.pr.mean(dim=('member','lat','lon')).resample(time='10Y').mean(dim='time').plot(label=plot_label,color=line_color,marker='o')

    # For South Florida, calculate the mean precipitation over members, latitude, and longitude dimensions
    # Resample the data annually and calculate the mean over time
    # Plot the resulting data with the given label
    plot_label=f"South Florida: {ds.attrs['experiment_id']}"
    ds_sf.pr.mean(dim=('member','lat','lon')).resample(time='10Y').mean(dim='time').plot(label=plot_label, color=line_color)
    plt.ylabel('Precipitation (mm/day)')

    # Close the file after reading the data
    ds.close()

# Add a legend outside of the plot
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left');
../../_images/e854b1cac7ec5b16545b2910f9b0ce3bafc2172299576296321cee49aba19ec8.png

4.2 Plot historical, RCP2.6, RCP4.5, and RCP8.5 for South Florida#

Calculate and plot mean decadal pr for historical, PRCP2.6, RCP4.5, and RCP8.5 data for South Florida

10 points : Complete the code below

files =['pr_CORDEX-NAM_historical_mon_197001-200512_FL.nc',
        'pr_CORDEX-NAM_rcp26_mon_200601-210012_FL.nc',
        'pr_CORDEX-NAM_rcp45_mon_200601-210012_FL.nc',
        'pr_CORDEX-NAM_rcp85_mon_200601-210012_FL.nc']

line_colors= ['black','green','orange','red']

#Loop for all files 

    #Open dataset 

    # Slice the dataset 'ds' to select data within the latitude range of 24.6 to 27.5 and longitude range of -83 to -79.7
    # Create a copy of the sliced data and assign it to the variable 'ds_sf'

    # For South Florida, calculate the mean precipitation over members, latitude, and longitude dimensions
    # Resample the data annually and calculate the mean over time
    # Plot the resulting data with the given label

    # Close the file after reading the data

# Add a legend outside of the plot