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 |