Re: [python-users] MetPy NEXRAD Level 2 - Can get lat, lon out to use for plotting map?

  • To: Brian Blaylock <blaylockbk@xxxxxxxxx>
  • Subject: Re: [python-users] MetPy NEXRAD Level 2 - Can get lat, lon out to use for plotting map?
  • From: Ryan Connelly <rconne01@xxxxxxxxx>
  • Date: Tue, 25 Apr 2017 18:39:07 -0400
Hi Kevin and Brian,

I used Brian's script, which successfully georeferences the radar data.
But I'm still not getting my Cartopy features to show up.  I would just use
Basemap, except that that throws an error:

AttributeError: 'GeoAxesSubplot' object has no attribute 'drawcoastlines'.


I've attached my modified version of the code, as well as an example plot.

Thanks,
Ryan

On Tue, Apr 25, 2017 at 11:06 AM, Brian Blaylock <blaylockbk@xxxxxxxxx>
wrote:

> Hi Ryan,
>
> I was just about to reply, when I saw Kevin's email. I did what he
> suggested (using pyproj to convert the range and azimuth to a latitude
> longitude). I documented my method here: http://kbkb-wx-python.
> blogspot.com/2016/07/plotting-radar-data-with-metpy-pyproj.html
>
>
>  *Brian*
>
> On Mon, Apr 24, 2017 at 4:36 PM, Ryan Connelly <rconne01@xxxxxxxxx> wrote:
>
>> Hi,
>>
>> Using this code:
>> https://unidata.github.io/MetPy/examples/formats/NEXRAD_Leve
>> l_2_File.html#sphx-glr-examples-formats-nexrad-level-2-file-py
>>
>> Ideally, I should be able to just extract a lat and a lon variable from
>> the file, except that I don't know if they exist, and if they do, what
>> their names are.
>>
>> From there, I'd like to plot the georeferenced data over a base map using
>> CartoPy.  Is this possible?  (I just happen to already have some shapefiles
>> on hand that I want to use that I know CartoPy can read in.)
>>
>> Thanks,
>> Ryan
>>
>> --
>> Ryan Connelly
>> M.S. Student in Atmospheric Sciences, Stony Brook University
>> B.S. in Meteorology with Minors in Mathematics and GIS, Valparaiso
>> University
>> rconne01@xxxxxxxxx
>> ryan.connelly@xxxxxxxxxxxxxx
>>
>> _______________________________________________
>> NOTE: All exchanges posted to Unidata maintained email lists are
>> recorded in the Unidata inquiry tracking system and made publicly
>> available through the web.  Users who post to any of the lists we
>> maintain are reminded to remove any personal information that they
>> do not want to be made public.
>>
>>
>> python-users mailing list
>> python-users@xxxxxxxxxxxxxxxxxxxxxxxx
>> For list information, to unsubscribe, or change your membership options,
>> visit: http://www.unidata.ucar.edu/mailing_lists/
>>
>
>


-- 
Ryan Connelly
M.S. Student in Atmospheric Sciences, Stony Brook University
B.S. in Meteorology with Minors in Mathematics and GIS, Valparaiso
University
rconne01@xxxxxxxxx
ryan.connelly@xxxxxxxxxxxxxx

Attachment: 2014-06-18 03:34:04_REF_ElvAngle_0.48.png
Description: PNG image

import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from numpy import ma
import cartopy.feature as cfeature
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
import pyproj
import sys
from pyproj import Geod
from metpy.cbook import get_test_data
from metpy.io import Level2File
from metpy.plots import ctables
import os
import datetime
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from mpl_toolkits.basemap import Basemap

def getProjection():
    proj = ccrs.LambertConformal(central_latitude=43.6,
        central_longitude=-97.,
        standard_parallels=[43.5,43.7])
    return proj

def get_refl_cmap():
    'Custom colormap'
    color_map = [[245,245,245], #  0.0
                 [127, 0, 255], # 18.0-20.0
                 [102,178,255], # 20.0-22.0
                 [  0, 0, 204], # 28.0
                 [  0, 77,  0], # 30.0-32.0
                 [  0,255,  0], # 38.0
                 [255,230,  0], # 40.0
                 [255,100, 51], # 48.0
                 [255,  0,  0], # 50.0
                 [102,  0,  0], # 58.0
                 [102,  0, 51], # 60.0
                 [255,  0,128]] # 68.0-70.0
    n_bins = [-10.000, 8.000, 10.000, 28.000, 29.000, 38.000, 39.000, 48.000, 
50.000, 58.000,
               60.000, 68.000]

    n_bins = [(l-n_bins[0]) for l in n_bins]
    n_bins = [(l/n_bins[-1]) for l in n_bins]
    color_map = [tuple([float(j)/255. for j in l]) for l in color_map]
    color_map = list(zip(n_bins,color_map))
    cmap = 
mpl.colors.LinearSegmentedColormap.from_list('ryan_dbz',color_map,N=81)
    return cmap

def get_vel_cmap():
    'Custom colormap'
    color_map = [[  0,  0,255], # -100 kts
                 [  0,255,255], # -75 kts
                 [  0,255,  0], # -50 kts
                 [  0,100,  0], # -25 kts
                 [ 80,100, 80], # -5 kts
                 [255,255,255], # 0 kts
                 [ 80, 60, 60], # 5 kts
                 [ 80,  0,  0], # 25 kts
                 [255,  0,  0], # 50 kts
                 [255,100,  0], # 75 kts
                 [255,255,  0]] # 100 kts
    n_bins = [-100.000, -75.000, -50.000, -25.000, -5.000, 0.000, 5.000, 
25.000, 50.000, 75.000,
               100.000]

    n_bins = [(l-n_bins[0]) for l in n_bins]
    n_bins = [(l/n_bins[-1]) for l in n_bins]
    color_map = [tuple([float(j)/255. for j in l]) for l in color_map]
    color_map = list(zip(n_bins,color_map))
    cmap = 
mpl.colors.LinearSegmentedColormap.from_list('ryan_dbz',color_map,N=201)
    return cmap

def main(argv):

    #### Some Settings
    radar = 'KFSD'
    date = datetime.datetime(2014,6,18,3,34,4)

    #file name example: KCBX20160805_205859_V06
    #filename = '%s%04d%02d%02d_%02d%02d%02d_V06' % (radar, 
date.year,date.month,date.day,date.hour,date.minute,date.second)

    f = Level2File('KFSD20140618_033404_V06.gz')

    rLAT = f.sweeps[0][0][1].lat
    rLON = f.sweeps[0][0][1].lon
    rDT = f.dt # this is in local time


    ## Create Figure and plot the background image outside the loop.
    ## Then, in each loop, we'll remove the radar data after we plotted and 
saved.

    ### ---------------- Create Basemap -------------------------
#    fig = plt.figure(1,figsize=[8,8])
#    ax  = fig.add_subplot(111)
    top_right_lat = rLAT+1.25
    top_right_lon = rLON+1.25
    bot_left_lat = rLAT-1
    bot_left_lon = rLON-1

    fig = plt.figure(figsize=(10,8))
    ax = fig.add_subplot(2,1,1,projection=getProjection(),anchor='S')
    ax.set_position([0.08,0.09,0.84,0.85],which='both')
    ax.outline_patch.set_linewidth(1.0)
    ax.outline_patch.set_zorder(1)

    ## Map in cylindrical projection
    #m = Basemap(resolution='i',projection='cyl',\
    #  llcrnrlon=bot_left_lon,llcrnrlat=bot_left_lat,\
    #  urcrnrlon=top_right_lon,urcrnrlat=top_right_lat,)
    #maps = [
    #  'ESRI_Imagery_World_2D',    # 0
    #  'ESRI_StreetMap_World_2D',  # 1
    #  'NatGeo_World_Map',         # 2
    #  'NGS_Topo_US_2D',           # 3
    #  'Ocean_Basemap',            # 4
    #  'USA_Topo_Maps',            # 5
    #  'World_Imagery',            # 6
    #  'World_Physical_Map',       # 7
    #  'World_Shaded_Relief',      # 8
    #  'World_Street_Map',         # 9
    #  'World_Terrain_Base',       # 10
    #  'World_Topo_Map'            # 11
    #  ]
    
    lakes1 = cfeature.NaturalEarthFeature(category='physical',
        name='lakes',scale='10m',facecolor='#ffffff',edgecolor='#999999')
    lakes2 = cfeature.NaturalEarthFeature(category='physical',
        name='lakes',scale='10m',facecolor='none',edgecolor='#999999')

    # U.S. Counties require a custom shapefile
    counties = 'cb_2016_us_county_5m.shp'
    # Census Bureau counties don't line up with cartopy states, so just use 
