71. Assignment 8 solution#
upload a notebook that
overlays your radar cases’s ground track on the nearest GOES cloud height image using the code in goes-earthcare overlay
Add a function that locates image row/column values along the radar lat/lon coordinates of the GOES height image. Use it to produce a height/distance plot that shows the radar reflectivity image with the colocated GOES HT heights overlaid as a line on the image. Do GOES and earthcare agree on the location of cloudtop?
71.1. Installation#
fetch and rebase to pick up the week13 folder with this ipynb file
I modified the end of the goes-earthcare overlay notebook to produce a new file called clipped_goes.tif which needs to be copied to
~/repos/a301/satdata/earthcare. In that file I also included the cartopy CRS so I could make a map of the GOES heights to show how to debug the satellite track.
71.2. Workflow#
Get the radar groundtrack
Read the GOES heights from
clipped_goes.tifFind the row, column on the image for every radar lat,lon point
Plot the radar reflectivity and add the GOES height lin for each of those points
71.3. Debugging#
In the last section I show how to plot the radar groundtrack on the satellie image, by setting the row, column pixels along the groundtrack to a high value show they show up.
from pathlib import Path
import xarray as xr
import numpy as np
import pyproj
from matplotlib import pyplot as plt
import datetime
import pytz
import pandas as pd
from pyproj import CRS, Transformer
import affine
from a301_extras.sat_lib import make_new_rioxarray
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import rioxarray
import xarray as xr
running __init__.py
/Users/phil/mini310/envs/a301/lib/python3.13/site-packages/goes2go/data.py:673: FutureWarning: 'H' is deprecated and will be removed in a future version. Please use 'h' instead of 'H'.
within=pd.to_timedelta(config["nearesttime"].get("within", "1h")),
/Users/phil/mini310/envs/a301/lib/python3.13/site-packages/goes2go/NEW.py:185: FutureWarning: 'H' is deprecated and will be removed in a future version. Please use 'h' instead of 'H'.
within=pd.to_timedelta(config["nearesttime"].get("within", "1h")),
data_dir = Path().home() / 'repos/a301/satdata/earthcare'
radar_filepath = list(data_dir.glob("**/*.nc"))[0]
radar_ds = xr.open_dataset(radar_filepath)
casenum = radar_ds.attrs['casenum']
radar_ds
<xarray.Dataset> Size: 21MB
Dimensions: (height: 218, distance: 8021)
Coordinates:
* height (height) float64 2kB 2.019e+04 2.009e+04 ... -1.494e+03
* distance (distance) float64 64kB 0.0 0.5027 1.006 ... 4.172e+03 4.172e+03
Data variables:
dbZ (height, distance) float32 7MB ...
velocity (height, distance) float32 7MB ...
binHeights (height, distance) float32 7MB ...
longitude (distance) float64 64kB ...
latitude (distance) float64 64kB ...
time (distance) datetime64[ns] 64kB ...
Attributes:
history: written by ec_to_xarray on 2025-03-29 09:50:41.584666
timezone: UTC
casenum: case471.3.1. Get the radar ground track#
latvec = radar_ds.latitude
lonvec = radar_ds.longitude
71.4. open clipped ht file#
ht_filepath = list(data_dir.glob("**/*.tif"))[0]
ht_filepath
PosixPath('/Users/phil/repos/a301/satdata/earthcare/clipped_goes.tif')
goes_ht = rioxarray.open_rasterio(ht_filepath).squeeze()
goes_ht.plot.imshow();
71.5. get row,column from lat,lon#
71.5.1. Function get_rowcol#
fixed 2025/4/9 – swapped row,col, then swapped back again
reuse code from goes-earthcare overlay and Comparing cloudtop and 11 \mu m temperatures
affine_transform = goes_ht.rio.transform()
goes_crs = goes_ht.rio.crs
latlon_crs = pyproj.CRS.from_epsg(4326)
goes_latlon_xy = Transformer.from_crs(latlon_crs, goes_crs,always_xy=True)
x_goes,y_goes = goes_latlon_xy.transform(lonvec,latvec)
def get_rowcol(affine_transform,x_coords,y_coords):
image_col, image_row = ~affine_transform * (x_coords,y_coords)
image_col = np.round(image_col).astype(np.int32)
image_row = np.round(image_row).astype(np.int32)
return image_col,image_row
track_col, track_row = get_rowcol(affine_transform,x_goes,y_goes)
71.6. Sample GOES heights along track#
the_heights = []
for col, row in zip(track_col, track_row):
the_heights.append(goes_ht[row,col].data)
71.7. Add to the radar reflectivity plot#
Not sure why GOES doesn’t see the cloud at 600 km, but overall good agreement. Notice that the GOES estimates are about 200 meters below the radar cloud top.
fig, ax = plt.subplots(1,1,figsize=(12,3))
radar_ds['dbZ'].plot(ax = ax, x="distance",y="height",vmin=-3,vmax=25);
ax.plot(radar_ds['distance'],the_heights,'r-')
ax.set_ylim(0,15000)
ax.set_xlabel("distance (km)")
ax.set_ylabel("height (m)")
ax.set_title(f"{casenum}");
71.8. To debug: check against image#
If GOES and the radar are not close to each other, then it might help to
see the radar track on the GOES image. To do that, use imshow to
show the heights, but modified the pixel values along the groundtrack
so the are clear in the image.
71.8.1. Make groundtrack heights stand out#
Set all the pixels along the ground track to 20000 m.
for col, row in zip(track_col, track_row):
goes_ht[row,col]=20000
71.8.2. Plot the modified image#
xmin = -145 #longitude degrees east
xmax = -85.
ymax = 70 #latitude degrees north
ymin = 20
xmin_goes,ymin_goes = goes_latlon_xy.transform(xmin,ymin)
xmax_goes,ymax_goes = goes_latlon_xy.transform(xmax,ymax)
extent = (xmin_goes,xmax_goes,ymin_goes,ymax_goes)
def make_cartopy_crs(wkt_string):
"""
Hack to solve cartopy bug which prevents it from using
pyproj CRS objects directly. I create the pyproj crs then
take it apart as a dictionary and put it back together
as a cartopy crs
"""
bad_cartopy_crs = ccrs.Projection(wkt_string)
terms=bad_cartopy_crs.to_dict()
globe_kwargs = dict(semimajor_axis = terms['a'],
semiminor_axis=6356752.3141,
inverse_flattening = terms['rf'])
crs_kwargs = dict(central_longitude = terms['lon_0'],
satellite_height = terms['h'],
sweep_axis = 'x')
globe=ccrs.Globe(ellipse=None, **globe_kwargs)
cartopy_crs = ccrs.Geostationary(**crs_kwargs,globe=globe)
return cartopy_crs
71.8.3. Use the CRS I wrote out in the tif file#
wkt_string = goes_ht.attrs['cartopy_crs']
extent = (xmin_goes,xmax_goes,ymin_goes,ymax_goes)
cartopy_crs = make_cartopy_crs(wkt_string)
fig,ax = plt.subplots(1,1,figsize=(10,8),subplot_kw={'projection':cartopy_crs})
goes_ht.plot.imshow(
ax = ax,
origin="upper",
extent= extent,
transform=cartopy_crs,
interpolation="nearest",
vmin=0,
vmax=16000
);
ax.coastlines(resolution="50m", color="black", linewidth=2)
ax.add_feature(ccrs.cartopy.feature.STATES,edgecolor="red")
/Users/phil/mini310/envs/a301/lib/python3.13/site-packages/pyproj/crs/crs.py:1295: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems
proj = self._crs.to_proj4(version=version)
<cartopy.mpl.feature_artist.FeatureArtist at 0x15a16c690>