Cropping GOES Imagery from IBTrACS

Introduction

Now that we can properly project and cross-reference GOES data, let’s try using the IBTrACS data to find where the storm is on an image and crop the image. We’ll use the same example, Hurricane Harvey in 2017, to drive the example here again.

In hindsight, I realize that this isn’t very different from the previous notebook. I started this notebook because I need a way to identify if a point in latitude/longitude space in the IBTrACS data was actually on the visible full disc GOES image. I had started this complicated method where I convert every pixel in the GOES image into a meshed grid of latitudes/longitudes, find the closest latitude and logitude in the image to the IBTrACS latitude and longitude, and then use that to determine whether or not the IBTrACS point was on the image. But performing calculations and comparisons on 10000 by 10000 element arrays is quite cumbersome. Then I realized that I can do it the other way - convert the latitude/longitude to the GOES projection and then find its closest point in the much smaller 10000 by 1 \(x\) and \(y\) arrays stored in the GOES netCDF file. I think I’ll still have to use the meshed grid to see if the closest point is on the disc, but this will now be a much shorter process, since I don’t need to find the closest latitude and longitude on that large array.

Import Functions

Let’s import functions we’ll need. I’ve also created functions to handle some of the code from the previous steps.

# Import modules
import datetime
import numpy as np
import os
from pyproj import Proj
import matplotlib.pyplot as plt

# Import functions I've written
os.chdir("..")
import goes
import ibtracs

Read IBTrACS Data

Now let’s read in the IBTrACS data, separating out Hurricane Harvey in 2017.

ibtracsPath = ibtracs.download_data(basin="NA",overwrite=False)
dfTracks = ibtracs.read_data(ibtracsPath,True,2017,2017)
dfTracks = dfTracks[dfTracks["NAME"]=="HARVEY"]
dfTracks.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

Fetch GOES16 Imagery

Now we’ll fetch the same GOES16 image as last time.

# 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)

Define Projections and Locate the Storm

We need to find the location of the IBTrACS data in the image, so we’ll convert the storm’s latitude and longitude into the same projection as the GOES imagery, identify the storm center on the image, and then plot a cropped storm with a buffer around the center of the storm.

# Get the latitudes/longitudes of the Hurricane Harvey track data
dfTracks = dfTracks[dfTracks['ISO_TIME']==date]
trackLat = dfTracks['LAT'].astype(float)
trackLon = dfTracks['LON'].astype(float)

# 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)

# Create a pyproj geostationary map object
p = Proj(proj='geos', h=satHeight, lon_0=satLon, sweep=satSweep)

# Convert lon/lat to x/y
trackX,trackY = p(trackLon,trackLat)

# 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

# Get the closest point to the IBTrACS data
xInd = np.nanargmin(abs(x-trackX))
yInd = np.nanargmin(abs(y-trackY))

# Plot a cropped with a buffer around the closest point of the storm
buffer = 300
plt.figure(figsize=(10,10));
plt.imshow(ds.Rad[yInd-buffer:yInd+buffer,xInd-buffer:xInd+buffer], cmap='gray');
plt.axis('off');
plt.title('Hurricane Harvey from GOES-16, '+date.strftime("%m/%d/%Y")+" at "+str(date.hour)+"Z",fontsize=18);

# Save the figure
plt.tight_layout()
filePath = './images/goes_harvey_projection_cropped.png'
plt.savefig(filePath)

goes_harvey_projection_cropped.png