Census states too
    # It actually runs significantly faster this way anyway
    states = 'cb_2016_us_state_5m.shp'

    # Plot features on map using zorder
    # Leave zorder=3 for plotted vars
    ax.add_geometries(Reader(counties).geometries(),
                  ccrs.PlateCarree(),
                  facecolor='#f5f5f5', edgecolor='#999999', 
linewidth=0.25,zorder=1)
    ax.add_geometries(Reader(counties).geometries(),
                  ccrs.PlateCarree(),
                  facecolor='none', edgecolor='#999999', 
linewidth=0.25,zorder=4)
    
ax.add_geometries(Reader(states).geometries(),ccrs.PlateCarree(),facecolor='#f5f5f5',edgecolor='#999999',linewidth=0.6,zorder=1)
    
ax.add_geometries(Reader(states).geometries(),ccrs.PlateCarree(),facecolor='none',edgecolor='#999999',linewidth=0.6,zorder=4)
    ax.add_feature(lakes1,edgecolor='#999999',linewidth=0.6,zorder=1)
    ax.add_feature(lakes2,edgecolor='#999999',linewidth=0.6,zorder=4)

    ## Instead of using blank background, get a high resolution image from ESRI
#    m.arcgisimage(service=maps[2], xpixels = 1000, verbose= True)
#    ax.drawcoastlines(zorder=1000)
#    ax.drawstates(zorder=1000)
#    ax.drawcounties(linewidth=.5,zorder=1000)

    ### ----------- Loop through each sweep (scan elevation) 
---------------------
    # Pull data out of the file
    # sweep reprsents the scan elevation angle (Note: sweep number is not in 
order of lowest to highest scan)
    # to get the elevation angle try: f.sweeps[x][0][0].el_angle where x is 
your sweep index

    #s = range(0,21) # a list of sweeps
    s = [1]
    for sweep in s:
        elv_angle = f.sweeps[sweep][0][0].el_angle
     

        # First item in ray is header, which has azimuth angle
        az = np.array([ray[0].az_angle for ray in f.sweeps[sweep]])
    
    
        # 5th item is a dict mapping a var name (byte string) to a tuple
        # of (header, data array)
        ref_hdr = f.sweeps[sweep][0][4][b'REF'][0]
        ref_range = np.arange(ref_hdr.num_gates) * ref_hdr.gate_width + 
ref_hdr.first_gate
        ref = np.array([ray[4][b'REF'][1] for ray in f.sweeps[sweep]])
        try:
            vel_hdr = f.sweeps[sweep][0][4][b'VEL'][0]
            vel_range = (np.arange(vel_hdr.num_gates + 1) - 0.5) * 
vel_hdr.gate_width + vel_hdr.first_gate
            vel = np.array([ray[4][b'VEL'][1] for ray in f.sweeps[sweep]])
            vel = vel * 1.94384   # Convert from m/s to kts
        except:
            pass
        try:
            sw_hdr = f.sweeps[sweep][0][4][b'SW'][0]
            sw_range = (np.arange(sw_hdr.num_gates + 1) - 0.5) * 
sw_hdr.gate_width + sw_hdr.first_gate
            sw = np.array([ray[4][b'SW'][1] for ray in f.sweeps[sweep]])
        except:
            pass
        try:
            rho_hdr = f.sweeps[sweep][0][4][b'RHO'][0]
            rho_range = (np.arange(rho_hdr.num_gates + 1) - 0.5) * 
rho_hdr.gate_width + rho_hdr.first_gate
            rho = np.array([ray[4][b'RHO'][1] for ray in f.sweeps[sweep]])
        except:
            pass
        try:
            phi_hdr = f.sweeps[sweep][0][4][b'PHI'][0]
            phi_range = (np.arange(phi_hdr.num_gates + 1) - 0.5) * 
phi_hdr.gate_width + phi_hdr.first_gate
            phi = np.array([ray[4][b'PHI'][1] for ray in f.sweeps[sweep]])
        except:
            pass
        try:
            zdr_hdr = f.sweeps[sweep][0][4][b'ZDR'][0]
            zdr_range = (np.arange(zdr_hdr.num_gates + 1) - 0.5) * 
