Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nice combo example #136

Open
dopplershift opened this issue May 17, 2023 · 1 comment
Open

Nice combo example #136

dopplershift opened this issue May 17, 2023 · 1 comment

Comments

@dopplershift
Copy link
Member

dopplershift commented May 17, 2023

Capturing this since I'm posting the image to MetPy Twitter. This needs Unidata/MetPy#3000.

from datetime import datetime

import cartopy.crs as ccrs
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
from metpy.io import parse_metar_file
import metpy.plots as mpplots
from metpy.remote import GOESArchive
import numpy as np
from siphon.catalog import TDSCatalog
import xarray as xr

# Parse the mesoscale discussion bounds
md_text = ('37190506 37460487 37670470 37810422 37860215 37720171 '
           '36970146 36160161 35430215 35170275 35700516 36000550 '
           '36730529 37190506')
md_time = datetime(2023, 5, 17, 18, 29)
md_pts = np.array([(int('-1' + item[-4:]) / 100, int(item[:4]) / 100) for item in md_text.split()])

# Grab the corresponding visible satellite image
prod = GOESArchive(satellite=16).get_product('ABI-L1b-RadC', md_time, channel=2)
vis_img = prod.parse().metpy.parse_cf('Rad')

# Get some METAR data
metar_cat = TDSCatalog('https://thredds.ucar.edu/thredds/catalog/noaaport/text/metar/catalog.xml')
sfc_obs = parse_metar_file(metar_cat.datasets.filter_time_nearest(md_time).remote_open(mode='t'))

# Keep only a single ob per station
sfc_obs = sfc_obs.set_index('date_time').groupby('station_id').first()

# Get MRMS data--need to work around some xarray + TDS incompatibilities
mrms_cat = TDSCatalog('https://thredds-test.unidata.ucar.edu/thredds/catalog/grib/NCEP/MRMS/CONUS/BaseRef/MRMS_CONUS_BaseReflectivity_20230517_1800.grib2/catalog.xml')
opendap_url = mrms_cat.datasets[0].access_urls['OPENDAP']
nc = xr.open_dataset(opendap_url, drop_variables='reftime')
ref = nc.metpy.parse_cf('MergedBaseReflectivityQC_altitude_above_msl')

# Select the data that matches our MD time. Also only plot > 25 dBz
ref = ref.sel(reftime4=md_time, method='nearest').squeeze()
ref.data[ref < 25] = np.nan

# Generate a base figure
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.LambertConformal(central_longitude=-102, central_latitude=37))
ax.set_extent((-107, -100, 34, 39))

# Plot satellite and radar as images
ax.imshow(vis_img, extent=(vis_img.metpy.x[0], vis_img.metpy.x[-1], vis_img.metpy.y[0], vis_img.metpy.y[-1]),
          cmap='gray', transform=vis_img.metpy.cartopy_crs, origin='lower')
ref_norm, ref_cmap = mpplots.colortables.get_with_steps('NWSStormClearReflectivity', -20, 0.5)
ax.imshow(ref,
          extent=(ref.metpy.x[0] - 360, ref.metpy.x[-1] - 360, ref.metpy.y[0], ref.metpy.y[-1]),
          transform=ref.metpy.cartopy_crs, cmap=ref_cmap, norm=ref_norm, origin='lower')

# Add base map features
ax.add_feature(mpplots.USCOUNTIES, edgecolor='lightgrey', linewidth=0.5)
ax.add_feature(mpplots.USSTATES)

# Plot the surface data
sp = mpplots.StationPlot(ax, sfc_obs.longitude, sfc_obs.latitude, transform=ccrs.PlateCarree(), clip_on=True)
sp.plot_parameter('NW', sfc_obs.air_temperature, color='red')
sp.plot_parameter('SW', sfc_obs.dew_point_temperature, color='green')
sp.plot_symbol('C', sfc_obs.cloud_coverage, mpplots.sky_cover)
sp.plot_barb(sfc_obs.eastward_wind, sfc_obs.northward_wind)

# Plot the MD
md = mpatches.Polygon(md_pts, transform=ccrs.PlateCarree(), path_effects=[mpplots.ScallopedStroke()],
                      edgecolor='brown', facecolor='none', linewidth=2)
ax.add_artist(md)

# Add a bit more decoration
ax.set_title(f'SPC Mesoscale Discussion Valid: {md_time:%Y-%m-%d %H:%M}Z')
mpplots.add_metpy_logo(fig, 25, 20, size='small')

This plots satellite, MRMS radar, surface obs, and a mesoscale discussion boundary. Would be better to have an automated source for us to pull the MD location.

@deeplycloudy
Copy link
Contributor

deeplycloudy commented May 26, 2023

Here is code for adding GLM flash and group centroid locations, also using the NOAA S3 archive.

In the 5 min window I used, there's lots of flashes, so it swamps the MRMS display at this scale.

# Grab the corresponding GLM data in the 5 min window before the MD.
glm_window = timedelta(minutes=5) # We want this much data
glm_prod_length = timedelta(seconds=20) # LCFA files are always 20s long
n_glm = int(glm_window/glm_prod_length)
glm_prod_times = [md_time - ti*glm_prod_length for ti in range(n_glm)][::-1]
glm_prods = [GOESArchive(satellite=16).get_product('GLM-L2-LCFA', ti).parse() for ti in glm_prod_times]

# Plot GLM
for glm in glm_prods:
    ax.plot(glm.flash_lon, glm.flash_lat, marker='D', color='w', markersize=4, linewidth=0, transform=ccrs.PlateCarree())
    ax.plot(glm.group_lon, glm.group_lat, marker='s', color='y', markersize=2, linewidth=0, transform=ccrs.PlateCarree())

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants