name = sys.argv[1] f = Level3File(name) # Pull the data out of the file object datadict = f.sym_block[0][0] # Turn into an array, then mask data = np.ma.array(datadict['data']) data[data == 0] = np.ma.masked # Grab azimuths and calculate a range based on number of gates az = np.array(datadict['start_az'] + [datadict['end_az'][-1]]) rng = np.linspace(0, f.max_range, data.shape[-1] + 1) # Convert az,range to x,y xlocs = rng * np.sin(np.deg2rad(az[:, np.newaxis])) ylocs = rng * np.cos(np.deg2rad(az[:, np.newaxis])) # Plot the data norm, cmap = colortables.get_with_steps(ctable, 16, 16) ax.pcolormesh(xlocs, ylocs, data, norm=norm, cmap=cmap) ax.set_aspect('equal', 'datalim') ax.set_xlim(xmin, xmax) ax.set_ylim(xmin, xmax) add_timestamp(ax, f.metadata['prod_time'], y=0.02, high_contrast=True) if len(sys.argv) < 3 or sys.argv[2] == 'plot': plt.show() else: plt.savefig(sys.argv[1] + '.png')
('NWS8bitVel', -100, 1.0)) # m/s for v, ctable, ax in zip(('N0Q', 'N0U'), ctables, axes): # Open the file name = get_test_data('nids/KOUN_SDUS54_{}TLX_201305202016'.format(v), as_file_obj=False) f = Level3File(name) # Pull the data out of the file object datadict = f.sym_block[0][0] # Turn into an array using the scale specified by the file data = f.map_data(datadict['data']) # Grab azimuths and calculate a range based on number of gates az = np.array(datadict['start_az'] + [datadict['end_az'][-1]]) rng = np.linspace(0, f.max_range, data.shape[-1] + 1) # Convert az,range to x,y xlocs = rng * np.sin(np.deg2rad(az[:, np.newaxis])) ylocs = rng * np.cos(np.deg2rad(az[:, np.newaxis])) # Plot the data norm, cmap = colortables.get_with_steps(*ctable) ax.pcolormesh(xlocs, ylocs, data, norm=norm, cmap=cmap) ax.set_aspect('equal', 'datalim') ax.set_xlim(-40, 20) ax.set_ylim(-30, 30) add_timestamp(ax, f.metadata['prod_time'], y=0.02, high_contrast=True) plt.show()
def main(): manager = mp.Manager() results = manager.dict() pool = mp.Pool(12) jobs = [] for filepath in glob.glob(join(args["NEXRADL3"], '*')): job = pool.apply_async(calculate_radar_stats, (results, filepath)) jobs.append(job) for job in tqdm(jobs, desc="Bounding & Searching Data"): job.get() pool.close() pool.join() print('Sorting...') columns = [ 'datetime', 'metadata', 'sensorData', 'indices', 'xlocs', 'ylocs', 'data', 'polyVerts', 'offset', 'areaValue', 'refValue', 'varRefValue' ] resultsDF = pd.DataFrame.from_dict(results, orient='index', columns=columns) resultsDF['datetime'] = pd.to_datetime(resultsDF.datetime) resultsDF.sort_values(by='datetime', inplace=True) #resultsDF.to_csv(args["output"] + '.csv', index = False) print(resultsDF[['areaValue', 'refValue']].head(5)) # --- Plot time series--- print('Plotting Slices...') fig, axes = plt.subplots(8, 8, figsize=(30, 30)) date_format = mpl_dates.DateFormatter('%H:%Mz') for i, (dt, record) in tqdm(enumerate(resultsDF.iterrows()), desc='Plotting Slices'): plotx = i % 8 ploty = int(i / 8) negXLim = -.5 posXLim = 1.5 negYLim = -1.0 posYLim = 1.0 norm, cmap = colortables.get_with_steps('NWSReflectivity', 18, 16) tempdata = record[ 'data'] # create a deep copy of data to maipulate for plotting tempdata[tempdata == 0] = np.ma.masked # mask out 0s for plotting axes[ploty][plotx].pcolormesh(record['xlocs'], record['ylocs'], tempdata, norm=norm, cmap=cmap) axes[ploty][plotx].set_aspect('equal', 'datalim') axes[ploty][plotx].set_xlim(negXLim, posXLim) axes[ploty][plotx].set_ylim(negYLim, posYLim) pVXs, pVYs = zip( *record['polyVerts'] ) # create lists of x and y values for transformed polyVerts axes[ploty][plotx].plot(pVXs, pVYs) if negXLim < record['offset'][1] < posXLim and negYLim < record[ 'offset'][0] < posYLim: axes[ploty][plotx].plot(record['offset'][1], record['offset'][0], 'o') # Location of the radar axes[ploty][plotx].text( record['offset'][1], record['offset'][0], record['sensorData']['siteID'] ) # will plot outside limits of subplot if site falls outside range axes[ploty][plotx].plot(0.0, 0.0, 'bx') # Location of the convection axes[ploty][plotx].text(0.0, 0.0, str(args["convLatLon"])) add_timestamp(axes[ploty][plotx], record['datetime'], y=0.02, high_contrast=True) axes[ploty][plotx].tick_params(axis='both', which='both') print('Calculating Statistics...') # pull data out of DF to make code cleaner datetimes = resultsDF['datetime'].tolist() #elapsedtimes = list(map(lambda x: x - min(datetimes), datetimes)) # not currently used, need to get this working areaValues = resultsDF['areaValue'].tolist() # area ≥ 35dbz within ROI refValues = ( np.array(resultsDF['refValue'].tolist()) - 65 ) * 0.5 # mean reflectivity ≥ 35dbz within ROI (conversion: (val-65)*0.5) [https://mesonet.agron.iastate.edu/GIS/rasters.php?rid=2] if np.nan in refValues: warnings.warn( "Radar inputs contains instance with no ref values >= thresh", UserWarning) #areaRefValues = np.multiply(areaValues, refValues) # product of area and reflectivity varValues = resultsDF['varRefValue'].tolist( ) # variance of mean reflectivity ≥ 35dbz within ROI cvValues = np.array([ a / b for a, b in zip(varValues, refValues) ]) * 0.5 # coeff. of variation for mean reflectivity ≥ 35dbz within ROI # Frequency N = len(refValues) T = 1.0 / N yf = fft(refValues) w = blackman(N) ywf = fft(refValues * w) # Normalization areaNorm = areaValues / np.max(areaValues) xf = np.linspace(0, 1.0 / (2.0 * T), N // 2) cvNorm = cvValues / np.max(cvValues) areaCVValuesNormalized = np.multiply(areaNorm, cvNorm) # Curve Smoothing window = len( resultsDF.index ) // 8 # ~2 hours/8 = ~15 mins ----> number of samples in moving average ( helps counteract more visible noise in higher temporal resolution data) yAreaAvg = movingaverage( areaValues, window)[window // 2:-window // 2] # create moving averages for time series' yRefAvg = movingaverage(refValues, window)[window // 2:-window // 2] yCVAvg = movingaverage(cvValues, window)[window // 2:-window // 2] yAreaCVNormAvg = movingaverage(areaCVValuesNormalized, window)[window // 2:-window // 2] # local minima & maxima on smoothed curves minTemporalwindow = window * 2 areaLocalMax = argrelmax(yAreaAvg) areaLocalMin = argrelmin(yAreaAvg) endpoints = [] if yAreaAvg[0] <= np.all(yAreaAvg[1:window]) or yAreaAvg[0] >= np.all( yAreaAvg[1:window]): endpoints.append(0) if yAreaAvg[-1] <= np.all( yAreaAvg[len(yAreaAvg - 1) - window:-2]) or yAreaAvg[-1] >= np.all( yAreaAvg[len(yAreaAvg - 1) - window:-2]): endpoints.append(len(yAreaAvg) - 1) areaExtremaRaw = sorted( areaLocalMax[0].tolist() + areaLocalMin[0].tolist() + endpoints ) # combine mins, maxes, and endpoints (if endpoints are an extreme) then sort areaExtrema = [ x for x in areaExtremaRaw[1:] if x - areaExtremaRaw[0] >= minTemporalwindow ] # remove maxima that are within threshold of first one areaExtrema = [areaExtremaRaw[0] ] + areaExtrema # add back in forst one to begining print(f'Area Extrema: {areaExtrema}') refLocalMax = argrelmax(yRefAvg) refLocalMin = argrelmin(yRefAvg) endpoints = [] if yRefAvg[0] <= np.all(yRefAvg[1:window]) or yRefAvg[0] >= np.all( yRefAvg[1:window]): endpoints.append(0) if yRefAvg[-1] <= np.all( yRefAvg[len(yRefAvg - 1) - window:-2]) or yRefAvg[-1] >= np.all( yRefAvg[len(yRefAvg - 1) - window:-2]): endpoints.append(len(yRefAvg) - 1) refExtremaRaw = sorted(refLocalMax[0].tolist() + refLocalMin[0].tolist() + endpoints) refExtrema = [ x for x in refExtremaRaw[1:] if x - refExtremaRaw[0] >= minTemporalwindow ] refExtrema = [refExtremaRaw[0]] + refExtrema print(f'Ref Extrema: {refExtrema}') #cvLocalMax = argrelmax(yCVAvg) #cvLocalMin = argrelmin(yCVAvg) #endpoints = [] #if yCVAvg[0] <= np.all(yCVAvg[1:window]) or yCVAvg[0] >= np.all(yCVAvg[1:window]): # endpoints.append(0) #if yCVAvg[-1] <= np.all(yCVAvg[len(yCVAvg-1)-window:-2]) or yCVAvg[-1] >= np.all(yCVAvg[len(yCVAvg-1)-window:-2]): # endpoints.append(len(yCVAvg)-1) #cvExtremaRaw = sorted(cvLocalMax[0].tolist()+cvLocalMin[0].tolist()+endpoints) #cvExtrema = [x for x in cvExtremaRaw[1:] if x-cvExtremaRaw[0]>=minTemporalwindow] #cvExtrema = [cvExtremaRaw[0]]+cvExtrema #print(f'CV Extrema: {cvExtrema}') yAreaCVNormLocalMax = argrelmax(yAreaCVNormAvg) yAreaCVNormLocalMin = argrelmin(yAreaCVNormAvg) endpoints = [] if yAreaCVNormAvg[0] <= np.all( yAreaCVNormAvg[1:window]) or yAreaCVNormAvg[0] >= np.all( yAreaCVNormAvg[1:window]): endpoints.append(0) if yAreaCVNormAvg[-1] <= np.all( yAreaCVNormAvg[len(yAreaCVNormAvg - 1) - window:-2]) or yAreaCVNormAvg[-1] >= np.all( yAreaCVNormAvg[len(yAreaCVNormAvg - 1) - window:-2]): endpoints.append(len(yAreaCVNormAvg) - 1) yAreaCVNormExtremaRaw = sorted(yAreaCVNormLocalMax[0].tolist() + yAreaCVNormLocalMin[0].tolist() + endpoints) yAreaCVNormExtrema = [ x for x in yAreaCVNormExtremaRaw[1:] if x - yAreaCVNormExtremaRaw[0] >= minTemporalwindow ] yAreaCVNormExtrema = [yAreaCVNormExtremaRaw[0]] + yAreaCVNormExtrema print(f'AreaCVNorm Extrema: {yAreaCVNormExtrema}') # Find slopes of Build-up Lines # Area xArea = np.array(datetimes[window // 2:-window // 2])[np.array( [areaExtrema[0], areaExtrema[1]] )] # grab datetime (x component) of the leftmost bounds (determined by window size), and the first extreme on the smoothed curve (sm curve is already bound by window, we need to apply bounds to datetimes) xAreaDiff = xArea[1] - xArea[ 0] # subtract the later value from the former to get our delta x yArea = yAreaAvg[np.array( [areaExtrema[0], areaExtrema[1]] )] # grab the values (y component) of the sm curve at the begining and at the first extreme yAreaDiff = yArea[1] - yArea[0] # subtract to find delta y slopeArea = np.arctan(yAreaDiff / xAreaDiff.seconds) # calc the slope angle print(f'Slope Area: {slopeArea}') # Reflectivity xRef = np.array(datetimes[window // 2:-window // 2])[np.array( [refExtrema[0], refExtrema[1]])] xRefDiff = xRef[1] - xRef[0] yRef = yRefAvg[np.array([refExtrema[0], refExtrema[1]])] yRefDiff = yRef[1] - yRef[0] slopeRef = np.arctan(yRefDiff / xRefDiff.seconds) print(f'Slope Reflectivity: {slopeRef}') # Product of Area and CV of ref xProduct = np.array(datetimes[window // 2:-window // 2])[np.array( [yAreaCVNormExtrema[0], yAreaCVNormExtrema[1]])] XProductDiff = xProduct[1] - xProduct[0] yProduct = yAreaCVNormAvg[np.array( [yAreaCVNormExtrema[0], yAreaCVNormExtrema[1]])] yProductDiff = yProduct[1] - yProduct[0] slopeProduct = np.arctan(yProductDiff / XProductDiff.seconds) print(f'Slope Product: {slopeProduct}') print('Plotting Additional Data and Saving Output...') # Area for Reflectivity ≥ 35dbz axes[-1][-5].plot_date(datetimes, areaValues, linestyle='solid', ms=2) axes[-1][-5].plot_date(datetimes[window // 2:-window // 2], yAreaAvg, linestyle='solid', ms=2) axes[-1][-5].plot_date( np.array(datetimes[window // 2:-window // 2])[np.array( [areaExtrema[0], areaExtrema[1]])], yAreaAvg[np.array([areaExtrema[0], areaExtrema[1]])], linestyle="solid", ms=2) axes[-1][-5].legend(['Area Delta', 'Sm. Area Delta', 'Build-up Rate']) axes[-1][-5].xaxis.set_major_formatter(date_format) plt.setp(axes[-1][-5].xaxis.get_majorticklabels(), rotation=45, ha="right", rotation_mode="anchor") axes[-1][-5].set_title('Area of Reflectivity ≥ 35dbz (km^2)') # TODO: map y axis to dbz for output # Mean of Reflectivity ≥ 35dbz axes[-1][-4].plot_date(datetimes, refValues, linestyle='solid', ms=2) #axes[-1][-4].plot_date(datetimes[window//2:-window//2], yRefAvg, linestyle='solid', ms=2) #axes[-1][-4].plot_date(np.array(datetimes[window//2:-window//2])[np.array([0,refLocalMax[0][0]])], yRefAvg[np.array([0,refLocalMax[0][0]])], linestyle="solid", ms=2) axes[-1][-4].plot_date(datetimes[window // 2:-window // 2], yRefAvg, linestyle='solid', ms=2) axes[-1][-4].plot_date(np.array( datetimes[window // 2:-window // 2])[np.array( [refExtrema[0], refExtrema[1]])], yRefAvg[np.array([refExtrema[0], refExtrema[1]])], linestyle="solid", ms=2) axes[-1][-4].legend(['Ref Delta', 'Sm. Ref Delta', 'Build-up Rate']) axes[-1][-4].xaxis.set_major_formatter(date_format) plt.setp(axes[-1][-4].xaxis.get_majorticklabels(), rotation=45, ha="right", rotation_mode="anchor") axes[-1][-4].set_title('Mean of Reflectivity ≥ 35dbz') # Product of cv reflectivity and area axes[-1][-3].plot_date(datetimes, areaCVValuesNormalized, linestyle='solid', ms=2) axes[-1][-3].plot_date(datetimes[window // 2:-window // 2], yAreaCVNormAvg, linestyle='solid', ms=2) axes[-1][-3].plot_date( np.array(datetimes[window // 2:-window // 2])[np.array( [yAreaCVNormExtrema[0], yAreaCVNormExtrema[1]])], yAreaCVNormAvg[np.array([yAreaCVNormExtrema[0], yAreaCVNormExtrema[1]])], linestyle="solid", ms=2) axes[-1][-3].legend( ['Area*cv_Ref Delta', 'Sm. Area*cv_Ref Delta', 'Build-up Rate']) axes[-1][-3].xaxis.set_major_formatter(date_format) plt.setp(axes[-1][-3].xaxis.get_majorticklabels(), rotation=45, ha="right", rotation_mode="anchor") axes[-1][-3].set_title('Norm Product: CV Reflectivity * Area ≥ 35dbz') # Coeff. of Variance of Reflectivity ≥ 35dbz axes[-1][-2].plot_date(datetimes, cvValues, linestyle='solid', ms=2) axes[-1][-2].plot_date(datetimes[window // 2:-window // 2], yCVAvg, linestyle='solid', ms=2) axes[-1][-2].legend(['CV Delta', 'Sm. CV Delta']) axes[-1][-2].xaxis.set_major_formatter(date_format) plt.setp(axes[-1][-2].xaxis.get_majorticklabels(), rotation=45, ha="right", rotation_mode="anchor") axes[-1][-2].set_title('CV of Reflectivity ≥ 35dbz') # Testing plot axes[-1][-1].semilogy(xf[1:N // 2], 2.0 / N * np.abs(yf[1:N // 2]), '-b') axes[-1][-1].semilogy(xf[1:N // 2], 2.0 / N * np.abs(ywf[1:N // 2]), '-r') axes[-1][-1].legend(['FFT', 'FFT w. Window']) #axes[-1][-1].plot(xf, 2.0/N * np.abs(yf[0:N//2]),linestyle='solid', ms=2) #axes[-1][-1].plot_date(datetimes, yCVAvg, linestyle='solid') #axes[-1][-1].xaxis.set_major_formatter(date_format) plt.setp(axes[-1][-1].xaxis.get_majorticklabels(), rotation=45, ha="right", rotation_mode="anchor") axes[-1][-1].set_title('Testing Plot (Frequency)') plt.tight_layout() plt.savefig(args["output"] + 'Nexrad.png') # Set the output file name #plt.show() f_o = open(args["output"] + 'log_stats_area_nexrad.txt', 'a') f_o.write(datetimes[0].strftime("%Y%m%d%H%M%S") + '\t' + str(args["convLatLon"]) + '\t' + str(args["convBearing"]) + '\t' + str(args["scaleFactor"]) + '\t' + str(np.max(areaValues)) + '\t' + str(np.max(refValues)) + '\t' + str(slopeArea) # std dev of LIS aligned data + '\t' + str(slopeRef) + '\t' + str(slopeProduct) + '\n') f_o.close()
add_metpy_logo(fig, 190, 85, size='large') for v, ctable, ax in zip(('N0Q', 'N0U'), ('NWSReflectivity', 'NWSVelocity'), axes): # Open the file name = get_test_data('nids/KOUN_SDUS54_{}TLX_201305202016'.format(v), as_file_obj=False) f = Level3File(name) # Pull the data out of the file object datadict = f.sym_block[0][0] # Turn into an array, then mask data = np.ma.array(datadict['data']) data[data == 0] = np.ma.masked # Grab azimuths and calculate a range based on number of gates az = np.array(datadict['start_az'] + [datadict['end_az'][-1]]) rng = np.linspace(0, f.max_range, data.shape[-1] + 1) # Convert az,range to x,y xlocs = rng * np.sin(np.deg2rad(az[:, np.newaxis])) ylocs = rng * np.cos(np.deg2rad(az[:, np.newaxis])) # Plot the data norm, cmap = colortables.get_with_steps(ctable, 16, 16) ax.pcolormesh(xlocs, ylocs, data, norm=norm, cmap=cmap) ax.set_aspect('equal', 'datalim') ax.set_xlim(-40, 20) ax.set_ylim(-30, 30) add_timestamp(ax, f.metadata['prod_time'], y=0.02, high_contrast=True) plt.show()
def plot_U_W_P_T(u, w, p, t, time, x, y, plot_prefix="workshop"): plot_filename = "%s.%s" % (plot_prefix, output_format) fig, ((ax1, ax2, ax3, ax4)) = P.subplots(4, 1, sharey=True, sharex=True, figsize=(6, 8)) yy, xx = N.meshgrid(y, x) yy = yy / 1000. xx = xx / 1000. clevels = N.arange(-35., 40., 5.) norm, cmap = colortables.get_with_steps('viridis', clevels.shape[0], 5.) plot = ax1.contourf(xx, yy, u, clevels, cmap=cmap) # cbar = ax1.colorbar(plot,location='right',pad="5%") # cbar.set_label("U") plot = ax1.contour(xx, yy, u, clevels[::2], colors='k', linewidths=0.5) title = ("U-Wind (m/s)") ax1.set_title(title, loc='left', fontsize=8) start, end = ax1.get_xlim() # ax1.xaxis.set_ticks(N.arange(start, end+6, 6)) ax1.xaxis.set_ticks(N.arange(start, end + 11, 10)) ax1.xaxis.set_major_formatter(ticker.FormatStrFormatter('%d')) start, end = ax1.get_ylim() ax1.yaxis.set_ticks(N.arange(start, end, 2)) ax1.yaxis.set_major_formatter(ticker.FormatStrFormatter('%d')) at = AnchoredText( "Max U: %4.1f \n Min U: %4.1f" % (u.max(), u.min()), loc=1, prop=dict(size=10), frameon=True, ) at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") ax1.add_artist(at) if N.abs(t).max() > 5.0: clevels = N.arange(-30., 32., 2.) else: clevels = N.arange(-1., 1.1, 0.1) / 10. norm, cmap = colortables.get_with_steps('viridis', clevels.shape[0], clevels[1] - clevels[0]) wmask = N.ma.masked_array(w, mask=[N.abs(w) <= _min_w]) plot = ax2.contourf(xx, yy, wmask, clevels, cmap=cmap) # cbar = plot.colorbar(plot,location='right',pad="5%") plot = ax2.contour(xx, yy, wmask, clevels[::2], colors='k', linewidths=0.5) # cbar.set_label('%s' % ("$m s^{-1}$")) title = ("Vertical Velocity (m/s)") ax2.set_title(title, loc='left', fontsize=8) at = AnchoredText( "Max W: %4.1f \n Min W: %4.1f" % (w.max(), w.min()), loc=1, prop=dict(size=10), frameon=True, ) at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") ax2.add_artist(at) if N.abs(t).max() > 5.0: clevels = N.arange(-16., 10., 1.) else: clevels = N.arange(-100, 105, 5) clevels = 0.01 * clevels[clevels != 0] norm, cmap = colortables.get_with_steps('viridis', clevels.shape[0], clevels[1] - clevels[0]) tmask = N.ma.masked_array(t, mask=[N.abs(t) <= 0.00001]) plot = ax3.contourf(xx, yy, tmask, clevels, cmap=cmap) # cbar = ax3.colorbar(plot,location='right',pad="5%") plot = ax3.contour(xx, yy, tmask, clevels, colors='k', linewidths=0.5) # cbar.set_label('%s' % ("K")) title = ("Pert. Potential Temperature (K)") ax3.set_title(title, loc='left', fontsize=8) at = AnchoredText( "Max TH: %5.3f \n Min TH: %5.3f" % (t.max(), t.min()), loc=1, prop=dict(size=10), frameon=True, ) at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") ax3.add_artist(at) if N.abs(t).max() > 5.0: clevels = N.arange(-1000., 1000., 100.0) # clevels = N.arange(-3.,3.,0.1) else: clevels = N.arange(-15., 15.5, 0.5) norm, cmap = colortables.get_with_steps('viridis', clevels.shape[0], clevels[1] - clevels[0]) plot = ax4.contourf(xx, yy, p, clevels, cmap=cmap) # cbar = ax4.colorbar(plot,location='right',pad="5%") plot = ax4.contour(xx, yy, p, clevels[::2], colors='k', linewidths=0.5) # cbar.set_label('%s' % ("mb")) title = ("Pressure (mb)") ax4.set_title(title, fontsize=8) ax4.set_xlabel('X km', fontsize=8) at = AnchoredText( "Max P: %4.1f \n Min P: %4.1f" % (p.max(), p.min()), loc=1, prop=dict(size=10), frameon=True, ) at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") ax4.add_artist(at) if int(time) < 1000: title = ("Time = %3d sec" % (int(time))) else: title = ("Time = %4d sec" % (int(time))) fig.suptitle(title, y=1.0, fontsize=10) P.tight_layout(h_pad=0.5) if output_format == "pdf": print("\n Saving file %s" % (plot_filename)) fig.savefig(plot_filename, format="pdf", dpi=300) if output_format == "png": print("\n Saving file %s" % (plot_filename)) fig.savefig(plot_filename, format="png", dpi=300) if interactive: print(plot_filename) os.system("open %s" % plot_filename) return plot_filename
def cref_uv850(initial_time, fhour=0, model='ShangHai', map_center=(117, 39), map_width=12, draw_wind=False): """ Analysis composite reflectivity and 850hPa wind. Arguments: initial_time {string or datetime}} -- initial time, string or datetime ojbect. like '18042008' or datetime(2018, 4, 20, 8). Keyword Arguments: fhour {int} -- forecast hour (default: {0}) model {str} -- model name (default: {'ShangHai'}) map_center {tuple} -- map center (default: {(117, 39)}) map_width {int} -- map width (default: {12}) draw_wind {bool} -- draw 850hPa wind or not (default: {False}) Raises: ValueError -- [description] """ # micaps data directory data_dirs = { 'SHANGHAI': ['SHANGHAI_HR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE', 'SHANGHAI_HR/UGRD/850', 'SHANGHAI_HR/VGRD/850'], 'BEIJING': ['BEIJING_MR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE', 'BEIJING_MR/UGRD/850', 'BEIJING_MR/VGRD/850'], 'GRAPES_MESO': ['GRAPES_MESO_HR/RADAR_COMBINATION_REFLECTIVITY', 'GRAPES_MESO_HR/UGRD/850', 'GRAPES_MESO_HR/VGRD/850'], 'GRAPES_3KM': ['GRAPES_3KM/RADAR_COMBINATION_REFLECTIVITY', 'GRAPES_3KM/UGRD/850', 'GRAPES_3KM/VGRD/850']} try: data_dir = data_dirs[model.strip().upper()] except KeyError: raise ValueError('Unknown model, choose ShangHai, BeiJing, Grapes_meso of Grapes_3km.') # get filename filename = model_filename(initial_time, fhour) # retrieve data from micaps server cref = get_model_grid(data_dir[0], filename=filename) if cref is None: return init_time = cref.coords['init_time'].values[0] if draw_wind: u850 = get_model_grid(data_dir[1], filename=filename) if u850 is None: return v850 = get_model_grid(data_dir[2], filename=filename) if v850 is None: return # prepare data data = np.ma.masked_array(cref.values) data[data == 9999] = np.ma.masked data[data < 10] = np.ma.masked cref_data = {'lon':cref.coords['lon'].values, 'lat':cref.coords['lat'].values, 'data':np.squeeze(data)} if draw_wind: uv850 = {'lon': u850.coords['lon'].values, 'lat': u850.coords['lat'].values, 'udata': np.squeeze(u850.values), 'vdata': np.squeeze(v850.values)} # set up map projection datacrs = ccrs.PlateCarree() plotcrs = ccrs.AlbersEqualArea( central_latitude=map_center[1], central_longitude=map_center[0], standard_parallels=[30., 60.]) # set up figure fig = plt.figure(figsize=(12, 9)) gs = mpl.gridspec.GridSpec( 1, 2, width_ratios=[1, .03], bottom=.01, top=.99, hspace=0.01, wspace=0.01) ax = plt.subplot(gs[0], projection=plotcrs) # add model title add_model_title( 'CREF (dBz), 850-hPa Winds', init_time, model=model, fhour=fhour, fontsize=18, multilines=True) # add map background map_extent = ( map_center[0] - map_width/2.0, map_center[0] + map_width/2.0, map_center[1] - map_width/3.0, map_center[1] + map_width/3.0) ax.set_extent(map_extent, crs=datacrs) add_china_map_2cartopy( ax, name='province', edgecolor='black', lw=2, zorder=100) # draw composite reflectivity x, y = np.meshgrid(cref_data['lon'], cref_data['lat']) norm, cmap = colortables.get_with_steps('NWSReflectivity', 12, 4) pm = ax.pcolormesh(x, y, cref_data['data'], norm=norm, cmap=cmap, transform=datacrs) cax = plt.subplot(gs[1]) cb = plt.colorbar(pm, cax=cax, orientation='vertical', extendrect='True') cb.set_label('Composite reflectivity', size=12) # draw wind vector if draw_wind: x, y = np.meshgrid(uv850['lon'], uv850['lat']) ax.quiver(x, y, uv850['udata'], uv850['vdata'], transform=datacrs, regrid_shape=25) # show figure gs.tight_layout(fig) plt.show()
def cref_uv850_compare(initial_time, fhour=0, map_center=(117, 39), map_width=12, draw_wind=False): """ Compare mesoscale model's composite reflectivity. Arguments: initial_time {string or datetime}} -- initial time, string or datetime ojbect. like '18042008' or datetime(2018, 4, 20, 8). Keyword Arguments: fhour {int} -- forecast hour (default: {0}) map_center {tuple} -- map center (default: {(117, 39)}) map_width {int} -- map width (default: {12}) draw_wind {bool} -- draw 850hPa wind or not (default: {False}) """ # micaps data directory data_dirs = {'SHANGHAI': ['SHANGHAI_HR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE', 'SHANGHAI_HR/UGRD/850', 'SHANGHAI_HR/VGRD/850'], 'BEIJING': ['BEIJING_MR/COMPOSITE_REFLECTIVITY/ENTIRE_ATMOSPHERE', 'BEIJING_MR/UGRD/850', 'BEIJING_MR/VGRD/850'], 'GRAPES_MESO': ['GRAPES_MESO_HR/RADAR_COMBINATION_REFLECTIVITY', 'GRAPES_MESO_HR/UGRD/850', 'GRAPES_MESO_HR/VGRD/850'], 'GRAPES_3KM': ['GRAPES_3KM/RADAR_COMBINATION_REFLECTIVITY', 'GRAPES_3KM/UGRD/850', 'GRAPES_3KM/VGRD/850']} # get filename filename = model_filename(initial_time, fhour) # set up map projection datacrs = ccrs.PlateCarree() plotcrs = ccrs.AlbersEqualArea( central_latitude=map_center[1], central_longitude=map_center[0], standard_parallels=[30., 60.]) # set up figure fig = plt.figure(figsize=(16, 12)) axes_class = (GeoAxes, dict(map_projection=plotcrs)) grid = AxesGrid(fig, 111, axes_class=axes_class, nrows_ncols=(2, 2), axes_pad=0.05, cbar_location='right', cbar_mode='single', cbar_pad=0.05, label_mode='') # loop every data directory for index, key in enumerate(data_dirs): # get axis and data directory ax = grid[index] data_dir = data_dirs[key] # retrieve data from micaps server cref = get_model_grid(data_dir[0], filename=filename) if cref is None: return init_time = cref.coords['init_time'].values[0] if draw_wind: u850 = get_model_grid(data_dir[1], filename=filename) if u850 is None: return v850 = get_model_grid(data_dir[2], filename=filename) if v850 is None: return # add title if index == 0: initial_str, fhour_str, valid_str = get_model_time_stamp(init_time, fhour) fig.suptitle('CREF (dBz), 850-hPa Winds ' + initial_str + '; ' + fhour_str + '; ' + valid_str, x=0.5, y=0.9, fontsize=16) # prepare data data = np.ma.masked_array(cref.values) data[data == 9999] = np.ma.masked data[data < 10] = np.ma.masked cref_data = {'lon':cref.coords['lon'].values, 'lat':cref.coords['lat'].values, 'data':np.squeeze(data)} if draw_wind: uv850 = {'lon': u850.coords['lon'].values, 'lat': u850.coords['lat'].values, 'udata': np.squeeze(u850.values), 'vdata': np.squeeze(v850.values)} # add map background map_extent = ( map_center[0] - map_width/2.0, map_center[0] + map_width/2.0, map_center[1] - map_width/3.0, map_center[1] + map_width/3.0) ax.set_extent(map_extent, crs=datacrs) add_china_map_2cartopy( ax, name='province', edgecolor='black', lw=2, zorder=100) # draw composite reflectivity x, y = np.meshgrid(cref_data['lon'], cref_data['lat']) norm, cmap = colortables.get_with_steps('NWSReflectivity', 12, 4) pm = ax.pcolormesh(x, y, cref_data['data'], norm=norm, cmap=cmap, transform=datacrs) # draw wind vector if draw_wind: x, y = np.meshgrid(uv850['lon'], uv850['lat']) ax.quiver(x, y, uv850['udata'], uv850['vdata'], transform=datacrs, regrid_shape=25) # add title add_titlebox(ax, key) # add color bar cbar = grid.cbar_axes[0].colorbar(pm) # show figure plt.show()