zdr_hdr.gate_width + zdr_hdr.first_gate
            zdr = np.array([ray[4][b'ZDR'][1] for ray in f.sweeps[sweep]])      
                  
        except:
            pass
        #fig, axes = plt.subplots(1, 2, figsize=(15, 8))
    
        if len(f.sweeps[sweep][0][4])==4:
            get_these = (ref,rho,phi,zdr)
            get_these_r = (ref_range,rho_range,phi_range,zdr_range)
            fignum = [1,2,3,4]
            names = ('REF','RHO','PHI','ZDR')
        elif len(f.sweeps[sweep][0][4])==3:
            get_these = (ref,sw,vel)
            get_these_r = (ref_range,sw_range,vel_range,)
            fignum = [1,2,3]
            names = ('REF','SW','VEL')
        else:
            get_these = (ref,rho,phi,zdr,sw,vel)
            get_these_r = 
(ref_range,rho_range,phi_range,zdr_range,sw_range,vel_range)
            fignum = [1,2,3,4,5,6]
            names = ('REF','RHO','PHI','ZDR','SW','VEL')
   
    
    #for var_data, var_range, ax in zip((ref, rho), (ref_range, rho_range), 
axes):

        for var_data, var_range, num, name in zip(get_these, get_these_r, 
fignum, names):
           
            #print name
           
            ax = fig.add_subplot(111)  # drawing axes
            # Turn into an array, then mask
            data = ma.array(var_data)
            data[np.isnan(data)] = ma.masked
    
            #rngs = np.array([ray[0].rad_length for ray in f.sweeps[sweep]]) 
            rng = np.linspace(0, var_range[-1], data.shape[-1] + 1)
            #print len(rng)
    
            # Convert az, range to a lat/lon
            g = Geod(ellps='clrk66') # This is the type of ellipse the earth is 
projected on. 
                                 # There are other types of ellipses you can 
use,
                                 # but the differences will be small
            center_lat = np.ones([len(az),len(rng)])*rLAT    
            center_lon = np.ones([len(az),len(rng)])*rLON
            az2D = np.ones_like(center_lat)*az[:,None]
            rng2D = np.ones_like(center_lat)*np.transpose(rng[:,None])*1000
            lon,lat,back=g.fwd(center_lon,center_lat,az2D,rng2D)
    
    
            # Convert az,range to x,y
            xlocs = var_range * np.sin(np.deg2rad(az[:, np.newaxis]))
            ylocs = var_range * np.cos(np.deg2rad(az[:, np.newaxis]))
    
            # Plot the data
            cmap = ctables.registry.get_colortable('viridis')

            #p = ax.pcolormesh(xlocs, ylocs, data, cmap=cmap)
            if name=='VEL':                
                p = 
ax.pcolormesh(lon,lat,data,cmap=get_vel_cmap(),vmax=100.,vmin=-100.,zorder=3)
            elif name=='REF':
                p = 
ax.pcolormesh(lon,lat,data,cmap=get_refl_cmap(),vmin=-10.,vmax=70.,zorder=3)
            else:
                p = 
ax.pcolormesh(lon,lat,data,cmap=cmap,vmin=-10.,vmax=70.,zorder=3)
            #m.set_aspect('equal', 'datalim')
            #ax.set_xlim(-40, 20)
            #ax.set_ylim(-30, 30)
        
            cb = plt.colorbar(p,orientation='horizontal',shrink=.8,pad=.01,
                       label='??')
    
            plt.title('%s\n%s at Elev Angle %.2f'%(date,name,elv_angle))
            plt.xlim([-97.5,-96.5])
            plt.ylim([43.2,43.93])
            
plt.savefig('/D2/ryan/python/%s_%s_ElvAngle_%.2f.png'%(date,name,elv_angle),bbox_inches='tight')
            print('saved',name)
            cb.remove()         # need to remove the colorbar before removing 
the pcolormesh    
            p.remove()

if __name__ == '__main__':
    main(sys.argv[1:])
  • 2017 messages navigation, sorted by:
    1. Thread
    2. Subject
    3. Author
    4. Date
    5. ↑ Table Of Contents
  • Search the python-users archives: