Cheat sheet |
---|
This page is http://www.atmos.albany.edu/facstaff/rfovell/ATM240/csheet.html.
Class web page is This page is http://www.atmos.albany.edu/facstaff/rfovell/ATM240/.
This is a living document and will be revised often.
Python version |
---|
import sys print("You are using Python {}.{}.".format(sys.version_info.major, sys.version_info.minor))
Openers [I copy and paste these lines into new notebooks] |
---|
%matplotlib inline import matplotlib.pyplot as plt import matplotlib.cm as cm from matplotlib.cm import get_cmap from matplotlib.colors import from_levels_and_colors from matplotlib.colors import LinearSegmentedColormap from matplotlib.ticker import MultipleLocator import numpy as np from numpy import genfromtxt import math from pyproj import Proj import xarray as xr import cartopy.crs as ccrs import cartopy.feature as cfeat import cartopy.geodesic import shapely import datetime from datetime import datetime import pandas as pd # MetPy from siphon.simplewebservice.wyoming import WyomingUpperAir # upper air data repository from metpy.units import units import metpy.plots as plots from metpy.plots import Hodograph import metpy.calc as mpcalc from mpl_toolkits.axes_grid1.inset_locator import inset_axes # for hodograph inset # for WRF from netCDF4 import Dataset from wrf import (getvar, to_np, get_cartopy, latlon_coords, vertcross, smooth2d, cartopy_xlim, cartopy_ylim, interpline, CoordPair, destagger, ALL_TIMES) # smoothing import scipy.ndimage # for contour smoothing from scipy.ndimage import gaussian_filter from scipy import stats from scipy.stats import norm, invgauss, skew, kurtosis from scipy.interpolate import interpn # histogram from scipy.interpolate import splrep, splev # smoothing normal curve SMALL_SIZE = 12 MEDIUM_SIZE = 14 BIGGER_SIZE = 16 plt.rc('font', size=SMALL_SIZE) # controls default text sizes plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
Some list stuff |
---|
• given a list 'mylist'
# forcibly replace oneth mylist element with new string mylist[1] = 'goodbye' # insert 'everyone' after the twoth (i.e., third) element mylist.insert(2,'everyone') # remove the list element matching '2' .. NOT the twoth element!! mylist.remove(2) # append provided value to the end of the list mylist.append(4.5)
• type of variable 'x'
type(x)• create a list of zeroes
n=20 listofzeros = [0] * n print(listofzeros)
Numpy and array stuff |
---|
• creating an empty array of specified length
# "empty" arrays can contain unwanted junk. Use zeros instead. cat = np.empty(8)• creating an array with arange
a = np.arange(6) # creates 1D array with values 0,1,2,3,4, and 5 b = np.arange(0,100,20) # creates 1D array with values 0,20,40,60,80• defining an array inline with specific values
x = np.array([1.,2.,4.,5.,5.]) y = np.array([0.,2.,4.5,5.,6.]) qi_levels = np.array([0.1,0.2,0.4,0.8,1.6,3.2,6.4,12.8]) # g/kg• defining an array from a list, various array types
mylist = [[2,3,-5],[21,-2,1]] a = np.array(mylist,dtype='d') # double precision floating point b = np.array(mylist,dtype='f') # single precision floating point c = np.array(mylist,dtype='i') # integer (long int no longer exists)• defining an array with Numpy functions
a = np.zeros((3,2),dtype='d') # a 3x2 array filled with double precision zeroes• shape of an array
print(" shape of array a = ",np.shape(a))• Slicing and indexing an array
print(x[3:5]) # prints out array entries 4 and 5, but only those two print(x[3:8]) # does not matter if ask for more entries than exist print(x[-1]) # print last entry in array print(x[-2]) # print second to last entry in array• Concatenating arrays
# key point is '(( ))' all_year=np.concatenate((np.array(old_year),np.array(recent_year))) year=np.concatenate((old_year,recent_year))• Mean, max, etc..
mean = np.mean(vals) # mean
max = np.max(vals) # max
min = np.min(vals) # min
std = np.std(vals) # standard deviation
• Sorting with argsort # smallest to largest idx = yyy.argsort() yyy = yyy[idx] # largest to smallest idx = (-yyy).argsort() yyy = yyy[idx]• rounding
lfr=np.around(lf,2) # rounds numpy array 'lf' to 2 decimal places• genfromtxt
ff = genfromtxt('/spare11/atm240/hrrr_swex_area_data.txt',skip_header=1) lat=ff[:,0] # latitude lon=ff[:,1] # longitude
• Make 1D array 3D (clone)
# make pressure 3D array pres # https://stackoverflow.com/questions/60044087/expand-and-copy-1d-numpy-array-to-3d pres = np.tile(p_levels[:, np.newaxis, np.newaxis], (1, len(lat), len(lon))) print(np.shape(pres))• Mask, masking
compos_reflec=np.where(compos_reflec>5,compos_reflec,np.nan) # replaces reflec < 5 w/ nan so won't plot
• datetime, datetime64
# datetime variables look like 2022-01-01 00:00:00 # numpy datetime64 variables look like 2022-01-01T00:00:00.000000 # to convert a datetime to datetime64: xday=np.datetime64(datetime(int(year),1,1,0,0))
Some Pandas stuff |
---|
# read a CSV dataset and let Pandas parse the date-like variables df = pd.read_csv('WHO_flu_data_22Nov2020.csv', low_memory=False, parse_dates=True) # read in the date-like variable, then convert it to datetime date_temp = df['Start date'] date = pd.to_datetime(date_temp) # read in space-delimited dataset without header, so provide column names separately df = pd.read_csv('all_deviations_nysm_july2017.txt',delim_whitespace=True) # if NO HEADER need header=None df.columns =['station', 'index', 'dwind', 'mean']
# Godawful way of reading in pandas month,day,year variables and constructing a datetime variable year=df['year'].to_numpy().astype(int) month=df['month'].to_numpy().astype(int) day=df['day'].to_numpy().astype(int) date=[] for i in range(len(year)): date.append(datetime(year[i],month[i],day[i])) # print(date)
Metpy |
---|
# u = west-east wind speed # v = north-south wind speed fwdir = mpcalc.wind_direction(u,v) # calc wind direction wdir # example with attaching units # this gives temperature irma_tmp units of Kelvin, relative humidity irma_rh units of percent # function result would be Celsius. The final piece converts to Kelvin irma_tdew = mpcalc.dewpoint_from_relative_humidity(irma_tmp * units.K, irma_rh * units.percent).to(units('kelvin'))
Loops and conditionals |
---|
• if, elif, else
if(mon == 'FEB'): monx = 2 elif(mon == 'MAR'): monx = 3 else: print(" not february or march")
if(fhr >= start and fhr <= end>): [do something] #• subsetting data examples
ww = np.copy(ogust) zz = np.copy(LT) # or w = ww[(zzz <= 6) | (zzz >= 18)] z = zz[(zzz <= 6) | (zzz >= 18)]
# and w = ww[(zzz >= 6) & (zzz <= 18)] z = zz[(zzz >= 6) & (zzz <= 18)]• for loop
for i in range(5): # this operates on 0, 1, 2, 3, and 4, but not 5 print(i) #• while loop
a = 1 while a < 10: print(a) a = a + 1
Matplotlib |
---|
• Basic plots
fig = plt.figure(figsize=(8,8)) # plot width, plot height plt.plot(x,y,c='lightgrey',linewidth=2,label='mylabel') # line plot plt.scatter(x,y,c='k',edgecolors='None',s=20) # scatterplot plt.bar(x,y,color='lightgrey',linewidth=2,label='mylabel') # bar chart plt.legend(loc='upper left') # legend plt.grid() # puts a grid on the plot plt.grid(axis='both', which='both') # vert grid too # on multi-y plots, have to do it before cloning x-axis plt.errorbar(theta_mean-theta2_mean,z_mean,xerr=theta_diff_std,c='grey',linewidth=0.5,zorder=1)• Contour plots
levels=np.arange(968.,1044.,4.) # max level not included! cs = ax.contour(lon,lat,slp,colors='k', levels=levels, linewidths=1, linestyles=':', transform=ccrs.PlateCarree()) # transform presumed map-projected data fmt = '%r ' # format for contour labels fmt = '%1.1f' # float, one decimal place ax.clabel(cs, cs.levels[::2], inline=True, fmt=fmt, fontsize=10) # [::2] only every other contour• Color fill plots
cmap = plt.cm.seismic # color table norm = plt.Normalize(-5.,5) # values bounds cm = ax.pcolormesh(lon,lat,snowd,shading='auto',cmap=cmap, norm=norm, transform=ccrs.PlateCarree()) # transform presumed map-projected data plt.colorbar(cm, orientation="vertical",shrink=0.5, label='label') # add colorbar (label optional) # for orientation="horizontal", use pad=0.01 to reduce gap between plot bottom and colorbar ##################################################################################### # putting a color bar on only ONE plot without changing plot size # used in plot_HRRR_NAM_OBS_maxgusts_BOULDER_V2.ipynb ##################################################################################### # first panel ax = fig.add_subplot(1,2,1,projection=proj) colors = ['blue', 'white', 'red'] cmap = LinearSegmentedColormap.from_list('name', colors) norm=plt.Normalize(0,50) cm = ax.pcolormesh(lon_hrrr,lat_hrrr,maxgust_hrrr,shading='auto',alpha=0.5,cmap=cmap, norm=norm, transform=ccrs.PlateCarree()) # second panel, using same cmap and norm ax = fig.add_subplot(1,2,2,projection=proj) cm = ax.pcolormesh(lon_nam,lat_nam,maxgust_nam,shading='auto',alpha=0.5,cmap=cmap, norm=norm, transform=ccrs.PlateCarree()) # now add the colorbar to a NEW axis cb_ax = fig.add_axes([.91,.124,.02,.754]) # third number controls WIDTH of colorbar fig.colorbar(cm,orientation='vertical',cax=cb_ax,label="maximum gust (m/s)")#,fraction=0.1)• Colormaps
# colormap cmap = ListedColormap(['green','green','green','green','green','green','brown','brown','green','yellow','yellow','yellow','lightgreen','red','yellow','white','white', 'blue','blue','blue','blue']) # reverses the colormap cmap_r = ListedColormap(cmap.colors[::-1]) cm = ax.pcolormesh(lonwrf,latwrf,greenfrac[3,:,:],shading='flat',norm=norm,cmap=cmap_r, transform=ccrs.PlateCarree())• Force plots to be square
# this bit of magic forces the plot to be square, appropriate because we have a square domain and no map projection plt.gca().set_aspect('equal', adjustable='box') # but this works too # make sure plot is square - appropriate as we have square domain and no map projection plt.axis('square')• Adding a 1:1 correspondence line
# dashed 1:1 line. I know the plot extent is 0-30 in x and y directions plt.plot([0, 40], [0, 40], c='lightgrey', lw=2, linestyle='dashed')# fancier version from Matt Seymour
import matplotlib.pyplot as plt import numpy as np %matplotlib inline fig = plt.figure(figsize=(10,10)) ax = plt.axes() # Create linspace for color filling x = np.linspace(-100, 100, 100) # Fill color above/below y=x line plt.fill_between(x, x, 100, facecolor='r', alpha=0.07, zorder=0) plt.fill_between(x, x, -100, facecolor='b', alpha=0.07, zorder=0) # Plot dashed lines every 2 [units] for k in range(-10,10,2): plt.plot(x, x+k, c='0.6', ls='--', lw=1, zorder=1) # Create thick dashed lines at x=0 and y=0 ax.axvline(0, color='k', ls='--', lw=1.5, zorder=2) ax.axhline(0, color='k', ls='--', lw=1.5, zorder=2) # Set axis limits, labels, and tick labels plt.xlim(-10,10) plt.ylim(-10,10) plt.xlabel('X Variable', fontsize=14) plt.ylabel('Y Variable', fontsize=14) plt.xticks(np.arange(-10,10,2), fontsize=12) plt.yticks(np.arange(-10,10,2), fontsize=12) plt.title('Sample Scatterplot Background', fontsize=16) # Barbs with specified spacing (q), color (cmap), range (norm), with C = windspeed, and linewidth adj q=4 uunow=uu10[timex-1,:,:] vvnow=vv10[timex-1,:,:] C=np.hypot(uunow,vvnow) colors = ['blue', 'red'] norm=plt.Normalize(0,40) cmap = LinearSegmentedColormap.from_list('name', colors) plt.barbs(to_np(lonwrf[::q,::q]),to_np(latwrf[::q,::q]),to_np(uu10[timex-1,::q,::q]), to_np(vv10[timex-1,::q,::q]),C[::q,::q],cmap=cmap,norm=norm,lw=1.5,transform=ccrs.PlateCarree()) # x-axis labels for vertical cross-sections that would otherwise have meaningless labels. # labels are forced and so need to be checked for accuracy but avoids MultipleLocator base crap # first get x dimensions of plot, and calc spacing between ticks (here 4) xmin, xmax = ax1.get_xlim() print(xmin,xmax) plt.xlim(xmin,xmax) xdif=(xmax-xmin)/4 print(" X ",xmax,xmin,xdif) # this works for forcing desired x-axis labels # I know the plot goes from -107 to -103 longitude for fixed latitude # I know I want 5 labels and I know what xmin, xmax are from get_xlim labels = ['-107','-106','-105','-104','-103'] xl = np.arange(xmin,xmax+xdif,xdif) print(" XL ",xl) plt.xticks(xl,labels)• Labels
# controlling label sizes for entire notebook SMALL_SIZE = 12 MEDIUM_SIZE = 14 BIGGER_SIZE = 16 plt.rc('font', size=SMALL_SIZE) # controls default text sizes plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels plt.rc('xtick', labelsize=SMALL_SIZE) # fontsize of the tick labels plt.rc('ytick', labelsize=SMALL_SIZE) # fontsize of the tick labels plt.rc('legend', fontsize=SMALL_SIZE) # legend fontsize plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title # plt.title('This is a test scatterplot') # plot title plt.xlabel('x',fontsize='medium') # x axis label plt.ylabel('y',fontsize='medium') # y axis label plt.xticks(np.arange(0,12,2),fontsize='small') # ticks plt.yticks(np.arange(0,12,2),fontsize='small') # ticks plt.xlim([0,10]) # limit range of x axis plt.ylim([0,10]) # limit range of y axis plt.xticks([]) # hides/suppresses x axis labels and ticks # Annotating numbers/labels on plots # gcount, cat, and gcc_3 are 1D arrays with number of items, x, and y axis values, respectively # the multiplicative factors shift the labels # the '%.0f' strips off decimal place for i, label in enumerate(gcount): plt.annotate('%.0f'%label, (cat[i]*1.03, gcc_3[i]*1.05)) # Another example of annotating labels # 'state' is a vector of labels w/ same length as x and y plt.scatter(x,y,s=25,c='k') for i,label in enumerate(state): plt.annotate(label, (x[i], y[i]),size=10,textcoords="offset points",xytext=(5,5)) # xytext pushes label up and to right a little # control decimal places on x, y axis labels from matplotlib.ticker import FormatStrFormatter ax.yaxis.set_major_formatter(FormatStrFormatter('%.1f')) # one decimal place for y-axis # control tick mark interval from matplotlib.ticker import MultipleLocator plt.xlim(datemin,datemax) ax.xaxis.set_major_locator(MultipleLocator(10)) # Change major ticks to show every 10. # this might work better for controlling spacing of date labels spacing=2 for label in ax.xaxis.get_ticklabels()[::spacing]: label.set_visible(False) # title for a multi-panel plot plt.suptitle(" this is my title ") # this can control space between top of plot and suptitle title. But it shifts figtext locations too fig.subplots_adjust(top=0.95) # make the title BOLD font plt.title(" WHO Influenza data for the United States 2019-2020",fontweight='bold') # add text on or near plot, Coordinates are in range [0,1] plt.figtext(0.735,0.84,'Text to be added',size=12) # this version makes font italic # adding ha='left' does left justify for horizontal arrangement (ha) # adding loc='left' starts title at left edge of plot plt.figtext(0.135,0.85,'Data from https://who.int/toolkits/flunet',size=12,fontstyle='italic') # adding text including floating point variable information, controlling number of decimals printed plt.figtext(0.28,0.84,f' CAPE {cape:.1f}',size=12) # printing a datetime object as a string, cutting out the ugly fractions of second, and adding a bounding box plt.figtext(0.24,0.15,'Plot valid '+ str(timenow.values)[0:19],size=12, bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=1')) # transform=ax.transAxes sets location of figtext in frame of the individual frame of multiplot figure [axis called 'ax'] plt.figtext(0.97,0.09,str(z0min)+' <= LU <= '+str(z0thresh),size=12,ha='right',transform=ax.transAxes) # draw a vertical line at x=0 with color lightgrey plt.axvline(x=0, lw=2,c='lightgrey') # draw a horizontal line at y=0 with color lightgrey plt.axhline(y=0, lw=2,c='lightgrey') # save a figure, and cut out some whitespace # facecolor='white', transparent=False removes transparency plt.savefig("xplot.png", bbox_inches = 'tight',dpi=300,facecolor='white', transparent=False)• Date axes / Date axis
datemin=datetime(2019,1,1) datemax=datetime(2020,11,16) ax1.xaxis_date() plt.xlim(datemin,datemax) datemin=datetime(2019,4,1,0) datemax=datetime(2019,5,1,0) plt.xlim(datemin,datemax) # Change major ticks to show every 10. from matplotlib.ticker import MultipleLocator ax.xaxis.set_major_locator(MultipleLocator(10))• Manipulating axes
ax2.invert_yaxis() # inverts y-axis plt.subplots_adjust(hspace=0.00) # squeeze out vertical space between plots• Wind direction on second axis
# the twinx command clones the ax axis object as ax2, so our new plot shares the same x-axis ax2 = ax.twinx() # now we plot wind direction, and ask for a different, more reasonable y-axis plot limits # this plot shows up on the secondary y-axis at right plt.scatter(date,MTIC1_wdir,c='red',s=7) # those wind direction dots were too large so we're downsizing plt.scatter(date1,MOIC1_wdir,c='blue',s=7) # those wind direction dots were too large so we're downsizing plt.ylim([0,360])• Colors
• Linear regression
a, b = np.polyfit(x, y, deg=1) # fits the linear regression (slope = a, intercept = b) correlation = np.corrcoef(x,y)[0,1] # fetches off-diagonal of 2x2 correlation matrix rsq = correlation*correlation # computes the R-squared f = a*x + b # computes the predicted values plt.scatter(x,y) plt.plot(x,f,c='red') # alternative from sklearn.linear_model import LinearRegression plt.scatter(x,y) model = LinearRegression() model.fit(x.reshape(-1, 1), y) x_new = np.linspace(np.min(x), np.max(x), 100) # for least squares line y_new = model.predict(x_new[:, np.newaxis]) plt.plot(x_new,y_new,c='orange',lw=2) # np.polyfit wants 2 1-D vectors, so can use np.ravel to flatten 2D arrays # x and y start out (1059, 1799) x=np.ravel(wspd[mlevel-1,:,:].values-wspd_hrrr_drift[mlevel-1,:,:]) y=np.ravel(wspd_hrrr[mlevel-1,:,:]-wspd_hrrr_drift[mlevel-1,:,:]) # x and y end up (1905141,)• 1D histograms (plt.hist)
x = np.copy(GF) # 2D array x = np.ravel(x) # make it 1D from 2D print(" shape of x ",np.shape(x)) specified_bins=np.arange(1.0,10,0.1) specified_midpoints=np.arange(1.1,10,0.1) # another try print(len(specified_bins)) print(len(specified_midpoints)) sigma = 3 # smoothing n, bins, patches = plt.hist(x, bins=specified_bins, facecolor='blue', edgecolor='k', alpha=0.5,label="Forecasts",zorder=1) print(" max n fwind ",np.max(n)," max fwind ",np.max(fwind),len(x)) n = gaussian_filter(n, sigma) plt.plot(specified_midpoints[5:],n[5:],c='blue',lw=3)
• 2D histograms (np.histogram2d) for scatter density plots
# hfxland, luland are 2D arrays (249x249) # first, xform into 1D arrays for histogram xx=np.ravel(hfxland) yy=np.ravel(luland) #print(np.shape(xx),np.shape(yy)) # set bins for xx (=qq) and yy (=rr) qq=np.arange(-100,500,25) # hfx rr=np.arange(1,17,1) # lu # 2D histogram data, x_e, y_e = np.histogram2d( xx, yy, bins = (qq,rr), density = False ) #print(" data ", data) #print(" x_e ",x_e) #print(" y_e ", y_e) # creates the colors to be assigned to the points z = scipy.interpolate.interpn( ( 0.5*(x_e[1:] + x_e[:-1]) , 0.5*(y_e[1:]+y_e[:-1]) ) , data , np.vstack([xx,yy]).T , method = "splinef2d", bounds_error = False) #To be sure to plot all data z[np.where(np.isnan(z))] = 0.0 # Sort the points by density, so that the densest points are plotted last idx = z.argsort() xx, yy, z = xx[idx], yy[idx], z[idx] plt.scatter(xx,yy,c=z,edgecolors='None',s=20)
WRF |
---|
rainnc = getvar(ncfile1, "RAINNC",timeidx=ALL_TIMES) # get all times, otherwise just gets last one latwrf = getvar(ncfile1, "XLAT",timeidx=-1) # just need one time lonwrf = getvar(ncfile1, "XLONG",timeidx=-1) wspd = getvar(ncfile1, "WSPD",timeidx=ALL_TIMES) # (times,lats,lons) GF = np.max(wspd,axis=0)/np.mean(wspd,axis=0) # (lats,lons)
# Read in a series of individual wrfout files, effectively combining them into single dataset ncfile=[Dataset(location + "wrfout_d01_2007-09-21_06:00:00"), Dataset(location + "wrfout_d01_2007-09-21_07:00:00"), Dataset(location + "wrfout_d01_2007-09-21_08:00:00"), Dataset(location + "wrfout_d01_2007-09-21_09:00:00"), Dataset(location + "wrfout_d01_2007-09-21_10:00:00"), Dataset(location + "wrfout_d01_2007-09-21_11:00:00"), Dataset(location + "wrfout_d01_2007-09-21_12:00:00"), Dataset(location + "wrfout_d01_2007-09-21_13:00:00"), Dataset(location + "wrfout_d01_2007-09-21_14:00:00"), Dataset(location + "wrfout_d01_2007-09-21_15:00:00"), Dataset(location + "wrfout_d01_2007-09-21_16:00:00"), Dataset(location + "wrfout_d01_2007-09-21_17:00:00"), Dataset(location + "wrfout_d01_2007-09-21_18:00:00"), Dataset(location + "wrfout_d01_2007-09-21_19:00:00"), Dataset(location + "wrfout_d01_2007-09-21_20:00:00"), Dataset(location + "wrfout_d01_2007-09-21_21:00:00"), Dataset(location + "wrfout_d01_2007-09-21_22:00:00"), Dataset(location + "wrfout_d01_2007-09-21_23:00:00"), Dataset(location + "wrfout_d01_2007-09-22_00:00:00"), Dataset(location + "wrfout_d01_2007-09-22_01:00:00"), Dataset(location + "wrfout_d01_2007-09-22_02:00:00"), Dataset(location + "wrfout_d01_2007-09-22_03:00:00"), Dataset(location + "wrfout_d01_2007-09-22_04:00:00"), Dataset(location + "wrfout_d01_2007-09-22_05:00:00"), Dataset(location + "wrfout_d01_2007-09-22_06:00:00")]
Cartopy |
---|
lat_0 = 43 lon_0 = -75 fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(1,1,1,projection=ccrs.LambertConformal(central_latitude=lat_0, central_longitude=lon_0)) ax.set_extent([-80,-71.5,40.2,45.25]) ax.add_feature(cfeat.LAND) # adds colorshading [yellow] to land areas ax.add_feature(cfeat.OCEAN) # adds colorshading [blue] to ocean areas ax.add_feature(cfeat.COASTLINE,alpha=0.5) ax.add_feature(cfeat.BORDERS,linestyle=':') # colon asks for dotted line ax.add_feature(cfeat.LAKES,alpha=0.5) # alpha sets transparency level ax.add_feature(cfeat.RIVERS) ax.add_feature(cfeat.STATES,linestyle=':') ax.gridlines() ax.scatter(-73.8,42.7,marker='*',s=400,c='k',transform=ccrs.PlateCarree()) # add a circle about a lat/lon location radius_in_meters = 1000. circle_points = cartopy.geodesic.Geodesic().circle(lon=lons[0], lat=lats[0], radius=radius_in_meters, endpoint=False) geom = shapely.geometry.Polygon(circle_points) ax.add_geometries((geom,), crs=ccrs.PlateCarree(), facecolor='none', edgecolor='red', linewidth=1) # adding on a Google-derived relief map as background from cartopy.io.img_tiles import GoogleTiles # for google tiles relief map # https://stackoverflow.com/questions/37423997/cartopy-shaded-relief class ShadedReliefESRI(GoogleTiles): # shaded relief def _image_url(self, tile): x, y, z = tile url = ('https://server.arcgisonline.com/ArcGIS/rest/services/' \ 'World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}.jpg').format( z=z, y=y, x=x) return url ax = plt.axes(projection=ShadedReliefESRI().crs) ax.set_extent([-112.64,-112.02,39.13,39.62]) ax.add_image(ShadedReliefESRI(), 8) # 12 is higher-res and sharper plt.show()
# A map with an inset, as used in plot_GFS_GRIB_analyses.ipynb fig = plt.figure(figsize=(16, 10)) # select our central latitude and longitude centlon = -97.5 centlat = 40. # Select a projection proj=ccrs.LambertConformal(central_latitude=centlat, central_longitude=centlon) # create our axis object 'ax', specifying Lambert Conformal projection ax = fig.add_subplot(1,1,1,projection=proj) # The features function we defined adds some cartopy features on. We pass it 'ax' features(ax) plot_bounds = [-135,-75,20,55] ax.set_extent(plot_bounds) # pcolormesh colors = ['skyblue', 'white', 'red'] cmap = LinearSegmentedColormap.from_list('name', colors) norm = plt.Normalize(0, 60) cm = ax.pcolormesh(lon_hrrr,lat_hrrr,wspd_diff,shading='auto',cmap=cmap, norm=norm, transform=ccrs.PlateCarree()) plt.colorbar(cm, orientation="vertical",shrink=0.5,label="wind speed (m/s)") q=10 plt.barbs(to_np(lon_hrrr[::q]),to_np(lat_hrrr[::q]),to_np(uu[::q,::q]),to_np(vv[::q,::q]),color='black',zorder=40,transform=ccrs.PlateCarree()) # and add a title plt.title(" Level "+str(p_levels[mlevel-1])+" mb GFS wind speed analysis (m/s) run "+str(filename)[0:14]); # semicolon suppresses unwanted text printed to screen # add inset locator box to main map # https://stackoverflow.com/questions/55303911/add-polygon-box-to-cartopy-python geom = geometry.box(minx=-110,maxx=-100,miny=36,maxy=43) ax.add_geometries([geom], crs=cartopy.crs.PlateCarree(), linewidth=3, facecolor='none', edgecolor='k') ############################################################################################################## # inset plot ############################################################################################################## # https://stackoverflow.com/questions/45527584/how-to-easily-add-a-sub-axes-with-proper-position-and-size-in-matplotlib-and-car # https://scipython.com/blog/inset-plots-in-matplotlib/ # select our central latitude and longitude for INSET centlon = -105.27055 centlat = 40.01499 proj2=ccrs.LambertConformal(central_latitude=centlat, central_longitude=centlon) ax2 = plt.axes([0, 0, 1, 1], projection=proj2) ax2.set_global() # Manually set the position and relative size of the inset axes within ax1 ip = InsetPosition(ax, [0.68,0.02,0.35,0.35]) #[0.4,0.2,0.5,0.5] ax2.set_axes_locator(ip) plot_bounds = [-110,-100,36,43] ax2.set_extent(plot_bounds) norm = plt.Normalize(0, 60) cm = ax2.pcolormesh(lon_hrrr,lat_hrrr,wspd_diff,shading='auto',cmap=cmap, norm=norm, zorder=1,transform=ccrs.PlateCarree()) features(ax2) ax2.add_feature(cfeat.STATES.with_scale('50m'),linestyle='dotted',linewidth=2) ax2.scatter(-105.27055,40.01499,marker='*',s=200,c='w',edgecolors='k',transform=ccrs.PlateCarree(),zorder=50) # Boulder ax2.scatter(-106.29,40.01,marker='o',s=125,c='w',edgecolors='k',transform=ccrs.PlateCarree(),zorder=50) # upwind qlon=7 qlat=4 print(np.shape(lon_hrrr[::qlon]),np.shape(lat_hrrr[::qlat]),np.shape(uu[::qlon,::qlat])) plt.barbs(to_np(lon_hrrr[::qlon]),to_np(lat_hrrr[::qlat]),to_np(uu[::qlat,::qlon]),to_np(vv[::qlat,::qlon]),color='black',zorder=40,transform=ccrs.PlateCarree()) ########## END ############
Plotting a sounding |
---|
# create figure and skew plot fig = plt.figure(figsize=(10,10)) skew = plots.SkewT(fig) # plot T and Td skew.plot(p, T, 'red') skew.plot(p, Td, 'green') # now the wind barbs, at selected vertical interval interval = np.arange(100,1000,50) * units.hPa # remember it does not include the last value of range!!! idx = mpcalc.resample_nn_1d(p, interval) # resample, using nearest-neighbor (nn), in 1 dimension (1d). Returns indices skew.plot_barbs(p[idx], u[idx], v[idx]) # Now only for indices defined in last cell # set axis limits skew.ax.set_ylim(1000,100) # limit y-axis to 1000 to 100 mb skew.ax.set_xlim(-50,30) # limit x-axis to -50 to +30 C # plot the reference curves/lines skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() # define parcel parcel_path = mpcalc.parcel_profile(p, T[0], Td[0]) # calculate CAPE and CIN cape, cin = mpcalc.cape_cin(p, T, Td, parcel_path) # shade CAPE and CIN skew.shade_cape(p, T, parcel_path) skew.shade_cin(p, T, parcel_path) # calculate parameters for LFC and EL defaulting to surface parcel # and indicate on plot if they exist lfc_p, lfc_t = mpcalc.lfc(p, T, Td) el_p, el_t = mpcalc.el(p, T, Td) if lfc_p: skew.ax.axhline(lfc_p) if el_p: skew.ax.axhline(el_p) # print CAPE and CIN on skew-t, in a box with black border and white background plt.figtext(0.29,0.16,f' CAPE {cape:.1f} \n CIN {cin:.1f} ',size=12, bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=1')) # make the hodograph inset # ax_hod = inset_axes(skew.ax, '35%', '35%', loc=1) # default but may obscure wind barbs ax_hod = inset_axes(skew.ax, '35%', '35%', loc='upper right', bbox_transform=skew.ax.transAxes, bbox_to_anchor=(-0.05, 0., 1, 1)) # shifts hodo a bit to the left h = Hodograph(ax_hod, component_range=80.) h.add_grid(increment=20) h.plot_colormapped(u, v, height);
Reading GRIB datasets |
---|
• Example for NAM GRIB2 file
ds = xr.open_dataset("/spare11/atm240/EXAMPLE02/nam.t00z.conusnest.hiresf06.tm00.grib2",engine='pynio') # get catalogue of variable names (could yield LOTS of output) names = ds.variables.keys() print("Variable names:", names) # ------------------------------------------------------------------------------------------------- # some fields to extract from GRIB2 data. We're plotting 500 mb height and SLP here. # ------------------------------------------------------------------------------------------------- hgt = ds.HGT_P0_L100_GLC0.sel(lv_ISBL0 = 50000.0) # 500 mb height u10m = ds.UGRD_P0_L103_GLC0.sel(lv_HTGL8 = 10.0) # 10 m wind speed (u) v10m = ds.VGRD_P0_L103_GLC0.sel(lv_HTGL8 = 10.0) # 10 m wind speed (v) hgt0 = ds.HGT_P0_L1_GLC0 # terrain height u80m = ds.UGRD_P0_L103_GLC0.sel(lv_HTGL8 = 80.0) # 80 m wind speed (u) v80m = ds.VGRD_P0_L103_GLC0.sel(lv_HTGL8 = 80.0) # 80 m wind speed (v) slp_pa = ds.PRMSL_P0_L101_GLC0 # sea-level pressure (SLP)• Great circle distance between 2 locations, in miles
# lat/lon in degrees x1 = math.radians(n_lat) # location 1 y1 = math.radians(n_lon) x2 = math.radians(target_lat) # location 2 y2 = math.radians(target_lon) # Great circle distance in radians angle1 = math.acos(math.sin(x1) * math.sin(x2) + math.cos(x1) * math.cos(x2) * math.cos(y1 - y2)) # Convert back to degrees. angle1 = math.degrees(angle1) # Each degree on a great circle of Earth is 60 nautical miles. distance1 = 60.0 * angle1 # Convert nautical miles to miles gcd= distance1*1.15078• cfgrib for GRIB2 file
filter_by_keys={'typeOfLevel': 'meanSea'} filter_by_keys={'typeOfLevel': 'hybrid'} filter_by_keys={'typeOfLevel': 'atmosphere'} filter_by_keys={'typeOfLevel': 'surface'} filter_by_keys={'typeOfLevel': 'planetaryBoundaryLayer'} filter_by_keys={'typeOfLevel': 'isobaricInPa'} filter_by_keys={'typeOfLevel': 'isobaricInhPa'} filter_by_keys={'typeOfLevel': 'heightAboveGround'} filter_by_keys={'typeOfLevel': 'depthBelowLandLayer'} filter_by_keys={'typeOfLevel': 'heightAboveSea'} filter_by_keys={'typeOfLevel': 'atmosphereSingleLayer'} filter_by_keys={'typeOfLevel': 'lowCloudLayer'} filter_by_keys={'typeOfLevel': 'middleCloudLayer'} filter_by_keys={'typeOfLevel': 'highCloudLayer'} filter_by_keys={'typeOfLevel': 'cloudCeiling'} filter_by_keys={'typeOfLevel': 'convectiveCloudBottom'} filter_by_keys={'typeOfLevel': 'lowCloudBottom'} filter_by_keys={'typeOfLevel': 'middleCloudBottom'} filter_by_keys={'typeOfLevel': 'highCloudBottom'} filter_by_keys={'typeOfLevel': 'convectiveCloudTop'} filter_by_keys={'typeOfLevel': 'lowCloudTop'} filter_by_keys={'typeOfLevel': 'middleCloudTop'} filter_by_keys={'typeOfLevel': 'highCloudTop'} filter_by_keys={'typeOfLevel': 'convectiveCloudLayer'} filter_by_keys={'typeOfLevel': 'boundaryLayerCloudLayer'} filter_by_keys={'typeOfLevel': 'nominalTop'} filter_by_keys={'typeOfLevel': 'heightAboveGroundLayer'} filter_by_keys={'typeOfLevel': 'tropopause'} filter_by_keys={'typeOfLevel': 'maxWind'} filter_by_keys={'typeOfLevel': 'isothermZero'} filter_by_keys={'typeOfLevel': 'highestTroposphericFreezing'} filter_by_keys={'typeOfLevel': 'pressureFromGroundLayer'} filter_by_keys={'typeOfLevel': 'sigmaLayer'} filter_by_keys={'typeOfLevel': 'sigma'} filter_by_keys={'typeOfLevel': 'potentialVorticity'} ds_hybrid = xr.open_dataset(location+filename,engine='cfgrib',filter_by_keys={'typeOfLevel': 'hybrid'}) ds_pressure = xr.open_dataset(location+filename,engine='cfgrib',filter_by_keys={'typeOfLevel': 'isobaricInhPa'}) ds_sfc = xr.open_dataset(location+filename_sfc,engine='cfgrib', filter_by_keys={'level':10,'stepType': 'instant','typeOfLevel': 'heightAboveGround'})
Extra stuff |
---|
• Labeling contours, contour labeling
theta_contours = ax1.contour(x, cross.gh[:,:], cross.theta[:,:], levels= thlevs, colors = 'k') theta_contours.clabel(theta_contours.levels[1::2], fontsize=8, colors='k', inline=1,inline_spacing=8, fmt='%i', rightside_up=True, use_clabeltext=True)
Opening remote files |
---|
• Example from https://towardsdatascience.com/an-efficient-way-to-read-data-from-the-web-directly-into-python-a526a0b4f4cb
import urllib.request url = 'ftp://ftp2.psl.noaa.gov/Datasets/ncep.reanalysis2.dailyavgs/gaussian_grid/air.2m.gauss.1979.nc' req = urllib.request.Request(url) with urllib.request.urlopen(req) as resp: ds = xr.open_dataset(io.BytesIO(resp.read())) ds
Objects |
---|
# Used minisom to create an object called 'som'. This command # prints out all of its attributes print(dir(som))