def plot_sounding(date, station): p, T, Td, u, v, windspeed = get_sounding_data(date, station) lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td) parcel_path = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(8, 8)) skew = SkewT(fig) # Plot the data temperature_line, = skew.plot(p, T, color='tab:red') dewpoint_line, = skew.plot(p, Td, color='blue') cursor = mplcursors.cursor([temperature_line, dewpoint_line]) # Plot thermodynamic parameters and parcel path skew.plot(p, parcel_path, color='black') if lcl_pressure: skew.ax.axhline(lcl_pressure, color='black') if lfc_pressure: skew.ax.axhline(lfc_pressure, color='0.7') # Add the relevant special lines skew.ax.axvline(0, color='c', linestyle='--', linewidth=2) skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() # Shade areas representing CAPE and CIN skew.shade_cin(p, T, parcel_path) skew.shade_cape(p, T, parcel_path) # Add wind barbs skew.plot_barbs(p, u, v) # Add an axes to the plot ax_hod = inset_axes(skew.ax, '30%', '30%', loc=1, borderpad=3) # Plot the hodograph h = Hodograph(ax_hod, component_range=100.) # Grid the hodograph h.add_grid(increment=20) # Plot the data on the hodograph mask = (p >= 100 * units.mbar) h.plot_colormapped(u[mask], v[mask], windspeed[mask]) # Plot a line colored by wind speed # Set some sensible axis limits skew.ax.set_ylim(1000, 100) skew.ax.set_xlim(-40, 60) return fig, skew
def test_hodograph_api(): """Basic test of Hodograph API.""" fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(1, 1, 1) hodo = Hodograph(ax, component_range=60) hodo.add_grid(increment=5, color='k') hodo.plot([1, 10], [1, 10], color='red') hodo.plot_colormapped(np.array([1, 3, 5, 10]), np.array([2, 4, 6, 11]), np.array([0.1, 0.3, 0.5, 0.9]), cmap='Greys') return fig
def test_hodograph_plot_colormapped(): """Test hodograph colored line with NaN values.""" u = np.arange(5., 65., 5) v = np.arange(-5., -65., -5) u[3] = np.nan v[6] = np.nan fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(1, 1, 1) hodo = Hodograph(ax, component_range=80) hodo.add_grid(increment=20, color='k') hodo.plot_colormapped(u, v, np.hypot(u, v), cmap='Greys') return fig
def test_hodograph_plot_arbitrary_layer(): """Test hodograph colored layers for arbitrary variables without interpolation.""" u = np.arange(5, 65, 5) * units('knot') v = np.arange(-5, -65, -5) * units('knot') speed = np.sqrt(u ** 2 + v ** 2) colors = ['red', 'green', 'blue'] levels = [0, 10, 20, 30] * units('knot') fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(1, 1, 1) hodo = Hodograph(ax, component_range=80) hodo.add_grid(increment=20, color='k') hodo.plot_colormapped(u, v, speed, bounds=levels, colors=colors) return fig
def test_hodograph_plot_arbitrary_layer(): """Test hodograph colored layers for arbitrary variables without interpolation.""" u = np.arange(5, 65, 5) * units('knot') v = np.arange(-5, -65, -5) * units('knot') speed = np.sqrt(u**2 + v**2) colors = ['red', 'green', 'blue'] levels = [0, 10, 20, 30] * units('knot') fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(1, 1, 1) hodo = Hodograph(ax, component_range=80) hodo.add_grid(increment=20, color='k') hodo.plot_colormapped(u, v, speed, bounds=levels, colors=colors) return fig
def test_hodograph_plot_layers_bound_units(): """Test hodograph colored height layers with interpolation and different units.""" u = np.zeros((6)) * units.knots v = np.array([0, 10, 20, 30, 40, 50]) * units.knots heights = np.array([0, 1000, 2000, 3000, 4000, 5000]) * units.m bounds = np.array([0.5, 1.5, 2.5, 3.5, 4.5]) * units.km colors = ['r', 'g', 'b', 'r'] fig = plt.figure(figsize=(7, 7)) ax1 = fig.add_subplot(1, 1, 1) h = Hodograph(ax1) h.add_grid(increment=10) h.plot_colormapped(u, v, heights, colors=colors, bounds=bounds) ax1.set_xlim(-50, 50) ax1.set_ylim(-5, 50) return fig
def test_hodograph_plot_layers_different_units(): """Test hodograph colored height layers with interpolation and different units.""" u = np.zeros(6) * units.knots v = np.array([0, 10, 20, 30, 40, 50]) * units.knots heights = np.array([0, 1, 2, 3, 4, 5]) * units.km intervals = np.array([500, 1500, 2500, 3500, 4500]) * units.m colors = ['r', 'g', 'b', 'r'] fig = plt.figure(figsize=(7, 7)) ax1 = fig.add_subplot(1, 1, 1) h = Hodograph(ax1) h.add_grid(increment=10) h.plot_colormapped(u, v, heights, colors=colors, intervals=intervals) ax1.set_xlim(-50, 50) ax1.set_ylim(-5, 50) return fig
def test_hodograph_plot_layers(): """Test hodograph colored height layers with interpolation.""" u = np.arange(5, 65, 5) * units('knot') v = np.arange(-5, -65, -5) * units('knot') h = [178, 213, 610, 656, 721, 914, 1060, 1219, 1372, 1412, 1512, 1524 ] * units('meter') colors = ['red', 'green'] levels = [0, 500, 1000] * units('meter') fig = plt.figure(figsize=(9, 9)) ax = fig.add_subplot(1, 1, 1) hodo = Hodograph(ax, component_range=80) hodo.add_grid(increment=20, color='k') hodo.plot_colormapped(u, v, h, bounds=levels, colors=colors) return fig
def plot_skewt(df): # We will pull the data out of the example dataset into individual variables # and assign units. hght = df['height'].values * units.hPa 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.wind_components(wind_speed, wind_dir) # Create a new figure. The dimensions here give a good aspect ratio. fig = plt.figure(figsize=(9, 12)) 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() # Create a hodograph ax_hod = inset_axes(skew.ax, '40%', '40%', loc=2) h = Hodograph(ax_hod, component_range=80.) h.add_grid(increment=20) h.plot_colormapped(u, v, hght) return skew
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 process_skewt(self): # Calculation index_p100 = get_pressure_level_index(self.p_i, 100) lcl_p, lcl_t = mpcalc.lcl(self.p_i[0], self.t_i[0], self.td_i[0]) lfc_p, lfc_t = mpcalc.lfc(self.p_i, self.t_i, self.td_i) el_p, el_t = mpcalc.el(self.p_i, self.t_i, self.td_i) prof = mpcalc.parcel_profile(self.p_i, self.t_i[0], self.td_i[0]).to('degC') cape, cin = mpcalc.cape_cin(self.p_i, self.t_i, self.td_i, prof) mucape, mucin = mpcalc.most_unstable_cape_cin(self.p_i, self.t_i, self.td_i) pwat = mpcalc.precipitable_water(self.td_i, self.p_i) i8 = get_pressure_level_index(self.p_i, 850) i7 = get_pressure_level_index(self.p_i, 700) i5 = get_pressure_level_index(self.p_i, 500) theta850 = mpcalc.equivalent_potential_temperature(850 * units('hPa'), self.t_i[i8], self.td_i[i5]) theta500 = mpcalc.equivalent_potential_temperature(500 * units('hPa'), self.t_i[i5], self.td_i[i5]) thetadiff = theta850 - theta500 k = self.t_i[i8] - self.t_i[i5] + self.td_i[i8] - (self.t_i[i7] - self.td_i[i7]) a = ((self.t_i[i8] - self.t_i[i5]) - (self.t_i[i8] - self.td_i[i5]) - (self.t_i[i7] - self.td_i[i7]) - (self.t_i[i5] - self.td_i[i5])) sw = c_sweat(np.array(self.t_i[i8].magnitude), np.array(self.td_i[i8].magnitude), np.array(self.t_i[i5].magnitude), np.array(self.u_i[i8].magnitude), np.array(self.v_i[i8].magnitude), np.array(self.u_i[i5].magnitude), np.array(self.v_i[i5].magnitude)) si = showalter_index(self.t_i[i8], self.td_i[i8], self.t_i[i5]) li = lifted_index(self.t_i[0], self.td_i[0], self.p_i[0], self.t_i[i5]) srh_pos, srh_neg, srh_tot = mpcalc.storm_relative_helicity(self.u_i, self.v_i, self.alt, 1000 * units('m')) sbcape, sbcin = mpcalc.surface_based_cape_cin(self.p_i, self.t_i, self.td_i) shr6km = mpcalc.bulk_shear(self.p_i, self.u_i, self.v_i, heights=self.alt, depth=6000 * units('m')) wshr6km = mpcalc.wind_speed(*shr6km) sigtor = mpcalc.significant_tornado(sbcape, delta_height(self.p_i[0], lcl_p), srh_tot, wshr6km)[0] # Plotting self.ax.set_ylim(1050, 100) self.ax.set_xlim(-40, 50) self.plot(self.p_i, self.t_i, 'r', linewidth=1) self.plot(self.p_i[:self.dp_idx], self.td_i[:self.dp_idx], 'g', linewidth=1) self.plot_barbs(self.p_i[:index_p100], self.u_i[:index_p100] * 1.94, self.v_i[:index_p100] * 1.94) self.plot(lcl_p, lcl_t, 'ko', markerfacecolor='black') self.plot(self.p_i, prof, 'k', linewidth=2) if cin.magnitude < 0: chi = -1 * cin.magnitude self.shade_cin(self.p_i, self.t_i, prof) elif cin.magnitude > 0: chi = cin.magnitude self.shade_cin(self.p_i, self.t_i, prof) else: chi = 0. self.shade_cape(self.p_i, self.t_i, prof) self.plot_dry_adiabats(linewidth=0.5) self.plot_moist_adiabats(linewidth=0.5) self.plot_mixing_lines(linewidth=0.5) plt.title('Skew-T Plot \nStation: {} Time: {}'.format(self.st, self.time.strftime('%Y.%m.%d %H:%M')), fontsize=14, loc='left') # Add hodograph ax = self._fig.add_axes([0.95, 0.71, 0.17, 0.17]) h = Hodograph(ax, component_range=50) h.add_grid(increment=20) h.plot_colormapped(self.u_i[:index_p100], self.v_i[:index_p100], self.alt[:index_p100], linewidth=1.2) # Annotate parameters # Annotate names namelist = ['CAPE', 'CIN', 'MUCAPE', 'PWAT', 'K', 'A', 'SWEAT', 'LCL', 'LFC', 'EL', 'SI', 'LI', 'T850-500', 'θse850-500', 'SRH', 'STP'] xcor = -50 ycor = -90 spacing = -9 for nm in namelist: ax.text(xcor, ycor, '{}: '.format(nm), fontsize=10) ycor += spacing # Annotate values varlist = [cape, chi, mucape, pwat, k, a, sw, lcl_p, lfc_p, el_p, si, li, self.t_i[i8] - self.t_i[i5], thetadiff, srh_tot, sigtor] xcor = 10 ycor = -90 for v in varlist: if hasattr(v, 'magnitude'): v = v.magnitude ax.text(xcor, ycor, str(np.round_(v, 2)), fontsize=10) ycor += spacing # Annotate units unitlist = ['J/kg', 'J/kg', 'J/kg', 'mm', '°C', '°C', '', 'hPa', 'hPa', 'hPa', '°C', '°C', '°C', '°C'] xcor = 45 ycor = -90 for u in unitlist: ax.text(xcor, ycor, ' {}'.format(u), fontsize=10) ycor += spacing
skew.ax.set_xlim(-40, 60) # 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) # Add the relevant special lines skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() # 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) h = Hodograph(ax_hod, component_range=80.) h.add_grid(increment=20) h.plot_colormapped(u, v, wind_speed) # Plot a line colored by wind speed # Show the plot plt.show()
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
pressure = df['pressure'].values * units(df.units['pressure']) temperature = df['temperature'].values * units(df.units['temperature']) wind_speed = df['speed'].values * units.knots print(temperature) dewpoint = df['dewpoint'].values * units(df.units['dewpoint']) print(dewpoint) u_wind = df['u_wind'].values * units(df.units['u_wind']) print(u_wind) v_wind = df['v_wind'].values * units(df.units['v_wind']) heights = df['height'].values * units(df.units['height']) print(mpcalc.wind_direction(u_wind,v_wind)) fig = plt.figure(figsize=(6,6)) ax = fig.add_subplot(1,1,1) h= Hodograph(ax,component_range=60.) h.plot(u_wind,v_wind,linewidth=5) h.add_grid(increment=10) #h.add_grid(increment=20,color='tab:orange',linestyle='-') h.plot_colormapped(u_wind, v_wind, wind_speed) # Plot a line colored by wind speed plt.savefig('hodograph.png') plt.show() sys.exit() #lcl_pressure, lcl_temperature = mpcalc.lcl(pressure[0], temperature[0], dewpoint[0]) #print(lcl_pressure, lcl_temperature) # Calculate the parcel profile. parcel_prof = mpcalc.parcel_profile(pressure, temperature[0], dewpoint[0]).to('degC')
ax2.yaxis.tick_left() ax2.tick_params(direction='in', pad=-5) #PLOT PARCEL STUFF plt.plot((37, 43), (mupcl.lfcpres,mupcl.lfcpres), 'r-',lw=1.5) ax2.annotate('LFC', xy=(40, mupcl.lfcpres-10), xytext=(40, mupcl.lfcpres-10),ha='center', color='r') plt.plot((37, 43), (mupcl.lclpres,mupcl.lclpres), 'g-',lw=1.5) ax2.annotate('LCL', xy=(40, mupcl.lclpres+50), xytext=(40, mupcl.lclpres+50),ha='center', color='g') # Create windbarbs and hodograph skew.plot_barbs(p, u, v, xloc=1.1) hgt_list = [0,3000,6000,9000,np.max(h)] hodo_color = ['r','g','y','c'] hodo_label = ['0-3km','3-6km','6-9km','>9km'] ax_hod = inset_axes(skew.ax, '40%', '40%', loc=1) for tick in ax_hod.xaxis.get_major_ticks(): tick.label.set_fontsize(10) tick.label.set_rotation(45) for tick in ax_hod.yaxis.get_major_ticks(): tick.label.set_fontsize(10) hodo = Hodograph(ax_hod, component_range=80.) hodo.add_grid(increment=20) for k in range(len(hgt_list)-1): index1 = min(range(len(h)), key=lambda i: abs(h[i]-hgt_list[k])) index2 = min(range(len(h)), key=lambda i: abs(h[i]-hgt_list[k+1])) hodo.plot(u[index1:index2+1],v[index1:index2+1],c=hodo_color[k],linewidth=2.0,label=hodo_label[k]) ax_hod.legend(loc=2,prop={'size':8}) plt.savefig('/home/kgoebber/http/soundings/launches/'+launch+'_'+ascent+'/'+launch+'_'+ascent+'_KVUM.png',dpi=150) #plt.show()
def main(): args = get_args() setup_logging(args["verbose"]) # Define input file file = args["inputfile"] output = args["outputfile"] ds = xr.open_dataset(file) ds_sel = ds.isel({"sounding": 0}) ds_sel = ds_sel.sortby(ds_sel.p, ascending=False) attrs = ds_sel.attrs ds_sel = ds_sel.metpy.quantify() p = ds_sel.p T = ds_sel.ta Td = ds_sel.dp wind_speed = ds_sel.wspd wind_dir = ds_sel.wdir ascend_rate = ds_sel.dz launch_time = attrs["time_of_launch_HHmmss"] platform = attrs["platform"] resolution = attrs["resolution"].replace(" ", "") # Filter nans idx = np.where( (np.isnan(T) + np.isnan(Td) + np.isnan(p) + np.isnan(wind_speed) + np.isnan(wind_dir)) is False, True, False, ) p = p[idx].metpy.convert_units("hPa") T = T[idx].metpy.convert_units("degC") Td = Td[idx].metpy.convert_units("degC") wind_speed = wind_speed[idx].metpy.convert_units("meter / second") wind_dir = wind_dir[idx] u, v = mpcalc.wind_components(wind_speed, wind_dir) lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]) parcel_prof = parcel_prof.metpy.convert_units("degC") direction = find_direction_of_sounding(ascend_rate) # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 10)) skew = SkewT(fig, rotation=30) # 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") # Plot only specific barbs to increase visibility pressure_levels_barbs = np.logspace(0.1, 1, 50) * 100 def find_nearest(array, value): array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] # Search for levels by providing pressures # (levels is the coordinate not pressure) pres_vals = p.isel(level=idx) closest_pressure_levels = np.unique( [find_nearest(pres_vals, p_) for p_ in pressure_levels_barbs]) _, closest_pressure_levels_idx, _ = np.intersect1d(pres_vals, closest_pressure_levels, return_indices=True) p_barbs = p.isel({"level": closest_pressure_levels_idx}) wind_speed_barbs = wind_speed.isel({"level": closest_pressure_levels_idx}) wind_dir_barbs = wind_dir.isel({"level": closest_pressure_levels_idx}) u_barbs, v_barbs = mpcalc.wind_components(wind_speed_barbs, wind_dir_barbs) # Find nans in pressure skew.plot_barbs(p_barbs, u_barbs, v_barbs, xloc=1.06) skew.ax.set_ylim(1020, 100) skew.ax.set_xlim(-50, 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(pres_vals, parcel_prof, "k", linewidth=1.6) # Shade areas of CAPE and CIN skew.shade_cin( pres_vals.metpy.convert_units("hPa").values, T.metpy.convert_units("degC").values, parcel_prof.metpy.convert_units("degC").values, ) skew.shade_cape( pres_vals.metpy.convert_units("hPa").values, T.metpy.convert_units("degC").values, parcel_prof.metpy.convert_units("degC").values, ) # Plot a zero degree 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() # 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, "35%", "35%", loc=1) h = Hodograph(ax_hod, component_range=75.0) h.add_grid(increment=20) h.plot_colormapped(u, v, wind_speed) # Plot a line colored by wind speed # Set title sounding_name = ds_sel.sounding.values sounding_name_str = str(sounding_name.astype("str")) skew.ax.set_title("{sounding}_{direction}".format( sounding=sounding_name_str, direction=direction)) if output is None: filename_fmt = "{platform}_SoundingProfile_skew_{launch_time}_{res}.png".format( platform=platform, res=resolution, launch_time=launch_time) # filename_fmt = launch_time.strftime(filename_fmt) output = filename_fmt else: output = output.format(platform=platform, direction=direction, resolution=resolution) # output = launch_time.strftime(output) logging.info("Write output to {}".format(output)) plt.savefig(output)
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 = fig5.add_subplot(gs[:2, 2:]) #gs.tight_layout(fig5) if np.nanmax(wind_kts) > 18: comprange = 35 else: comprange = 20 h = Hodograph(ax_hod, component_range=comprange) h.add_grid(increment=5) h.plot_colormapped(u, v, pres, cmap=cmocean.cm.deep_r) ax_hod.set_title('Hodograph (kts)') ax_hod.yaxis.set_ticklabels([]) #ax_hod.set_xlabel('Wind Speed (kts)') # Finland Map - ISOBAR if mission == 'ISOBAR': # llcrnrlat = 33.6 # urcrnrlat = 37.2 # llcrnrlon = -103.2 # urcrnrlon = -94.2 lllat = 55.34 urlat = 70.54 lat_0 = 65. lon_0 = 24.
def plot_skewt(snd: Sounding, save_to: Optional[str] = None, p_top: int = 100): """ Plots a skew-T from the given Sounding. :param snd: The Sounding. :param save_to: Where to save the figure. Default None, which does not save the figure, and instead shows it. :param p_top: Pressure at the top of the skew-T. If you change this, Metpy might change the rotation of the isotherms. No known fix yet. :return: None. """ #################################################################################################################### # Data extraction and masking # Extract data from sounding. p = snd.p T = snd.T Td = snd.Td Tw = snd.Tw Te = snd.thetaE z = snd.z cf = snd["CFRL"] omega = snd.omega u, v = snd.wind_components() e = mpcalc.saturation_vapor_pressure(T) rv = mpcalc.mixing_ratio(e, p) w = mpcalc.vertical_velocity(omega, p, T, rv).to("cm/s") # Create masks to filter what data is plotted. mask_dewpoint = Td > -9000. * units.degC # Plot only non-missing dewpoints. mask_wetbulb = Tw > -9000. * units.degC # Plot only non-missing dewpoints. mask_thetae = Te > 0. * units.K # Plot only non-missing theta-es. mask_barbs = p > p_top * units.hPa # Plot only winds below the top of the sounding. #################################################################################################################### # Define intervals of height for coloring barbs and hodograph. z_interval_levels = [1500, 3000, 6000, 9000, 12000, 99999] z_interval_colors = ["red", "orange", "green", "blue", "purple", "grey"] z_colors = [] for item in z: for color, interval in zip(z_interval_colors, z_interval_levels): if item <= interval * units.meter: z_colors.append(color) break #################################################################################################################### # Plotting skew-T fig = plt.figure(figsize=(11, 11)) ax_hodo = fig.add_axes([0.70, 0.675, 0.25, 0.25]) ax_thte = fig.add_axes([0.70, 0.375, 0.25, 0.25]) skew = SkewT(fig, rotation=45, rect=[0.05, 0.05, 0.60, 0.9]) # Plot temperature, dewpoint, and wet-bulb. skew.plot(p, T, 'r') skew.plot(p[mask_dewpoint], Td[mask_dewpoint], 'g') skew.plot(p[mask_wetbulb], Tw[mask_wetbulb], color='#009999', linewidth=1) # Calculate and plot surface parcel trace. sfc_trace = snd.parcel_trace(0).to('degC') sfc_trace_plot = skew.plot(p, sfc_trace, c='orange', linewidth=2, zorder=-10) # Calculate and plot MU parcel trace. mu_level_index = np.argmax(Te[p > 750. * units.hPa]) mu_trace = snd.parcel_trace(mu_level_index).to('degC') mu_trace_plot = skew.plot(p[mu_level_index:], mu_trace, c='gray', linewidth=2, zorder=-9) # Plot each barb individually for control over color. Unfortunately, the c arg of plot_barbs doesn't work for this # purpose. for p_, u_, v_, c_ in zip(p[mask_barbs][::BARB_DENSITY], u[mask_barbs][::BARB_DENSITY], v[mask_barbs][::BARB_DENSITY], np.array(z_colors)[mask_barbs][::BARB_DENSITY]): skew.plot_barbs(p_, u_, v_, y_clip_radius=0.03, barbcolor=c_) #################################################################################################################### # Cloud fraction and omega zero_line = 1 / 15 cf_plot = (cf * zero_line) / 100 w_plot = (w.magnitude / 20) + zero_line skew.ax.plot(np.zeros(cf_plot.shape) + 1 / 15, snd.p, transform=skew.ax.get_yaxis_transform(), color="grey") skew.ax.plot(cf_plot, snd.p, transform=skew.ax.get_yaxis_transform(), color="black") skew.ax.plot(w_plot, snd.p, transform=skew.ax.get_yaxis_transform(), color="purple") skew.ax.text(np.max(w_plot), snd.p[np.argmax(w_plot)], " {:.1f}".format(np.max(w.magnitude)), color="purple", ha="left", va="center", transform=skew.ax.get_yaxis_transform()) skew.ax.text(max(np.min(w_plot), 0), snd.p[np.argmin(w_plot)], " {:.1f}".format(np.min(w.magnitude)), color="purple", ha="left", va="center", transform=skew.ax.get_yaxis_transform()) # skew.ax.fill_betweenx(snd.p, cloud_fractions, np.zeros(cloud_fractions.shape)) #################################################################################################################### # Tweaking skew.ax.set_xlim(-30, 40) skew.ax.set_ylim(1020, p_top) skew.ax.set_xlabel("") skew.ax.set_ylabel("") # Add legend for the parcel traces. skew.ax.legend(handles=[ mlines.Line2D([], [], color='orange', label='Surface parcel'), mlines.Line2D([], [], color='gray', label=r"Max $\theta_e$ below 750mb"), mlines.Line2D([], [], color='black', label=r"Cloud fraction"), mlines.Line2D([], [], color='purple', label=r"Vertical velocity (cm/s)"), ], loc="upper center") # Add adiabats and isohumes. skew.plot_dry_adiabats(t0=np.arange(233, 533, 10) * units.K, alpha=0.25, color='orangered') skew.plot_moist_adiabats(t0=np.arange(233, 400, 5) * units.K, alpha=0.25, color='tab:green') # Reshape required as a quirk of metpy. skew.plot_mixing_lines(w=np.array( [1, 2, 3, 4, 6, 8, 10, 12, 16, 20, 24, 28, 36]).reshape(-1, 1) / 1000., p=np.arange(1000, 99, -100) * units.hPa, linestyle='dotted', color='tab:blue') plt.title('RAP sounding at {}'.format(snd.params["STID"]), loc='left') plt.title('{:.0f}-hour forecast valid at {}'.format( snd.params["STIM"], snd.params["TIME"]), loc='right') #################################################################################################################### # Theta-E plot # Set up axis for theta-e plot. ax_thte.plot(Te[mask_thetae], p[mask_thetae]) ax_thte.set_xlim(300, 360) ax_thte.set_ylim(1020, p_top) ax_thte.set_yscale("log") ax_thte.set_yticks(np.arange(p_top, 1001, 100)) ax_thte.set_yticklabels(np.arange(p_top, 1001, 100)) ax_thte.set_xlabel("") ax_thte.grid(axis="both") plt.text(0.5, 0.9, "Theta-E (Kelvins)", ha="center", va="center", transform=ax_thte.transAxes) #################################################################################################################### # Hodograph # Set up axis for hodograph. h = Hodograph(ax_hodo, component_range=100) h.add_grid(20) # Plot each segment individually for control over color, reversed so that the full hodograph is plotted first, # followed by all but the last segment, etc. Unfortunately, the plot_colormapped() function doesn't work for this # purpose. for color, interval in zip(reversed(z_interval_colors), reversed(z_interval_levels)): mask = z < interval * units.meter h.plot(u.magnitude[mask], v.magnitude[mask], c=color) for vector in snd.bunkers_storm_motion(): h.plot(vector[0], vector[1], c="black", markersize=3, marker="o") ax_hodo.set_xticks([]) ax_hodo.set_yticks([]) ax_hodo.set_xlim(-60, 100) ax_hodo.set_ylim(-60, 100) plt.text(0.1, 0.9, "Velocity (knots)", ha="left", va="center", transform=ax_hodo.transAxes) for a in range(20, 61, 20): ax_hodo.text(-a * 0.71, -a * 0.71, a, ha="center", va="center") ######################################################################################################################## parameter_names = ["SB STP", "0-1 SRH", "SB CAPE", "SB CIN"] parameters = [ snd.significant_tornado()[0], snd.storm_relative_helicity()[2], snd.cape_cin(0)[0], snd.cape_cin(0)[1] ] for name, value, i in zip(parameter_names, parameters, range(len(parameters))): s = "{:15} {:10.3f}".format(name, value.magnitude) fig.text(0.70, 0.32 - (0.02 * i), s, ha="left", va="top", family="monospace", transform=fig.transFigure) ######################################################################################################################## if save_to is None: plt.show() else: plt.savefig(save_to) plt.close()
def skewt_plot(p, tc, tdc, t0, date, u=None, v=None, fout='sounding.png', latlon='', title='', show=False): """ h: heights p: pressure tc: Temperature [C] tdc: Dew point [C] date: date of the forecast u,v: u,v wind components adapted from: https://geocat-examples.readthedocs.io/en/latest/gallery/Skew-T/NCL_skewt_3_2.html#sphx-glr-gallery-skew-t-ncl-skewt-3-2-py """ Pmax = 150 # XXX upper limit print('Checking units') if p.attrs['units'] != 'hPa': print('P wrong units') exit() if tc.attrs['units'] != 'degC': print('Tc wrong units') exit() if tdc.attrs['units'] != 'degC': print('Tdc wrong units') exit() if t0.attrs['units'] != 'degC': print('T0 wrong units') exit() if type(u) != type(None) and type(v) != type(None): if u.attrs['units'] != 'm s-1': print('Wind wrong units') exit() LG.info('Inside skewt plot') p = p.values tc = tc.values tdc = tdc.values t0 = t0.mean().values u = u.values * 3.6 # km/h v = v.values * 3.6 # km/h # Grid plot LG.info('creating figure') fig = plt.figure(figsize=(11, 12)) LG.info('created figure') LG.info('creating axis') gs = gridspec.GridSpec(1, 2, width_ratios=[4, 1]) fig.subplots_adjust(wspace=0., hspace=0.) # ax1 = plt.subplot(gs[1:-1,0]) # Adding the "rotation" kwarg will over-ride the default MetPy rotation of # 30 degrees for the 45 degree default found in NCL Skew-T plots LG.info('created axis') LG.info('Creatin SkewT') skew = SkewT(fig, rotation=45, subplot=gs[0, 0]) ax = skew.ax LG.info('Created SkewT') if len(latlon) > 0: ax.text(0, 1, latlon, va='top', ha='left', color='k', fontsize=12, bbox=dict(boxstyle="round", ec=None, fc=(1., 1., 1., 0.9)), zorder=100, transform=ax.transAxes) # Plot the data, T and Tdew vs pressure skew.plot(p, tc, 'C3') skew.plot(p, tdc, 'C0') LG.info('plotted dew point and sounding') # LCL lcl_pressure, lcl_temperature = mpcalc.lcl(p[0] * units.hPa, t0 * units.degC, tdc[0] * units.degC) skew.plot(lcl_pressure, lcl_temperature, 'k.') # Calculate the parcel profile #XXX units workaround parcel_prof = mpcalc.parcel_profile(p * units.hPa, t0 * units.degC, tdc[0] * units.degC).to('degC') # Plot cloud base ind_cross = np.argmin(np.abs(parcel_prof.magnitude - tc)) p_base = np.max([lcl_pressure.magnitude, p[ind_cross]]) t_base = np.max([lcl_temperature.magnitude, tc[ind_cross]]) m_base = mpcalc.pressure_to_height_std(np.array(p_base) * units.hPa) m_base = m_base.to('m').magnitude skew.ax.axhline(p_base, color=(0.5, 0.5, 0.5), ls='--') skew.plot(p_base, t_base, 'C3o', zorder=100) skew.ax.text(t_base, p_base, f'{m_base:.0f}m', ha='left') # Plot the parcel profile as a black line skew.plot(p, parcel_prof, 'k', linewidth=1) LG.info('plotted parcel profile') # shade CAPE and CIN skew.shade_cape(p * units.hPa, tc * units.degC, parcel_prof) skew.shade_cin(p * units.hPa, tc * units.degC, parcel_prof, tdc * units.degC) LG.info('plotted CAPE and CIN') if type(u) != type(None) and type(v) != type(None): LG.info('Plotting wind') ax2 = plt.subplot(gs[0, 1], sharey=ax, zorder=-1) # ax2.yaxis.set_visible(False) ax2.yaxis.tick_right() # ax2.xaxis.tick_top() wspd = np.sqrt(u * u + v * v) ax2.scatter(wspd, p, c=p, cmap=HEIGHTS, zorder=10) gnd = mpcalc.pressure_to_height_std(np.array(p[0]) * units.hPa) gnd = gnd.to('m') # Ground ax2.axhline(p[0], c='k', ls='--') ax2.text(56, p[0], f'{int(gnd.magnitude)}m', horizontalalignment='right') # Techo ax2.axhline(p_base, c=(0.5, 0.5, 0.5), ls='--') ### Background colors ## #for i,c in enumerate(WindSpeed.colors): # rect = Rectangle((i*4, 150), 4, 900, color=c, alpha=0.5,zorder=-1) # ax2.add_patch(rect) ######################### ax2.set_xlim(0, 56) ax2.set_xlabel('Wspeed (km/h)') ax2.grid() def p2h(x): """ x in hPa """ y = mpcalc.pressure_to_height_std(np.array(x) * units.hPa) # y = y.metpy.convert_units('m') y = y.to('m') return y.magnitude def h2p(x): """ x in m """ # x = x.values y = mpcalc.height_to_pressure_std(np.array(x) * units.m) # y = y.metpy.convert_units('hPa') y = y.to('hPa') return y.magnitude # print('------') # print(p[0]) # print('---') # print(p2h(p[0])) # print('---') # print(h2p(p2h(p[0]))) # print('------') # exit() ax2y = ax2.secondary_yaxis(1.02, functions=(p2h, h2p)) ax2y.set_ylabel('height (m)') # ax2y.set_yticks(np.array([1000,2000,3000,4000,6000,6000,10000])) # XXX Not working ax2y.yaxis.set_major_formatter(ScalarFormatter()) ax2y.yaxis.set_minor_formatter(ScalarFormatter()) ################# ax2y.set_color('red') ax2y.tick_params(colors='red', size=7, width=1, which='both') # 'both' refers to minor and major axes # ax2y.set_yticks([1,2,3,4]) #ax2.set_xticks([0,5,10,15,20,30,40,50]) #ax2.set_xticklabels(['0','','10','','20','30','40','50']) ax2.set_xticks([0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 56]) ax2.set_xticklabels( ['0', '', '8', '', '16', '', '24', '32', '40', '48', '56'], fontsize=11, va='center') plt.setp(ax2.get_yticklabels(), visible=False) # Hodograph ax_hod = inset_axes(ax2, '110%', '30%', loc=1) ax_hod.set_yticklabels([]) ax_hod.set_xticklabels([]) L = 80 ax_hod.text(0, L - 5, 'N', horizontalalignment='center', verticalalignment='center') ax_hod.text(L - 5, 0, 'E', horizontalalignment='center', verticalalignment='center') ax_hod.text(-(L - 5), 0, 'W', horizontalalignment='center', verticalalignment='center') ax_hod.text(0, -(L - 5), 'S', horizontalalignment='center', verticalalignment='center') h = Hodograph(ax_hod, component_range=L) h.add_grid(increment=20) h.plot_colormapped( -u, -v, p, cmap=HEIGHTS ) #'viridis_r') # Plot a line colored by pressure (altitude) LG.info('Plotted wind') # # print('=-=-=-=-=-=-=') # # print(ax2.get_yscale()) # # print(ax2y.get_yscale()) # # print('=-=-=-=-=-=-=') # # ax2y.yaxis.tick_right() # # # ax2y.set_ylim(*reversed(ax.get_ylim())) # # ax2y.set_ylim(*ax.get_ylim()) # # # calc pressure to height # # locs = ax2.get_yticks() # # labels = [mpcalc.pressure_to_height_std(h*units.hPa) for h in locs] # # labels = [round(l.to('m'),1) for l in labels] # # for xp,xh in zip(locs,labels): # # print(xp,xh) # # ax2y.set_yticks(locs) # # ax2y.set_yticklabels([f'{int(l.magnitude)}' for l in labels]) # Plot only every n windbarb n = 4 inds, = np.where(p > Pmax) break_p = 25 inds_low = inds[:break_p] inds_high = inds[break_p:] inds = np.append(inds_low[::n], inds_high) skew.plot_barbs( pressure=p[inds], #[::n], # * units.hPa, u=u[inds], #[::n], v=v[inds], #[::n], xloc=0.985, # fill_empty=True, sizes=dict(emptybarb=0.075, width=0.1, height=0.2)) # # # Draw line underneath wind barbs # # line = mlines.Line2D([1.05, 1.05], [0, 1], color='gray', linewidth=0.5, # # transform=ax.transAxes, # # dash_joinstyle='round', # # clip_on=False, # # zorder=0) # # ax.add_line(line) # Add relevant special lines # Choose starting temperatures in Kelvin for the dry adiabats LG.info('Plot adiabats, and other grid lines') skew.ax.text(t0, p[0], f'{t0:.1f}°C', va='top') skew.ax.axvline(t0, color=(0.5, 0.5, 0.5), ls='--') t0 = units.K * np.arange(243.15, 473.15, 10) skew.plot_dry_adiabats(t0=t0, linestyles='solid', colors='gray', linewidth=1) # Choose temperatures for moist adiabats t0 = units.K * np.arange(281.15, 306.15, 4) msa = skew.plot_moist_adiabats(t0=t0, linestyles='solid', colors='lime', linewidths=.75) # Choose mixing ratios w = np.array([0.001, 0.002, 0.003, 0.005, 0.008, 0.012, 0.020]).reshape(-1, 1) # Choose the range of pressures that the mixing ratio lines are drawn over p_levs = units.hPa * np.linspace(1000, 400, 7) skew.plot_mixing_lines(mixing_ratio=w, pressure=p_levs, linestyle='dotted', linewidths=1, colors='lime') LG.info('Plotted adiabats, and other grid lines') skew.ax.set_ylim(1000, Pmax) skew.ax.set_xlim(-20, 43) # skew.ax.set_xlim(-30, 40) # XXX gvutil not installed # gvutil.set_titles_and_labels(ax, maintitle="ATS Rawinsonde: degC + Thin wind") # Set axes limits and ticks # gvutil.set_axes_limits_and_ticks(ax=ax, xlim=[-30, 50], # yticks=[1000, 850, 700, 500, 400, 300, 250, 200, 150, 100]) # Change the style of the gridlines ax.grid(True, which='major', axis='both', color='tan', linewidth=1.5, alpha=0.5) ax.set_xlabel("Temperature (C)") ax.set_ylabel("P (hPa)") if len(title) == 0: title = f"{(date).strftime('%d/%m/%Y-%H:%M')} (local time)" ax.set_title(title, fontsize=20) else: ax.set_title(title, fontsize=20) if show: plt.show() LG.info('saving') fig.savefig(fout, bbox_inches='tight', pad_inches=0.1, dpi=150, quality=90) LG.info('saved') plt.close('all')
# Shade areas of CAPE and CIN skew.shade_cin(p, T, parcel_prof, Td) skew.shade_cape(p, T, parcel_prof) # Plot a zero degree isotherm skew.ax.axvline(0, color='c', linestyle='--', linewidth=3) # Add the relevant special lines skew.plot_dry_adiabats(linewidth=2.5) skew.plot_moist_adiabats(linewidth=2.5) skew.plot_mixing_lines(linewidth=2.5) ax1 = fig.add_subplot(gs[0:7, 4]) h = Hodograph(ax1, component_range=50.) h.add_grid(increment=12.5) h.plot(u, v, color='#0080ff') ax1.tick_params(labelsize=15.) ax1.set_xticks(np.arange(-50., 75., 25.)) ax1.set_yticks(np.arange(-50., 75., 25.)) ax1.set_xticklabels([]) ax1.set_title('Hodograph', fontsize=20.) ax1.set_xlabel('wind speed ($m$ $s^{-1}$)', fontsize=15.) ax1.set_ylabel('wind speed ($m$ $s^{-1}$)', fontsize=15.) ax2 = fig.add_subplot(gs[9:15, 4]) [ax2.add_patch(PolygonPatch(shape, fc='none')) for shape in shapes] ax2.scatter(lon[10:], lat[10:], c='r', s=10) ax2.tick_params(labelsize=15.) ax2.set_xticks(np.arange(119.5, 122., 0.5)) ax2.set_yticks(np.arange(22., 24.5, 0.5))
# Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 9)) add_metpy_logo(fig, 115, 100) # Grid for plots 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) # Add the relevant special lines skew.plot_dry_adiabats() skew.plot_moist_adiabats() skew.plot_mixing_lines() # Good bounds for aspect ratio skew.ax.set_xlim(-50, 60) # Create a hodograph ax_hod = inset_axes(skew.ax, '40%', '40%', loc=1) h = Hodograph(ax_hod, component_range=80.) h.add_grid(increment=20) h.plot_colormapped(u, v, np.hypot(u, v)) # Show the plot plt.show()
def _plot_hodograph(self, skew): # Create an array that indicates which layer (10-3, 3-1, 0-1 km) the # wind belongs to. The array, agl, will be set to the height # corresponding to the top of the layer. The resulting array will look # something like this: # # agl = [1.0 1.0 1.0 3.0 3.0 3.0 10.0 10.0 10.0 10.87 ] # # Where the values above 10 km are unchanged, and there are three levels # in each of the 3 layers of interest. # agl = np.copy(self.atmo_profiles.get('gh', {}).get('data')).to('km') # Retrieve the wind data profiles u_wind = self.atmo_profiles.get('u', {}).get('data') v_wind = self.atmo_profiles.get('v', {}).get('data') # Create an inset axes object that is 28% width and height of the # figure and put it in the upper left hand corner. ax = inset_axes(skew.ax, '25%', '25%', loc=2) h = Hodograph(ax, component_range=80.) h.add_grid(increment=20, linewidth=0.5) intervals = [0, 1, 3, 10] * agl.units colors = ['xkcd:salmon', 'xkcd:aquamarine', 'xkcd:navy blue'] line_width = 1.5 # Plot the line colored by height AGL only up to the 10km level lines = h.plot_colormapped( u_wind, v_wind, agl, colors=colors, intervals=intervals, linewidth=line_width, ) # Local function to create a proxy line object for creating a legend on # a LineCollection returned from plot_colormapped. Using lines and # colors from outside scope. def make_proxy(zval, idx=None, **kwargs): color = colors[idx] if idx < len(colors) else lines.cmap(zval - 1) return Line2D([0, 1], [0, 1], color=color, linewidth=line_width, **kwargs) # Make a list of proxies proxies = [ make_proxy(item, idx=i) for i, item in enumerate(intervals.magnitude) ] # Draw the legend ax.legend( proxies[:-1], ['0-1 km', '1-3 km', '3-10 km', ''], fontsize='small', loc='lower left', )
def main(): args = get_args() setup_logging(args['verbose']) # Define input file file = args['inputfile'] output = args['outputfile'] ds = xr.open_dataset(file) ds_sel = ds.isel({'sounding': 0}) ds_sel = ds_sel.sortby(ds_sel.pressure, ascending=False) p = ds_sel.pressure.values T = ds_sel.temperature.values Td = ds_sel.dewPoint.values wind_speed = ds_sel.windSpeed.values wind_dir = ds_sel.windDirection.values # Filter nans idx = np.where((np.isnan(T) + np.isnan(Td) + np.isnan(p) + np.isnan(wind_speed) + np.isnan(wind_dir)) == False, True, False) p = p[idx] T = T[idx] Td = Td[idx] wind_speed = wind_speed[idx] wind_dir = wind_dir[idx] # Add units p = p * units.hPa T = T * units.degC Td = Td * units.degC wind_speed = wind_speed * (units.meter / units.second) wind_dir = wind_dir * units.degrees u, v = mpcalc.wind_components(wind_speed, wind_dir) lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0]) parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC') # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(9, 10)) skew = SkewT(fig, rotation=30) # 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') # Plot only specific barbs to increase visibility pressure_levels_barbs = np.logspace(0.1, 1, 50) * 100 def find_nearest(array, value): array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] # Search for levels by providing pressures # (levels is the coordinate not pressure) pres_vals = ds_sel.pressure.values[idx] closest_pressure_levels = np.unique( [find_nearest(pres_vals, p_) for p_ in pressure_levels_barbs]) _, closest_pressure_levels_idx, _ = np.intersect1d(pres_vals, closest_pressure_levels, return_indices=True) p_barbs = ds_sel.pressure.isel({ 'levels': closest_pressure_levels_idx }).values * units.hPa wind_speed_barbs = ds_sel.windSpeed.isel({ 'levels': closest_pressure_levels_idx }).values * (units.meter / units.second) wind_dir_barbs = ds_sel.windDirection.isel({ 'levels': closest_pressure_levels_idx }).values * units.degrees u_barbs, v_barbs = mpcalc.wind_components(wind_speed_barbs, wind_dir_barbs) # Find nans in pressure # p_non_nan_idx = np.where(~np.isnan(pres_vals)) skew.plot_barbs(p_barbs, u_barbs, v_barbs, xloc=1.06) # set axes limits: skew.ax.set_ylim(1020, 100) skew.ax.set_xlim(-50, 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(pres_vals, parcel_prof, 'k', linewidth=1.6) # Shade areas of CAPE and CIN skew.shade_cin(pres_vals, T, parcel_prof) skew.shade_cape(pres_vals, T, parcel_prof) # Plot a zero degree 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() # 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, '35%', '35%', loc=1) h = Hodograph(ax_hod, component_range=75.) h.add_grid(increment=20) h.plot_colormapped(u, v, wind_speed) # Plot a line colored by wind speed # Set title sounding_name = ds_sel.sounding.values sounding_name_str = str(sounding_name.astype('str')) skew.ax.set_title('{sounding}'.format(sounding=sounding_name_str)) if output is None: output = str(os.path.basename(file).split('.')[0]) + '.pdf' logging.info('Write output to {}'.format(output)) plt.savefig(output)