In this exercise, you will learn how to extract satellite data in polar stereographic projection (defined by xgrid and ygrid) around a set of points specified by longitude, latitude, and time coordinates. These coordinates could represent data from animal telemetry tags, ship tracks, or glider tracks.
The exercise demonstrates the following techniques:
Loading animal telemetry tags data from tab- or comma-separated files
Extracting satellite data along a track
Plotting animal tracks and satellite data on a map
Datasets Used:
Sea Ice Concentration Satellite Data
This dataset contains daily and monthly Climate Data Records (CDR) of sea ice concentration, processed by the NOAA/NSIDC team for the Arctic at a 25 km resolution, spanning from 1978 to the most recent annual data processing update. The sea ice concentration data are derived from microwave remote sensing. Due to processing and quality control, CDR data has a slight delay in availability, but near real-time data is available for more recent dates..
For this tutorial, the monthly sea ice concentration data is used. To preview and download CDR data, visit NOAA PolarWatch CDR Data.
Adelie Penguin Telemetry Track
Telemetry data from Adelie penguins (Pygoscelis adeliae) were collected via Argos satellites in the Southern Ocean between October 29, 1996, and February 19, 2013, as part of the U.S. Antarctic Marine Living Resources project. Additionally, a turtle raised in captivity in Japan was tagged and released on May 4, 2005, in the Central Pacific.
The telemetry track dataset is included in the data/ folder of this module. For more information about the project and to download the full dataset, visit the NOAA NCEI webpage.
Import the required Python modules
Packages
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport xarray as xrimport cartopy.crs as ccrs import cartopy.feature as cfeatureimport warningsfrom cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatterwarnings.filterwarnings("ignore")
Loading the sea ice data from PolarWatch ERDDAP
# Get sea ice data by sending data request using xarray to ERDDAP using its unique ID 'nsidcG02202v4shmday'ds = xr.open_dataset("https://polarwatch.noaa.gov/erddap/griddap/nsidcG02202v4shmday")
This project was supported in part by a grant from the NOAA Climate Data Record Program. Production of original NASA Team and Bootstrap algorithm estimates supported by the NASA Polar Distributed Active Archive Center. The sea ice concentration algorithms were developed by Donald J. Cavalieri, Josefino C. Comiso, Claire L. Parkinson, and others at the NASA Goddard Space Flight Center in Greenbelt, MD.
cdm_data_type :
Grid
cdr_variable :
cdr_seaice_conc_monthly
contributor_name :
Walter N. Meier, Florence Fetterer, Ann Windnagel, J. Scott Stewart, Trey Stafford, Matt Fisher
contributor_role :
principal investigator, author, author, software developer, software developer, software developer
PROJCS["NSIDC Sea Ice Polar Stereographic South",GEOGCS["Unspecified datum based upon the Hughes 1980 ellipsoid",DATUM["Not_specified_based_on_Hughes_1980_ellipsoid",SPHEROID["Hughes 1980",6378273,298.279411123061,AUTHORITY["EPSG","7058"]],AUTHORITY["EPSG","6054"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4054"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",-70],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],AUTHORITY["EPSG","3412"],AXIS["X",UNKNOWN],AXIS["Y",UNKNOWN]]
The proj_crs_code attribute references a registered projection identifier (i.e. EPSG) when available. If the projection is not registered, non-standard then this attribute references a PolarWatch assigned internal identifier.
project :
NOAA/NSIDC passive microwave sea ice concentration climate data record
references :
Comiso, J. C., and F. Nishio. 2008. Trends in the Sea Ice Cover Using Enhanced and Compatible AMSR-E, SSM/I, and SMMR Data. Journal of Geophysical Research 113, C02S07, doi:10.1029/2007JC0043257. ; Comiso, J. C., D. Cavalieri, C. Parkinson, and P. Gloersen. 1997. Passive Microwave Algorithms for Sea Ice Concentrations: A Comparison of Two Techniques. Remote Sensing of the Environment 60(3):357-84. ; Comiso, J. C. 1984. Characteristics of Winter Sea Ice from Satellite Multispectral Microwave Observations. Journal of Geophysical Research 91(C1):975-94. ; Cavalieri, D. J., P. Gloersen, and W. J. Campbell. 1984. Determination of Sea Ice Parameters with the NIMBUS-7 SMMR. Journal of Geophysical Research 89(D4):5355-5369. ; Cavalieri, D. J., C. l. Parkinson, P. Gloersen, J. C. Comiso, and H. J. Zwally. 1999. Deriving Long-term Time Series of Sea Ice Cover from Satellite Passive-Microwave Multisensor Data Sets. Journal of Geophysical Research 104(7): 15,803-15,814. ; Comiso, J.C., R.A. Gersten, L.V. Stock, J. Turner, G.J. Perez, and K. Cho. 2017. Positive Trend in the Antarctic Sea Ice Cover and Associated Changes in Surface Temperature. J. Climate, 30, 2251?2267, https://doi.org/10.1175/JCLI-D-16-0408.1
This data set provides a passive microwave sea ice concentration climate data record (CDR) based on gridded brightness temperatures (TBs) from the Defense Meteorological Satellite Program (DMSP) series of passive microwave radiometers: the Nimbus-7 Scanning Multichannel Microwave Radiometer (SMMR), the Special Sensor Microwave Imager (SSM/I) and the Special Sensor Microwave Imager/Sounder (SSMIS). The sea ice concentration CDR is an estimate of sea ice concentration that is produced by combining concentration estimates from two algorithms developed at the NASA Goddard Space Flight Center (GSFC): the NASA Team algorithm and the Bootstrap algorithm. The individual algorithms are used to process and combine brightness temperature data at National Snow and Ice Data Center (NSIDC). This product is designed to provide a consistent time series of sea ice concentrations (the fraction, or percentage, of ocean area covered by sea ice) from November 1978 to the present which spans the coverage of several passive microwave instruments. The data are gridded on the NSIDC polar stereographic grid with 25 x 25 km grid cells, and are available in Network Common Data Format (NetCDF) file format. Each file contains a variable with the CDR concentration values as well as variables that hold the NASA Team and Bootstrap concentrations for reference. Variables containing standard deviation, quality flags, and projection information are also included. Data are available from NSIDC via FTP see https://nsidc.org/data/G02202/versions/4/. Data are also distributed via the PolarWatch ERDDAP at https://polarwatch.noaa.gov/erddap. Note that the data format available through PolarWatch is different from the NSIDC FTP NetCDF files. The PolarWatch data server stores projection information as global attributes (with the prefix grid_mapping) instead of as a variable; and the timestamp is served in different units (seconds since 1970).
time_coverage_duration :
P1M
time_coverage_end :
2024-03-01T00:00:00Z
time_coverage_resolution :
P1M
time_coverage_start :
1978-11-01T00:00:00Z
title :
Sea Ice Concentration, NOAA/NSIDC Climate Data Record V4, Southern Hemisphere, 25km, Science Quality, 1978-Present, Monthly
Plotting Sea Ice Data on a Map
# Select sea ice concentration variable of first timestepsic = ds['cdr_seaice_conc_monthly'][0]# Based on the metadata, values above 1 represent variouag flags, therefore we will # remove the values greater than 1.sic = sic.where(sic <=1, np.nan)# Set coordinate reference system (crs) based on the projection attribute from dspolar_crs = ccrs.SouthPolarStereo(central_longitude=0.0, true_scale_latitude=-70)# Set figure sizeplt.figure(figsize=(5,5))# Set the map projection and associated boundaries based on the metadataax = plt.axes(projection = polar_crs)ax.set_extent([-3950000.0, 3950000.0, -3950000.0, 4350000.0], polar_crs) ax.coastlines()ax.add_feature(cfeature.LAND)# Plot first time-stepcs = ax.pcolormesh(ds['xgrid'], ds['ygrid'], sic, cmap=plt.cm.Blues, transform= polar_crs) #transform default is basemap specsplt.colorbar(cs, ax=ax, location='right', shrink =0.8)ax.set_title('Ice Concentration of timestep 1')
Text(0.5, 1.0, 'Ice Concentration of timestep 1')
Loading penguin telemetry data in csv
# Load penguin data into pandas data framepenguin = pd.read_csv('../data/copa_adpe_ncei.csv')penguin.head()
BirdId
Sex
Age
Breed Stage
DateGMT
TimeGMT
Latitude
Longitude
ArgosQuality
0
ADPE1
female
adult
incubation
28/10/1997
7:54:00
-62.171667
-58.445000
2
1
ADPE1
female
adult
incubation
28/10/1997
9:32:00
-62.173333
-58.463333
2
2
ADPE1
female
adult
incubation
28/10/1997
18:15:00
-62.158333
-58.426667
1
3
ADPE1
female
adult
incubation
28/10/1997
19:57:00
-62.175000
-58.441667
2
4
ADPE1
female
adult
incubation
28/10/1997
21:37:00
-62.171667
-58.445000
2
Processing Penguin Data
For this exercise, we will select ADPE24, female penguin whose track records are highest within the female group, and will follow her journey in the Arctic.
# Find BirdID with the most count by sexpenguin.groupby('Sex')['BirdId'].apply(lambda x: x.value_counts().idxmax())# Extract ADPE24 track dataadpe24 = penguin[penguin['BirdId']=='ADPE24']# Format Dateadpe24['DateGMT'] = pd.to_datetime(adpe24['DateGMT'], format='%d/%m/%Y')adpe24['Year_Month'] = adpe24['DateGMT'].dt.strftime('%Y-%m')# unique penguin datesadpe_dates = adpe24['Year_Month'].unique()print(f"Date Range: {adpe24['DateGMT'].min()}, {adpe24['DateGMT'].max()}")print(f"Unique Month: {adpe24['Year_Month'].unique()}")
latlon_crs = ccrs.PlateCarree() # lat and lonpolar_crs = ccrs.epsg('3412') # South poletransformed_coords = polar_crs.transform_points(latlon_crs, adpe24_df['Longitude'].values, adpe24_df['Latitude'].values)adpe24_df['xgrid'] = transformed_coords[:, 0]adpe24_df['ygrid'] = transformed_coords[:, 1]adpe24_df.head()
Latitude
Longitude
erddap_date
matched_ygrid
matched_xgrid
matched_sea_ice_concen
xgrid
ygrid
DateGMT
2003-01-16
-62.177000
-58.452600
NaN
NaN
NaN
NaN
-2.618256e+06
1.607450e+06
2003-01-17
-62.176370
-58.425000
NaN
NaN
NaN
NaN
-2.617543e+06
1.608749e+06
2003-01-18
-62.339500
-57.683400
NaN
NaN
NaN
NaN
-2.580691e+06
1.632492e+06
2003-01-19
-62.547353
-57.539765
NaN
NaN
NaN
NaN
-2.556494e+06
1.626173e+06
2003-01-20
-62.163853
-58.457471
NaN
NaN
NaN
NaN
-2.619678e+06
1.608017e+06
Extracting Satellite Data to match penguin track and date
# Add new columns to the dataframeadpe24_df[["erddap_date", "matched_ygrid", "matched_xgrid", "matched_sea_ice_concen"]] = np.nan# Subset the satellite datafor i inrange(0, len(adpe24_df)):# Download the satellite data temp_ds = ds['cdr_seaice_conc_monthly'].sel(time='{0:%Y-%m-%d}'.format(adpe24_df.index[i]), ygrid=adpe24_df.iloc[i]['ygrid'], xgrid=adpe24_df.iloc[i]['xgrid'], method='nearest' )# Add to the dataframe adpe24_df.loc[adpe24_df.index[i], ["erddap_date", "matched_ygrid","matched_xgrid", "matched_sea_ice_concen"] ] = [temp_ds.time.values, np.round(temp_ds.ygrid.values, 5), # round 5 dec np.round(temp_ds.xgrid.values, 5), # round 5 dec np.round(temp_ds.values, 2) # round 2 decimals ]
Plotting Penguin Tracks with Matched Sea Ice Concentration Data
plt.figure(figsize=(14, 10))# set the projectionax1 = plt.subplot(211, projection=crs_epsg)# Use the lon and lat ranges to set the extent of the mapax1.set_extent([-90, -30, -75, -55], ccrs.PlateCarree()) # South Pole# Add grid linegl = ax1.gridlines(draw_labels=True, crs=ccrs.PlateCarree(), linestyle='--')gl.xlabels_top =Falsegl.ylabels_right =Falsegl.xformatter = LongitudeFormatter()gl.yformatter = LatitudeFormatter()# Add geographical featuresax1.add_feature(cfeature.LAND, facecolor='0.6')ax1.coastlines()# build and plot coordinates onto mapx,y =list(adpe24_df.Longitude), list(adpe24_df.Latitude)ax1 = plt.scatter(x, y, transform=ccrs.PlateCarree(), marker='o', c=adpe24_df.matched_sea_ice_concen, cmap=plt.get_cmap('Blues'), edgecolor='Black', linewidth=0.25 )ax1=plt.plot(x[0],y[0],marker='*', label='start', color='red', transform=ccrs.PlateCarree(), markersize=10)ax1=plt.plot(x[-1],y[-1],marker='X', label='end',color='orange', transform=ccrs.PlateCarree(), markersize=10)# control color bar values spacinglevs2 = np.arange(0, 1, 0.1)cbar=plt.colorbar()cbar.set_label("Sea Ice Concentration", size=12, labelpad=20)# set the labels to be exp(levs2) so the label reflect values of chl-a, not log(chl-a)cbar.ax.set_yticklabels(np.round(levs2, 1), size=10)plt.legend()plt.title("Sea Ice Concen Matchup to Penguin Track", size=15)plt.show()