The following demonstrator cracks open a time series of GOES-R (GOES-16, a.k.a., GOES-East) and displays the image as a series of time series.
The GOES Advanced Baseline Imager (ABI) is the primary operational imager aboard the new GOES R-series platforms.
GOES-16 data is available from the NOAA NESDIS CLASS Archiving and Server system in netCDF format. Images are available as mesoscale localized snapshoots that vary with needed focus (e.g., storm systems, hurricanes, etc.), full disk, half disk and the Contiguous US (CONUS) regions.
The 1-km resolution channels in this set are 1000x1000 pixels The 0.5-km resolution channels in this set are 1000x1000 pixels
This dataset is using the Mesoscale "floater" images over Hurricane Dorian as it approched landfall on the US Eastern Seaboard between 1500-1700 UTC 05 September 2019 (one-minute temporal resolution).
The following libraries are sourced here.
#############################################
#
# Load Python Libraries Because I am use to
# doing them up-front with NCAR Command Language
#
#
# Numerical Python
#
import numpy as np
#
# Matplotlib plotting libraries (accessed by xarray)
#
import matplotlib.pyplot as plt
#
# Remove File HTML Access
#
import urllib3 as ur
#
# Remove Xarray Scientific Data Model Access
#
import xarray as xr
#
# Remove Xarray Scientific Data Model Access
#
import datetime as dt
#
# Animation and Related Graphics Support
#
import matplotlib.animation as animation
import IPython.display as display
#
#############################################
SD Mines has a THREDDS Server to manage and dispence specific project data. The front page is found here at http://kyrill.ias.sdsmt.edu:8080/thredds with data accessable through OPeNDAP for data retrieval. The THREDDS Data Service also allows direct HTML as a plain file server.
Demonstrator data collected from the CLASS system is available here: http://kyrill.ias.sdsmt.edu:8080/thredds/catalog/HURRICANE_DORIAN/catalog.html
###################################################################
#
# URL Location for SD Mines Thredds Server for OPeNDAP Access
#
opendap_root = 'http://kyrill.ias.sdsmt.edu:8080/thredds/dodsC/HURRICANE_DORIAN/M1/'
tdshtml_root = 'http://kyrill.ias.sdsmt.edu:8080/thredds/fileServer/HURRICANE_DORIAN/M1/'
#
###################################################################
The user has the option of changing the channel by altering the _selectedchannel variable between API Bands 1 through 14.
ABI Band | Central Wavelength(µm) | Type | Nickname | Best Spatial Resolution (km) |
---|---|---|---|---|
1 | 0.47 | Visible | Blue | 1 |
2 | 0.64 | Visible | Red | 0.5 |
3 | 0.86 | Near-Infrared | Veggie | 1 |
4 | 1.37 | Near-Infrared | Cirrus | 2 |
5 | 1.6 | Near-Infrared | Snow/Ice | 1 |
6 | 2.2 | Near-Infrared | Cloud particle size | 2 |
7 | 3.9 | Infrared | Shortwave window | 2 |
8 | 6.2 | Infrared | Upper-level water vapor | 2 |
9 | 6.9 | Infrared | Midlevel water vapor | 2 |
10 | 7.3 | Infrared | Lower-level water vapor | 2 |
11 | 8.4 | Infrared | Cloud-top phase | 2 |
12 | 9.6 | Infrared | Ozone | 2 |
13 | 10.3 | Infrared | "Clean" longwave window | 2 |
14 | 11.2 | Infrared | Longwave window | 2 |
15 | 12.3 | Infrared | "Drity" longwave window | 2 |
16 | 13.3 | Infrared | CO2 longwave | 2 |
###################################################################
#
# Large List of Files Held on SD Mines Thredds Server
#
# (files produced on server with "ls -1 */*.nc" command
# and leaves a trailing line return tha tmust be removed)
#
selected_channel = 3 # two-digit with leading zero [index on 1]
channel_listfile = 'Image_List_C' + '{:02d}'.format(selected_channel) + '.txt'
channel_tdsurl = tdshtml_root + channel_listfile
#
# Lookup table for
#
wavelength = ['0',
'0.47 µm', # Visible Blue
'0.64 µm', # Visible Red
'0.86 µm', # Near-Infrared Vegetation
'1.37 µm', # Near-Infrared Cirrus
'1.6 µm', # Near-Infrared Snow/Ice
'2.2 µm', # Near-Infrared Cloud particle size
'3.9 µm', # Infrared Shortwave window
'6.2 µm', # Infrared Upper-level water vapor
'6.9 µm', # Infrared Midlevel water vapor
'7.3 µm', # Infrared Lower-level water vapor
'8.4 µm', # Infrared Cloud-top phase
'9.6 µm', # Infrared Ozone
'10.3 µm', # Infrared "Clean" longwave window
'11.2 µm', # Infrared Longwave window
'12.3 µm', # Infrared "Drity" longwave window
'13.3 µm'] # Infrared CO2 longwave
print('Processing Band ', selected_channel, ' (', wavelength[selected_channel], ')')
#
# pull large file list
#
http = ur.PoolManager()
response = http.request('GET', channel_tdsurl)
file_list = response.data.decode('utf-8').split("\n")
file_list = file_list[:len(file_list)-1] # Remove Blank Last Line
total_time_steps = len(file_list)
print("Total Number of Available Frames :", total_time_steps)
#
###################################################################
We're using a simple loop to produce a series of matplotlib.pyplot images
###################################################################
#
# Generate Figures for Each Image
#
for file in file_list :
full_url = opendap_root + file
image_file = xr.load_dataset(full_url)
time = image_file.t.values
image = image_file.Rad
image.plot(cmap='gray', vmin = 0)
plt.title("GOES-16 Channel " + str(selected_channel) + " (" + wavelength[selected_channel] + ") " + np.datetime_as_string(time, unit='m'))
plt.show()
figure_size = plt.rcParams["figure.figsize"]
#
###################################################################
Finally we are producing an amimated image of the satellite data.
Step one is to create the frame generating function.
###################################################################
#
# Create Image Frame Function for Animation
#
def update_goes_frame(time_step):
full_url = opendap_root + file_list[time_step]
image_file = xr.load_dataset(full_url)
time = image_file.t.values
image = image_file.Rad
plt.gcf().clf() # clear the current graph
image.plot(cmap='gray', vmin = 0)
plt.title("GOES-16 Channel " +
str(selected_channel) +
" (" +
wavelength[selected_channel]
+
") " +
np.datetime_as_string(time, unit='m'))
#
###################################################################
We now generate the figure itself
####################################################################
#
# Create the Animation Figure
#
print("Producing Animation (you need to be patient here)")
#
# We first create the subplot canvas
#
fig, ax = plt.subplots(figsize = figure_size)
#
# and here is where we create the animation
#
ani = animation.FuncAnimation(fig, # the graphical "device"
update_goes_frame, # the update "function"
frames=total_time_steps) # the loop to run through
#
# Drop to an animated GIF
#
ani.save(filename = './GOES-16_Dorian_CH-' +
'{:02d}'.format(selected_channel) +
'.gif',
writer = 'imagemagick')
#
# finally we can drop the animation into our Jupyter notebook.
#
# (this takes a while) It also doesn't always work for
# big figures
#
display.HTML(ani.to_html5_video())
#
###################################################################
################################################################
#
# Loading Version Information
#
%load_ext version_information
%version_information numpy, matplotlib, urllib3, xarray, datetime, version_information
#
################################################################