generic.py

changeset 27
74f7617f5356
parent 24
b148076f7295
child 32
022f6f2bc09c
equal deleted inserted replaced
25:563705a26f85 27:74f7617f5356
3 from operator import itemgetter 3 from operator import itemgetter
4 4
5 # Science imports 5 # Science imports
6 import numpy as np 6 import numpy as np
7 import matplotlib as mpl 7 import matplotlib as mpl
8 from matplotlib.ticker import ScalarFormatter
8 from matplotlib import pyplot as plt 9 from matplotlib import pyplot as plt
9 import netCDF4 as netcdf 10 import netCDF4 as netcdf
10 11
11 netcdf_format = 'NETCDF3_CLASSIC' # choose one of 'NETCDF3_CLASSIC', 'NETCDF3_64BIT', 'NETCDF4_CLASSIC' and 'NETCDF4' 12 netcdf_format = 'NETCDF3_CLASSIC' # choose one of 'NETCDF3_CLASSIC', 'NETCDF3_64BIT', 'NETCDF4_CLASSIC' and 'NETCDF4'
12 13
147 148
148 m = self.__class__() # Create an object of the same type as this one. 149 m = self.__class__() # Create an object of the same type as this one.
149 for (channel_name, channel) in self.channels.items(): 150 for (channel_name, channel) in self.channels.items():
150 m.channels[channel_name] = channel.subset_by_time(start_time, stop_time) 151 m.channels[channel_name] = channel.subset_by_time(start_time, stop_time)
151 m.update() 152 m.update()
153 return m
154
155 def subset_by_bins(self, b_min = 0, b_max = None):
156 """Remove some height bins from the file. This could be needed to
157 remove aquisition artifacts at the start or the end of the files.
158 """
159
160 m = self.__class__() # Create an object of the same type as this one.
161
162 for (channel_name, channel) in self.channels.items():
163 m.channels[channel_name] = channel.subset_by_bins(b_min, b_max)
164
165 m.update()
166
152 return m 167 return m
153 168
154 def r_plot(self): 169 def r_plot(self):
155 #Make a basic plot of the data. 170 #Make a basic plot of the data.
156 #Should include some dictionary with params to make plot stable. 171 #Should include some dictionary with params to make plot stable.
388 dt = stop_time - start_time 403 dt = stop_time - start_time
389 t_mean = start_time + dt / 2 404 t_mean = start_time + dt / 2
390 return t_mean 405 return t_mean
391 406
392 407
393 class Lidar_channel: 408 class LidarChannel:
394 409
395 def __init__(self,channel_parameters): 410 def __init__(self, channel_parameters):
396 c = 299792458 #Speed of light 411 c = 299792458 # Speed of light
397 self.wavelength = channel_parameters['name'] 412 self.wavelength = channel_parameters['name']
398 self.name = str(self.wavelength) 413 self.name = str(self.wavelength)
399 self.binwidth = float(channel_parameters['binwidth']) # in microseconds 414 self.binwidth = float(channel_parameters['binwidth']) # in microseconds
400 self.data = {} 415 self.data = {}
401 self.resolution = self.binwidth * c / 2 416 self.resolution = self.binwidth * c / 2
402 self.z = np.arange(len(channel_parameters['data'])) * self.resolution + self.resolution/2.0 # Change: add half bin in the z 417 self.z = np.arange(len(channel_parameters['data'])) * self.resolution + self.resolution/2.0 # Change: add half bin in the z
403 self.points = len(channel_parameters['data']) 418 self.points = len(channel_parameters['data'])
404 self.rc = [] 419 self.rc = []
405 self.duration = 60 420 self.duration = 60
406 421
407 def calculate_rc(self): 422 def calculate_rc(self):
408 background = np.mean(self.matrix[:,4000:], axis = 1) #Calculate the background from 30000m and above 423 background = np.mean(self.matrix[:,4000:], axis = 1) # Calculate the background from 30000m and above
409 self.rc = (self.matrix.transpose()- background).transpose() * (self.z **2) 424 self.rc = (self.matrix.transpose()- background).transpose() * (self.z **2)
410 425
411 426
412 def update(self): 427 def update(self):
413 self.start_time = min(self.data.keys()) 428 self.start_time = min(self.data.keys())
440 455
441 subset_time = time_array[condition] 456 subset_time = time_array[condition]
442 subset_data = dict([(c_time, self.data[c_time]) for c_time in subset_time]) 457 subset_data = dict([(c_time, self.data[c_time]) for c_time in subset_time])
443 458
444 #Create a list with the values needed by channel's __init__() 459 #Create a list with the values needed by channel's __init__()
445 parameters_values = {'name': self.wavelength, 460 parameter_values = {'name': self.wavelength,
446 'binwidth': self.binwidth, 461 'binwidth': self.binwidth,
447 'data': subset_data[subset_time[0]],} 462 'data': subset_data[subset_time[0]],}
448 463
449 c = Lidar_channel(parameters_values) 464 # We should use __class__ instead of class name, so that this works properly
465 # with subclasses
466 # Ex: c = self.__class__(parameters_values)
467 # This does not currently work with Licel files though
468 c = LidarChannel(parameter_values)
450 c.data = subset_data 469 c.data = subset_data
451 c.update() 470 c.update()
452 return c 471 return c
453 472
454 473 def subset_by_bins(self, b_min = 0, b_max = None):
474 """Remove some height bins from the file. This could be needed to
475 remove aquisition artifacts at the start or the end of the files.
476 """
477
478 subset_data = {}
479
480 for ctime, cdata in self.data.items():
481 subset_data[ctime] = cdata[b_min:b_max]
482
483 #Create a list with the values needed by channel's __init__()
484 parameters_values = {'name': self.wavelength,
485 'binwidth': self.binwidth,
486 'data': subset_data[subset_data.keys()[0]],} # We just need any array with the correct length
487
488 c = LidarChannel(parameters_values)
489 c.data = subset_data
490 c.update()
491 return c
492
455 def profile(self,dtime, signal_type = 'rc'): 493 def profile(self,dtime, signal_type = 'rc'):
456 t, idx = self._nearest_dt(dtime) 494 t, idx = self._nearest_dt(dtime)
457 if signal_type == 'rc': 495 if signal_type == 'rc':
458 data = self.rc 496 data = self.rc
459 else: 497 else:
510 else: 548 else:
511 if show_plot: 549 if show_plot:
512 plt.show() 550 plt.show()
513 #plt.close() ??? 551 #plt.close() ???
514 552
515 def draw_plot(self,ax1, cmap = plt.cm.jet, signal_type = 'rc', zoom = [0,12000,0,-1], z0 = None, cmap_label = 'a.u.', cb_format = None, vmin = 0, vmax = 1.3 * 10 ** 7): 553 def draw_plot(self,ax1, cmap = plt.cm.jet, signal_type = 'rc',
554 zoom = [0,12000,0,-1], z0 = None,
555 add_colorbar = True, cmap_label = 'a.u.', cb_format = None,
556 vmin = 0, vmax = 1.3 * 10 ** 7):
516 557
517 if signal_type == 'rc': 558 if signal_type == 'rc':
518 if len(self.rc) == 0: 559 if len(self.rc) == 0:
519 self.calculate_rc() 560 self.calculate_rc()
520 data = self.rc 561 data = self.rc
559 #vmin = data[:,10:400].max() * 0.1, 600 #vmin = data[:,10:400].max() * 0.1,
560 vmax = vmax, 601 vmax = vmax,
561 #vmax = data[:,10:400].max() * 0.9, 602 #vmax = data[:,10:400].max() * 0.9,
562 extent = [ts1,ts2,self.z[zoom[0]]/1000.0 + z0/1000., self.z[hmax_idx]/1000.0 + z0/1000.], 603 extent = [ts1,ts2,self.z[zoom[0]]/1000.0 + z0/1000., self.z[hmax_idx]/1000.0 + z0/1000.],
563 ) 604 )
564 605
565 if cb_format: 606 if add_colorbar:
566 cb1 = plt.colorbar(im1, format = cb_format) 607 if cb_format:
567 else: 608 cb1 = plt.colorbar(im1, format = cb_format)
568 cb1 = plt.colorbar(im1) 609 else:
569 cb1.ax.set_ylabel(cmap_label) 610 cb1 = plt.colorbar(im1)
570 611 cb1.ax.set_ylabel(cmap_label)
571 # Make the ticks of the colorbar smaller, two points smaller than the default font size 612
572 cb_font_size = mpl.rcParams['font.size'] - 2 613 # Make the ticks of the colorbar smaller, two points smaller than the default font size
573 for ticklabels in cb1.ax.get_yticklabels(): 614 cb_font_size = mpl.rcParams['font.size'] - 2
574 ticklabels.set_fontsize(cb_font_size) 615 for ticklabels in cb1.ax.get_yticklabels():
575 cb1.ax.yaxis.get_offset_text().set_fontsize(cb_font_size) 616 ticklabels.set_fontsize(cb_font_size)
576 617 cb1.ax.yaxis.get_offset_text().set_fontsize(cb_font_size)
618
619
620 def draw_plot_new(self, ax1, cmap = plt.cm.jet, signal_type = 'rc',
621 zoom = [0, 12000, 0, None], z0 = None,
622 add_colorbar = True, cmap_label = 'a.u.',
623 cb_format = None, power_limits = (-2, 2),
624 date_labels = False,
625 vmin = 0, vmax = 1.3 * 10 ** 7):
626
627 if signal_type == 'rc':
628 if len(self.rc) == 0:
629 self.calculate_rc()
630 data = self.rc
631 else:
632 data = self.matrix
633
634 hmax_idx = self.index_at_height(zoom[1])
635 hmin_idx = self.index_at_height(zoom[0])
636
637 # If z0 is given, then the plot is a.s.l.
638 if z0:
639 ax1.set_ylabel('Altitude a.s.l. [km]')
640 else:
641 ax1.set_ylabel('Altitude a.g.l. [km]')
642 z0 = 0
643
644 ax1.set_xlabel('Time UTC [hh:mm]')
645 #y axis in km, xaxis /2 to make 30s measurements in minutes. Only for 1064
646 #dateFormatter = mpl.dates.DateFormatter('%H.%M')
647 #hourlocator = mpl.dates.HourLocator()
648
649
650 if date_labels:
651 dayFormatter = mpl.dates.DateFormatter('%H:%M\n%d/%m/%Y')
652 daylocator = mpl.dates.AutoDateLocator(minticks = 3, maxticks = 8, interval_multiples=True)
653 ax1.axes.xaxis.set_major_formatter(dayFormatter)
654 ax1.axes.xaxis.set_major_locator(daylocator)
655 else:
656 hourFormatter = mpl.dates.DateFormatter('%H:%M')
657 hourlocator = mpl.dates.AutoDateLocator(minticks = 3, maxticks = 8, interval_multiples=True)
658 ax1.axes.xaxis.set_major_formatter(hourFormatter)
659 ax1.axes.xaxis.set_major_locator(hourlocator)
660
661
662 # Get the values of the time axis
663 dt = datetime.timedelta(seconds = self.duration)
664
665 time_cut = self.time[zoom[2]:zoom[3]]
666 time_last = time_cut[-1] + dt # The last element needed for pcolormesh
667
668 time_all = time_cut + (time_last,)
669
670 t_axis = mpl.dates.date2num(time_all)
671
672 # Get the values of the z axis
673 z_cut = self.z[hmin_idx:hmax_idx] - self.resolution / 2.
674 z_last = z_cut[-1] + self.resolution
675
676 z_axis = np.append(z_cut, z_last) / 1000. + z0 / 1000. # Convert to km
677
678 # Plot
679 im1 = ax1.pcolormesh(t_axis, z_axis, data.T[hmin_idx:hmax_idx, zoom[2]:zoom[3]],
680 cmap = cmap,
681 vmin = vmin,
682 vmax = vmax,
683 )
684
685 if add_colorbar:
686 if cb_format:
687 cb1 = plt.colorbar(im1, format = cb_format)
688 else:
689 cb_formatter = ScalarFormatter()
690 cb_formatter.set_powerlimits(power_limits)
691 cb1 = plt.colorbar(im1, format = cb_formatter)
692 cb1.ax.set_ylabel(cmap_label)
693
694 # Make the ticks of the colorbar smaller, two points smaller than the default font size
695 cb_font_size = mpl.rcParams['font.size'] - 2
696 for ticklabels in cb1.ax.get_yticklabels():
697 ticklabels.set_fontsize(cb_font_size)
698 cb1.ax.yaxis.get_offset_text().set_fontsize(cb_font_size)
699
577 def index_at_height(self, height): 700 def index_at_height(self, height):
578 idx = np.array(np.abs(self.z - height).argmin()) 701 idx = np.array(np.abs(self.z - height).argmin())
579 if idx.size > 1: 702 if idx.size > 1:
580 idx =idx[0] 703 idx =idx[0]
581 return idx 704 return idx

mercurial