¶Introductions
Now that we’ve explored the GOES satellite data and the IBTrACS data in Python, let’s put them both together. In order to do so, we’ll have to obtain the projection data of the GOES imagery, project the IBTrACS latitudes/longitudes using the GOES projection data, and then overlay the track on the GOES imagery.
Rather than using the entirety of the IBTrACS data, we focus specifically on the track of Hurricane Harvey in 2017. This was a devastating storm that first made landfall in Texas. I chose this storm because I’m pretty familiar with it and know roughly what to expect for the imagery and the track.
¶Import Modules
Let’s first import the modules we need to run the code. I’ve written some functions for getting the IBTrACS and GOES data, so let’s import those functions now too.
# Import modules import matplotlib.pyplot as plt import os import datetime from pyproj import Proj from mpl_toolkits.basemap import Basemap import numpy as np # Import functions I've written os.chdir("..") import goes import ibtracs
¶Retrieve IBTrACS Data
Now let’s load up the IBTrACS data, as we did in a previous notebook, and then drill down on the track for Hurricane Harvey in 2017.
# Set the file path for the IBTrACS data filePath = ibtracs.download_data(basin="NA",overwrite=False) # Read the data from the CSV df = ibtracs.read_data(filePath) # Keep only the Hurricane Harvey (2017) track df = df[df['SEASON'] == 2017] df = df[df['NAME'] == 'HARVEY'] # Show a preview df.head()
SID | SEASON | NUMBER | NAME | ISO_TIME | NATURE | LAT | LON | WMO_WIND | WMO_PRES | TRACK_TYPE | DIST2LAND | LANDFALL | IFLAG | STORM_SPEED | STORM_DIR | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
118592 | 2017228N14314 | 2017 | 61 | HARVEY | Timestamp | (2017-08-16 06:00:00) | DS | 13.7 | -45.8 | 25 | 1013 | main | 1209 | 1157 | O_____________ | 16 | 271 |
118593 | 2017228N14314 | 2017 | 61 | HARVEY | Timestamp | (2017-08-16 09:00:00) | DS | 13.713 | -46.5999 | main | 1157 | 1109 | P_____________ | 16 | 270 | ||
118594 | 2017228N14314 | 2017 | 61 | HARVEY | Timestamp | (2017-08-16 12:00:00) | DS | 13.7 | -47.4 | 25 | 1010 | main | 1109 | 1067 | O_____________ | 16 | 268 |
118595 | 2017228N14314 | 2017 | 61 | HARVEY | Timestamp | (2017-08-16 15:00:00) | DS | 13.6497 | -48.2001 | main | 1057 | 1018 | P_____________ | 16 | 266 | ||
118596 | 2017228N14314 | 2017 | 61 | HARVEY | Timestamp | (2017-08-16 18:00:00) | DS | 13.6 | -49.0 | 25 | 1009 | main | 1018 | 986 | O_____________ | 16 | 268 |
¶Retrieve GOES16 Image
Now let’s grab a GOES16 image corresponding to Hurricane Harvey. It made landfall in Texas around August 25, 2017, so we’ll set the date for the image to be that day.
# Set image specific parameters bucketName = 'noaa-goes16' date = datetime.datetime(2017,8,25,18) product = 'ABI-L1b-RadF' credPath = "secrets.csv" band = 3 # Get the GOES data ds = goes.download_data(date,credPath,bucketName,product,band)
Next, let’s plot the GOES full disk image.
# Create plot fig, ax = plt.subplots(figsize=(10,10)); ax.imshow(ds.Rad, cmap='gray'); ax.set_title('GOES-16, '+date.isoformat(),fontsize=22); ax.axis('off'); # Save the figure plt.tight_layout() filePath = './images/goes_harvey_example.png' plt.savefig(filePath)
¶Overlay State and Country Borders with Basemap
Now let’s experiment with projections. To make sure we’ve got the projection right, we start by overlaying the boundaries of states, countries, and coastlines on the GOES imagery. In order to do so, we need to get the projection of the GOES data. This information is stored in the netCDF metadata, primarily as attributes for the variable goes_imager_projection
. So once we get the projection data, we’ll load this into the base map, and then the borders should be easily drawn using the base map utilities.
# Get dataset projection data satHeight = ds.goes_imager_projection.perspective_point_height satLon = ds.goes_imager_projection.longitude_of_projection_origin satSweep = ds.goes_imager_projection.sweep_angle_axis majorMinorAxes = (ds.goes_imager_projection.semi_major_axis,ds.goes_imager_projection.semi_minor_axis) # The projection x and y coordinates equals the scanning angle (in radians) multiplied by the satellite height x = ds.variables['x'][:] * satHeight y = ds.variables['y'][:] * satHeight # Set the geostationary projection m = Basemap(projection='geos', lon_0=satLon, rsphere=majorMinorAxes, resolution='i', area_thresh=5000, llcrnrx=x.min(),llcrnry=y.min(), urcrnrx=x.max(),urcrnry=y.max()) # Create the plot plt.figure(figsize=(10,10)) m.imshow(np.flipud(ds.Rad), cmap='gray'); m.drawcoastlines(); m.drawcountries(); m.drawstates(); plt.axis('off'); plt.title('GOES-16, '+date.isoformat(),fontsize=22); # Save the figure plt.tight_layout() filePath = './images/goes_harvey_projection_example.png' plt.savefig(filePath)
¶Overlay IBTRaCS Data
Now that we can see the projection is working properly, let’s add the Hurricane Harvey track as of August 25, 2017 at 18Z. We first need to grab the latitude longitudes from the IBTRaCS data. We can then use pyproj.Proj
to convert longitudes and latitudes to the \(x\) and \(y\) space of the projected GOES image.
I don’t fully understand why this is the case, but the netCDF \(x\) and \(y\) arrays go symmetrically from -5434394 to 5434394, but the basemap seems to span from 0 to 10868788. So to properly draw the tracks, we’ll need to add 5434394 to the output \(x\) and \(y\) of pyproj.Proj
for each longitude and latitude in the track.
# Get the latitudes/longitudes of the Hurricane Harvey track data df = df[df['ISO_TIME']<=date] latList = list(df['LAT']) lonList = list(df['LON']) # Create a pyproj geostationary map object p = Proj(proj='geos', h=satHeight, lon_0=satLon, sweep=satSweep) # Convert lon/lat to x/y xList,yList = p(lonList,latList) # Projected coordinates are negative, but matplotlib starts at 0. # Add half of the image width and height to properly draw on map xList = [point+float(x.max()) for point in xList] yList = [point+float(y.max()) for point in yList] # Add track to the basemap plot plt.figure(figsize=(10,10)) m.imshow(np.flipud(ds.Rad), cmap='gray'); m.drawcoastlines(); m.drawcountries(); m.drawstates(); m.plot(xList,yList,linewidth=2.5,color='r') plt.axis('off'); plt.title('GOES-16, '+date.isoformat(),fontsize=22); # Save the figure plt.tight_layout() filePath = './images/goes_harvey_projected_storm_track_example.png' plt.savefig(filePath)