generic.py

changeset 36
a281a26f4626
parent 35
b1146c96f727
child 37
7c76fdbdf1a3
--- a/generic.py	Mon Feb 22 16:50:03 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,714 +0,0 @@
-# General imports
-import datetime
-from operator import itemgetter
-
-# Science imports
-import numpy as np
-import matplotlib as mpl
-from matplotlib.ticker import ScalarFormatter
-from matplotlib import pyplot as plt
-import netCDF4 as netcdf
-
-netcdf_format = 'NETCDF3_CLASSIC' # choose one of 'NETCDF3_CLASSIC', 'NETCDF3_64BIT', 'NETCDF4_CLASSIC' and 'NETCDF4'
-
-
-class BaseLidarMeasurement():
-    """ This is the general measurement object.
-    It is meant to become a general measurement object 
-    independent of the input files.
-    
-    Each subclass should implement the following:
-    * the import_file method.
-    * set the "extra_netcdf_parameters" variable to a dictionary that includes the appropriate parameters.
-    
-    You can override the get_PT method to define a custom procedure to get ground temperature and pressure.
-    The one implemented by default is by using the MILOS meteorological station data. 
-    
-    """
-    
-    def __init__(self, filelist = None):
-        self.info = {}
-        self.dimensions = {}
-        self.variables =  {}
-        self.channels = {}
-        self.attributes = {}
-        self.files = []
-        self.dark_measurement = None
-        
-        if filelist:
-            self.import_files(filelist)
-        
-    def import_files(self, filelist):
-        for f in filelist:
-            self.import_file(f)
-        self.update()
-
-    def import_file(self,filename):
-        raise NotImplementedError('Importing files should be defined in the instrument-specific subclass.')
-
-    def update(self):
-        '''
-        Update the the info, variables and dimensions of the lidar measurement based 
-        on the information found in the channels.
-        
-        Reading of the scan_angles parameter is not implemented.
-        '''
-        
-        # Initialize
-        start_time =[]
-        stop_time = []
-        points = []
-        all_time_scales = []
-        channel_name_list = []
-        
-        # Get the information from all the channels
-        for channel_name, channel in self.channels.items():
-            channel.update()
-            start_time.append(channel.start_time)
-            stop_time.append(channel.stop_time)
-            points.append(channel.points)
-            all_time_scales.append(channel.time)
-            channel_name_list.append(channel_name)
-            
-        # Find the unique time scales used in the channels
-        time_scales = set(all_time_scales)
-        
-        # Update the info dictionary
-        self.info['start_time'] = min(start_time)
-        self.info['stop_time'] = max(stop_time)
-        self.info['duration'] = self.info['stop_time'] - self.info['start_time']
-        
-        # Update the dimensions dictionary
-        self.dimensions['points'] = max(points)
-        self.dimensions['channels'] = len(self.channels)
-        # self.dimensions['scan angles'] = 1
-        self.dimensions['nb_of_time_scales'] = len(time_scales)
-        
-        # Update the variables dictionary
-        # Write time scales in seconds
-        raw_Data_Start_Time = []
-        raw_Data_Stop_Time = []
-        
-        for current_time_scale in list(time_scales): 
-            raw_start_time = np.array(current_time_scale) - min(start_time) # Time since start_time
-            raw_start_in_seconds = np.array([t.seconds for t in raw_start_time]) # Convert in seconds
-            raw_Data_Start_Time.append(raw_start_in_seconds) # And add to the list
-            # Check if this time scale has measurements every 30 or 60 seconds.
-            
-            duration = self._get_duration(raw_start_in_seconds)
-            
-            raw_stop_in_seconds = raw_start_in_seconds + duration
-            raw_Data_Stop_Time.append(raw_stop_in_seconds)
-            
-        self.variables['Raw_Data_Start_Time'] = raw_Data_Start_Time
-        self.variables['Raw_Data_Stop_Time'] = raw_Data_Stop_Time
-    
-        # Make a dictionary to match time scales and channels
-        channel_timescales = []
-        for (channel_name, current_time_scale) in zip(channel_name_list, all_time_scales):
-            # The following lines are PEARL specific. The reason they are here is not clear.
-            # if channel_name =='1064BLR':
-            #     channel_name = '1064'
-            for (ts,n) in zip(time_scales, range(len(time_scales))):
-                if current_time_scale == ts:
-                    channel_timescales.append([channel_name,n])
-        self.variables['id_timescale'] = dict(channel_timescales)
-    
-    def _get_duration(self, raw_start_in_seconds):
-        ''' Return the duration for a given time scale. In some files (e.g. Licel) this
-        can be specified from the files themselves. In others this must be guessed.
-         
-        '''
-        # The old method, kept here for reference
-        #dt = np.mean(np.diff(raw_start_in_seconds))
-        #for d in duration_list:
-        #    if abs(dt - d) <15: #If the difference of measuremetns is 10s near the(30 or 60) seconds
-        #        duration = d
-        
-        duration = np.diff(raw_start_in_seconds)[0]
-
-        return duration
-    
-    def subset_by_channels(self, channel_subset):
-        ''' Get a measurement object containing only the channels with names
-        contained in the channel_sublet list '''
-        
-        m = self.__class__() # Create an object of the same type as this one.
-        m.channels = dict([(channel, self.channels[channel]) for channel 
-                            in channel_subset])
-        m.update()
-        return m
-        
-    def subset_by_time(self, start_time, stop_time):
-    
-        if start_time > stop_time:
-            raise ValueError('Stop time should be after start time')
-            
-        if (start_time < self.info['start_time']) or (stop_time > self.info['stop_time']):
-            raise ValueError('The time interval specified is not part of the measurement')
-
-        m = self.__class__() # Create an object of the same type as this one.
-        for (channel_name, channel)  in self.channels.items():
-            m.channels[channel_name] = channel.subset_by_time(start_time, stop_time)
-        m.update()
-        return m
-    
-    def subset_by_bins(self, b_min = 0, b_max = None):
-        """Remove some height bins from the file. This could be needed to 
-        remove aquisition artifacts at the start or the end of the files.
-        """
-        
-        m = self.__class__() # Create an object of the same type as this one.
-        
-        for (channel_name, channel)  in self.channels.items():
-            m.channels[channel_name] = channel.subset_by_bins(b_min, b_max)
-        
-        m.update()
-        
-        return m
-    
-    def r_plot(self):
-        #Make a basic plot of the data.
-        #Should include some dictionary with params to make plot stable.
-        pass 
-    
-    def r_pdf(self):
-        # Create a pdf report using a basic plot and meta-data.
-        pass
-    
-    def save(self):
-        #Save the current state of the object to continue the analysis later.
-        pass
-        
-    def get_PT(self):
-        ''' Sets the pressure and temperature at station level .
-        The results are stored in the info dictionary.        
-        '''
-    
-        self.info['Temperature'] = 10.0
-        self.info['Pressure'] = 930.0
-        
-    def subtract_dark(self):
-        
-        if not self.dark_measurement:
-            raise IOError('No dark measurements have been imported yet.')
-        
-        for (channel_name, dark_channel) in self.dark_measurement.channels.iteritems():
-            dark_profile = dark_channel.average_profile()
-            channel = self.channels[channel_name]
-            
-            for measurement_time, data in channel.data.iteritems():
-                channel.data[measurement_time] = data - dark_profile
-                
-            channel.update()
-    
-    def save_as_netcdf(self, filename = None):
-        """Saves the measurement in the netcdf format as required by the SCC.
-        Input: filename. If no filename is provided <measurement_id>.nc will
-               be used. 
-        """
-        params = self.extra_netcdf_parameters
-        needed_parameters = ['Measurement_ID', 'Temperature', 'Pressure']
-        
-        for parameter in needed_parameters:
-            stored_value = self.info.get(parameter, None)
-            if stored_value is None:
-                raise ValueError('A value needs to be specified for %s' % parameter)
-        
-        if not filename:
-            filename = "%s.nc" % self.info['Measurement_ID']
-                
-        dimensions = {'points': 1,
-                'channels': 1,
-                'time': None,
-                'nb_of_time_scales': 1,
-                'scan_angles': 1,}  # Mandatory dimensions. Time bck not implemented
-
-        global_att = {'Measurement_ID': None,
-                    'RawData_Start_Date': None,
-                    'RawData_Start_Time_UT': None,
-                    'RawData_Stop_Time_UT': None,
-                    'RawBck_Start_Date': None,
-                    'RawBck_Start_Time_UT': None,
-                    'RawBck_Stop_Time_UT': None,
-                    'Sounding_File_Name': None,
-                    'LR_File_Name': None,
-                    'Overlap_File_Name': None,
-                    'Location': None,
-                    'System': None,
-                    'Latitude_degrees_north': None,
-                    'Longitude_degrees_east': None,
-                    'Altitude_meter_asl': None}
-
-        channel_variables = \
-                    {'channel_ID': (('channels', ), 'i'),
-                    'Background_Low': (('channels', ), 'd'),
-                    'Background_High': (('channels', ), 'd'),
-                    'LR_Input': (('channels', ), 'i'),
-                    'DAQ_Range': (('channels', ), 'd'), 
-                    'Depolarization_Factor': (('channels', ), 'd'), }
-                    
-        
-        channels = self.channels.keys()
-
-        input_values = dict(self.dimensions, **self.variables)
-        
-        # Add some mandatory global attributes
-        input_values['Measurement_ID'] = self.info['Measurement_ID']
-        input_values['RawData_Start_Date'] = self.info['start_time'].strftime('%Y%m%d')
-        input_values['RawData_Start_Time_UT'] = self.info['start_time'].strftime('%H%M%S')
-        input_values['RawData_Stop_Time_UT'] = self.info['stop_time'].strftime('%H%M%S')
-        
-        # Add some optional global attributes
-        input_values['System'] = params.general_parameters['System']
-        input_values['Latitude_degrees_north'] = params.general_parameters['Latitude_degrees_north']
-        input_values['Longitude_degrees_east'] = params.general_parameters['Longitude_degrees_east']
-        input_values['Altitude_meter_asl'] = params.general_parameters['Altitude_meter_asl']
-        
-        # Open a netCDF4 file
-        f = netcdf.Dataset(filename,'w', format = netcdf_format) # the format is specified in the begining of the file
-        
-        # Create the dimensions in the file
-        for (d,v) in dimensions.iteritems():
-            v = input_values.pop(d, v)
-            f.createDimension(d,v)
-        
-        # Create global attributes
-        for (attrib,value) in global_att.iteritems():
-            val = input_values.pop(attrib,value)
-            if val: 
-                setattr(f, attrib, val)
-        
-        """ Variables """
-        # Write the values of fixes channel parameters
-        for (var,t) in channel_variables.iteritems():
-            temp_v = f.createVariable(var,t[1],t[0])
-            for (channel, n) in zip(channels, range(len(channels))):
-                temp_v[n] = params.channel_parameters[channel][var]
-        
-        # Write the id_timescale values
-        temp_id_timescale = f.createVariable('id_timescale','i',('channels',))
-        for (channel, n) in zip(channels, range(len(channels))):
-            temp_id_timescale[n] = self.variables['id_timescale'][channel]
-        
-        # Laser pointing angle
-        temp_v = f.createVariable('Laser_Pointing_Angle','d',('scan_angles',))
-        temp_v[:] = params.general_parameters['Laser_Pointing_Angle']
-        
-        # Molecular calculation
-        temp_v = f.createVariable('Molecular_Calc','i')
-        temp_v[:] = params.general_parameters['Molecular_Calc']    
-
-        # Laser pointing angles of profiles
-        temp_v = f.createVariable('Laser_Pointing_Angle_of_Profiles','i',('time','nb_of_time_scales'))
-        for (time_scale,n) in zip(self.variables['Raw_Data_Start_Time'],
-                                  range(len(self.variables['Raw_Data_Start_Time']))):
-            temp_v[:len(time_scale), n] = 0  # The lidar has only one laser pointing angle
-        
-        # Raw data start/stop time
-        temp_raw_start = f.createVariable('Raw_Data_Start_Time','i',('time','nb_of_time_scales'))
-        temp_raw_stop = f.createVariable('Raw_Data_Stop_Time','i',('time','nb_of_time_scales'))
-        for (start_time, stop_time,n) in zip(self.variables['Raw_Data_Start_Time'],
-                                             self.variables['Raw_Data_Stop_Time'],
-                                             range(len(self.variables['Raw_Data_Start_Time']))):
-            temp_raw_start[:len(start_time),n] = start_time
-            temp_raw_stop[:len(stop_time),n] = stop_time
-
-        #Laser shots
-        temp_v =  f.createVariable('Laser_Shots','i',('time','channels'))
-        for (channel,n) in zip(channels, range(len(channels))):
-            time_length = len(self.variables['Raw_Data_Start_Time'][self.variables['id_timescale'][channel]])
-            # Array slicing stoped working as usual ex. temp_v[:10] = 100 does not work. ??? np.ones was added.
-            temp_v[:time_length, n] = np.ones(time_length) * params.channel_parameters[channel]['Laser_Shots']
-
-        #Raw lidar data
-        temp_v = f.createVariable('Raw_Lidar_Data','d',('time', 'channels','points'))
-        for (channel,n) in zip(channels, range(len(channels))):
-            c = self.channels[channel]
-            temp_v[:len(c.time),n, :c.points] = c.matrix
-        
-        self.add_dark_measurements_to_netcdf(f, channels)
-            
-        #Pressure at lidar station
-        temp_v = f.createVariable('Pressure_at_Lidar_Station','d')
-        temp_v[:] = self.info['Pressure']
-
-        #Temperature at lidar station
-        temp_v = f.createVariable('Temperature_at_Lidar_Station','d')
-        temp_v[:] = self.info['Temperature']   
-        
-        self.save_netcdf_extra(f)
-        f.close()
-   
-    def add_dark_measurements_to_netcdf(self, f, channels):
-
-        # Get dark measurements. If it is not given in self.dark_measurement
-        # try to get it using the get_dark_measurements method. If none is found
-        # return without adding something.
-        if self.dark_measurement is None:
-            self.dark_measurement = self.get_dark_measurements()
-        
-        if self.dark_measurement is None:
-            return
-        
-        dark_measurement = self.dark_measurement
-        
-        # Calculate the length of the time_bck dimensions
-        number_of_profiles = [len(c.time) for c in dark_measurement.channels.values()]
-        max_number_of_profiles = np.max(number_of_profiles)
-        
-        # Create the dimension
-        f.createDimension('time_bck', max_number_of_profiles)
-         
-        # Save the dark measurement data
-        temp_v = f.createVariable('Background_Profile','d',('time_bck', 'channels', 'points'))
-        for (channel,n) in zip(channels, range(len(channels))):
-            c = dark_measurement.channels[channel]
-            temp_v[:len(c.time),n, :c.points] = c.matrix
-        
-        # Dark profile start/stop time
-        temp_raw_start = f.createVariable('Raw_Bck_Start_Time','i',('time_bck','nb_of_time_scales'))
-        temp_raw_stop = f.createVariable('Raw_Bck_Stop_Time','i',('time_bck','nb_of_time_scales'))
-        for (start_time, stop_time,n) in zip(dark_measurement.variables['Raw_Data_Start_Time'],
-                                             dark_measurement.variables['Raw_Data_Stop_Time'],
-                                             range(len(dark_measurement.variables['Raw_Data_Start_Time']))):
-            temp_raw_start[:len(start_time),n] = start_time
-            temp_raw_stop[:len(stop_time),n] = stop_time
-        
-        # Dark measurement start/stop time
-        f.RawBck_Start_Date = dark_measurement.info['start_time'].strftime('%Y%m%d')
-        f.RawBck_Start_Time_UT = dark_measurement.info['start_time'].strftime('%H%M%S')
-        f.RawBck_Stop_Time_UT = dark_measurement.info['stop_time'].strftime('%H%M%S')
-
-
-
-    def save_netcdf_extra(self, f):
-        pass
-        
-    def _gettime(self, date_str, time_str):        
-        t = datetime.datetime.strptime(date_str+time_str,'%d/%m/%Y%H.%M.%S')
-        return t
-    
-    def plot(self):
-        for channel in self.channels:
-            self.channels[channel].plot(show_plot = False)
-        plt.show()
-    
-    def get_dark_measurements(self):
-        return None
-    
-    @property
-    def mean_time(self):
-        start_time = self.info['start_time']
-        stop_time = self.info['stop_time']
-        dt = stop_time - start_time
-        t_mean = start_time + dt / 2
-        return t_mean
-
-
-class LidarChannel:
-
-    def __init__(self, channel_parameters):
-        c = 299792458  # Speed of light
-        self.wavelength = channel_parameters['name']
-        self.name = str(self.wavelength)
-        self.binwidth = float(channel_parameters['binwidth'])  # in microseconds
-        self.data = {}
-        self.resolution = self.binwidth * c / 2
-        self.z = np.arange(len(channel_parameters['data'])) * self.resolution + self.resolution / 2.0 # Change: add half bin in the z 
-        self.points = len(channel_parameters['data'])
-        self.rc = []
-        self.duration  = 60
-        
-    def calculate_rc(self, idx_min = 4000, idx_max = 5000):
-        background = np.mean(self.matrix[:,idx_min:idx_max], axis = 1)  # Calculate the background from 30000m and above
-        self.rc = (self.matrix.transpose()- background).transpose() * (self.z **2)
-        
-    
-    def update(self):
-        self.start_time = min(self.data.keys())
-        self.stop_time = max(self.data.keys()) + datetime.timedelta(seconds = self.duration)
-        self.time = tuple(sorted(self.data.keys()))
-        sorted_data = sorted(self.data.iteritems(), key=itemgetter(0))
-        self.matrix =  np.array(map(itemgetter(1),sorted_data))
-    
-    def _nearest_dt(self,dtime):
-        margin = datetime.timedelta(seconds = 300)        
-        if ((dtime + margin) < self.start_time)| ((dtime - margin)   > self.stop_time):
-            print "Requested date not covered in this file"
-            raise
-        dt = abs(self.time - np.array(dtime))
-        dtmin = min(dt)
-
-        if dtmin > datetime.timedelta(seconds = 60):
-            print "Nearest profile more than 60 seconds away. dt = %s." % dtmin
-        ind_t = np.where(dt == dtmin)
-        ind_a= ind_t[0]
-        if len(ind_a) > 1:
-            ind_a = ind_a[0]
-        chosen_time = self.time[ind_a]
-        return chosen_time, ind_a
-    
-    def subset_by_time(self, start_time, stop_time):
-        
-        time_array = np.array(self.time)
-        condition = (time_array >= start_time) & (time_array <= stop_time)
-        
-        subset_time = time_array[condition]
-        subset_data = dict([(c_time, self.data[c_time]) for c_time in subset_time])
-        
-        #Create a list with the values needed by channel's __init__()
-        parameter_values = {'name': self.wavelength, 
-                             'binwidth': self.binwidth, 
-                             'data': subset_data[subset_time[0]],}
-        
-        # We should use __class__ instead of class name, so that this works properly
-        # with subclasses
-        # Ex: c = self.__class__(parameters_values)  
-        # This does not currently work with Licel files though
-        c = LidarChannel(parameter_values)
-        c.data = subset_data
-        c.update()
-        return c
-    
-    def subset_by_bins(self, b_min = 0, b_max = None):
-        """Remove some height bins from the file. This could be needed to 
-        remove aquisition artifacts at the start or the end of the files.
-        """
-        
-        subset_data = {}
-        
-        for ctime, cdata in self.data.items():
-            subset_data[ctime] = cdata[b_min:b_max]
-            
-        #Create a list with the values needed by channel's __init__()
-        parameters_values = {'name': self.wavelength, 
-                             'binwidth': self.binwidth, 
-                             'data': subset_data[subset_data.keys()[0]],}  # We just need any array with the correct length
-
-        c = LidarChannel(parameters_values)
-        c.data = subset_data
-        c.update()
-        return c
-        
-    def profile(self,dtime, signal_type = 'rc'):
-        t, idx = self._nearest_dt(dtime)
-        if signal_type == 'rc':
-            data = self.rc
-        else:
-            data = self.matrix
-        
-        prof = data[idx,:][0]
-        return prof, t
-
-    def get_slice(self, starttime, endtime, signal_type = 'rc'):
-        if signal_type == 'rc':
-            data = self.rc
-        else:
-            data = self.matrix
-        tim = np.array(self.time)
-        starttime = self._nearest_dt(starttime)[0]
-        endtime = self._nearest_dt(endtime)[0]
-        condition = (tim >= starttime) & (tim <= endtime)
-        sl  = data[condition, :]
-        t = tim[condition]
-        return sl,t
-    
-    def profile_for_duration(self, tim, duration = datetime.timedelta(seconds = 0), signal_type = 'rc'):
-        """ Calculates the profile around a specific time (tim). """
-        starttime = tim - duration/2
-        endtime = tim + duration/2
-        d,t = self.get_slice(starttime, endtime, signal_type = signal_type)
-        prof = np.mean(d, axis = 0)
-        tmin = min(t)
-        tmax = max(t)
-        tav = tmin + (tmax-tmin)/2
-        return prof,(tav, tmin,tmax)
-    
-    def average_profile(self):
-        """ Return the average profile (NOT range corrected) for all the duration of the measurement. """
-        prof = np.mean(self.matrix, axis = 0)
-        return prof
-    
-    def plot(self, signal_type = 'rc', filename = None, zoom = [0,12000,0,-1], show_plot = True, cmap = plt.cm.jet, z0 = None, title = None, vmin = 0, vmax = 1.3 * 10 ** 7):
-        #if filename is not None:
-        #    matplotlib.use('Agg')
-        
-        fig = plt.figure()
-        ax1 = fig.add_subplot(111)
-        self.draw_plot(ax1, cmap = cmap, signal_type = signal_type, zoom = zoom, z0 = z0, vmin = vmin, vmax = vmax)
-        
-        if title:
-            ax1.set_title(title)
-        else:
-            ax1.set_title("%s signal - %s" % (signal_type.upper(), self.name)) 
-        
-        if filename is not None:
-            pass
-            #plt.savefig(filename)
-        else:
-            if show_plot:
-                plt.show()
-        #plt.close() ???
-    
-    def draw_plot(self,ax1, cmap = plt.cm.jet, signal_type = 'rc', 
-                            zoom = [0,12000,0,-1], z0 = None, 
-                            add_colorbar = True, cmap_label = 'a.u.',  cb_format = None, 
-                            vmin = 0, vmax = 1.3 * 10 ** 7):
-        
-        if signal_type == 'rc':
-            if len(self.rc) == 0:
-                self.calculate_rc()
-            data = self.rc
-        else:
-            data = self.matrix
-        
-        hmax_idx = self.index_at_height(zoom[1])
-        
-        # If z0 is given, then the plot is a.s.l.
-        if z0:
-            ax1.set_ylabel('Altitude a.s.l. [km]')
-        else:
-            ax1.set_ylabel('Altitude a.g.l. [km]')
-            z0 = 0
-            
-        ax1.set_xlabel('Time UTC [hh:mm]')
-        #y axis in km, xaxis /2 to make 30s measurements in minutes. Only for 1064
-        #dateFormatter = mpl.dates.DateFormatter('%H.%M')
-        #hourlocator = mpl.dates.HourLocator()
-        
-        #dayFormatter = mpl.dates.DateFormatter('\n\n%d/%m')
-        #daylocator = mpl.dates.DayLocator()       
-        hourFormatter = mpl.dates.DateFormatter('%H:%M')
-        hourlocator = mpl.dates.AutoDateLocator(minticks = 3, maxticks = 8, interval_multiples=True)
-
-        
-        #ax1.axes.xaxis.set_major_formatter(dayFormatter)
-        #ax1.axes.xaxis.set_major_locator(daylocator)
-        ax1.axes.xaxis.set_major_formatter(hourFormatter)
-        ax1.axes.xaxis.set_major_locator(hourlocator)
-
-        
-        ts1 = mpl.dates.date2num(self.start_time)
-        ts2 = mpl.dates.date2num(self.stop_time)
-        
-        
-        im1 = ax1.imshow(data.transpose()[zoom[0]:hmax_idx,zoom[2]:zoom[3]],
-            aspect = 'auto',
-            origin = 'lower',
-            cmap = cmap,
-            vmin = vmin,
-            #vmin = data[:,10:400].max() * 0.1,
-            vmax = vmax,
-            #vmax = data[:,10:400].max() * 0.9,
-            extent = [ts1,ts2,self.z[zoom[0]]/1000.0 + z0/1000., self.z[hmax_idx]/1000.0 + z0/1000.],
-            )
-            
-        if add_colorbar:
-            if cb_format:
-                cb1 = plt.colorbar(im1, format = cb_format)
-            else:
-                cb1 = plt.colorbar(im1)
-            cb1.ax.set_ylabel(cmap_label)
-            
-            # Make the ticks of the colorbar smaller, two points smaller than the default font size
-            cb_font_size = mpl.rcParams['font.size'] - 2
-            for ticklabels in cb1.ax.get_yticklabels():
-                ticklabels.set_fontsize(cb_font_size)
-            cb1.ax.yaxis.get_offset_text().set_fontsize(cb_font_size)
-
-    
-    def draw_plot_new(self, ax1, cmap = plt.cm.jet, signal_type = 'rc', 
-                            zoom = [0, 12000, 0, None], z0 = None, 
-                            add_colorbar = True, cmap_label = 'a.u.', 
-                            cb_format = None, power_limits = (-2, 2),
-                            date_labels = False, 
-                            vmin = 0, vmax = 1.3 * 10 ** 7):
-        
-        if signal_type == 'rc':
-            if len(self.rc) == 0:
-                self.calculate_rc()
-            data = self.rc
-        else:
-            data = self.matrix
-        
-        hmax_idx = self.index_at_height(zoom[1])
-        hmin_idx = self.index_at_height(zoom[0])
-        
-        # If z0 is given, then the plot is a.s.l.
-        if z0:
-            ax1.set_ylabel('Altitude a.s.l. [km]')
-        else:
-            ax1.set_ylabel('Altitude a.g.l. [km]')
-            z0 = 0
-            
-        ax1.set_xlabel('Time UTC [hh:mm]')
-        #y axis in km, xaxis /2 to make 30s measurements in minutes. Only for 1064
-        #dateFormatter = mpl.dates.DateFormatter('%H.%M')
-        #hourlocator = mpl.dates.HourLocator()
-        
-        
-        if date_labels:
-            dayFormatter = mpl.dates.DateFormatter('%H:%M\n%d/%m/%Y')
-            daylocator = mpl.dates.AutoDateLocator(minticks = 3, maxticks = 8, interval_multiples=True)
-            ax1.axes.xaxis.set_major_formatter(dayFormatter)
-            ax1.axes.xaxis.set_major_locator(daylocator)
-        else:
-            hourFormatter = mpl.dates.DateFormatter('%H:%M')
-            hourlocator = mpl.dates.AutoDateLocator(minticks = 3, maxticks = 8, interval_multiples=True)
-            ax1.axes.xaxis.set_major_formatter(hourFormatter)
-            ax1.axes.xaxis.set_major_locator(hourlocator)
-
-        
-        # Get the values of the time axis
-        dt = datetime.timedelta(seconds = self.duration)
-        
-        time_cut = self.time[zoom[2]:zoom[3]]
-        time_last = time_cut[-1] + dt  # The last element needed for pcolormesh
-        
-        time_all = time_cut + (time_last,)
-        
-        t_axis = mpl.dates.date2num(time_all)
-        
-        # Get the values of the z axis
-        z_cut = self.z[hmin_idx:hmax_idx] - self.resolution / 2.
-        z_last = z_cut[-1] + self.resolution
-        
-        z_axis = np.append(z_cut, z_last) / 1000. + z0 / 1000. # Convert to km
-        
-        # Plot
-        im1 = ax1.pcolormesh(t_axis, z_axis, data.T[hmin_idx:hmax_idx, zoom[2]:zoom[3]],
-                                cmap = cmap,
-                                vmin = vmin,
-                                vmax = vmax,
-                                )
-        
-        if add_colorbar:
-            if cb_format:
-                cb1 = plt.colorbar(im1, format = cb_format)
-            else:
-                cb_formatter = ScalarFormatter()
-                cb_formatter.set_powerlimits(power_limits)                
-                cb1 = plt.colorbar(im1, format = cb_formatter)
-            cb1.ax.set_ylabel(cmap_label)
-
-            # Make the ticks of the colorbar smaller, two points smaller than the default font size
-            cb_font_size = mpl.rcParams['font.size'] - 2
-            for ticklabels in cb1.ax.get_yticklabels():
-                ticklabels.set_fontsize(cb_font_size)
-            cb1.ax.yaxis.get_offset_text().set_fontsize(cb_font_size)
-    
-    def index_at_height(self, height):
-        idx = np.array(np.abs(self.z - height).argmin())
-        if idx.size > 1:
-            idx =idx[0]
-        return idx
-    
-def netcdf_from_files(LidarClass, filename, files, channels, measurement_ID):
-    #Read the lidar files and select channels
-    temp_m = LidarClass(files)
-    m = temp_m.subset_by_channels(channels)
-    m.get_PT()
-    m.info['Measurement_ID'] = measurement_ID
-    m.save_as_netcdf(filename)
-

mercurial