Custom Color Enhancement For GOES-16 Imagery

Received the following question:

I attended the Virtual Training on GEO Satellite Imagery Processing and I would like to combine the custom color scale from Script 08 with the reprojected imagery from Script 14. How can I do that?

Please find an example script below, with both concepts combined:

# Training: Python and GOES-R Imagery: Script 14 - Reprojection with GDAL
#-----------------------------------------------------------------------------------------------------------
# Required modules
from netCDF4 import Dataset # Read / Write NetCDF4 files
import matplotlib.pyplot as plt # Plotting library
from datetime import datetime # Basic Dates and time types
import cartopy, cartopy.crs as ccrs # Plot maps
import os # Miscellaneous operating system interfaces
from osgeo import osr # Python bindings for GDAL
from osgeo import gdal # Python bindings for GDAL
import numpy as np # Scientific computing with Python
from utilities import download_CMI # Our function for download
gdal.PushErrorHandler('CPLQuietErrorHandler') # Ignore GDAL warnings
#-----------------------------------------------------------------------------------------------------------
# Input and output directories
input = "Samples"; os.makedirs(input, exist_ok=True)
output = "Output"; os.makedirs(output, exist_ok=True)
# Desired extent
extent = [-64.0, -35.0, -35.0, -15.0] # Min lon, Max lon, Min lat, Max lat
# AMAZON repository information
# https://noaa-goes16.s3.amazonaws.com/index.html
bucket_name = 'noaa-goes16'
product_name = 'ABI-L2-CMIPF'
yyyymmddhhmn = '202102181800'
band = '13'
# Download the file
file_name = download_CMI(yyyymmddhhmn, band, input)
#-----------------------------------------------------------------------------------------------------------
# CUSTOM COLORMAP EXAMPLE 2
# Creating the INPE DISSM IR colormap
# Online color picker: https://imagecolorpicker.com/
from matplotlib import cm # Colormap handling utilities
vmin2 = -80 # Min. value
vmax2 = 40 # Max. value
gray_cmap = cm.get_cmap('gray_r', 120) # Read the reversed 'gray' cmap
gray_cmap = gray_cmap(np.linspace(0, 1, 120)) # Create the array
colors = ["#ffa0ff", "#0806ff", "#3bcfff", "#feff65", "#ff7516"] # Custom colors
my_colors = cm.colors.ListedColormap(colors) # Create a custom colormap
my_colors = my_colors(np.linspace(0, 1, 50)) # Create the array
gray_cmap[:50, :] = my_colors # Join both cmaps arrays
my_cmap2 = cm.colors.ListedColormap(gray_cmap) # Create the custom colormap
#-----------------------------------------------------------------------------------------------------------
# Variable
var = 'CMI'
# Open the file
img = gdal.Open(f'NETCDF:{input}/{file_name}.nc:' + var)
# Read the header metadata
metadata = img.GetMetadata()
scale = float(metadata.get(var + '#scale_factor'))
offset = float(metadata.get(var + '#add_offset'))
undef = float(metadata.get(var + '#_FillValue'))
dtime = metadata.get('NC_GLOBAL#time_coverage_start')
# Load the data
ds = img.ReadAsArray(0, 0, img.RasterXSize, img.RasterYSize).astype(float)
# Apply the scale, offset and convert to celsius
ds = (ds * scale + offset) - 273.15
# Read the original file projection and configure the output projection
source_prj = osr.SpatialReference()
source_prj.ImportFromProj4(img.GetProjectionRef())
target_prj = osr.SpatialReference()
target_prj.ImportFromProj4("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
# Reproject the data
GeoT = img.GetGeoTransform()
driver = gdal.GetDriverByName('MEM')
raw = driver.Create('raw', ds.shape[0], ds.shape[1], 1, gdal.GDT_Float32)
raw.SetGeoTransform(GeoT)
raw.GetRasterBand(1).WriteArray(ds)
# Define the parameters of the output file
kwargs = {'format': 'netCDF', \
'srcSRS': source_prj, \
'dstSRS': target_prj, \
'outputBounds': (extent[0], extent[3], extent[2], extent[1]), \
'outputBoundsSRS': target_prj, \
'outputType': gdal.GDT_Float32, \
'srcNodata': undef, \
'dstNodata': 'nan', \
'xRes': 0.02, \
'yRes': 0.02, \
'resampleAlg': gdal.GRA_NearestNeighbour}
# Write the reprojected file on disk
gdal.Warp(f'{output}/{file_name}_ret.nc', raw, **kwargs)
#-----------------------------------------------------------------------------------------------------------
# Open the reprojected GOES-R image
file = Dataset(f'{output}/{file_name}_ret.nc')
# Get the pixel values
data = file.variables['Band1'][:]
#-----------------------------------------------------------------------------------------------------------
# Choose the plot size (width x height, in inches)
plt.figure(figsize=(10,10))
# Use the Geostationary projection in cartopy
ax = plt.axes(projection=ccrs.PlateCarree())
# Define the image extent
img_extent = [extent[0], extent[2], extent[1], extent[3]]
# Define the color scale based on the channel
colormap = "gray_r" # White to black for IR channels
# Plot the image
img = ax.imshow(data, origin='upper', extent=img_extent, vmin=vmin2, vmax=vmax2, cmap=my_cmap2)
# Add coastlines, borders and gridlines
ax.coastlines(resolution='10m', color='white', linewidth=0.8)
ax.add_feature(cartopy.feature.BORDERS, edgecolor='white', linewidth=0.5)
gl = ax.gridlines(crs=ccrs.PlateCarree(), color='gray', alpha=1.0, linestyle='--', linewidth=0.25, xlocs=np.arange(-180, 180, 5), ylocs=np.arange(-90, 90, 5), draw_labels=True)
gl.top_labels = False
gl.right_labels = False
gl.xpadding = -100
gl.ypadding = -100
gl.xlabel_style = {'color': 'red'}
gl.ylabel_style = {'color': 'red'}
# Add a colorbar
plt.colorbar(img, label='Brightness Temperatures (°C)', extend='both', orientation='horizontal', pad=0.05, fraction=0.05)
# Extract the date
date = (datetime.strptime(dtime, '%Y-%m-%dT%H:%M:%S.%fZ'))
# Add a title
plt.title('GOES-16 Band 13 ' + date.strftime('%Y-%m-%d %H:%M') + ' UTC', fontweight='bold', fontsize=10, loc='left')
plt.title('Reg.: ' + str(extent) , fontsize=10, loc='right')
#-----------------------------------------------------------------------------------------------------------
# Save the image
plt.savefig(f'{output}/{file_name}_ret.png', bbox_inches='tight', pad_inches=0, dpi=300)
# Show the image
plt.show()

Cropping GOES-16 Derived Stability Indices

Received the following question:

I would like to crop the GOES-16 DSIF files for an specific region (based on lat lon coordinates), but I do not know how to determine the x and y intervals. Do you have an example script for this?

Please find below an example script. The conversion between lat / lons and GOES-R x / y (seen on the utilities.py script) may be found on the GOES-R Series PUG, page 21.

# Python and GOES-R Imagery Exampe: Cropping the DSIF imagery
#-----------------------------------------------------------------------------------------------------------
# Required modules
from netCDF4 import Dataset # Read / Write NetCDF4 files
import matplotlib.pyplot as plt # Plotting library
from datetime import datetime # Basic Dates and time types
import cartopy, cartopy.crs as ccrs # Plot maps
import os # Miscellaneous operating system interfaces
from utilities import download_CMI # Our own utilities
from utilities import geo2grid, convertExtent2GOESProjection # Our own utilities
#-----------------------------------------------------------------------------------------------------------
# Input and output directories
input = "Samples"; os.makedirs(input, exist_ok=True)
output = "Output"; os.makedirs(output, exist_ok=True)
# Desired extent
extent = [-64.0, -36.0, -40.0, -15.0] # Min lon, Max lon, Min lat, Max lat
#-----------------------------------------------------------------------------------------------------------
# Open the GOES-R image
file = Dataset('OR_ABI-L2-DSIF-M6_G16_s20210632010164_e20210632019472_c20210632020547.nc')
# Convert lat/lon to grid-coordinates
lly, llx = geo2grid(extent[1], extent[0], file)
ury, urx = geo2grid(extent[3], extent[2], file)
# Get the pixel values
data = file.variables['CAPE'][ury:lly, llx:urx]
#-----------------------------------------------------------------------------------------------------------
# Compute data-extent in GOES projection-coordinates
img_extent = convertExtent2GOESProjection(extent)
#-----------------------------------------------------------------------------------------------------------
# Choose the plot size (width x height, in inches)
plt.figure(figsize=(10,10))
# Use the Geostationary projection in cartopy
ax = plt.axes(projection=ccrs.Geostationary(central_longitude=-75.0, satellite_height=35786023.0))
# Define the color scale based on the channel
colormap = "jet" # White to black for IR channels
# Plot the image
img = ax.imshow(data, origin='upper', extent=img_extent, cmap=colormap)
# Add coastlines, borders and gridlines
ax.coastlines(resolution='10m', color='black', linewidth=0.8)
ax.add_feature(cartopy.feature.BORDERS, edgecolor='black', linewidth=0.5)
ax.gridlines(color='black', alpha=0.5, linestyle='--', linewidth=0.5)
# Add a colorbar
plt.colorbar(img, label='CAPE', extend='both', orientation='horizontal', pad=0.05, fraction=0.05)
# Extract the date
date = (datetime.strptime(file.time_coverage_start, '%Y-%m-%dT%H:%M:%S.%fZ'))
# Add a title
plt.title('GOES-16 CAPE ' + date.strftime('%Y-%m-%d %H:%M') + ' UTC', fontweight='bold', fontsize=10, loc='left')
plt.title('Reg.: ' + str(extent) , fontsize=10, loc='right')
#-----------------------------------------------------------------------------------------------------------
# Save the image
plt.savefig(f'OR_ABI-L2-DSIF-M6_G16_s20210632010164_e20210632019472_c20210632020547.png', bbox_inches='tight', pad_inches=0, dpi=300)
# Show the image
plt.show()

You may find the utilities.py script, used in this example, at this link.

Reading MODIS / TERRA HDF Files with PyHDF

Received the following question:

I’m trying to process MODIS / TERRA “MOD14” data (Thermal Anomalies / Fires) downloaded from: https://ladsweb.modaps.eosdis.nasa.gov/search/

These images are in the HDF format. Do you have any examples to read it with Python and PyHDF?

Yes! The former Blended TPW files from GNC-A were HDF’s and I had to use PyHDF to read them. Please find an example code below, which worked with a MODIS sample downloaded from the provided link:

from pyhdf.SD import SD, SDC # Import the HDF library
# Reading the file:
path = "MOD14.A2021085.0315.006.2021085095713.hdf"
file = SD(path, SDC.READ)
# Printing all the datasets names
datasets_dic = file.datasets()
for idx,sds in enumerate(datasets_dic.keys()):
print (idx,sds)
# Reading the dataset
sds_obj = file.select('fire mask') # select sds
data = sds_obj.get() # get sds data
# Check the dimensions
print(data.shape)

Hint: If you want to quickly check the content of HDF, NetCDF or GRIB files without programming, I recommend using NASA’s Panoply:

https://www.giss.nasa.gov/tools/panoply/

Presentations From The 9th GEONETCast-Americas User Group Webinar

GNC UGW.png

Hi GEONETCasters!

Please find below the presentations from the 9th GEONETCast-Americas User Group Webinar (click on the images to download):

NOAA UPDATES

INPE UPDATES

GNC-A USER CASE STUDIES

MARN – MINISTRY OF ENVIRONMENT AND NATURAL RESOURCES – EL SALVADOR

Thank you to all the participants!

Please find the presentations from the other GEONETCast-Americas User Group Webinars, at the following links:

Reminder: 9th GEONETCast-Americas User Group Webinar

GNC UGW.png

GEONETCasters;

Save the date! We hope to see you there.

We have scheduled the next GNC-A User Group Meeting Webex/Telecon to be held on March 25th, 2021 at 11:00 EDT / 15:00 UTC to 12:30 EDT / 16:30 UTC.

Webex Link:

 https://spsd.webex.com/spsd/j.php?MTID=mbcef1b910764c1f370d302353830c0af

Meeting Number: 198 124 3991

Meeting Password: gnc1

Join by Phone Info: +1-415-527-5035 US Toll
Access code: 198 124 3991

We ask that attendees use the Webex VOIP or the above number to join the webex.

The slides will be sent out shortly before the meeting.

Tentative Agenda:
1. Opening remarks/role call
2. NOAA updates
3. GNC-A Broadcast Status
4. INPE updates
5. User case study
6. User Outreach

New SHOWCast Release: v 2.3.0

Esta imagem possuí um atributo alt vazio; O nome do arquivo é showcast_logo.png

Please download SHOWCast v.2.3.0 at the link below:

SHOWCast v 2.3.0 Download

SHOWCast v 2.3.0 product selection interface

Changes on this version:

  • GFS data processing and visualization

In this initial set, the following plots / scripts are provided: 2 m Temperature, Total Precipitation, PSML + Winds (850 hPa), Galvez Davison Index (GDI), Relative Vorticity + Geopotential Height (500 hPa), PSML + Geopotential Difference (1000 – 850 hPa) + Winds (925 hPa) + Mean RH (1000~400 hPa), Precipitable Water + CAPE, Low-Middle-High Clouds, Wind Speed and Direction (500 to 850 hPa).

By default, only the analysis is plotted, and users may change the configuration on the gfs scripts. In the example below, the GFS plots will be made from 00 h (analysis) until 90 h, with 3 h intervals. In order to plot only the analysis, just leave “hour_end” and “hour_inc” with the same value.

Configuring the GFS plots in SHOWCast
GFS processing scripts provided in SHOWCast v2.3.0

Note: In the showcast_config.py please select as “True” OR South America OR Central America + Caribbean.

  • 20 second GLM data processing, accumulation, and visualization
  • GLM density (10 min in this example) being visualized on SHOWCast

    Note: By default, for the density and heatmap products the GLM data is accumulated every 10 minutes. Users may change that if needed, in the “acum_minutes” variable:

    • Forecast charts visualization
    Quantitative Precipitation Forecast being visualized
    • NWS ISCS “International Services and Communication Systems” data filtering and display

    In this initial set, at the showcast_config.py script, users may select to process the following ISCS data: SYNOP, DRIFTING BUOYS, METAR, SPECI, TAF, SIGMETS, AIRMETS, VOLCANIC ASH and TSUNAMI Warnings. At the “identifier” variable for each product, users may select the WMO Country Territory Designators: https://www.weather.gov/tg/tablec1

    ISCS Data Selection Menu
    METAR messages being visualized for Argentina in this example
    • Blended TOAST (Ozone) processing and visualization

    Please find below the procedure to install SHOWCast v 2:

    SHOWCast 2 Installation Procedure

    Please find below previous posts about SHOWCast:

    GNC-A GOES Product Outage

    There will be a GOES outage today at 1400Z that will last for 6 hours until 2000Z. This will affect all CMI and non-CMI full disk imagery for both GOES-16 and GOES-17, as well as the 20-second GLM data provided by NESDIS. The 5-minute aggregated INPE provided GLM product will still be available as well as all the other non-NOAA data products.

    During the outage, users have the option to use the SHOWCast Cloud module, to download data automatically from AWS or UNIDATA THREDDS.

    SHOWCast_Cloud_1

    GFS Processing / Visualization Being Added to SHOWCast [2]

    Stay tuned for news!