def get_parcels(self): ''' Function to generate various parcels and parcel traces. Returns nothing, but sets the following variables: self.mupcl : Most Unstable Parcel self.sfcpcl : Surface Based Parcel self.mlpcl : Mixed Layer Parcel self.fcstpcl : Forecast Surface Parcel self.ebottom : The bottom pressure level of the effective inflow layer self.etop : the top pressure level of the effective inflow layer self.ebotm : The bottom, meters (agl), of the effective inflow layer self.etopm : The top, meters (agl), of the effective inflow layer Parameters ---------- None Returns ------- None ''' self.mupcl = params.parcelx( self, flag=3 ) if self.mupcl.lplvals.pres == self.pres[self.sfc]: self.sfcpcl = self.mupcl else: self.sfcpcl = params.parcelx( self, flag=1 ) self.fcstpcl = params.parcelx( self, flag=2 ) self.mlpcl = params.parcelx( self, flag=4 ) self.usrpcl = params.Parcel() ## get the effective inflow layer data self.ebottom, self.etop = params.effective_inflow_layer( self, mupcl=self.mupcl ) ## if there was no effective inflow layer, set the values to masked if self.etop is ma.masked or self.ebottom is ma.masked: self.ebotm = ma.masked; self.etopm = ma.masked self.effpcl = self.sfcpcl # Default to surface parcel, as in params.DefineProfile(). ## otherwise, interpolate the heights given to above ground level else: self.ebotm = interp.to_agl(self, interp.hght(self, self.ebottom)) self.etopm = interp.to_agl(self, interp.hght(self, self.etop)) # The below code was adapted from params.DefineProfile() # Lifting one additional parcel probably won't slow the program too much. # It's just one more lift compared to all the lifts in the params.effective_inflow_layer() call. mtha = params.mean_theta(self, self.ebottom, self.etop) mmr = params.mean_mixratio(self, self.ebottom, self.etop) effpres = (self.ebottom+self.etop)/2. efftmpc = thermo.theta(1000., mtha, effpres) effdwpc = thermo.temp_at_mixrat(mmr, effpres) self.effpcl = params.parcelx(self, flag=5, pres=effpres, tmpc=efftmpc, dwpc=effdwpc) #This is the effective parcel.
def lift_parcels(prof): """Lift all the parcels within a given height interval and return the CAPEs, CINHs, and LFCs""" ## the height bottom, top, and interval zvals = np.arange(0, 5000, 100) pvals = interp.pres(prof, interp.to_msl(prof, zvals)) tvals = interp.temp(prof, pvals) dvals = interp.dwpt(prof, pvals) hvals = interp.hght(prof, pvals) hvals = interp.to_agl(prof, hvals) ## empty lists for storing the result cape_arr = [] cinh_arr = [] lfc_arr = [] ## lift each parcel in the vertical profile for p, t, td, h in zip(pvals, tvals, dvals, hvals): ## use SHARPpy to compute the parcel indices pcl = params.parcelx(prof, pres=p, tmpc=t, dwpc=td) ## store the parcel indices cape_arr.append(pcl.bplus) cinh_arr.append(pcl.bminus) lfc_arr.append(pcl.lfchght - h) ## return the data return np.ma.masked_invalid(cape_arr), np.ma.masked_invalid( cinh_arr), np.ma.masked_invalid(lfc_arr)
def draw_ensemble_point(self, qp, prof): # Plot the profile index on the scatter plot if 'pbl_h' not in dir( prof ): # Make sure a PBL top has been found in the profile object ppbl_top = params.pbl_top(prof) setattr(prof, 'pbl_h', interp.to_agl(prof, interp.hght(prof, ppbl_top))) if 'sfcpcl' not in dir( prof ): # Make sure a surface parcel has been lifted in the profile object setattr(prof, 'sfcpcl', params.parcelx(prof, flag=1)) #x = self.x_to_xpix() #y = self.y_to_ypix() color = QtCore.Qt.red qp.setPen(QtGui.QPen(color)) qp.setBrush(QtGui.QBrush(color)) x = self.x_to_xpix(prof.pbl_h) - 50 / 2. y = self.y_to_ypix(prof.sfcpcl.bplus) - (self.fsize - 1) / 2 qp.drawEllipse(x, y, 3, 3) return
def indices(prof, debug=False): # return a formatted-string list of stability and kinematic indices sfcpcl = params.parcelx(prof, flag=1) mupcl = params.parcelx(prof, flag=3) # most unstable mlpcl = params.parcelx(prof, flag=4) # 100 mb mean layer parcel pcl = mupcl 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) sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) #print "0-3 km Pressure-Weighted Mean Wind (kt):", utils.comp2vec(mean_3km[0], mean_3km[1])[1] #print "0-6 km Shear (kt):", utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] srwind = params.bunkers_storm_motion(prof) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1]) #print "0-3 km Storm Relative Helicity [m2/s2]:",srh3km[0] #### Calculating variables based off of the effective inflow layer: # The effective inflow layer concept is used to obtain the layer of buoyant parcels that feed a storm's inflow. # Here are a few examples of how to compute variables that require the effective inflow layer in order to calculate them: stp_fixed = params.stp_fixed( sfcpcl.bplus, sfcpcl.lclhght, srh1km[0], utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]) ship = params.ship(prof) # If you get an error about not converting masked constant to python int # use the round() function instead of int() - Ahijevych May 11 2016 # 2nd element of list is the # of decimal places indices = { 'SBCAPE': [sfcpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'SBCIN': [sfcpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'SBLCL': [sfcpcl.lclhght, 0, 'm AGL'], 'SBLFC': [sfcpcl.lfchght, 0, 'm AGL'], 'SBEL': [sfcpcl.elhght, 0, 'm AGL'], 'SBLI': [sfcpcl.li5, 0, 'C'], 'MLCAPE': [mlpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'MLCIN': [mlpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'MLLCL': [mlpcl.lclhght, 0, 'm AGL'], 'MLLFC': [mlpcl.lfchght, 0, 'm AGL'], 'MLEL': [mlpcl.elhght, 0, 'm AGL'], 'MLLI': [mlpcl.li5, 0, 'C'], 'MUCAPE': [mupcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'], 'MUCIN': [mupcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'], 'MULCL': [mupcl.lclhght, 0, 'm AGL'], 'MULFC': [mupcl.lfchght, 0, 'm AGL'], 'MUEL': [mupcl.elhght, 0, 'm AGL'], 'MULI': [mupcl.li5, 0, 'C'], '0-1 km SRH': [srh1km[0], 0, '$\mathregular{m^{2}s^{-2}}$'], '0-1 km Shear': [utils.comp2vec(sfc_1km_shear[0], sfc_1km_shear[1])[1], 0, 'kt'], '0-3 km SRH': [srh3km[0], 0, '$\mathregular{m^{2}s^{-2}}$'], '0-6 km Shear': [utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1], 0, 'kt'], 'PWV': [params.precip_water(prof), 2, 'inch'], 'K-index': [params.k_index(prof), 0, ''], 'STP(fix)': [stp_fixed, 1, ''], 'SHIP': [ship, 1, ''] } eff_inflow = params.effective_inflow_layer(prof) if any(eff_inflow): ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0])) etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1])) #print "Effective Inflow Layer Bottom Height (m AGL):", ebot_hght #print "Effective Inflow Layer Top Height (m AGL):", etop_hght effective_srh = winds.helicity(prof, ebot_hght, etop_hght, stu=srwind[0], stv=srwind[1]) indices['Eff. SRH'] = [ effective_srh[0], 0, '$\mathregular{m^{2}s^{-2}}$' ] #print "Effective Inflow Layer SRH (m2/s2):", effective_srh[0] ebwd = winds.wind_shear(prof, pbot=eff_inflow[0], ptop=eff_inflow[1]) ebwspd = utils.mag(*ebwd) indices['EBWD'] = [ebwspd, 0, 'kt'] #print "Effective Bulk Wind Difference:", ebwspd scp = params.scp(mupcl.bplus, effective_srh[0], ebwspd) indices['SCP'] = [scp, 1, ''] stp_cin = params.stp_cin(mlpcl.bplus, effective_srh[0], ebwspd, mlpcl.lclhght, mlpcl.bminus) indices['STP(cin)'] = [stp_cin, 1, ''] #print "Supercell Composite Parameter:", scp #print "Significant Tornado Parameter (w/CIN):", stp_cin #print "Significant Tornado Parameter (fixed):", stp_fixed # Update the indices within the indices dictionary on the side of the plot. string = '' for index, value in sorted(indices.items()): if np.ma.is_masked(value[0]): if debug: print("skipping masked value for index=", index) continue if debug: print("index=", index) print("value=", value) format = '%.' + str(value[1]) + 'f' string += index + ": " + format % value[0] + " " + value[2] + '\n' return string
''' Create the Sounding (Profile) Object '''
# 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) sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km) srwind = params.bunkers_storm_motion(prof) srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1]) srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1])
def do_sharppy(spc_file): """ Based on the tutorial which can be found here: http://nbviewer.ipython.org/github/sharppy/SHARPpy/blob/master/tutorials/SHARPpy_basics.ipynb SHARPpy can be found here: https://github.com/sharppy/SHARPpy Credit goes to: Patrick Marsh (SPC) Kelton Halbert (OU School of Meteorology) Greg Blumberg (OU/CIMMS) Tim Supinie (OU School of Meteorology) """ import sharppy import sharppy.sharptab.profile as profile import sharppy.sharptab.interp as interp import sharppy.sharptab.winds as winds import sharppy.sharptab.utils as utils import sharppy.sharptab.params as params import sharppy.sharptab.thermo as thermo import matplotlib.pyplot as plt from StringIO import StringIO from matplotlib.axes import Axes import matplotlib.transforms as transforms import matplotlib.axis as maxis import matplotlib.spines as mspines import matplotlib.path as mpath from matplotlib.projections import register_projection spc_file = open('skewt_data', 'r').read() def parseSPC(spc_file): ## read in the file data = np.array([l.strip() for l in spc_file.split('\n')]) ## necessary index points title_idx = np.where(data == '%TITLE%')[0][0] start_idx = np.where(data == '%RAW%')[0] + 1 finish_idx = np.where(data == '%END%')[0] ## create the plot title data_header = data[title_idx + 1].split() location = data_header[0] + ' ' + data_header[1] time = data_header[2] title = location + ' ' + time ## put it all together for StringIO full_data = '\n'.join(data[start_idx:finish_idx][:]) sound_data = StringIO(full_data) ## read the data into arrays p, h, T, Td, wdir, wspd = np.genfromtxt(sound_data, delimiter=',', comments="%", unpack=True) return p, h, T, Td, wdir, wspd, title pres, hght, tmpc, dwpc, wdir, wspd, title = parseSPC(spc_file) prof = profile.create_profile(profile='default', pres=pres, hght=hght, tmpc=tmpc, \ dwpc=dwpc, wspd=wspd, wdir=wdir, missing=-9999, strictQC=True) 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 msl_hght = prof.hght[prof.sfc] # Grab the surface height value print "SURFACE HEIGHT (m MSL):", msl_hght agl_hght = interp.to_agl(prof, msl_hght) # Converts to AGL print "SURFACE HEIGHT (m AGL):", agl_hght msl_hght = interp.to_msl(prof, agl_hght) # Converts to MSL print "SURFACE HEIGHT (m MSL):", msl_hght print "Most-Unstable CAPE:", mupcl.bplus # J/kg print "Most-Unstable CIN:", mupcl.bminus # J/kg print "Most-Unstable LCL:", mupcl.lclhght # meters AGL print "Most-Unstable LFC:", mupcl.lfchght # meters AGL print "Most-Unstable EL:", mupcl.elhght # meters AGL print "Most-Unstable LI:", mupcl.li5 # C class SkewXTick(maxis.XTick): def draw(self, renderer): if not self.get_visible(): return renderer.open_group(self.__name__) lower_interval = self.axes.xaxis.lower_interval upper_interval = self.axes.xaxis.upper_interval if self.gridOn and transforms.interval_contains( self.axes.xaxis.get_view_interval(), self.get_loc()): self.gridline.draw(renderer) if transforms.interval_contains(lower_interval, self.get_loc()): if self.tick1On: self.tick1line.draw(renderer) if self.label1On: self.label1.draw(renderer) if transforms.interval_contains(upper_interval, self.get_loc()): if self.tick2On: self.tick2line.draw(renderer) if self.label2On: self.label2.draw(renderer) renderer.close_group(self.__name__) # This class exists to provide two separate sets of intervals to the tick, # as well as create instances of the custom tick class SkewXAxis(maxis.XAxis): def __init__(self, *args, **kwargs): maxis.XAxis.__init__(self, *args, **kwargs) self.upper_interval = 0.0, 1.0 def _get_tick(self, major): return SkewXTick(self.axes, 0, '', major=major) @property def lower_interval(self): return self.axes.viewLim.intervalx def get_view_interval(self): return self.upper_interval[0], self.axes.viewLim.intervalx[1] # This class exists to calculate the separate data range of the # upper X-axis and draw the spine there. It also provides this range # to the X-axis artist for ticking and gridlines class SkewSpine(mspines.Spine): def _adjust_location(self): trans = self.axes.transDataToAxes.inverted() if self.spine_type == 'top': yloc = 1.0 else: yloc = 0.0 left = trans.transform_point((0.0, yloc))[0] right = trans.transform_point((1.0, yloc))[0] pts = self._path.vertices pts[0, 0] = left pts[1, 0] = right self.axis.upper_interval = (left, right) # This class handles registration of the skew-xaxes as a projection as well # as setting up the appropriate transformations. It also overrides standard # spines and axes instances as appropriate. class SkewXAxes(Axes): # The projection must specify a name. This will be used be the # user to select the projection, i.e. ``subplot(111, # projection='skewx')``. name = 'skewx' def _init_axis(self): #Taken from Axes and modified to use our modified X-axis self.xaxis = SkewXAxis(self) self.spines['top'].register_axis(self.xaxis) self.spines['bottom'].register_axis(self.xaxis) self.yaxis = maxis.YAxis(self) self.spines['left'].register_axis(self.yaxis) self.spines['right'].register_axis(self.yaxis) def _gen_axes_spines(self): spines = { 'top': SkewSpine.linear_spine(self, 'top'), 'bottom': mspines.Spine.linear_spine(self, 'bottom'), 'left': mspines.Spine.linear_spine(self, 'left'), 'right': mspines.Spine.linear_spine(self, 'right') } return spines def _set_lim_and_transforms(self): """ This is called once when the plot is created to set up all the transforms for the data, text and grids. """ rot = 30 #Get the standard transform setup from the Axes base class Axes._set_lim_and_transforms(self) # Need to put the skew in the middle, after the scale and limits, # but before the transAxes. This way, the skew is done in Axes # coordinates thus performing the transform around the proper origin # We keep the pre-transAxes transform around for other users, like the # spines for finding bounds self.transDataToAxes = self.transScale + ( self.transLimits + transforms.Affine2D().skew_deg(rot, 0)) # Create the full transform from Data to Pixels self.transData = self.transDataToAxes + self.transAxes # Blended transforms like this need to have the skewing applied using # both axes, in axes coords like before. self._xaxis_transform = ( transforms.blended_transform_factory( self.transScale + self.transLimits, transforms.IdentityTransform()) + transforms.Affine2D().skew_deg(rot, 0)) + self.transAxes # Now register the projection with matplotlib so the user can select # it. register_projection(SkewXAxes) pcl = mupcl # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(6.5875, 6.2125)) ax = fig.add_subplot(111, projection='skewx') ax.grid(True) pmax = 1000 pmin = 10 dp = -10 presvals = np.arange(int(pmax), int(pmin) + dp, dp) # plot the moist-adiabats for t in np.arange(-10, 45, 5): tw = [] for p in presvals: tw.append(thermo.wetlift(1000., t, p)) ax.semilogy(tw, presvals, 'k-', alpha=.2) def thetas(theta, presvals): return ((theta + thermo.ZEROCNK) / (np.power( (1000. / presvals), thermo.ROCP))) - thermo.ZEROCNK # plot the dry adiabats for t in np.arange(-50, 110, 10): ax.semilogy(thetas(t, presvals), presvals, 'r-', alpha=.2) plt.title(title, fontsize=14, loc='left') # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dicatated by the typical meteorological plot ax.semilogy(prof.tmpc, prof.pres, 'r', lw=2) ax.semilogy(prof.dwpc, prof.pres, 'g', lw=2) ax.semilogy(pcl.ttrace, pcl.ptrace, 'k-.', lw=2) # An example of a slanted line at constant X l = ax.axvline(0, color='b', linestyle='--') l = ax.axvline(-20, color='b', linestyle='--') # Disables the log-formatting that comes with semilogy ax.yaxis.set_major_formatter(plt.ScalarFormatter()) ax.set_yticks(np.linspace(100, 1000, 10)) ax.set_ylim(1050, 100) ax.xaxis.set_major_locator(plt.MultipleLocator(10)) ax.set_xlim(-50, 50) plt.show() ##PLOTS SKEWT OK ABOVE HERE ## """
hght=hght.to('m').m, tmpc=tmpc.to('degree_Celsius').m, dwpc=dwpc.to('degree_Celsius').m, wspd=wspd.to('knots').m, wdir=wdir, latitude=latitude, longitude=longitude, strictQC=True) #### Adding a Parcel Trace sfc_pcl = 1 # Surface Parcel fcstpcl = 2 # Forecast Parcel mupcl = 3 # Most-Unstable Parcel in lowest 400 hPa mlpcl = 4 # 100 mb Mean Layer Parcel # Set the parcel trace to be plotted as the Most-Unstable parcel. pcl = params.parcelx(prof, flag=mupcl) # Temperature, dewpoint, virtual temperature, wetbulb, parcel profiles temperature_trace, = skew.plot(prof.pres, prof.tmpc, 'r', linewidth=2) # temperature profile # annotate temperature in F at bottom of T profile temperatureF = skew.ax.text(prof.tmpc[0], prof.pres[0] + 10, utils.INT2STR(thermo.ctof(prof.tmpc[0])), verticalalignment='top', horizontalalignment='center', size=7, color=temperature_trace.get_color()) vtemp_trace, = skew.plot(prof.pres, prof.vtmp, 'r', linewidth=0.5) # Virtual temperature profile wetbulb_trace, = skew.plot(prof.pres, prof.wetbulb,
def do_sharppy(spc_file): """ Based on the tutorial which can be found here: http://nbviewer.ipython.org/github/sharppy/SHARPpy/blob/master/tutorials/SHARPpy_basics.ipynb SHARPpy can be found here: https://github.com/sharppy/SHARPpy Credit goes to: Patrick Marsh (SPC) Kelton Halbert (OU School of Meteorology) Greg Blumberg (OU/CIMMS) Tim Supinie (OU School of Meteorology) """ import sharppy import sharppy.sharptab.profile as profile import sharppy.sharptab.interp as interp import sharppy.sharptab.winds as winds import sharppy.sharptab.utils as utils import sharppy.sharptab.params as params import sharppy.sharptab.thermo as thermo import matplotlib.pyplot as plt from StringIO import StringIO from matplotlib.axes import Axes import matplotlib.transforms as transforms import matplotlib.axis as maxis import matplotlib.spines as mspines import matplotlib.path as mpath from matplotlib.projections import register_projection spc_file = open('skewt_data', 'r').read() def parseSPC(spc_file): ## read in the file data = np.array([l.strip() for l in spc_file.split('\n')]) ## necessary index points title_idx = np.where( data == '%TITLE%')[0][0] start_idx = np.where( data == '%RAW%' )[0] + 1 finish_idx = np.where( data == '%END%')[0] ## create the plot title data_header = data[title_idx + 1].split() location = data_header[0]+' '+data_header[1] time = data_header[2] title = location+' '+time ## put it all together for StringIO full_data = '\n'.join(data[start_idx : finish_idx][:]) sound_data = StringIO( full_data ) ## read the data into arrays p, h, T, Td, wdir, wspd = np.genfromtxt( sound_data, delimiter=',', comments="%", unpack=True ) return p, h, T, Td, wdir, wspd, title pres, hght, tmpc, dwpc, wdir, wspd, title = parseSPC(spc_file) prof = profile.create_profile(profile='default', pres=pres, hght=hght, tmpc=tmpc, \ dwpc=dwpc, wspd=wspd, wdir=wdir, missing=-9999, strictQC=True) 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 msl_hght = prof.hght[prof.sfc] # Grab the surface height value print "SURFACE HEIGHT (m MSL):",msl_hght agl_hght = interp.to_agl(prof, msl_hght) # Converts to AGL print "SURFACE HEIGHT (m AGL):", agl_hght msl_hght = interp.to_msl(prof, agl_hght) # Converts to MSL print "SURFACE HEIGHT (m MSL):",msl_hght print "Most-Unstable CAPE:", mupcl.bplus # J/kg print "Most-Unstable CIN:", mupcl.bminus # J/kg print "Most-Unstable LCL:", mupcl.lclhght # meters AGL print "Most-Unstable LFC:", mupcl.lfchght # meters AGL print "Most-Unstable EL:", mupcl.elhght # meters AGL print "Most-Unstable LI:", mupcl.li5 # C class SkewXTick(maxis.XTick): def draw(self, renderer): if not self.get_visible(): return renderer.open_group(self.__name__) lower_interval = self.axes.xaxis.lower_interval upper_interval = self.axes.xaxis.upper_interval if self.gridOn and transforms.interval_contains( self.axes.xaxis.get_view_interval(), self.get_loc()): self.gridline.draw(renderer) if transforms.interval_contains(lower_interval, self.get_loc()): if self.tick1On: self.tick1line.draw(renderer) if self.label1On: self.label1.draw(renderer) if transforms.interval_contains(upper_interval, self.get_loc()): if self.tick2On: self.tick2line.draw(renderer) if self.label2On: self.label2.draw(renderer) renderer.close_group(self.__name__) # This class exists to provide two separate sets of intervals to the tick, # as well as create instances of the custom tick class SkewXAxis(maxis.XAxis): def __init__(self, *args, **kwargs): maxis.XAxis.__init__(self, *args, **kwargs) self.upper_interval = 0.0, 1.0 def _get_tick(self, major): return SkewXTick(self.axes, 0, '', major=major) @property def lower_interval(self): return self.axes.viewLim.intervalx def get_view_interval(self): return self.upper_interval[0], self.axes.viewLim.intervalx[1] # This class exists to calculate the separate data range of the # upper X-axis and draw the spine there. It also provides this range # to the X-axis artist for ticking and gridlines class SkewSpine(mspines.Spine): def _adjust_location(self): trans = self.axes.transDataToAxes.inverted() if self.spine_type == 'top': yloc = 1.0 else: yloc = 0.0 left = trans.transform_point((0.0, yloc))[0] right = trans.transform_point((1.0, yloc))[0] pts = self._path.vertices pts[0, 0] = left pts[1, 0] = right self.axis.upper_interval = (left, right) # This class handles registration of the skew-xaxes as a projection as well # as setting up the appropriate transformations. It also overrides standard # spines and axes instances as appropriate. class SkewXAxes(Axes): # The projection must specify a name. This will be used be the # user to select the projection, i.e. ``subplot(111, # projection='skewx')``. name = 'skewx' def _init_axis(self): #Taken from Axes and modified to use our modified X-axis self.xaxis = SkewXAxis(self) self.spines['top'].register_axis(self.xaxis) self.spines['bottom'].register_axis(self.xaxis) self.yaxis = maxis.YAxis(self) self.spines['left'].register_axis(self.yaxis) self.spines['right'].register_axis(self.yaxis) def _gen_axes_spines(self): spines = {'top':SkewSpine.linear_spine(self, 'top'), 'bottom':mspines.Spine.linear_spine(self, 'bottom'), 'left':mspines.Spine.linear_spine(self, 'left'), 'right':mspines.Spine.linear_spine(self, 'right')} return spines def _set_lim_and_transforms(self): """ This is called once when the plot is created to set up all the transforms for the data, text and grids. """ rot = 30 #Get the standard transform setup from the Axes base class Axes._set_lim_and_transforms(self) # Need to put the skew in the middle, after the scale and limits, # but before the transAxes. This way, the skew is done in Axes # coordinates thus performing the transform around the proper origin # We keep the pre-transAxes transform around for other users, like the # spines for finding bounds self.transDataToAxes = self.transScale + (self.transLimits + transforms.Affine2D().skew_deg(rot, 0)) # Create the full transform from Data to Pixels self.transData = self.transDataToAxes + self.transAxes # Blended transforms like this need to have the skewing applied using # both axes, in axes coords like before. self._xaxis_transform = (transforms.blended_transform_factory( self.transScale + self.transLimits, transforms.IdentityTransform()) + transforms.Affine2D().skew_deg(rot, 0)) + self.transAxes # Now register the projection with matplotlib so the user can select # it. register_projection(SkewXAxes) pcl = mupcl # Create a new figure. The dimensions here give a good aspect ratio fig = plt.figure(figsize=(6.5875, 6.2125)) ax = fig.add_subplot(111, projection='skewx') ax.grid(True) pmax = 1000 pmin = 10 dp = -10 presvals = np.arange(int(pmax), int(pmin)+dp, dp) # plot the moist-adiabats for t in np.arange(-10,45,5): tw = [] for p in presvals: tw.append(thermo.wetlift(1000., t, p)) ax.semilogy(tw, presvals, 'k-', alpha=.2) def thetas(theta, presvals): return ((theta + thermo.ZEROCNK) / (np.power((1000. / presvals),thermo.ROCP))) - thermo.ZEROCNK # plot the dry adiabats for t in np.arange(-50,110,10): ax.semilogy(thetas(t, presvals), presvals, 'r-', alpha=.2) plt.title(title, fontsize=14, loc='left') # Plot the data using normal plotting functions, in this case using # log scaling in Y, as dicatated by the typical meteorological plot ax.semilogy(prof.tmpc, prof.pres, 'r', lw=2) ax.semilogy(prof.dwpc, prof.pres, 'g', lw=2) ax.semilogy(pcl.ttrace, pcl.ptrace, 'k-.', lw=2) # An example of a slanted line at constant X l = ax.axvline(0, color='b', linestyle='--') l = ax.axvline(-20, color='b', linestyle='--') # Disables the log-formatting that comes with semilogy ax.yaxis.set_major_formatter(plt.ScalarFormatter()) ax.set_yticks(np.linspace(100,1000,10)) ax.set_ylim(1050,100) ax.xaxis.set_major_locator(plt.MultipleLocator(10)) ax.set_xlim(-50,50) plt.show() ##PLOTS SKEWT OK ABOVE HERE ## """
start_idx = np.where(data == '%RAW%')[0] finish_idx = np.where(data == '%END%')[0] plot_title = data[title_idx + 1] full_data = '\n'.join(data[start_idx:finish_idx][:]) sound_data = StringIO(full_data) P, h, T, Td, wdir, wspd = np.genfromtxt(sound_data, delimiter=',', comments="%", unpack=True) prof = profile.create_profile(pres=P, hght=h, tmpc=T, dwpc=Td, wdir=wdir, wspd=wspd) pcl = parcelx(prof) sfcpcl = tab.params.parcelx(prof, flag=1) #Surface Parcel fcstpcl = tab.params.parcelx(prof, flag=2) #Forecast Parcel mupcl = tab.params.parcelx(prof, flag=3) #Most-Unstable Parcel mlpcl = tab.params.parcelx(prof, flag=4) #100 mb Mean Layer Parcel csvfile = open(('Lift_Parcel_' + filename[:-4] + '.txt'), 'wb') writer = csv.writer(csvfile, delimiter=' ') writer.writerow([plot_title]) writer.writerow('\r') loop_idx = range(1) for idx in loop_idx: a = [('Surface CAPE = ' + str(sfcpcl.bplus))] #J/Kg writer.writerow(a) b = [('Surface CIN = ' + str(sfcpcl.bminus))] #J/Kg writer.writerow(b)
print "skipping", sfile continue skew.ax.set_title(title, horizontalalignment="left", x=0, fontsize=12) print "reading", sfile data = open(sfile).read() pres, hght, tmpc, dwpc, wdir, wspd, latitude, longitude = parseGEMPAK(data) if wdir.size == 0: print "no good data lines. empty profile" continue prof = profile.create_profile(profile='default', pres=pres, hght=hght, tmpc=tmpc, dwpc=dwpc, wspd=wspd, wdir=wdir, latitude=latitude, longitude=longitude, missing=-999., strictQC=True) #### Adding a Parcel Trace 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 # Set the parcel trace to be plotted as the Most-Unstable parcel. pcl = mupcl # Temperature, dewpoint, virtual temperature, wetbulb, parcel profiles temperature_trace, = skew.plot(prof.pres, prof.tmpc, 'r', linewidth=2) # temperature profile # annotate temperature in F at bottom of T profile temperatureF = skew.ax.text(prof.tmpc[0], prof.pres[0]+10, utils.INT2STR(thermo.ctof(prof.tmpc[0])), verticalalignment='top', horizontalalignment='center', size=7, color=temperature_trace.get_color()) skew.plot(prof.pres, prof.vtmp, 'r', linewidth=0.5) # Virtual temperature profile skew.plot(prof.pres, prof.wetbulb, 'c-') # wetbulb profile dwpt_trace, = skew.plot(prof.pres, prof.dwpc, 'g', linewidth=2) # dewpoint profile # annotate dewpoint in F at bottom of dewpoint profile