def test_speed_dir_roundtrip(): """Test round-tripping between speed/direction and components.""" # Test each quadrant of the whole circle wspd = np.array([15., 5., 2., 10.]) * units.meters / units.seconds wdir = np.array([160., 30., 225., 350.]) * units.degrees u, v = get_wind_components(wspd, wdir) wdir_out = get_wind_dir(u, v) wspd_out = get_wind_speed(u, v) assert_array_almost_equal(wspd, wspd_out, 4) assert_array_almost_equal(wdir, wdir_out, 4)
def test_wind_comps_basic(): """Test the basic wind component calculation.""" speed = np.array([4, 4, 4, 4, 25, 25, 25, 25, 10.]) * units.mph dirs = np.array([0, 45, 90, 135, 180, 225, 270, 315, 360]) * units.deg s2 = np.sqrt(2.) u, v = get_wind_components(speed, dirs) true_u = np.array([0, -4 / s2, -4, -4 / s2, 0, 25 / s2, 25, 25 / s2, 0]) * units.mph true_v = np.array([-4, -4 / s2, 0, 4 / s2, 25, 25 / s2, 0, -25 / s2, -10]) * units.mph assert_array_almost_equal(true_u, u, 4) assert_array_almost_equal(true_v, v, 4)
def plot_sounding(sndg_data, yr, day, mo, hr, diablo_sounding): plt.rcParams['figure.figsize'] = (9, 9) skew_evening = SkewT() one_sounding = sndg_data.loc[sndg_data[' Hour'] == hr] T = convert_temperature(one_sounding[' Temp'].values, 'F', 'C') rh = one_sounding[' RH'].values one_sounding[' Dewpt'] = calc_dewpt(T, rh) one_sounding = one_sounding.dropna(subset=(' Temp', ' Dewpt'), how='all').reset_index(drop=True) T = convert_temperature(one_sounding[' Temp'].values, 'F', 'C') * units.degC p = one_sounding[' Pres'].values * units.hPa Td = one_sounding[' Dewpt'].values * units.degC wind_speed = one_sounding[' Spd'].values * units.knots wind_dir = one_sounding[' Dir '].values * units.degrees u, v = mpcalc.get_wind_components(wind_speed, wind_dir) skew_evening.plot(p, T, 'r') skew_evening.plot(p, Td, 'g') skew_evening.plot_barbs(p, u, v) skew_evening.plot_dry_adiabats() skew_evening.plot_moist_adiabats() skew_evening.plot_mixing_lines() skew_evening.ax.set_ylim(1000, 100) plt.title('OAK Sounding: ' + str(int(mo)) + '/' + str(int(day)) + '/' + str(int(yr)) + ': ' + str(int(hr)) + ' UTC') plt.savefig('../Images/20180703/' + diablo_sounding + '/OAK_sounding_eve_' + str(int(mo)) + '_' + str(int(day)) + '_' + str(int(yr)) + '_' + str(int(hr)) + 'UTC.png') plt.close() return one_sounding
def getMesoData(procYear, procMonth, procDay, procStation): # first check for internet connection iswifi = check_internet() if iswifi: baseURL = 'http://mesonet.org/index.php/dataMdfMts/dataController/getFile/' URL = baseURL + '%4.4d%2.2d%2.2d%s/mts/TEXT/' % (procYear, procMonth, procDay, procStation.lower()) fd = urllib2.urlopen(URL) data_long = fd.read() data = data_long.split('\n') time_, RH_, T2m_, T9m_, speed_, direction_, p_ = ([] for i in range(7)) for i in np.arange(3, len(data)-1): time_.append(float(data[i].split()[2])) RH_.append(float(data[i].split()[3])) T2m_.append(float(data[i].split()[4])) T9m_.append(float(data[i].split()[14])) speed_.append(float(data[i].split()[5])) direction_.append(float(data[i].split()[7])) p_.append(float(data[i].split()[12])) speed_kts = [i * 1.94 for i in speed_] u,v = mcalc.get_wind_components(speed_kts*units.kts, direction_ * units.deg) u = u.to(units.kts) / units.kts v = v.to(units.kts) / units.kts return np.array([time_, RH_, T2m_, T9m_, u, v, p_]) else: return np.array([])
def test_storm_relative_helicity(): """Test function for SRH calculations on an eigth-circle hodograph.""" # Create larger arrays for everything except pressure to make a smoother graph hgt_int = np.arange(0, 2050, 50) hgt_int = hgt_int * units('meter') dir_int = np.arange(180, 272.25, 2.25) spd_int = np.zeros((hgt_int.shape[0])) spd_int[:] = 2. u_int, v_int = get_wind_components(spd_int * units('m/s'), dir_int * units.degree) # Put in the correct value of SRH for a eighth-circle, 2 m/s hodograph # (SRH = 2 * area under hodo, in this case...) srh_true_p = (.25 * np.pi * (2**2)) * units('m^2/s^2') # Since there's only positive SRH in this case, total SRH will be equal to positive SRH and # negative SRH will be zero. srh_true_t = srh_true_p srh_true_n = 0 * units('m^2/s^2') p_srh, n_srh, T_srh = storm_relative_helicity(u_int, v_int, hgt_int, 1000 * units('meter'), bottom=0 * units('meter'), storm_u=0 * units.knot, storm_v=0 * units.knot) assert_almost_equal(p_srh, srh_true_p, 2) assert_almost_equal(n_srh, srh_true_n, 2) assert_almost_equal(T_srh, srh_true_t, 2)
def clean_up(self, drop_time=True, mask_invalid_wind=True, mask_relative_wind=True, convert_to_uv=True, convert_to_mps=True): """ Clean up the dataset and add essential attributes. Arguments --------- drop_time: bool Remove additional time variable (and leave only the index) mask_invalid_wind: bool Mask out wind speed and wind angle values if $INMWV Status is not "A" mask_relative_wind: bool Mask out wind speed and wind angle values if $INMWV Reference is not "T" convert_to_uv: bool Convert wind speed and wind angle to u- and v-components convert_to_mps: bool Convert units of wind speed and water speed from knots to m/s """ self.ds.longitude.attrs['units'] = 'degrees_east' self.ds.latitude.attrs['units'] = 'degrees_north' if drop_time: self.ds = self.ds.drop(labels=['time']) self.ds.rename(dict(index='time'), inplace=True) if mask_invalid_wind: self.ds.wind_angle.values[self.ds.status != 'A'] = np.nan self.ds.wind_speed.values[self.ds.status != 'A'] = np.nan self.ds = self.ds.drop(labels=['status']) if mask_relative_wind: self.ds.wind_angle.values[self.ds.reference != 'T'] = np.nan self.ds.wind_speed.values[self.ds.reference != 'T'] = np.nan self.ds = self.ds.drop(labels=['reference']) if convert_to_mps: kt2mps = metunits.units('knots').to('m/s') self.ds['wind_speed'] *= kt2mps self.ds['water_speed_knots'] *= kt2mps self.ds.rename(dict(water_speed_knots='water_speed'), inplace=True) else: kt2mps = metunits.units('knots') if convert_to_uv: u, v = mcalc.get_wind_components( self.ds.wind_speed.values * kt2mps, self.ds.wind_angle.values * metunits.units('degrees')) self.ds = self.ds.drop(labels=['wind_speed', 'wind_angle']) self.ds = self.ds.assign( u=xr.Variable(dims='time', data=u, attrs=dict(units='m s**-1', long_name='U component of wind', short_name='eastward_wind')), v=xr.Variable(dims='time', data=v, attrs=dict(units='m s**-1', long_name='V component of wind', short_name='northward_wind')))
def get_upper_air_data(date, station): """Get upper air observations from the test data cache. Parameters ---------- time : datetime The date and time of the desired observation. station : str The three letter ICAO identifier of the station for which data should be downloaded. Returns ------- dict : upper air data """ soudning_key = '{0:%Y-%m-%dT%HZ}_{1:}'.format(date, station) sounding_files = {'2016-05-22T00Z_DDC': 'may22_sounding.txt', '2013-01-20T12Z_OUN': 'jan20_sounding.txt', '1999-05-04T00Z_OUN': 'may4_sounding.txt', '2002-11-11T00Z_BNA': 'nov11_sounding.txt', '2010-12-09T12Z_BOI': 'dec9_sounding.txt'} fname = sounding_files[soudning_key] fobj = get_test_data(fname) def to_float(s): # Remove all whitespace and replace empty values with NaN if not s.strip(): s = 'nan' return float(s) # Skip dashes, column names, units, and more dashes for _ in range(4): fobj.readline() # Initiate lists for variables arr_data = [] # Read all lines of data and append to lists only if there is some data for row in fobj: level = to_float(row[0:7]) values = (to_float(row[7:14]), to_float(row[14:21]), to_float(row[21:28]), to_float(row[42:49]), to_float(row[49:56])) if any(np.invert(np.isnan(values[1:]))): arr_data.append((level,) + values) p, z, t, td, direc, spd = np.array(arr_data).T p = p * units.hPa z = z * units.meters t = t * units.degC td = td * units.degC direc = direc * units.degrees spd = spd * units.knots u, v = get_wind_components(spd, direc) return {'pressure': p, 'height': z, 'temperature': t, 'dewpoint': td, 'direction': direc, 'speed': spd, 'u_wind': u, 'v_wind': v}
def get_obs(ts, mybb): # copied from the browser url box metar_cat_url = 'http://thredds.ucar.edu/thredds/catalog/nws/metar/ncdecoded/catalog.xml?dataset=nws/metar/ncdecoded/Metar_Station_Data_fc.cdmr' # parse the xml metar_cat = TDSCatalog(metar_cat_url) # what datasets are here? only one "dataset" in this catalog dataset = list(metar_cat.datasets.values())[0] ncss_url = dataset.access_urls["NetcdfSubset"] ncss = NCSS(ncss_url) query = ncss.query().accept('csv').time(ts - datetime.timedelta(minutes=1)) query.lonlat_box(**mybb) query.variables('air_temperature', 'dew_point_temperature', 'inches_ALTIM', 'wind_speed', 'wind_from_direction', 'cloud_area_fraction', 'weather') try: data = ncss.get_data(query) lats = data['latitude'][:] lons = data['longitude'][:] tair = data['air_temperature'][:] dewp = data['dew_point_temperature'][:] slp = (data['inches_ALTIM'][:] * units('inHg')).to('mbar') # Convert wind to components u, v = mpcalc.get_wind_components(data['wind_speed'] * units.knot, data['wind_from_direction'] * units.deg) # Need to handle missing (NaN) and convert to proper code cloud_cover = 8 * data['cloud_area_fraction'] cloud_cover[np.isnan(cloud_cover)] = 9 cloud_cover = cloud_cover.astype(np.int) # For some reason these come back as bytes instead of strings stid = [s.decode() for s in data['station']] # Convert the text weather observations to WMO codes we can map to symbols if data['weather'].dtype != bool: wx_text = [s.decode('ascii') for s in data['weather']] wx_codes = np.array(list(to_code(wx_text))) else: wx_codes = np.array([0] * len(data['weather'])) sfc_data = {'latitude': lats, 'longitude': lons, 'air_temperature': tair, 'dew_point_temperature': dewp, 'eastward_wind': u, 'northward_wind': v, 'cloud_coverage': cloud_cover, 'air_pressure_at_sea_level': slp, 'present_weather': wx_codes} have_obs = True except: have_obs = False sfc_data = {} return sfc_data, have_obs
def test_wind_comps_basic(): """Test the basic wind component calculation.""" speed = np.array([4, 4, 4, 4, 25, 25, 25, 25, 10.]) * units.mph dirs = np.array([0, 45, 90, 135, 180, 225, 270, 315, 360]) * units.deg s2 = np.sqrt(2.) u, v = get_wind_components(speed, dirs) true_u = np.array([0, -4 / s2, -4, -4 / s2, 0, 25 / s2, 25, 25 / s2, 0 ]) * units.mph true_v = np.array([-4, -4 / s2, 0, 4 / s2, 25, 25 / s2, 0, -25 / s2, -10 ]) * units.mph assert_array_almost_equal(true_u, u, 4) assert_array_almost_equal(true_v, v, 4)
def build_pd(stn_id): key = 'b1c91e501782441d97ac056e2501b5b0' m = Meso(token=key) time = m.timeseries(stid=stn_id, start='199801010000', end='201801010000') ob = time['STATION'][0] temp = np.expand_dims(np.array(ob['OBSERVATIONS']['air_temp_set_1'], dtype=np.float), axis=1) wind_dir = np.expand_dims(np.array( ob['OBSERVATIONS']['wind_direction_set_1'], dtype=np.float), axis=1) * units.degrees wind_spd = np.expand_dims(np.array(ob['OBSERVATIONS']['wind_speed_set_1'], dtype=np.float), axis=1) * 1.9438445 wind_max = np.expand_dims(np.array( ob['OBSERVATIONS']['peak_wind_speed_set_1'], dtype=np.float), axis=1) * 1.9438445 u, v = mpcalc.get_wind_components(wind_spd, wind_dir) rel_hum = np.expand_dims(np.array( ob['OBSERVATIONS']['relative_humidity_set_1'], dtype=np.float), axis=1) dates = ob['OBSERVATIONS']['date_time'] years = float(dates[0][0:4]) months = float(dates[0][5:7]) hours = float(dates[0][8:10]) days = float(dates[0][11:13]) for i in range(len(dates) - 1): years = np.vstack((years, float(dates[i + 1][0:4]))) months = np.vstack((months, float(dates[i + 1][5:7]))) days = np.vstack((days, float(dates[i + 1][8:10]))) hours = np.vstack((hours, float(dates[i + 1][11:13]))) minutes = np.expand_dims(np.ones(len(hours)) * 55.0, axis=1) cols = [ 'Year', 'Month', 'Day', 'Hour', 'Minutes', 'Temp', 'RH', 'Dir', 'Spd', 'Max', 'U', 'V' ] data = np.hstack((years, months, days, hours, minutes, temp, rel_hum, wind_dir, wind_spd, wind_max, u, v)) data = pd.DataFrame(data=data, columns=cols) pickle.dump(data, open('../Data/pickles/' + stn_id + '_20yr_RAWS.p', 'wb')) return data
def plot_skewt(df): # We will pull the data out of the example dataset into individual variables # and assign units. p = df['pressure'].values * units.hPa T = df['temperature'].values * units.degC Td = df['dewpoint'].values * units.degC wind_speed = df['speed'].values * units.knots wind_dir = df['direction'].values * units.degrees u, v = mpcalc.get_wind_components(wind_speed, wind_dir) # Create a new figure. The dimensions here give a good aspect ratio. fig = plt.figure(figsize=(9, 9)) add_metpy_logo(fig, 115, 100) skew = SkewT(fig, rotation=45) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-40, 60) # Calculate LCL height and plot as black dot lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black') # Calculate full parcel profile and add to plot as black line prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') skew.plot(p, prof, 'k', linewidth=2) # An example of a slanted line at constant T -- in this case the 0 # isotherm skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) # Add the relevant special lines skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() return skew
def test_helicity(): """Test function for SRH calculations on an eigth-circle hodograph.""" pres_test = np.asarray([ 1013.25, 954.57955706, 898.690770743, 845.481604002, 794.85264282 ]) * units('hPa') hgt_test = hgt_test = np.asarray([0, 500, 1000, 1500, 2000]) # Create larger arrays for everything except pressure to make a smoother graph hgt_int = np.arange(0, 2050, 50) hgt_int = hgt_int * units('meter') dir_int = np.arange(180, 272.25, 2.25) spd_int = np.zeros((hgt_int.shape[0])) spd_int[:] = 2. u_int, v_int = get_wind_components(spd_int * units('m/s'), dir_int * units.degree) # Interpolate pressure to that graph pres_int = np.interp(hgt_int, hgt_test, np.log(pres_test.magnitude)) pres_int = np.exp(pres_int) * units('hPa') # Put in the correct value of SRH for a eighth-circle, 2 m/s hodograph # (SRH = 2 * area under hodo, in this case...) srh_true_p = (.25 * np.pi * (2**2)) * units('m^2/s^2') # Since there's only positive SRH in this case, total SRH will be equal to positive SRH and # negative SRH will be zero. srh_true_t = srh_true_p srh_true_n = 0 * units('m^2/s^2') p_srh, n_srh, T_srh = storm_relative_helicity(u_int, v_int, pres_int, hgt_int, 1000 * units('meter'), bottom=0 * units('meter'), storm_u=0 * units.knot, storm_v=0 * units.knot) assert_almost_equal(p_srh, srh_true_p, 2) assert_almost_equal(n_srh, srh_true_n, 2) assert_almost_equal(T_srh, srh_true_t, 2)
# Remove bad data from wind information wind_speed = np.array([w[0] for w in wind]) wind_dir = np.array([w[1] for w in wind]) good_indices = np.where((~np.isnan(wind_dir)) & (~np.isnan(wind_speed))) x = x[good_indices] y = y[good_indices] wind_speed = wind_speed[good_indices] wind_dir = wind_dir[good_indices] ########################################### # Calculate u and v components of wind and then interpolate both. # # Both will have the same underlying grid so throw away grid returned from v interpolation. u, v = get_wind_components((wind_speed * units('m/s')).to('knots'), wind_dir * units.degree) windgridx, windgridy, uwind = interpolate(x, y, np.array(u), interp_type='cressman', search_radius=400000, hres=100000) _, _, vwind = interpolate(x, y, np.array(v), interp_type='cressman', search_radius=400000, hres=100000) ########################################### # Get temperature information levels = list(range(-20, 20, 1)) cmap = plt.get_cmap('viridis') norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True) xt, yt, t = station_test_data('air_temperature', from_proj, to_proj) xt, yt, t = remove_nan_observations(xt, yt, t)
0), np.nanmean( np.cos(Direction_deg[indCopter][indTimeAvg] * np.pi / 180.), 0)) * 180. / np.pi ######################################## ## Convert wind to kts, fix direction ## ######################################## #wind_kts = np.array([w * 1.94 for w in wind]) wind_kts = wind * 1.94 iNeg = np.squeeze(np.where(direction < 0.)) direction[iNeg] = direction[iNeg] + 360. u, v = mcalc.get_wind_components(wind_kts * units.kts, direction * units.deg) u = u.to(units.kts) v = v.to(units.kts) ################################## ## Find average between sensors ## ################################## TArr = np.array([t1, t2, t3, t4]) RHArr = np.array([rh1, rh2, rh3, rh4]) Tmean = np.nanmean(TArr, 0) RHmean = np.nanmean(RHArr, 0) if np.isnan(RHmean).all(): isRH = 0 else:
def plotUAVskewT(filenamecsv): ''' Input filepath of post-processed uav data Outputs Skew-T log-p plot of UAV data, includes hodograph and some convective parameters ''' copdata = csvread_copter(filenamecsv) lat = copdata[0] lon = copdata[1] alt = copdata[2] pressure = copdata[3] temperature = copdata[4] dewpoint = copdata[5] speed = copdata[9] speed_kts = speed * 1.94 direction = copdata[10] site = findSite(lat[0], lon[0]) sitename, sitelong = site.split('/') fname = filenamecsv.split('\\')[-1] timeTakeoff = datetime.strptime(fname[:15], '%Y%m%d_%H%M%S') copterNum = fname[-10] u,v = mcalc.get_wind_components(speed_kts*units.kts, direction * units.deg) u = u.to(units.kts) v = v.to(units.kts) # Wind shear bulkshear = speed_kts[-3] - speed_kts[0] print '0-%d m Bulk Shear: %.0f kts' % (alt[-3], bulkshear) if np.isnan(dewpoint).all(): moist = 0 else: moist = 1 print 'Plotting...' fignum = plt.figure(figsize=(12,9)) gs = gridspec.GridSpec(4, 4) skew = SkewT(fignum, rotation=20, subplot=gs[:, :2]) skew.plot(pressure, temperature, 'r', linewidth = 2) skew.plot(pressure, dewpoint, 'g', linewidth = 2) skew.plot_barbs(pressure[0::4], u[0::4], v[0::4], x_clip_radius = 0.12, \ y_clip_radius = 0.12) # Plot convective parameters if moist: plcl, Tlcl, isbelowlcl, profile = parcelUAV(temperature, dewpoint, pressure) SBCAPE = uavCAPE(temperature * units.degC, profile, pressure * units.hPa) skew.plot(plcl, Tlcl, 'ko', markerfacecolor='black') skew.plot(pressure, profile, 'k', linewidth=2) else: isbelowlcl = 0 # set up plot limits and labels - use LCL as max if higher than profile # if moist: # xmin = math.floor(np.nanmin(dewpoint)) + 2 # else: # xmin = math.floor(np.nanmin(temperature)) # xmax = math.floor(np.nanmax(temperature)) + 20 xmin = 0. xmax = 50. if isbelowlcl: ymin = round((plcl / units.mbar), -1) - 10 else: ymin = round(np.nanmin(pressure),-1) - 10 ymax = round(np.nanmax(pressure),-1) + 10 skew.ax.set_ylim(ymax, ymin) skew.ax.set_xlim(xmin, xmax) skew.ax.set_yticks(np.arange(ymin, ymax+10, 10)) skew.ax.set_xlabel('Temperature ($^\circ$C)') skew.ax.set_ylabel('Pressure (hPa)') titleName = 'Coptersonde-%s %s UTC - %s' % (copterNum, timeTakeoff.strftime('%d-%b-%Y %H:%M:%S'), sitename) skew.ax.set_title(titleName) skew.plot_dry_adiabats(linewidth=0.75) skew.plot_moist_adiabats(linewidth=0.75) skew.plot_mixing_lines(linewidth=0.75) # Hodograph ax_hod = fignum.add_subplot(gs[:2,2:]) #gs.tight_layout(fig5) if np.nanmax(speed_kts) > 18: comprange = 35 else: comprange = 20 h = Hodograph(ax_hod, component_range=comprange) h.add_grid(increment=5) h.plot_colormapped(u, v, pressure, cmap=cmocean.cm.deep_r) ax_hod.set_title('Hodograph (kts)') ax_hod.yaxis.set_ticklabels([]) #ax_hod.set_xlabel('Wind Speed (kts)') # Map - Oklahoma llcrnrlat = 33.6 urcrnrlat = 37.2 llcrnrlon = -103.2 urcrnrlon = -94.2 ax_map = fignum.add_subplot(gs[2, 2:]) m = Basemap(projection='merc', llcrnrlat=llcrnrlat, urcrnrlat=urcrnrlat, llcrnrlon=llcrnrlon,urcrnrlon=urcrnrlon, lat_ts=20, resolution='l', ax=ax_map) print 'Basemap...' m.drawcounties() m.drawstates() x,y = m(lon[0], lat[0]) plt.plot(x,y,'b.') plt.text(x+40000, y-5000, sitelong, bbox=dict(facecolor='yellow', alpha=0.5)) if moist: # Convective parameter values ax_data = fignum.add_subplot(gs[3, 2]) plt.axis('off') datastr = 'LCL = %.0f hPa\nSBCAPE = %.0f J kg$^{-1}$\n0-%.0f m bulk shear\n\ = %.0f kts' % \ (plcl.magnitude, SBCAPE.magnitude, alt[-3], bulkshear) boxprops = dict(boxstyle='round', facecolor='none') ax_data.text(0.05, 0.95, datastr, transform=ax_data.transAxes, fontsize=14, verticalalignment='top', bbox=boxprops) # Logos ax_png = fignum.add_subplot(gs[3, 3]) img = mpimg.imread(logoName) plt.axis('off') plt.imshow(img) else: # Logos ax_png = fignum.add_subplot(gs[3, 2:]) img = mpimg.imread(logoName) plt.axis('off') plt.imshow(img) plt.show(block=False) return
def do(ts): """Process this date timestamp""" asos = get_dbconn('asos', user='******') iemaccess = get_dbconn('iem') icursor = iemaccess.cursor() df = read_sql(""" select station, network, iemid, drct, sknt, valid at time zone tzname as localvalid, tmpf, dwpf from alldata d JOIN stations t on (t.id = d.station) where (network ~* 'ASOS' or network = 'AWOS') and valid between %s and %s and t.tzname is not null and date(valid at time zone tzname) = %s ORDER by valid ASC """, asos, params=(ts - datetime.timedelta(days=2), ts + datetime.timedelta(days=2), ts.strftime("%Y-%m-%d")), index_col=None) # derive some parameters df['relh'] = mcalc.relative_humidity_from_dewpoint( df['tmpf'].values * munits.degF, df['dwpf'].values * munits.degF).to(munits.percent) df['feel'] = mcalc.apparent_temperature( df['tmpf'].values * munits.degF, df['relh'].values * munits.percent, df['sknt'].values * munits.knots ) df['u'], df['v'] = mcalc.get_wind_components( df['sknt'].values * munits.knots, df['drct'].values * munits.deg ) df['localvalid_lag'] = df.groupby('iemid')['localvalid'].shift(1) df['timedelta'] = df['localvalid'] - df['localvalid_lag'] ndf = df[pd.isna(df['timedelta'])] df.loc[ndf.index.values, 'timedelta'] = pd.to_timedelta( ndf['localvalid'].dt.hour * 3600. + ndf['localvalid'].dt.minute * 60., unit='s' ) df['timedelta'] = df['timedelta'] / np.timedelta64(1, 's') table = "summary_%s" % (ts.year,) for iemid, gdf in df.groupby('iemid'): if len(gdf.index) < 6: # print(" Quorum not meet for %s" % (gdf.iloc[0]['station'], )) continue ldf = gdf.copy() ldf.interpolate(inplace=True) totsecs = ldf['timedelta'].sum() avg_rh = clean((ldf['relh'] * ldf['timedelta']).sum() / totsecs, 1, 100) min_rh = clean(ldf['relh'].min(), 1, 100) max_rh = clean(ldf['relh'].max(), 1, 100) uavg = (ldf['u'] * ldf['timedelta']).sum() / totsecs vavg = (ldf['u'] * ldf['timedelta']).sum() / totsecs drct = clean( mcalc.get_wind_dir(uavg * munits.knots, vavg * munits.knots), 0, 360) avg_sknt = clean( (ldf['sknt'] * ldf['timedelta']).sum() / totsecs, 0, 150 # arb ) max_feel = clean(ldf['feel'].max(), -150, 200) avg_feel = clean( (ldf['feel'] * ldf['timedelta']).sum() / totsecs, -150, 200 ) min_feel = clean(ldf['feel'].min(), -150, 200) def do_update(): """Inline updating""" icursor.execute(""" UPDATE """ + table + """ SET avg_rh = %s, min_rh = %s, max_rh = %s, avg_sknt = %s, vector_avg_drct = %s, min_feel = %s, avg_feel = %s, max_feel = %s WHERE iemid = %s and day = %s """, (avg_rh, min_rh, max_rh, avg_sknt, drct, min_feel, avg_feel, max_feel, iemid, ts)) do_update() if icursor.rowcount == 0: print(('compute_daily Adding %s for %s %s %s' ) % (table, gdf.iloc[0]['station'], gdf.iloc[0]['network'], ts)) icursor.execute(""" INSERT into """ + table + """ (iemid, day) values (%s, %s) """, (iemid, ts)) do_update() icursor.close() iemaccess.commit() iemaccess.close()
def test_get_wind_components(): """Test that get_wind_components wrapper works (deprecated in 0.9).""" u, v = get_wind_components(8 * units('m/s'), 150 * units.deg) assert_almost_equal(u, -4 * units('m/s'), 3) assert_almost_equal(v, 6.9282 * units('m/s'), 3)
# Remove bad data from wind information wind_speed = np.array([w[0] for w in wind]) wind_dir = np.array([w[1] for w in wind]) good_indices = np.where((~np.isnan(wind_dir)) & (~np.isnan(wind_speed))) x = x[good_indices] y = y[good_indices] wind_speed = wind_speed[good_indices] wind_dir = wind_dir[good_indices] ########################################### # Calculate u and v components of wind and then interpolate both. # # Both will have the same underlying grid so throw away grid returned from v interpolation. u, v = get_wind_components((wind_speed * units('m/s')).to('knots'), wind_dir * units.degree) windgridx, windgridy, uwind = interpolate(x, y, np.array(u), interp_type='cressman', search_radius=400000, hres=100000) _, _, vwind = interpolate(x, y, np.array(v), interp_type='cressman', search_radius=400000, hres=100000)
h_new_labels = h_new_labels[0:index + 1] p_interped_func = interpolate.interp1d(h, p) p_interped = p_interped_func(h_new[0:index + 1]) # Add units to the data arrays p = p * units.mbar p_std = p_std * units.mbar T = T * units.degC Td = Td * units.degC spd = spd * units.knot spd_std = spd_std * units.knot direc = direc * units.deg direc_std = direc_std * units.deg # Convert wind speed and direction to components u, v = get_wind_components(spd, direc) u_std, v_std = get_wind_components(spd_std, direc_std) #PARCEL CALCULATIONS with sharppy sfcpcl = params.parcelx(prof, flag=1) # Surface Parcel fcstpcl = params.parcelx(prof, flag=2) # Forecast Parcel mupcl = params.parcelx(prof, flag=3) # Most-Unstable Parcel mlpcl = params.parcelx(prof, flag=4) # 100 mb Mean Layer Parcel sfc = prof.pres[prof.sfc] p3km = interp.pres(prof, interp.to_msl(prof, 3000.)) p6km = interp.pres(prof, interp.to_msl(prof, 6000.)) p1km = interp.pres(prof, interp.to_msl(prof, 1000.)) mean_3km = winds.mean_wind(prof, pbot=sfc, ptop=p3km) sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km) sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km)
def test_warning_dir(): """Test that warning is raised wind direction > 2Pi.""" with pytest.warns(UserWarning): get_wind_components(3. * units('m/s'), 270)
# coding: utf-8 import matplotlib.pyplot as plt import numpy as np from metpy.calc import get_wind_components from metpy.plots import SkewT # Parse the data p, T, Td, direc, spd = np.loadtxt('../testdata/sounding_data.txt', usecols=(0, 2, 3, 6, 7), unpack=True) u, v = get_wind_components(spd, direc) # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) skew = SkewT(fig) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) # Add the relevant special lines skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() skew.ax.set_ylim(1000, 100) # Show the plot plt.show()
# Get wind information and mask where either speed or direction is unavailable wind_speed = (data['wind_speed'].values * units('m/s')).to('knots') wind_dir = data['wind_dir'].values * units.degree good_indices = np.where((~np.isnan(wind_dir)) & (~np.isnan(wind_speed))) x_masked = xp[good_indices] y_masked = yp[good_indices] wind_speed = wind_speed[good_indices] wind_dir = wind_dir[good_indices] ########################################### # Calculate u and v components of wind and then interpolate both. # # Both will have the same underlying grid so throw away grid returned from v interpolation. u, v = get_wind_components(wind_speed, wind_dir) windgridx, windgridy, uwind = interpolate(x_masked, y_masked, np.array(u), interp_type='cressman', search_radius=400000, hres=100000) _, _, vwind = interpolate(x_masked, y_masked, np.array(v), interp_type='cressman', search_radius=400000, hres=100000)
# Set up the map projection proj = ccrs.LambertConformal(central_longitude=13, central_latitude=47, standard_parallels=[35]) # Use the cartopy map projection to transform station locations to the map and # then refine the number of stations plotted by setting a 300km radius point_locs = proj.transform_points(ccrs.PlateCarree(), df['longitude'].values, df['latitude'].values) df = df[reduce_point_density(point_locs, 1000.)] # Map weather strings to WMO codes, which we can use to convert to symbols # Only use the first symbol if there are multiple df['weather'] = df['weather'].replace('-SG','SG') df['weather'] = df['weather'].replace('FZBR','FZFG') wx = [wx_code_map[s.split()[0] if ' ' in s else s] for s in df['weather'].fillna('')] # Get the wind components, converting from m/s to knots as will be appropriate # for the station plot. u, v = get_wind_components(((df['wind_speed'].values)*units('m/s')).to('knots'), (df['wind_from_direction'].values) * units.degree) cloud_frac = df['cloud_area_fraction'] # Change the DPI of the resulting figure. Higher DPI drastically improves the # look of the text rendering. # plt.rcParams['savefig.dpi'] = 100 # ============================================================================ # Create the figure and an axes set to the projection. # fig = plt.figure(figsize=(20, 8)) # ax = fig.add_subplot(1, 1, 1, projection=proj) # # Set up a cartopy feature for state borders. state_boundaries = feat.NaturalEarthFeature(category='cultural', name='admin_0_countries', scale='10m', facecolor='none')
# then refine the number of stations plotted by setting a 300km radius point_locs = proj.transform_points(ccrs.PlateCarree(), data['lon'].values, data['lat'].values) data = data[reduce_point_density(point_locs, 300000.)] ########################################### # Now that we have the data we want, we need to perform some conversions: # # - Get wind components from speed and direction # - Convert cloud fraction values to integer codes [0 - 8] # - Map METAR weather codes to WMO codes for weather symbols # Get the wind components, converting from m/s to knots as will be appropriate # for the station plot. u, v = get_wind_components( (data['wind_speed'].values * units('m/s')).to('knots'), data['wind_dir'].values * units.degree) # Convert the fraction value into a code of 0-8 and compensate for NaN values, # which can be used to pull out the appropriate symbol cloud_frac = (8 * data['cloud_fraction']) cloud_frac[np.isnan(cloud_frac)] = 10 cloud_frac = cloud_frac.astype(int) # Map weather strings to WMO codes, which we can use to convert to symbols # Only use the first symbol if there are multiple wx_codes = { '': 0, 'HZ': 5, 'BR': 10, '-DZ': 51,
text_time = ax.text(0.01, 0.01, timestamp.strftime('%d %B %Y %H%MZ'), horizontalalignment='left', transform=ax.transAxes, color='white', fontsize=100, weight='bold') outline_effect = [patheffects.withStroke(linewidth=15, foreground='black')] text_time.set_path_effects(outline_effect) ax.set_extent([-124.5, -105, 38.5, 50]) # Transform plane heading to a map direction and plot a rotated marker u, v = mpcalc.get_wind_components(1 * units('m/s'), data['heading'] * units('degrees')) u, v = proj.transform_vectors(ccrs.PlateCarree(), np.array([data['longitude']]), np.array([data['latitude']]), np.array([u.m]), np.array([v.m])) map_direction = -mpcalc.get_wind_dir(u, v).to('degrees') map_direction = map_direction[0].m ax.scatter(data['longitude'], data['latitude'], transform=ccrs.PlateCarree(), marker=(3, 0, map_direction), color='red', s=4000) ax.text(data['longitude'],
data['dew_point_temperature'] = data_arr['dewpoint'] * units.degC data['air_pressure_at_sea_level'] = data_arr['slp'] * units('mbar') ########################################### # Notice that the names (the keys) in the dictionary are the same as those that the # layout is expecting. # # Now perform a few conversions: # # - Get wind components from speed and direction # - Convert cloud fraction values to integer codes [0 - 8] # - Map METAR weather codes to WMO codes for weather symbols # Get the wind components, converting from m/s to knots as will be appropriate # for the station plot u, v = get_wind_components(data_arr['wind_speed'] * units('m/s'), data_arr['wind_dir'] * units.degree) data['eastward_wind'], data['northward_wind'] = u, v # Convert the fraction value into a code of 0-8, which can be used to pull out # the appropriate symbol data['cloud_coverage'] = (8 * data_arr['cloud_fraction']).astype(int) # Map weather strings to WMO codes, which we can use to convert to symbols # Only use the first symbol if there are multiple wx_text = [s.decode('ascii') for s in data_arr['weather']] wx_codes = {'': 0, 'HZ': 5, 'BR': 10, '-DZ': 51, 'DZ': 53, '+DZ': 55, '-RA': 61, 'RA': 63, '+RA': 65, '-SN': 71, 'SN': 73, '+SN': 75} data['present_weather'] = [wx_codes[s.split()[0] if ' ' in s else s] for s in wx_text] ########################################### # All the data wrangling is finished, just need to set up plotting and go:
def test_wind_comps_scalar(): """Test wind components calculation with scalars.""" u, v = get_wind_components(8 * units('m/s'), 150 * units.deg) assert_almost_equal(u, -4 * units('m/s'), 3) assert_almost_equal(v, 6.9282 * units('m/s'), 3)
def plot_upper_air(station='11035', date=False): ''' ----------------------------- Default use of plot_upper_air: This will plot a SkewT sounding for station '11035' (Wien Hohe Warte) plot_upper_air(station='11035', date=False) ''' # sns.set(rc={'axes.facecolor':'#343837', 'figure.facecolor':'#343837', # 'grid.linestyle':'','axes.labelcolor':'#04d8b2','text.color':'#04d8b2', # 'xtick.color':'#04d8b2','ytick.color':'#04d8b2'}) # Get time in UTC station = str(station) if date is False: now = datetime.utcnow() # If morning then 0z sounding, otherwise 12z if now.hour < 12: hour = 0 else: hour = 12 date = datetime(now.year, now.month, now.day, hour) datestr = date.strftime('%Hz %Y-%m-%d') print('{}'.format(date)) else: year = int(input('Please specify the year: ')) month = int(input('Please specify the month: ')) day = int(input('Please specify the day: ')) hour = int(input('Please specify the hour: ')) if hour < 12: hour = 0 else: hour = 12 date = datetime(year, month, day, hour) datestr = date.strftime('%Hz %Y-%m-%d') print('You entered {}'.format(date)) # This requests the data 11035 is df = WyomingUpperAir.request_data(date, station) # Create single variables wih the right units p = df['pressure'].values * units.hPa T = df['temperature'].values * units.degC Td = df['dewpoint'].values * units.degC wind_speed = df['speed'].values * units.knots wind_dir = df['direction'].values * units.degrees wind_speed_6k = df['speed'][df.height <= 6000].values * units.knots wind_dir_6k = df['direction'][df.height <= 6000].values * units.degrees u, v = mpcalc.get_wind_components(wind_speed, wind_dir) u6, v6 = mpcalc.get_wind_components(wind_speed_6k, wind_dir_6k) # Calculate the LCL lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) print(lcl_pressure, lcl_temperature) # Calculate the parcel profile. parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') cape, cin = mpcalc.cape_cin(p, T, Td, parcel_prof) ############################# # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) gs = gridspec.GridSpec(3, 3) skew = SkewT(fig, rotation=45, subplot=gs[:, :2]) # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-45, 40) # Plot LCL as black dot skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black') # Plot the parcel profile as a black line skew.plot(p, parcel_prof, 'k', linewidth=2) # Shade areas of CAPE and CIN skew.shade_cin(p, T, parcel_prof) skew.shade_cape(p, T, parcel_prof) # Plot a zero degree isotherm skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) skew.ax.set_title('Station: ' + str(station) + '\n' + datestr) # set title skew.ax.set_xlabel('Temperature (C)') skew.ax.set_ylabel('Pressure (hPa)') # Add the relevant special lines skew.plot_dry_adiabats(linewidth=0.7) skew.plot_moist_adiabats(linewidth=0.7) skew.plot_mixing_lines(linewidth=0.7) # Create a hodograph # Create an inset axes object that is 40% width and height of the # figure and put it in the upper right hand corner. # ax_hod = inset_axes(skew.ax, '40%', '40%', loc=1) ax = fig.add_subplot(gs[0, -1]) h = Hodograph(ax, component_range=60.) h.add_grid(increment=20) # Plot a line colored by windspeed h.plot_colormapped(u6, v6, wind_speed_6k) # add another subplot for the text of the indices # ax_t = fig.add_subplot(gs[1:,2]) skew2 = SkewT(fig, rotation=0, subplot=gs[1:, 2]) skew2.plot(p, T, 'r') skew2.plot(p, Td, 'g') # skew2.plot_barbs(p, u, v) skew2.ax.set_ylim(1000, 700) skew2.ax.set_xlim(-30, 10) # Show the plot plt.show() return cape
# print(avg_speed.to_base_units()) # put in the base units (m/s) # print(avg_speed.to('mph')) # put in mph # # It also lets us avoid worrying about the exact units of arguments to # # calculation functions: # from metpy.calc import saturation_vapor_pressure # e = saturation_vapor_pressure(Td) # es = saturation_vapor_pressure(T) # rh = e / es # relative humidity # print(e) # in millibar # print(es) # in millibar # print(rh) # dimensionless # Convert wind speed and direction to components from metpy.calc import get_wind_components u, v = get_wind_components(spd, direc) ################## PLOTTING ON A SKEW-T logP ###################### import matplotlib.pyplot as plt from metpy.plots import SkewT # create a new figure. The dimensions here gove a good aspect ratio fig = plt.figure(figsize=(7, 9)) skew = SkewT(fig) # passing the figure, use skewT # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dictated by the typical meteorological plot skew.plot(p, T, 'r') # pressure and temperature in red skew.plot(p, Td, 'g') skew.plot_barbs(p, u, v) skew.ax.set_ylim(1000, 100) # Y limits from 1000 in the botton to 100 millibars to the top
def test_get_wind_components(): """Test that get_wind_components wrapper works (deprecated in 0.9).""" with pytest.warns(MetpyDeprecationWarning): u, v = get_wind_components(8 * units('m/s'), 150 * units.deg) assert_almost_equal(u, -4 * units('m/s'), 3) assert_almost_equal(v, 6.9282 * units('m/s'), 3)
data['dew_point_temperature'] = data_arr['dew_point_temperature'] * units.degC data['air_pressure_at_sea_level'] = data_arr['slp'] * units('mbar') ########################################### # Notice that the names (the keys) in the dictionary are the same as those that the # layout is expecting. # # Now perform a few conversions: # # - Get wind components from speed and direction # - Convert cloud fraction values to integer codes [0 - 8] # - Map METAR weather codes to WMO codes for weather symbols # Get the wind components, converting from m/s to knots as will be appropriate # for the station plot u, v = get_wind_components(data_arr['wind_speed'] * units('m/s'), data_arr['wind_dir'] * units.degree) data['eastward_wind'], data['northward_wind'] = u, v # Convert the fraction value into a code of 0-8, which can be used to pull out # the appropriate symbol data['cloud_coverage'] = (8 * data_arr['cloud_fraction']).astype(int) # Map weather strings to WMO codes, which we can use to convert to symbols # Only use the first symbol if there are multiple wx_text = [s.decode('ascii') for s in data_arr['weather']] wx_codes = { '': 0, 'HZ': 5, 'BR': 10, '-DZ': 51, 'DZ': 53,
import metpy.calc as mpcalc from metpy.units import units data = pd.read_csv( '~/Data/masdar_station_data/wyoming/metar+rs/201712/AbuDhabi_upperair_2017122112.csv' ) data = data.apply(pd.to_numeric, errors='coerce') #pd.set_option('display.float_format', '{:.2E}'.format) #new_data=pd.concat([data['PRES'][1::][::-1],data['TEMP'][1::][::-1]+273.15,data['MIXR'][1::][::-1]/1000,data['MIXR'][1::][::-1]*0,(data['MIXR'][1::][::-1]*0).astype(int) ],axis=1 ) #new_data.to_csv('/home/vkvalappil/Data/modelWRF/LES/UCLALES-SALSA/bin/datafiles/dsrt.lay',sep=',',index=False,float_format='%.3E') wind_speed = (data['SKNT'] * 0.514).values * units('m/s') wind_dir = data['DRCT'].values * units.deg #data['u_wind'], data['v_wind'] = mpcalc.get_wind_components(data['SKNT'][1::]*0.51,np.deg2rad(data['DRCT'][1::])) data['u_wind'], data['v_wind'] = mpcalc.get_wind_components( wind_speed, wind_dir) #u, v = mpcalc.get_wind_components(data['SKNT'][1::], data['DRCT'][1::]) new_data = pd.concat([ data['HGHT'][1::], data['TEMP'][1::] + 273.15, data['MIXR'][1::], data['u_wind'][1::], data['v_wind'][1::] ], axis=1) new_data.to_csv( '/home/vkvalappil/Data/modelWRF/LES/UCLALES-SALSA/bin/sound_in_2017122112', sep=',', index=False) #float_format='%.3E'
from metpy.units import units ########################################### # Upper air data can be obtained using the siphon package, but for this example we will use # some of MetPy's sample data. col_names = [ 'pressure', 'height', 'temperature', 'dewpoint', 'direction', 'speed' ] df = pd.read_fwf(get_test_data('may4_sounding.txt', as_file_obj=False), skiprows=5, usecols=[0, 1, 2, 3, 6, 7], names=col_names) df['u_wind'], df['v_wind'] = mpcalc.get_wind_components( df['speed'], np.deg2rad(df['direction'])) # Drop any rows with all NaN values for T, Td, winds df = df.dropna(subset=('temperature', 'dewpoint', 'direction', 'speed', 'u_wind', 'v_wind'), how='all').reset_index(drop=True) ########################################### # We will pull the data out of the example dataset into individual variables and # assign units. p = df['pressure'].values * units.hPa T = df['temperature'].values * units.degC Td = df['dewpoint'].values * units.degC wind_speed = df['speed'].values * units.knots wind_dir = df['direction'].values * units.degrees
data = np.concatenate([all_data[all_stids.index(site)].reshape(1,) for site in whitelist]) ########################################### # Now that we have the data we want, we need to perform some conversions: # # - Get a list of strings for the station IDs # - Get wind components from speed and direction # - Convert cloud fraction values to integer codes [0 - 8] # - Map METAR weather codes to WMO codes for weather symbols # Get all of the station IDs as a list of strings stid = [s.decode('ascii') for s in data['stid']] # Get the wind components, converting from m/s to knots as will be appropriate # for the station plot u, v = get_wind_components((data['wind_speed'] * units('m/s')).to('knots'), data['wind_dir'] * units.degree) # Convert the fraction value into a code of 0-8, which can be used to pull out # the appropriate symbol cloud_frac = (8 * data['cloud_fraction']).astype(int) # Map weather strings to WMO codes, which we can use to convert to symbols # Only use the first symbol if there are multiple wx_text = [s.decode('ascii') for s in data['weather']] wx_codes = {'': 0, 'HZ': 5, 'BR': 10, '-DZ': 51, 'DZ': 53, '+DZ': 55, '-RA': 61, 'RA': 63, '+RA': 65, '-SN': 71, 'SN': 73, '+SN': 75} wx = [wx_codes[s.split()[0] if ' ' in s else s] for s in wx_text] ########################################### # Now all the data wrangling is finished, just need to set up plotting and go # Set up the map projection and set up a cartopy feature for state borders
def radar_plus_obs(station, my_datetime, radar_title=None, bb=None, station_radius=75000., station_layout=simple_layout, field='reflectivity', vmin=None, vmax=None, sweep=0): if radar_title is None: radar_title = 'Area ' radar = get_radar_from_aws(station, my_datetime) # Lets get some geographical context if bb is None: lats = radar.gate_latitude lons = radar.gate_longitude min_lon = lons['data'].min() min_lat = lats['data'].min() max_lat = lats['data'].max() max_lon = lons['data'].max() bb = {'north' : max_lat, 'south' : min_lat, 'east' : max_lon, 'west' : min_lon} else: min_lon = bb['west'] min_lat = bb['south'] max_lon = bb['east'] max_lat = bb['north'] print('min_lat:', min_lat, ' min_lon:', min_lon, ' max_lat:', max_lat, ' max_lon:', max_lon) index_at_start = radar.sweep_start_ray_index['data'][sweep] time_at_start_of_radar = num2date(radar.time['data'][index_at_start], radar.time['units']) pacific = pytz.timezone('US/Central') local_time = pacific.fromutc(time_at_start_of_radar) fancy_date_string = local_time.strftime('%A %B %d at %I:%M %p %Z') print(fancy_date_string) metar_cat = TDSCatalog('http://thredds.ucar.edu/thredds/catalog/nws/metar/ncdecoded/catalog.xml?' 'dataset=nws/metar/ncdecoded/Metar_Station_Data_fc.cdmr') dataset = list(metar_cat.datasets.values())[0] ncss = NCSS(dataset.access_urls["NetcdfSubset"]) query = ncss.query().accept('csv').time(time_at_start_of_radar) query.lonlat_box(north=max_lat, south=min_lat, east=max_lon, west=min_lon) query.variables('air_temperature', 'dew_point_temperature', 'inches_ALTIM', 'wind_speed', 'wind_from_direction', 'cloud_area_fraction', 'weather') data = ncss.get_data(query) lats = data['latitude'][:] lons = data['longitude'][:] tair = data['air_temperature'][:] dewp = data['dew_point_temperature'][:] slp = (data['inches_ALTIM'][:] * units('inHg')).to('mbar') # Convert wind to components u, v = mpcalc.get_wind_components(data['wind_speed'] * units.knot, data['wind_from_direction'] * units.deg) # Need to handle missing (NaN) and convert to proper code cloud_cover = 8 * data['cloud_area_fraction'] cloud_cover[np.isnan(cloud_cover)] = 9 cloud_cover = cloud_cover.astype(np.int) # For some reason these come back as bytes instead of strings stid = [s.decode() for s in data['station']] # Convert the text weather observations to WMO codes we can map to symbols #wx_text = [s.decode('ascii') for s in data['weather']] #wx_codes = np.array(list(to_code(wx_text))) sfc_data = {'latitude': lats, 'longitude': lons, 'air_temperature': tair, 'dew_point_temperature': dewp, 'eastward_wind': u, 'northward_wind': v, 'cloud_coverage': cloud_cover, 'air_pressure_at_sea_level': slp}#, 'present_weather': wx_codes} fig = plt.figure(figsize=(10, 8)) display = pyart.graph.RadarMapDisplayCartopy(radar) lat_0 = display.loc[0] lon_0 = display.loc[1] # Set our Projection projection = cartopy.crs.Mercator(central_longitude=lon_0, min_latitude=min_lat, max_latitude=max_lat) # Call our function to reduce data filter_data(sfc_data, projection, radius=station_radius, sort_key='present_weather') print(sweep) display.plot_ppi_map( field, sweep, colorbar_flag=True, title=radar_title +' area ' + field + ' \n' + fancy_date_string, projection=projection, min_lon=min_lon, max_lon=max_lon, min_lat=min_lat, max_lat=max_lat, vmin=vmin, vmax=vmax) # Mark the radar display.plot_point(lon_0, lat_0, label_text='Radar') # Get the current axes and plot some lat and lon lines gl = display.ax.gridlines(draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xlabels_top = False gl.ylabels_right = False # Make the station plot stationplot = StationPlot(display.ax, sfc_data['longitude'], sfc_data['latitude'], transform=cartopy.crs.PlateCarree(), fontsize=12) station_layout.plot(stationplot, sfc_data) return display, time_at_start_of_radar
sounding_data = fall_soundings.loc[ (fall_soundings[cols[1]]==mo) & (fall_soundings[cols[0]]==yr) & (fall_soundings[cols[2]]==day)] T = convert_temperature(sounding_data[cols[6]].values,'F','C') rh = sounding_data[cols[8]].values sounding_data[cols[7]] = calc_dewpt(T,rh) sounding_data = sounding_data.dropna(subset = (' Temp', ' Dewpt'),how='all').reset_index(drop=True) hours = [np.min(sounding_data[cols[3]]), np.max(sounding_data[cols[3]])] for i in range(len(hours)): one_sounding = sounding_data.loc[sounding_data[cols[3]]==hours[i]] T = convert_temperature(one_sounding[cols[6]].values,'F','C') * units.degC p = one_sounding[cols[5]].values * units.hPa Td = one_sounding[cols[7]].values * units.degC wind_speed = one_sounding[cols[-3]].values * units.knots wind_dir = one_sounding[cols[-2]].values * units.degrees u, v = mpcalc.get_wind_components(wind_speed, wind_dir) plt.rcParams['figure.figsize'] = (9, 9) skew = SkewT() skew.plot(p,T,'r') skew.plot(p,Td,'g') skew.plot_barbs(p,u,v) skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() skew.ax.set_ylim(1000, 100) plt.title('OAK Sounding: '+ str(mo) + '/' + str(day) + '/' + str(yr) +': ' +str(int(hours[i]))+' UTC' ) plt.savefig('images/OAK_sounding_'+ str(mo) + '_'+str(day) + '_' + str(yr) +'_' +str(int(hours[i]))+'UTC.pdf')