#!/usr/bin/env python # -*- coding: UTF-8 -*- ''' Plotting tool for BeCOOL datasets 1.2 & 2.2 reference python environment : - python 3.9 - numpy 1.20 - xarray 2022.3 - matplotlib 3.4 module "python/meso-3.9" on Mesocentre ESPRI IPSL contains these packages ''' __project__ = 'plotting tools for BeCOOL' __author__ = 'Thomas LESIGNE (thomas.lesigne@latmos.ipsl.fr)' __date__ = '2023/07/06' __version__ = '1.0' import numpy as np import xarray as xr import matplotlib.pyplot as plt import matplotlib.colors as mcolors def becool_curtain(ds, ax=None, var='bt2', ymin=-1, ymax=21, colorbar=True, concat_mode='normal', title=None): ''' plotting 2D lidar curtain (time Vs altitude) Parameters - ds (xarray dataset) - ax (matplotlib.axes, default:None) - matplotlib axes where to plot the data. If None a new figure will be created - var ('bt2', 'beta_part' or 'scattering_ratio' ) - variable to plot - ymin, ymax (float or int) : altitude boundaries in km - colorbar (bool, default:True) - draw colorbar - concat_mode ('normal' or 'night') - temporal concatenationn of profiles - title (string) - title of the plot ''' # initialize figure if necessary if ax is None: fig, ax = plt.subplots(figsize=(18,9)) # set dynamic bounds and colormap if var =='bt2': vmin=1e-6 vmax=1e-2 cmap = 'inferno' elif var == 'beta_part': vmin = 1e-10 vmax = 5e-3 cmap='turbo' elif var == 'scattering_ratio': vmin = 1 vmax = 2e4 cmap='jet' # build 2D altitudes variable ds['altitudes'] = ds.alti - ds.range if concat_mode == 'normal': data = ds[var].values altitudes = ds.altitudes.values # start time of measurements t_start = ds.time_start.values # delta_t between start of consecutive measurements delta = list(ds.time_start.diff('time', label='lower').values) delta.append(min(delta)) delta = np.array(delta) # end time of measurements t_stop = ds.time_stop.values # if delta[i,i+1] < 2min, t_stop[i] = t-start[i+1] t_start_plus = list(t_start[1:]) t_start_plus.append(t_stop[-1]) t_start_plus = np.array(t_start_plus) t_stop = np.where(delta < np.timedelta64(2,'m'), t_start_plus, t_stop) elif concat_mode == 'night': # add sequence_idx as coordinate ds.coords['sequence_idx'] = ds.sequence_idx # start time of measurements t_start = ds.groupby('sequence_idx').map(lambda x: x.time_start[0]).values # stop time of measurements t_stop = ds.groupby('sequence_idx').map(lambda x: x.time_stop[-1]).values # delta_t between start of consecutive measurements delta = list(np.diff(t_start)) delta.append(min(delta)) delta = np.array(delta) # if delta[i,i+1] < 25 min, t_stop[i] = t-start[i+1] t_start_plus = list(t_start[1:]) t_start_plus.append(t_stop[-1]) t_start_plus = np.array(t_start_plus) t_stop = np.where(delta < np.timedelta64(25,'m').astype('