示例#1
0
文件: dropsondes.py 项目: tjlang/AWOT
class DropSondes(object):
    '''
    Description:

    class to analyze dropsonde and sounding data
    #==========================
    requirements:

    thermodynaic calculations

    windshear calculations

    skew x axis class
    #==========================
    '''
    def __init__(self):

        # ============================================#
        # initiate a new instance of thermocalcs class#
        # ============================================#

        self.tC = ThermoCalcs()

        # ===========================================#
        # initiate a new instance of shearcalcs class#
        # ===========================================#

        self.sC = ShearCalcs()

        # Global height arrays for wind shear

        self.u_3km = []
        self.v_3km = []
        self.u_6km = []
        self.v_6km = []
        self.u_9km = []
        self.v_9km = []
        self.u_12km = []
        self.v_12km = []

    def get_sounding_data(self, filePath):
        '''
        method to retrieve standard sounding data from noaa radiosonde
        and U of Wyoming repository.

        Inputs:

        file path
        # ============

        output:

        # Dictionary with variable for use in plotting

        '''

        data = filePath
        fp = open(data, 'r')
        lines = fp.readlines()
        header = lines[1]
        fp.close()
        fp = open(data, 'r')
        sounding_data = fp
        p, h, T, Td, RH, MIXR, wd, ws = np.genfromtxt(
            sounding_data,
            skip_header=8,
            usecols=range(0, 8),
            dtype=float,
            delimiter=None,
            autostrip=True,
            missing_values='-9999.00',
            unpack=True,
            usemask=True)

        u = -ws * np.sin(np.radians(wd))
        v = -ws * np.cos(np.radians(wd))
        # RH = self.tC._dewpoint_to_RH(T+273.15, Td+273.15)

        mask = T.mask
        T = T[~mask]
        TD = Td[~mask]
        P = p[~mask]
        H = h[~mask]
        RH = RH[~mask]

        mask = u.mask
        U = u[~mask]
        V = v[~mask]

        data = dict()
        data['Header'] = header
        data['Temperature'] = T
        data['Dewpoint'] = Td
        data['Pressure'] = p
        data['Relative Humidity'] = RH
        data['U Component'] = U
        data['V Component'] = V
        data['Height'] = h
        data['Type'] = 'radioSonde'

        fp.close()

        # self.type = 'radioSonde'

        return data

    def get_dropsonde_data(self, filePath):
        '''
        method to retrieve dropsonde data

        Inputs:

        file path
        #============

        output:

        #Dictionary with variable for use in plotting

        '''

        data = filePath
        fp = open(data, 'r')
        lines = fp.readlines()
        header = lines[1]
        fp.close()
        fp = open(data, 'r')
        sounding_data = fp

        p, T, Td, RH, u, v, h = np.genfromtxt(sounding_data,
                                              skip_header=15,
                                              usecols=(1, 2, 3, 4, 5, 6, 14),
                                              dtype=float,
                                              missing_values='9999.0',
                                              unpack=True,
                                              usemask=True)

        # mask incoming T and dewpoint data

        T = np.ma.masked_greater_equal(T, 999.0)
        Td = np.ma.masked_greater_equal(Td, 999.0)
        RH = np.ma.masked_greater_equal(RH, 999.0)
        h = np.ma.masked_greater_equal(h, 99999.0)

        mask = T.mask
        T = T[~mask]
        TD = Td[~mask]
        P = p[~mask]
        H = h[~mask]
        RH = RH[~mask]

        mask = u.mask
        U = u[~mask]
        V = v[~mask]

        data = dict()
        data['Header'] = header
        data['Temperature'] = T
        data['Dewpoint'] = TD
        data['Pressure'] = P
        data['Relative Humidity'] = RH
        data['U Component'] = U
        data['V Component'] = V
        data['Height'] = H
        data['Type'] = 'dropsonde'

        return data

    def plot_skewtlogp(self, data, **kwargs):
        '''
        method to plot sounding or dropsonde data

        Inputs:

        dictionary of sounding data

        keyword arguments min, max, titles, and label.

        #============

        output:

        #Image

        '''

        T = data['Temperature']
        TD = data['Dewpoint']
        P = data['Pressure']

        self.fig = plt.figure(figsize=(10, 8))
        self.ax1 = self.fig.add_axes([0.05, 0.1, 0.6, 0.8], projection='skewx')
        plt.grid(True)

        self.plot_dryadiabats()

        self.ax1.semilogy(T, P, 'r-', linewidth=1.5)
        self.ax1.semilogy(TD, P, 'g-', linewidth=1.5)

        # Plot the data using normal plotting functions, in this case using
        # log scaling in Y, as dictated by the typical meteorological plot
        # Disables the log-formatting that comes with semilogy
        # set bounds for data on Skew T chart

        self.ax1.yaxis.set_major_formatter(ScalarFormatter())
        self.ax1.set_yticks(np.linspace(100, 1000, 10))
        self.ax1.set_ylim(1050, 100)
        self.ax1.set_ylabel('Pressure mb')
        self.ax1.set_xlabel('Temperature C')
        self.ax1.xaxis.set_major_locator(MultipleLocator(10))
        self.ax1.set_title('Skew T log P')

        self.y_min = kwargs.get('y_min')
        self.y_max = kwargs.get('y_max')

        self.x_min = kwargs.get('x_min')
        self.x_max = kwargs.get('x_max')

        # data label, title and font sizes value assignments
        # default values above.

        y_label = kwargs.get('y_label')
        x_label = kwargs.get('x_label')
        title = kwargs.get('title')
        font_size = kwargs.get('font_size')

        for item in ([self.ax1.xaxis.label, self.ax1.yaxis.label] +
                     self.ax1.get_xticklabels() + self.ax1.get_yticklabels()):
            item.set_fontsize(font_size)

        # set the labels and titles defaults to 'none'

        self.ax1.set_ylabel(y_label)
        self.ax1.set_xlabel(x_label)
        self.ax1.set_title(title)

        self.ax1.set_ylim(self.y_max, self.y_min)
        self.ax1.set_xlim(self.x_min, self.x_max)

    def plot_hodograph(self, data):
        '''
        method to plot wind data on a hodograph

        Inputs:

        dictionary containing wind data.

        file path
        # ============

        output:

        # Image

        '''

        self.ax2 = self.fig.add_axes([.05, 0.6, 0.25, 0.3])

        # create axis and invert masks and assign values
        # for U, V, and h coordinates

        U = data['U Component']
        V = data['V Component']
        H = data['Height']

        # =====================================================#
        # loop to place hodograph data into proper height array
        # 0-3km
        # 3-6km
        # 6-9km
        # 9-12km
        # ======#

        if data['Type'] == 'radioSonde':

            for unew, vnew, hnew in zip(U, V, H):
                if hnew <= 3001.0:
                    self.u_3km.append(unew)
                    self.v_3km.append(vnew)
                elif hnew <= 6001.0:
                    self.u_6km.append(unew)
                    self.v_6km.append(vnew)
                elif hnew <= 9000.0:
                    self.u_9km.append(unew)
                    self.v_9km.append(vnew)
                elif hnew <= 12000.0:
                    self.u_12km.append(unew)
                    self.v_12km.append(vnew)

        # print(len(self.u_3km))
        # print(len(self.v_3km))
        # =============================================================#
        # take the first point of the next height level and attach it
        # to the last point of the previous line segment to
        # connect hodograph segments
        # should only be done for soundings and non dense data
        # type determines how the data is placed in the array.
        # Soundings require endpoints be joined so that
        # the hodograph is continuous.
        # =============================================================#

        if data['Type'] == 'radioSonde':

            self.u_3km.append(self.u_6km[0])
            self.u_6km.append(self.u_9km[0])
            self.u_9km.append(self.u_12km[0])

            self.v_3km.append(self.v_6km[0])
            self.v_6km.append(self.v_9km[0])
            self.v_9km.append(self.v_12km[0])

        # ==============================#
        # Mask the arrays U and V coords
        # ==============================#

        self.v_3km = np.ma.asarray(self.v_3km)
        self.v_6km = np.ma.asarray(self.v_6km)
        self.v_9km = np.ma.asarray(self.v_9km)
        self.v_12km = np.ma.asarray(self.v_12km)

        self.u_3km = np.ma.asarray(self.u_3km)
        self.u_6km = np.ma.asarray(self.u_6km)
        self.u_9km = np.ma.asarray(self.u_9km)
        self.u_12km = np.ma.asarray(self.u_12km)

        # plotting of the hodograph information
        # Different colors are sued to represent different height levels
        # r = 0-3km
        # y = 3-6km
        # g = 6-9km
        # b = 9-12km

        self.ax2.plot(self.u_3km, self.v_3km, 'r-', linewidth=3)
        self.ax2.plot(
            self.u_6km,
            self.v_6km,
            'y-',
            linewidth=3,
        )
        self.ax2.plot(self.u_9km, self.v_9km, 'g-', linewidth=3)
        self.ax2.plot(self.u_12km, self.v_12km, 'b-', linewidth=3)

        # set the default limits on the hodo axes
        # remove spines and set the axes to be invisible.

        self.ax2.spines['left'].set_position('zero')
        self.ax2.spines['right'].set_color('none')
        self.ax2.spines['bottom'].set_position('zero')
        self.ax2.spines['top'].set_color('none')
        self.ax2.xaxis.set_ticks_position('bottom')
        self.ax2.yaxis.set_ticks_position('left')
        self.ax2.set_ylim(-50, 50)
        self.ax2.set_xlim(-50, 50)

        # Draw hodograph range rings
        # 10 20 30 40 m/s circles

        circ1 = patches.Circle((0, 0), 10, fc='white')
        circ2 = patches.Circle((0, 0), 20, fc='white')
        circ3 = patches.Circle((0, 0), 30, fc='white')
        circ4 = patches.Circle((0, 0), 40, fc='white')

        # Add circles to plot as patches#
        # descending order to make sure they layer ontop of each other.

        self.ax2.add_patch(circ4)
        self.ax2.add_patch(circ3)
        self.ax2.add_patch(circ2)
        self.ax2.add_patch(circ1)

    def plot_aux_graph(self, x_value, y_value, **kwargs):
        '''
        method to plot an auxiliary graph of user defined data

        Inputs:

        # sounding data (User specified)
        # kwargs to adjust plot dimensions scales label, and title.
        # ============

        output:

        # Image

        '''

        # define axes fro figure.
        # set grid and plot user specified data

        self.ax3 = self.fig.add_axes([.7, 0.7, .29, .24])
        plt.grid(True)
        self.ax3.plot(x_value, y_value)

        # Max and min graph bonds value assignment. Defaults to autoscale.

        y_min = kwargs.get('y_min')
        y_max = kwargs.get('y_max')

        x_min = kwargs.get('x_min')
        x_max = kwargs.get('x_max')

        # data label, title and font size value assignments .

        y_lable = kwargs.get('y_lable')
        x_lable = kwargs.get('x_lable')
        title = kwargs.get('title')
        font_size = kwargs.get('font_size')

        # keyword arguments for minimum and maximum values

        self.ax3.set_ylim(y_min, y_max)
        self.ax3.set_xlim(x_min, x_max)

        # set label and tick fontsizes to user defined value. Defaults to 10pt.

        for item in ([self.ax3.xaxis.label, self.ax3.yaxis.label] +
                     self.ax3.get_xticklabels() + self.ax3.get_yticklabels()):
            item.set_fontsize(font_size)

        # set the labels and title from keyword arguments. Defaults to 'none'

        self.ax3.set_ylabel(y_lable)
        self.ax3.set_xlabel(x_lable)
        self.ax3.set_title(title)

    def generate_parameter_list(self):
        '''
        method to generate a list of parameters calculated
        from the sounding data

        Inputs:

        # None
        # ============

        output:

        # Blank axis for plotting
        '''

        # Set axes position and set both axes invisible

        self.ax4 = self.fig.add_axes([.65, 0.1, .35, .54])
        self.ax4.xaxis.set_visible(False)
        self.ax4.yaxis.set_visible(False)

    def run_thermo_calcs(self, data):
        '''
        method to calculate thermodynamic parameters from dropsonde data

        Inputs:

        # Dictionary of sounding data.
        # Uses calculations from thermocalcs.py
        # ============

        output:

        # multiple arrays containing thermodynamic information

        '''

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        self.LCLT = round(
            (self.tC._LCL_Temperature(h, T + 273.15, Td + 273.15) - 273.15), 2)
        self.LCLP = round(
            (self.tC._LCL_Pressure(h, p, T + 273.15, Td + 273.15)), 0)
        self.LCLZ = round((self.tC._LCL_Height(h, p, T + 273.15, Td + 273.15)),
                          0)
        self.THETA = self.tC._PTk2_Theta(p, T + 273.15)
        self.MIXR = self.tC._RH_2_MixR(RH, p, T + 273.15)
        self.THETAE = self.tC._Tk_RH_MixR_2_ThetaE(p, T + 273.15, RH,
                                                   self.MIXR / 1000.)
        self.ESAT = self.tC._esat(T + 273.15)

    def plot_thermo_calcs(self):
        '''
        method to plot the thermodynamic parameters on the parameter list.

        Inputs:

        # None
        # ============

        output:

        # Image
        '''

        # plot the parameters on the list generated.
        self.ax4.text(.01, .01, 'LCL Pressure: ' + str(self.LCLP) + (' hPa'))
        self.ax4.text(.01, .04, 'LCL Temp: ' + str(self.LCLT) + ' c')
        self.ax4.text(.01, .07, 'LCL Height: ' + str(self.LCLZ) + ' m')

    def plot_dryadiabats(self, **kwargs):
        '''
        method to plot the dry adibats. Used in the plotskewtlogp method.

        Inputs:

        # kwargs (does not function)
        # ============

        output:

        # Image

        '''
        # test = self.shear1km

        # temperature array and pressure array

        t0 = np.linspace(200, 430, 17)
        press = np.linspace(100, 1000.)

        # retrieve desired line style from user kwargs

        line_style = kwargs.get('line_style')
        if line_style is None:
            line_style = '-'

        # loop to calculate using Poisson's equation the
        # dry adiabats for the skew t.

        for temp in t0:
            theta = temp * (press / 1000.)**(2. / 7.)

            # plot the dry adiabats given a specified color

            self.ax1.semilogy((theta - 273.15),
                              press,
                              line_style,
                              color='#7F4B10',
                              linewidth=0.5)

    def plot_wind_barbs(self, data, **kwargs):

        P = data['Pressure']
        U = data['U Component']
        V = data['V Component']
        H = data['Height']

        # Copy y axis to plot wind barbs
        # Set x lim for windpbarbs
        # adjust location of barbs from x =0
        # plot every 30th windbarb
        # set axis to invisible
        self.ax1_copy = self.ax1.twiny()
        self.ax1_copy.set_xlim(self.x_min, self.x_max)
        self.ax1_copy.set_ylim(self.y_min, self.y_max)
        x_const = np.zeros(P.shape) + (self.x_max - 2)
        self.ax1_copy.xaxis.set_visible(False)

        if data['Type'] == 'radioSonde':

            mask = U.mask
            U = U[~mask]
            V = V[~mask]
            P = P[~mask]

            self.ax1_copy.barbs(x_const[::3], P[::3], U[::3], V[::3])

        else:

            self.ax1_copy.barbs(x_const[::40], P[::40], U[::40], V[::40])

    def run_shear_calcs(self, data):
        '''
        method to calculate thermodynamic parameters from dropsonde data

        Inputs:

        # Dictionary of sounding data.
        # Uses calculations from thermocalcs.py
        # ============

        output:

        # multiple arrays containing thermodynamic information

        '''

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        mask = h.mask
        u = u[~mask]
        v = v[~mask]
        h = h[~mask]

        self.SHEAR1KM = self.sC._VertShear_Sfc_to_1km(h, u, v)
        self.SHEAR3KM = self.sC._VertShear_Sfc_to_3km(h, u, v)
        self.SHEAR6KM = self.sC._VertShear_Sfc_to_6km(h, u, v)
        self.BULKSHEAR1km = round(self.sC._bulkshear_sfc_1km(h, u, v), 2)
        self.BULKSHEAR3km = round(self.sC._bulkshear_sfc_3km(h, u, v), 2)
        self.BULKSHEAR6km = round(self.sC._bulkshear_sfc_6km(h, u, v), 2)
        # self.ax4.text(.01, .1, '0-1 km shear: '+str(self.SHEAR1KM)+(' 1/s'))

    def plot_shear_calcs(self):
        '''
        method to plot the thermodynamic parameters on the parameter list.

        Inputs:

        # None
        # ============

        output:

        # Image
        '''

        # bitch = self.SHEAR1KM

        # plot the parameters on the list generated.
        self.ax4.text(.01, .1,
                      '0-1 km shear: ' + str(self.SHEAR1KM) + (' 1/s'))
        self.ax4.text(.01, .14, '0-3 km shear: ' + str(self.SHEAR3KM) + ' 1/s')
        self.ax4.text(.01, .18, '0-6 km shear: ' + str(self.SHEAR6KM) + ' 1/s')
        self.ax4.text(.01, .22,
                      '0-1km Bulk Shear: ' + str(self.BULKSHEAR1km) + ' m/s')
        self.ax4.text(.01, .26,
                      '0-3km Bulk Shear: ' + str(self.BULKSHEAR3km) + ' m/s')
        self.ax4.text(.01, .3,
                      '0-6km Bulk Shear: ' + str(self.BULKSHEAR6km) + ' m/s')

    def dry_lift(self, data):

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        t_parcel, p_parcel = self.tC.dry_lift(T, p, self.LCLT, self.LCLP)

        # print(t_parcel,p_parcel)

        self.ax1.semilogy(t_parcel, p_parcel, 'k--', ms=1)
示例#2
0
文件: dropsondes.py 项目: tjlang/AWOT
class DropSondes(object):

    '''
    Description:

    class to analyze dropsonde and sounding data
    #==========================
    requirements:

    thermodynaic calculations

    windshear calculations

    skew x axis class
    #==========================
    '''

    def __init__(self):

        # ============================================#
        # initiate a new instance of thermocalcs class#
        # ============================================#

        self.tC = ThermoCalcs()

        # ===========================================#
        # initiate a new instance of shearcalcs class#
        # ===========================================#

        self.sC = ShearCalcs()

        # Global height arrays for wind shear

        self.u_3km = []
        self.v_3km = []
        self.u_6km = []
        self.v_6km = []
        self.u_9km = []
        self.v_9km = []
        self.u_12km = []
        self.v_12km = []

    def get_sounding_data(self, filePath):

        '''
        method to retrieve standard sounding data from noaa radiosonde
        and U of Wyoming repository.

        Inputs:

        file path
        # ============

        output:

        # Dictionary with variable for use in plotting

        '''

        data = filePath
        fp = open(data, 'r')
        lines = fp.readlines()
        header = lines[1]
        fp.close()
        fp = open(data, 'r')
        sounding_data = fp
        p, h, T, Td, RH, MIXR, wd, ws = np.genfromtxt(
            sounding_data, skip_header=8, usecols=range(0, 8),
            dtype=float, delimiter=None, autostrip=True,
            missing_values='-9999.00', unpack=True, usemask=True)

        u = -ws*np.sin(np.radians(wd))
        v = -ws*np.cos(np.radians(wd))
        # RH = self.tC._dewpoint_to_RH(T+273.15, Td+273.15)

        mask = T.mask
        T = T[~mask]
        TD = Td[~mask]
        P = p[~mask]
        H = h[~mask]
        RH = RH[~mask]

        mask = u.mask
        U = u[~mask]
        V = v[~mask]

        data = dict()
        data['Header'] = header
        data['Temperature'] = T
        data['Dewpoint'] = Td
        data['Pressure'] = p
        data['Relative Humidity'] = RH
        data['U Component'] = U
        data['V Component'] = V
        data['Height'] = h
        data['Type'] = 'radioSonde'

        fp.close()

        # self.type = 'radioSonde'

        return data

    def get_dropsonde_data(self, filePath):

        '''
        method to retrieve dropsonde data

        Inputs:

        file path
        #============

        output:

        #Dictionary with variable for use in plotting

        '''

        data = filePath
        fp = open(data, 'r')
        lines = fp.readlines()
        header = lines[1]
        fp.close()
        fp = open(data, 'r')
        sounding_data = fp

        p, T, Td, RH, u, v, h = np.genfromtxt(
            sounding_data, skip_header=15, usecols=(1, 2, 3, 4, 5, 6, 14),
            dtype=float, missing_values='9999.0', unpack=True, usemask=True)

        # mask incoming T and dewpoint data

        T = np.ma.masked_greater_equal(T, 999.0)
        Td = np.ma.masked_greater_equal(Td, 999.0)
        RH = np.ma.masked_greater_equal(RH, 999.0)
        h = np.ma.masked_greater_equal(h, 99999.0)

        mask = T.mask
        T = T[~mask]
        TD = Td[~mask]
        P = p[~mask]
        H = h[~mask]
        RH = RH[~mask]

        mask = u.mask
        U = u[~mask]
        V = v[~mask]

        data = dict()
        data['Header'] = header
        data['Temperature'] = T
        data['Dewpoint'] = TD
        data['Pressure'] = P
        data['Relative Humidity'] = RH
        data['U Component'] = U
        data['V Component'] = V
        data['Height'] = H
        data['Type'] = 'dropsonde'

        return data

    def plot_skewtlogp(self, data, **kwargs):

        '''
        method to plot sounding or dropsonde data

        Inputs:

        dictionary of sounding data

        keyword arguments min, max, titles, and label.

        #============

        output:

        #Image

        '''

        T = data['Temperature']
        TD = data['Dewpoint']
        P = data['Pressure']

        self.fig = plt.figure(figsize=(10, 8))
        self.ax1 = self.fig.add_axes([0.05, 0.1, 0.6, 0.8],
                                     projection='skewx')
        plt.grid(True)

        self.plot_dryadiabats()

        self.ax1.semilogy(T, P, 'r-', linewidth=1.5)
        self.ax1.semilogy(TD, P, 'g-', linewidth=1.5)

        # Plot the data using normal plotting functions, in this case using
        # log scaling in Y, as dictated by the typical meteorological plot
        # Disables the log-formatting that comes with semilogy
        # set bounds for data on Skew T chart

        self.ax1.yaxis.set_major_formatter(ScalarFormatter())
        self.ax1.set_yticks(np.linspace(100, 1000, 10))
        self.ax1.set_ylim(1050, 100)
        self.ax1.set_ylabel('Pressure mb')
        self.ax1.set_xlabel('Temperature C')
        self.ax1.xaxis.set_major_locator(MultipleLocator(10))
        self.ax1.set_title('Skew T log P')

        self.y_min = kwargs.get('y_min')
        self.y_max = kwargs.get('y_max')

        self.x_min = kwargs.get('x_min')
        self.x_max = kwargs.get('x_max')

        # data label, title and font sizes value assignments
        # default values above.

        y_label = kwargs.get('y_label')
        x_label = kwargs.get('x_label')
        title = kwargs.get('title')
        font_size = kwargs.get('font_size')

        for item in ([self.ax1.xaxis.label, self.ax1.yaxis.label] +
                     self.ax1.get_xticklabels()+self.ax1.get_yticklabels()):
            item.set_fontsize(font_size)

        # set the labels and titles defaults to 'none'

        self.ax1.set_ylabel(y_label)
        self.ax1.set_xlabel(x_label)
        self.ax1.set_title(title)

        self.ax1.set_ylim(self.y_max, self.y_min)
        self.ax1.set_xlim(self.x_min, self.x_max)

    def plot_hodograph(self, data):

        '''
        method to plot wind data on a hodograph

        Inputs:

        dictionary containing wind data.

        file path
        # ============

        output:

        # Image

        '''

        self.ax2 = self.fig.add_axes([.05, 0.6, 0.25, 0.3])

        # create axis and invert masks and assign values
        # for U, V, and h coordinates

        U = data['U Component']
        V = data['V Component']
        H = data['Height']

        # =====================================================#
        # loop to place hodograph data into proper height array
        # 0-3km
        # 3-6km
        # 6-9km
        # 9-12km
        # ======#

        if data['Type'] == 'radioSonde':

            for unew, vnew, hnew in zip(U, V, H):
                if hnew <= 3001.0:
                    self.u_3km.append(unew)
                    self.v_3km.append(vnew)
                elif hnew <= 6001.0:
                    self.u_6km.append(unew)
                    self.v_6km.append(vnew)
                elif hnew <= 9000.0:
                    self.u_9km.append(unew)
                    self.v_9km.append(vnew)
                elif hnew <= 12000.0:
                    self.u_12km.append(unew)
                    self.v_12km.append(vnew)

        # print(len(self.u_3km))
        # print(len(self.v_3km))
        # =============================================================#
        # take the first point of the next height level and attach it
        # to the last point of the previous line segment to
        # connect hodograph segments
        # should only be done for soundings and non dense data
        # type determines how the data is placed in the array.
        # Soundings require endpoints be joined so that
        # the hodograph is continuous.
        # =============================================================#

        if data['Type'] == 'radioSonde':

            self.u_3km.append(self.u_6km[0])
            self.u_6km.append(self.u_9km[0])
            self.u_9km.append(self.u_12km[0])

            self.v_3km.append(self.v_6km[0])
            self.v_6km.append(self.v_9km[0])
            self.v_9km.append(self.v_12km[0])

        # ==============================#
        # Mask the arrays U and V coords
        # ==============================#

        self.v_3km = np.ma.asarray(self.v_3km)
        self.v_6km = np.ma.asarray(self.v_6km)
        self.v_9km = np.ma.asarray(self.v_9km)
        self.v_12km = np.ma.asarray(self.v_12km)

        self.u_3km = np.ma.asarray(self.u_3km)
        self.u_6km = np.ma.asarray(self.u_6km)
        self.u_9km = np.ma.asarray(self.u_9km)
        self.u_12km = np.ma.asarray(self.u_12km)

        # plotting of the hodograph information
        # Different colors are sued to represent different height levels
        # r = 0-3km
        # y = 3-6km
        # g = 6-9km
        # b = 9-12km

        self.ax2.plot(self.u_3km, self.v_3km, 'r-', linewidth=3)
        self.ax2.plot(self.u_6km, self.v_6km, 'y-', linewidth=3,)
        self.ax2.plot(self.u_9km, self.v_9km, 'g-', linewidth=3)
        self.ax2.plot(self.u_12km, self.v_12km, 'b-', linewidth=3)

        # set the default limits on the hodo axes
        # remove spines and set the axes to be invisible.

        self.ax2.spines['left'].set_position('zero')
        self.ax2.spines['right'].set_color('none')
        self.ax2.spines['bottom'].set_position('zero')
        self.ax2.spines['top'].set_color('none')
        self.ax2.xaxis.set_ticks_position('bottom')
        self.ax2.yaxis.set_ticks_position('left')
        self.ax2.set_ylim(-50, 50)
        self.ax2.set_xlim(-50, 50)

        # Draw hodograph range rings
        # 10 20 30 40 m/s circles

        circ1 = patches.Circle((0, 0), 10, fc='white')
        circ2 = patches.Circle((0, 0), 20, fc='white')
        circ3 = patches.Circle((0, 0), 30, fc='white')
        circ4 = patches.Circle((0, 0), 40, fc='white')

        # Add circles to plot as patches#
        # descending order to make sure they layer ontop of each other.

        self.ax2.add_patch(circ4)
        self.ax2.add_patch(circ3)
        self.ax2.add_patch(circ2)
        self.ax2.add_patch(circ1)

    def plot_aux_graph(self, x_value, y_value, **kwargs):

        '''
        method to plot an auxiliary graph of user defined data

        Inputs:

        # sounding data (User specified)
        # kwargs to adjust plot dimensions scales label, and title.
        # ============

        output:

        # Image

        '''

        # define axes fro figure.
        # set grid and plot user specified data

        self.ax3 = self.fig.add_axes([.7, 0.7, .29, .24])
        plt.grid(True)
        self.ax3.plot(x_value, y_value)

        # Max and min graph bonds value assignment. Defaults to autoscale.

        y_min = kwargs.get('y_min')
        y_max = kwargs.get('y_max')

        x_min = kwargs.get('x_min')
        x_max = kwargs.get('x_max')

        # data label, title and font size value assignments .

        y_lable = kwargs.get('y_lable')
        x_lable = kwargs.get('x_lable')
        title = kwargs.get('title')
        font_size = kwargs.get('font_size')

        # keyword arguments for minimum and maximum values

        self.ax3.set_ylim(y_min, y_max)
        self.ax3.set_xlim(x_min, x_max)

        # set label and tick fontsizes to user defined value. Defaults to 10pt.

        for item in ([self.ax3.xaxis.label, self.ax3.yaxis.label] +
                     self.ax3.get_xticklabels()+self.ax3.get_yticklabels()):
            item.set_fontsize(font_size)

        # set the labels and title from keyword arguments. Defaults to 'none'

        self.ax3.set_ylabel(y_lable)
        self.ax3.set_xlabel(x_lable)
        self.ax3.set_title(title)

    def generate_parameter_list(self):

        '''
        method to generate a list of parameters calculated
        from the sounding data

        Inputs:

        # None
        # ============

        output:

        # Blank axis for plotting
        '''

        # Set axes position and set both axes invisible

        self.ax4 = self.fig.add_axes([.65, 0.1, .35, .54])
        self.ax4.xaxis.set_visible(False)
        self.ax4.yaxis.set_visible(False)

    def run_thermo_calcs(self, data):

        '''
        method to calculate thermodynamic parameters from dropsonde data

        Inputs:

        # Dictionary of sounding data.
        # Uses calculations from thermocalcs.py
        # ============

        output:

        # multiple arrays containing thermodynamic information

        '''

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        self.LCLT = round((
            self.tC._LCL_Temperature(h, T+273.15, Td+273.15)-273.15), 2)
        self.LCLP = round((
            self.tC._LCL_Pressure(h, p, T+273.15, Td+273.15)), 0)
        self.LCLZ = round((
            self.tC._LCL_Height(h, p, T+273.15, Td+273.15)), 0)
        self.THETA = self.tC._PTk2_Theta(p, T+273.15)
        self.MIXR = self.tC._RH_2_MixR(RH, p, T+273.15)
        self.THETAE = self.tC._Tk_RH_MixR_2_ThetaE(
            p, T+273.15, RH, self.MIXR/1000.)
        self.ESAT = self.tC._esat(T+273.15)

    def plot_thermo_calcs(self):

        '''
        method to plot the thermodynamic parameters on the parameter list.

        Inputs:

        # None
        # ============

        output:

        # Image
        '''

        # plot the parameters on the list generated.
        self.ax4.text(.01, .01, 'LCL Pressure: ' + str(self.LCLP) + (' hPa'))
        self.ax4.text(.01, .04, 'LCL Temp: ' + str(self.LCLT) + ' c')
        self.ax4.text(.01, .07, 'LCL Height: ' + str(self.LCLZ) + ' m')

    def plot_dryadiabats(self, **kwargs):

        '''
        method to plot the dry adibats. Used in the plotskewtlogp method.

        Inputs:

        # kwargs (does not function)
        # ============

        output:

        # Image

        '''
        # test = self.shear1km

        # temperature array and pressure array

        t0 = np.linspace(200, 430, 17)
        press = np.linspace(100, 1000.)

        # retrieve desired line style from user kwargs

        line_style = kwargs.get('line_style')
        if line_style is None:
            line_style = '-'

        # loop to calculate using Poisson's equation the
        # dry adiabats for the skew t.

        for temp in t0:
            theta = temp * (press/1000.)**(2./7.)

            # plot the dry adiabats given a specified color

            self.ax1.semilogy((theta-273.15), press, line_style,
                              color='#7F4B10', linewidth=0.5)

    def plot_wind_barbs(self, data, **kwargs):

        P = data['Pressure']
        U = data['U Component']
        V = data['V Component']
        H = data['Height']

        # Copy y axis to plot wind barbs
        # Set x lim for windpbarbs
        # adjust location of barbs from x =0
        # plot every 30th windbarb
        # set axis to invisible
        self.ax1_copy = self.ax1.twiny()
        self.ax1_copy.set_xlim(self.x_min, self.x_max)
        self.ax1_copy.set_ylim(self.y_min, self.y_max)
        x_const = np.zeros(P.shape) + (self.x_max - 2)
        self.ax1_copy.xaxis.set_visible(False)

        if data['Type'] == 'radioSonde':

            mask = U.mask
            U = U[~mask]
            V = V[~mask]
            P = P[~mask]

            self.ax1_copy.barbs(x_const[::3], P[::3], U[::3], V[::3])

        else:

            self.ax1_copy.barbs(x_const[::40], P[::40], U[::40], V[::40])

    def run_shear_calcs(self, data):

        '''
        method to calculate thermodynamic parameters from dropsonde data

        Inputs:

        # Dictionary of sounding data.
        # Uses calculations from thermocalcs.py
        # ============

        output:

        # multiple arrays containing thermodynamic information

        '''

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        mask = h.mask
        u = u[~mask]
        v = v[~mask]
        h = h[~mask]

        self.SHEAR1KM = self.sC._VertShear_Sfc_to_1km(h, u, v)
        self.SHEAR3KM = self.sC._VertShear_Sfc_to_3km(h, u, v)
        self.SHEAR6KM = self.sC._VertShear_Sfc_to_6km(h, u, v)
        self.BULKSHEAR1km = round(self.sC._bulkshear_sfc_1km(h, u, v), 2)
        self.BULKSHEAR3km = round(self.sC._bulkshear_sfc_3km(h, u, v), 2)
        self.BULKSHEAR6km = round(self.sC._bulkshear_sfc_6km(h, u, v), 2)
        # self.ax4.text(.01, .1, '0-1 km shear: '+str(self.SHEAR1KM)+(' 1/s'))

    def plot_shear_calcs(self):

        '''
        method to plot the thermodynamic parameters on the parameter list.

        Inputs:

        # None
        # ============

        output:

        # Image
        '''

        # bitch = self.SHEAR1KM

        # plot the parameters on the list generated.
        self.ax4.text(.01, .1, '0-1 km shear: '+str(self.SHEAR1KM)+(' 1/s'))
        self.ax4.text(.01, .14, '0-3 km shear: '+str(self.SHEAR3KM)+' 1/s')
        self.ax4.text(.01, .18, '0-6 km shear: '+str(self.SHEAR6KM)+' 1/s')
        self.ax4.text(
            .01, .22, '0-1km Bulk Shear: '+str(self.BULKSHEAR1km)+' m/s')
        self.ax4.text(
            .01, .26, '0-3km Bulk Shear: '+str(self.BULKSHEAR3km)+' m/s')
        self.ax4.text(
            .01, .3, '0-6km Bulk Shear: '+str(self.BULKSHEAR6km)+' m/s')

    def dry_lift(self, data):

        T = data['Temperature']
        Td = data['Dewpoint']
        p = data['Pressure']
        RH = data['Relative Humidity']
        u = data['U Component']
        v = data['V Component']
        h = data['Height']

        t_parcel, p_parcel = self.tC.dry_lift(T, p, self.LCLT, self.LCLP)

        # print(t_parcel,p_parcel)

        self.ax1.semilogy(t_parcel, p_parcel, 'k--', ms=1)