eldamwl_plot.py

changeset 2
763a7ac22031
parent 0
fce4cae19357
child 4
75213aef70b8
equal deleted inserted replaced
1:f0db47eb70b1 2:763a7ac22031
1 from typing import List, Any 1 # import nc as nc
2 2 # import xarray as xr
3 import xarray as xr
4 from config import * 3 from config import *
5 import plotly.graph_objects as go 4 import plotly.graph_objects as go
6 from plotly.subplots import make_subplots 5 from plotly.subplots import make_subplots
7 import netCDF4 as nc 6 import netCDF4 as nc
8 from datetime import datetime 7 from datetime import datetime
58 print(f"The file '{nc_file_path}' does not exist.") 57 print(f"The file '{nc_file_path}' does not exist.")
59 except Exception as e: 58 except Exception as e:
60 print(f"The group {e} does not exist.") 59 print(f"The group {e} does not exist.")
61 60
62 61
62 def read_global_attribute(nc_file_path, attribute_name):
63 # Open the NetCDF file in read mode
64 with nc.Dataset(nc_file_path, 'r') as dataset:
65 # with netCDF4.Dataset(nc_file_path, 'r') as nc:
66 # Check if the attribute exists
67 if attribute_name in dataset.ncattrs():
68 # Read the attribute value
69 attribute_value = dataset.getncattr(attribute_name)
70 return attribute_value
71 else:
72 print(f"Attribute '{attribute_name}' not found in the NetCDF file.")
73
74
63 def read_variable_in_group2(nc_file_path, group_name, variable_name): 75 def read_variable_in_group2(nc_file_path, group_name, variable_name):
64 try: 76 try:
65 with nc.Dataset(nc_file_path, 'r') as dataset: 77 with nc.Dataset(nc_file_path, 'r') as dataset:
66 # Find the group 78 # Find the group
67 group = dataset.groups[group_name] 79 group = dataset.groups[group_name]
87 99
88 # Fetch the dimension values 100 # Fetch the dimension values
89 dimension_values = {} 101 dimension_values = {}
90 for dim_name in dimensions: 102 for dim_name in dimensions:
91 dim_values = group.variables[dim_name][:] 103 dim_values = group.variables[dim_name][:]
92 dimension_values[dim_name] = dim_values 104 dimension_values[dim_name] = dim_values.tolist()
93 # Adjust the index array for slicing 105 # Adjust the index array for slicing
94 index_array[variable.dimensions.index(dim_name)] = 0 106 index_array[variable.dimensions.index(dim_name)] = 0
95 107
96 # Now you have the variable data and its associated dimensions in a dictionary 108 # Now you have the variable data and its associated dimensions in a dictionary
97 # result = {'data': variable_data, 'dimensions': dimension_values, 'metadata': variable_metadata} 109 # result = {'data': variable_data, 'dimensions': dimension_values, 'metadata': variable_metadata}
152 for v in range(len(variables)): 164 for v in range(len(variables)):
153 for t in range(len(dimensions['time'])): 165 for t in range(len(dimensions['time'])):
154 for w in range(len(dimensions['wavelength'])): 166 for w in range(len(dimensions['wavelength'])):
155 tn = str(datetime.fromtimestamp(dimensions['time'][t])) 167 tn = str(datetime.fromtimestamp(dimensions['time'][t]))
156 wn = str(dimensions['wavelength'][w]) 168 wn = str(dimensions['wavelength'][w])
157 if timeinrows == True: 169 if timeinrows:
158 lgnd = wn + ' nm' 170 lgnd = wn + ' nm'
159 rown = t + 1 171 rown = t + 1
160 colorint = 1
161 colorind = 0 172 colorind = 0
162 subtitle = str(datetime.fromtimestamp(dimensions['time'][t])) 173 # subtitle = str(datetime.fromtimestamp(dimensions['time'][t]))
163 else: 174 else:
164 lgnd = wn + ' nm - ' + tn 175 lgnd = wn + ' nm - ' + tn
165 rown = 1 176 rown = 1
166 colorind = t 177 colorind = t
167 colorint = 1 - (0.4 * t)
168 178
169 # colour definition 179 # colour definition
170 if abs(dimensions['wavelength'][w] - 1064) < 1: 180 if abs(dimensions['wavelength'][w] - 1064) < 1:
171 clr = clrs[2, colorind] 181 clr = clrs[2, colorind]
172 # clr = 'rgb(235,70,20)' # 'rgba(215,27,96,0.4)' 182 # clr = 'rgb(235,70,20)' # 'rgba(215,27,96,0.4)'
176 clr = clrs[0, colorind] 186 clr = clrs[0, colorind]
177 else: 187 else:
178 clr = 'rgb(0,0,0)' 188 clr = 'rgb(0,0,0)'
179 189
180 data_values = data[variables[v]][w, t, :] 190 data_values = data[variables[v]][w, t, :]
181 error_values = positive_error_array[variables[v]][w, t, :] 191 if np.average(np.ma.masked_array(data_values, np.isnan(data_values))) is not np.ma.masked:
182 vertical_levels = y_array["data"][t, :] 192 vertical_levels = y_array["data"][t, :]
183 193 error_values = positive_error_array[variables[v]][w, t, :]
184 # Add trace 194
185 fig.add_trace(go.Scatter( 195 # Add trace
186 x=data_values, 196 fig.add_trace(go.Scatter(
187 y=vertical_levels, 197 x=data_values,
188 error_x=dict(array=error_values, width=0, thickness=0.1), 198 y=vertical_levels,
189 # ToDo Include distinction between positive and negative errors 199 error_x=dict(array=error_values, width=0, thickness=0.1),
190 mode='lines', 200 # ToDo Include distinction between positive and negative errors
191 line=dict(width=2, color=clr), 201 mode='lines',
192 name=lgnd), 202 line=dict(width=2, color=clr),
193 row=rown, col=v + 1, 203 name=lgnd),
194 ) 204 row=rown, col=v + 1,
195 205 )
196 # ToDo Check formatting options (showlegend, mapbox) 206
197 fig.update_xaxes({"title": xaxis_label[v]}, row=rown, col=v + 1) 207 # ToDo Check formatting options (showlegend, mapbox)
198 fig.update_xaxes({"mirror": True, "ticks": 'outside', "showline": True, "color": "black"}, row=rown, 208 fig.update_xaxes({"title": xaxis_label[v]}, row=rown, col=v + 1)
199 col=v + 1) 209 fig.update_xaxes({"mirror": True, "ticks": 'outside', "showline": True, "color": "black"}, row=rown,
200 210 col=v + 1)
201 fig.update_xaxes(ticks="outside") 211
202 fig.update_yaxes(ticks="outside", row=rown, col=v + 1) # ToDo check tickformat (i.e. tickformat=":.2e") 212 fig.update_xaxes(ticks="outside")
203 if v == 0: 213 fig.update_yaxes(ticks="outside", row=rown, col=v + 1)
204 fig.update_yaxes({"title": yaxis_label}, row=rown, col=v + 1) 214 # ToDo check tickformat (i.e. tickformat=":.2e")
215 if v == 0:
216 fig.update_yaxes({"title": yaxis_label}, row=rown, col=v + 1)
217
218 # ToDo add boxes
219 a = fig.layout['xaxis']['domain']
220 # print(a)
221 b = fig.layout['yaxis']['domain']
222 # print(b)
223 # fig.add_hline(y=b[0], line=dict(color="yellow", width=2), row=rown, col=v+1)
224 # fig.add_hline(y=b[1], line=dict(color="purple", width=2), row=rown, col=v+1)
225 # fig.add_vline(x=a[0], line=dict(color="orange", width=2), row=rown, col=v+1)
226 # fig.add_vline(x=a[1], line=dict(color="pink", width=2), row=rown, col=v+1)
227 # fig.add_shape(type="line", xref="paper", yref="paper", x0=a[0], y0=b[0], x1=a[1], y1=b[1],
228 # line=dict(color="grey", width=2, ), row=rown, col=v+1)
229 # fig.add_shape(type="line", xref="paper", yref="paper", x0=1, y0=1, x1=1, y1=0,
230 # line=dict(color="blue", width=2, ), row=rown, col=v+1)
231 # fig.add_shape(type="line", xref="paper", yref="paper", x0=0, y0=0, x1=1, y1=0,
232 # line=dict(color="red", width=2, ), row=rown, col=v+1)
233 # fig.add_shape(type="line", xref="paper", yref="paper", x0=0, y0=0, x1=0, y1=1,
234 # line=dict(color="green", width=2, ), row=rown, col=v+1)
235 # fig.add_hline(y=0, line=dict(color="yellow", width=2))
236 # print(fig.data[0]['x'])
205 237
206 # Set axis labels and title 238 # Set axis labels and title
207 fig.update_layout( 239 fig.update_layout(
208 yaxis_title=yaxis_label, 240 yaxis_title=yaxis_label,
209 title=title, 241 title=title,
214 ) 246 )
215 247
216 return fig 248 return fig
217 249
218 250
251 def plot_vertical_profiles_plotly_allres(variables, data, dimensions, y_array, positive_error_array,
252 negative_error_array, xaxis_label, yaxis_label, title):
253 """
254 ToDo Complete
255 Plot vertical profiles using plotly
256
257 Parameters:
258 -
259
260 Returns:
261 - fig: html
262 """
263
264 # Set number of columns, number of rows, and subtitles if needed
265 ncols = len(variables)
266 nrows = 1
267 subtitles = ''
268
269 # Create figure
270 fig = make_subplots(rows=nrows, cols=ncols,
271 subplot_titles=subtitles,
272 shared_yaxes=True)
273
274 # Define colours
275 clrs = [['rgb(0,35,255)', 'rgb(0,20,150)'], # UV
276 ['rgb(90,210,50)', 'rgb(40,90,25)'], # VIS
277 ['rgb(250,30,30)', 'rgb(130,30,10)']] # IR
278 clrs = np.array(clrs)
279
280 # Plot
281 for v in range(len(variables)):
282 for t in range(len(dimensions['time'])):
283 for w in range(len(dimensions['wavelength_res'])):
284 wl = float(dimensions['wavelength_res'][w].split(' ')[0])
285 wn = str(dimensions['wavelength_res'][w])
286 lgnd = wn.replace(' ', ' nm ')
287 rown = 1
288 if wn.find('LR') > 0:
289 colorind = 0
290 else:
291 colorind = 1
292
293 # colour definition
294 if abs(wl - 1064) < 1:
295 clr = clrs[2, colorind]
296 elif abs(wl - 532) < 1:
297 clr = clrs[1, colorind]
298 elif abs(wl - 355) < 1:
299 clr = clrs[0, colorind]
300 else:
301 clr = 'rgb(0,0,0)'
302
303 data_values = data[variables[v]][w, t, :]
304 if np.average(np.ma.masked_array(data_values, np.isnan(data_values))) is not np.ma.masked:
305 vertical_levels = y_array["data"][t, :]
306 error_values = positive_error_array[variables[v]][w, t, :]
307 # Add trace
308 fig.add_trace(go.Scatter(
309 x=data_values,
310 y=vertical_levels,
311 error_x=dict(array=error_values, width=0, thickness=0.1),
312 # ToDo Include distinction between positive and negative errors
313 mode='lines',
314 line=dict(width=2, color=clr),
315 name=lgnd),
316 row=rown, col=v + 1,
317 )
318
319 # ToDo Check formatting options (showlegend, mapbox)
320 fig.update_xaxes({"title": xaxis_label[v]}, row=rown, col=v + 1)
321 fig.update_xaxes({"mirror": True, "ticks": 'outside', "showline": True, "color": "black"}, row=rown,
322 col=v + 1)
323
324 fig.update_xaxes(ticks="outside")
325 fig.update_yaxes(ticks="outside", row=rown, col=v + 1)
326 # ToDo check tickformat (i.e. tickformat=":.2e")
327 if v == 0:
328 fig.update_yaxes({"title": yaxis_label}, row=rown, col=v + 1)
329
330 # ToDo add boxes
331 a = fig.layout['xaxis']['domain']
332 # print(a)
333 b = fig.layout['yaxis']['domain']
334 # print(b)
335 # fig.add_hline(y=b[0], line=dict(color="yellow", width=2), row=rown, col=v+1)
336 # fig.add_hline(y=b[1], line=dict(color="purple", width=2), row=rown, col=v+1)
337 # fig.add_vline(x=a[0], line=dict(color="orange", width=2), row=rown, col=v+1)
338 # fig.add_vline(x=a[1], line=dict(color="pink", width=2), row=rown, col=v+1)
339 # fig.add_shape(type="line", xref="paper", yref="paper", x0=a[0], y0=b[0], x1=a[1], y1=b[1],
340 # line=dict(color="grey", width=2, ), row=rown, col=v+1)
341 # fig.add_shape(type="line", xref="paper", yref="paper", x0=1, y0=1, x1=1, y1=0,
342 # line=dict(color="blue", width=2, ), row=rown, col=v+1)
343 # fig.add_shape(type="line", xref="paper", yref="paper", x0=0, y0=0, x1=1, y1=0,
344 # line=dict(color="red", width=2, ), row=rown, col=v+1)
345 # fig.add_shape(type="line", xref="paper", yref="paper", x0=0, y0=0, x1=0, y1=1,
346 # line=dict(color="green", width=2, ), row=rown, col=v+1)
347 # fig.add_hline(y=0, line=dict(color="yellow", width=2))
348 # print(fig.data[0]['x'])
349
350 # Set axis labels and title
351 fig.update_layout(
352 yaxis_title=yaxis_label,
353 title=title,
354 template="seaborn", # You can change the template as per your preference
355 # ['ggplot2', 'seaborn', 'simple_white', 'plotly', 'plotly_white', 'plotly_dark', 'presentation',
356 # 'xgridoff', 'ygridoff', 'gridon', 'none']
357 height=max(600, 450 * rown), width=min(max(400 * len(variables), 750), 1400),
358 )
359
360 return fig
361
362
219 # Files for testing 363 # Files for testing
220 # netcdf_file = 'hpb_012_0000598_201810172100_201810172300_20181017oh00_ELDAmwl_v0.0.1.nc' # Backscatter and extinction, no error 364 # Backscatter and extinction, no error:
221 # netcdf_file = 'hpb_012_0000627_202308240200_202308240400_20230824hpb0200_ELDAmwl_v0.0.1.nc' # Extinction with error 365 # netcdf_file = 'hpb_012_0000598_201810172100_201810172300_20181017oh00_ELDAmwl_v0.0.1.nc'
366 # Extinction with error:
367 # netcdf_file = 'hpb_012_0000627_202308240200_202308240400_20230824hpb0200_ELDAmwl_v0.0.1.nc'
222 368
223 369
224 try: 370 try:
225 netcdf_file = sys.argv[1] 371 netcdf_file = sys.argv[1]
226 except: 372 except:
227 print('Syntax is incorrect, you need to pass the filename of the file to be plotted.\n' 373 print('Syntax is incorrect, you need to pass the filename of the file to be plotted.\n'
228 'Example: ./eldamwl_plot.py hpb_012_0000598_201810172100_201810172300_20181017oh00_ELDAmwl_v0.0.1.nc') 374 'Example: ./eldamwl_plot.py hpb_012_0000598_201810172100_201810172300_20181017oh00_ELDAmwl_v0.0.1.nc')
229 exit() 375 exit()
230 376
377 # Print help
378 if netcdf_file == '-h' or netcdf_file == '--h':
379 print('Syntax: ./eldamwl_plot.py hpb_012_0000598_201810172100_201810172300_20181017oh00_ELDAmwl_v0.0.1.nc')
380 exit()
381
231 netcdf_file_path = netcdf_path + netcdf_file 382 netcdf_file_path = netcdf_path + netcdf_file
232 383
233 file_exists = exists(netcdf_file_path) 384 file_exists = exists(netcdf_file_path)
234 if not file_exists: 385 if not file_exists:
235 print('The file that you provided does not exist.') 386 print('The file that you provided does not exist.')
238 # Groups of data in the NetCDF file (low and high resolution) 389 # Groups of data in the NetCDF file (low and high resolution)
239 groups = ['lowres_products', 'highres_products'] 390 groups = ['lowres_products', 'highres_products']
240 groups_names = ['Low resolution', 'High resolution'] 391 groups_names = ['Low resolution', 'High resolution']
241 392
242 # Variables that we want to plot 393 # Variables that we want to plot
243 variable = ['backscatter', 'extinction', 'lidarratio', 'volumedepolarization', 'particledepolarization'] # ToDo Test particledepolarization when available 394 variable = ['backscatter', 'extinction', 'lidarratio', 'volumedepolarization',
395 'particledepolarization'] # ToDo Test particledepolarization when available
244 # Errors associated to the variables 396 # Errors associated to the variables
245 variable_error = ['error_backscatter', 'error_extinction', 'error_lidarratio', 397 variable_error = ['error_backscatter', 'error_extinction', 'error_lidarratio',
246 'positive_systematic_error_volumedepolarization', 'error_particledepolarization'] 398 'positive_systematic_error_volumedepolarization', 'error_particledepolarization']
247 variable_negative_error_volumedepol = 'negative_systematic_error_volumedepolarization' 399 variable_negative_error_volumedepol = 'negative_systematic_error_volumedepolarization'
248 # Other variables: 400 # ToDo Consider adding other variables:
249 # cloud_mask (time, level) 401 # cloud_mask (time, level)
250 402
251 403 # Read global attributes
404 station_id = read_global_attribute(netcdf_file_path, 'station_ID')
405 station_location = read_global_attribute(netcdf_file_path, 'location')
406
407 # Read data
252 for g in range(len(groups)): 408 for g in range(len(groups)):
253 # Read the altitude variable 409 # Read the altitude variable
254 altitude = read_variable_in_group(netcdf_file_path, groups[g], 'altitude') 410 altitude = read_variable_in_group(netcdf_file_path, groups[g], 'altitude')
255 411
256 if altitude['metadata']['units'] == 'm': 412 if altitude['metadata']['units'] == 'm':
303 else: 459 else:
304 print(f'There is no data for {variable[v]} in the {groups_names[g]} group.') 460 print(f'There is no data for {variable[v]} in the {groups_names[g]} group.')
305 461
306 dimensions = dim 462 dimensions = dim
307 463
308 # Ask user if he/she wants to plot different temporal profiles in different rows 464 # Save lowres and highres in variables to plot them together afterwards
465 if groups[g] == 'lowres_products':
466 altitude_lr = altitude
467 dimensions_lr = dim
468 data_lr = data
469 data_error_positive_lr = data_error_positive
470 data_error_negative_lr = data_error_negative
471 variables_with_data_lr = variables_with_data
472 variables_axis_lr = variables_axis
473 if groups[g] == 'highres_products':
474 altitude_hr = altitude
475 dimensions_hr = dim
476 data_hr = data
477 data_error_positive_hr = data_error_positive
478 data_error_negative_hr = data_error_negative
479 variables_with_data_hr = variables_with_data
480 variables_axis_hr = variables_axis
481
482 # If interactive is set to True, ask user if he/she wants to plot different temporal profiles in different rows
483 # If interactive is set to False, proceed with default values
309 if g == 0: 484 if g == 0:
310 # Initialize 485 # Initialize
311 timeinplots = False 486 timeinplots = True
312 timeinrows = False 487 timeinrows = False
313 # Ask user how he/she wants the plot 488 # If interactive (config.py) = True, ask user how he/she wants the plot
314 if len(dimensions['time']) > 1: 489 if interactive and len(dimensions['time']) > 1:
315 answer = input( 490 answer = input(
316 f"There are {len(dimensions['time'])} temporal profiles, do you want to plot them on different plots [y/n]? ") 491 f"There are {len(dimensions['time'])} temporal profiles, "
317 if answer[0:1].lower() == 'y': 492 f"do you want to plot them on different plots [y/n]? ")
318 timeinplots = True 493 if answer[0:1].lower() == 'n':
319 if timeinplots == False: 494 timeinplots = False
495 if not timeinplots:
320 answer = input( 496 answer = input(
321 f"There are {len(dimensions['time'])} temporal profiles, do you want to plot them on different rows [y/n]? ") 497 f"There are {len(dimensions['time'])} temporal profiles, "
498 f"do you want to plot them on different rows [y/n]? ")
322 if answer[0:1].lower() == 'y': 499 if answer[0:1].lower() == 'y':
323 timeinrows = True 500 timeinrows = True
324 501
325 if variables_with_data is not None: 502 if variables_with_data is not None:
326 timeiter = dimensions['time'] 503 timeiter = dimensions['time']
327 if timeinplots == True: 504 if timeinplots:
505 # Default plotting
328 dimensions_t = dimensions 506 dimensions_t = dimensions
329 for t in range(len(dimensions['time'])): 507 for t in range(len(dimensions['time'])):
330 dimensions_t['time'] = [timeiter[t]] 508 dimensions_t['time'] = [timeiter[t]]
331 for vr in range(len(variables_with_data)): 509 for vr in range(len(variables_with_data)):
332 if vr == 0: 510 if vr == 0:
341 y_array=altitude, 519 y_array=altitude,
342 positive_error_array=data_error_positive, 520 positive_error_array=data_error_positive,
343 negative_error_array=data_error_negative, 521 negative_error_array=data_error_negative,
344 xaxis_label=variables_axis, 522 xaxis_label=variables_axis,
345 yaxis_label=altitude['metadata']['long_name'] + ' [' + altitude['metadata']['units'] + ']', 523 yaxis_label=altitude['metadata']['long_name'] + ' [' + altitude['metadata']['units'] + ']',
346 title=netcdf_file[0:3].upper() + " - " + str( 524 title=station_location + " (" + station_id.upper() + ") - " + str(
347 datetime.fromtimestamp(dimensions_t['time'][0]).strftime( 525 datetime.fromtimestamp(dimensions_t['time'][0]).strftime('%d/%m/%Y %H:%M:%S')) +
348 '%d/%m/%Y %H:%M:%S')) + " - ELDA MWL " + 526 " - ELDA MWL " + groups_names[g],
349 groups_names[g],
350 timeinrows=True 527 timeinrows=True
351 ) 528 )
352 529
353 # Show the plot (in Jupyter Notebook or Jupyter Lab) 530 # Show the plot (in Jupyter Notebook or Jupyter Lab)
354 fig.show() 531 # fig.show()
355 532
356 # Save the plot 533 # Save the plot
357 filename = "ELDAmwl_" + netcdf_file[0:3].upper() + "_" + datetime.fromtimestamp( 534 filename = "ELDAmwl_" + netcdf_file[0:3].upper() + "_" + datetime.fromtimestamp(
358 dimensions['time'][0]).strftime('%Y%m%d-%H%M%S') + "_" + groups[g] + ".html" 535 dimensions['time'][0]).strftime('%Y%m%d-%H%M%S') + "_" + groups[g] + ".html"
359 fig.write_html(html_path + filename) 536 fig.write_html(html_path + filename)
367 altitude, 544 altitude,
368 data_error_positive, 545 data_error_positive,
369 data_error_negative, 546 data_error_negative,
370 xaxis_label=variables_axis, 547 xaxis_label=variables_axis,
371 yaxis_label=altitude['metadata']['long_name'] + ' [' + altitude['metadata']['units'] + ']', 548 yaxis_label=altitude['metadata']['long_name'] + ' [' + altitude['metadata']['units'] + ']',
372 title=netcdf_file[0:3].upper() + " - " + str( 549 title=station_location + " (" + station_id.upper() + ") - " + str(
373 datetime.fromtimestamp(dimensions['time'][0]).strftime('%d/%m/%Y')) + " - ELDA MWL " + groups_names[ 550 datetime.fromtimestamp(dimensions['time'][0]).strftime('%d/%m/%Y')) + " - ELDA MWL " + groups_names[
374 g], 551 g],
375 timeinrows=timeinrows 552 timeinrows=timeinrows
376 ) 553 )
377 554
378 # Show the plot (in Jupyter Notebook or Jupyter Lab) 555 # Show the plot (in Jupyter Notebook or Jupyter Lab)
379 fig.show() 556 # fig.show()
380 557
381 # Save the plot 558 # Save the plot
382 if timeinrows == True: 559 if timeinrows:
383 filename = "ELDAmwl_" + netcdf_file[0:3].upper() + "_" + datetime.fromtimestamp( 560 filename = "ELDAmwl_" + station_id.upper() + "_" + datetime.fromtimestamp(
384 dimensions['time'][0]).strftime('%Y%m%d%H%M%S') + '-' + datetime.fromtimestamp( 561 dimensions['time'][0]).strftime('%Y%m%d%H%M%S') + '-' + datetime.fromtimestamp(
385 dimensions['time'][-1]).strftime('%Y%m%d%H%M%S') + "_" + groups[g] + "_timeinrows.html" 562 dimensions['time'][-1]).strftime('%Y%m%d%H%M%S') + "_" + groups[g] + "_timeinrows.html"
386 else: 563 else:
387 filename = "ELDAmwl_" + netcdf_file[0:3].upper() + "_" + datetime.fromtimestamp( 564 filename = "ELDAmwl_" + station_id.upper() + "_" + datetime.fromtimestamp(
388 dimensions['time'][0]).strftime('%Y%m%d%H%M%S') + '-' + datetime.fromtimestamp( 565 dimensions['time'][0]).strftime('%Y%m%d%H%M%S') + '-' + datetime.fromtimestamp(
389 dimensions['time'][-1]).strftime('%Y%m%d%H%M%S') + "_" + groups[g] + ".html" 566 dimensions['time'][-1]).strftime('%Y%m%d%H%M%S') + "_" + groups[g] + ".html"
390 567
391 fig.write_html(html_path + filename) 568 fig.write_html(html_path + filename)
392 569
393 else: 570 else:
394 print(f'There is no data to be plotted in the {groups_names[g]} group.') 571 print(f'There is no data to be plotted in the {groups_names[g]} group.')
572
573 # Plotting high and low resolution together
574 if len(variables_with_data_lr) > 0 and len(variables_with_data_hr) > 0:
575 print(f'We have low and high resolution data, let''s combine it!')
576
577 # Variables with data
578 variables_with_data = list(variables_with_data_lr)
579 variables_with_data.extend(x for x in variables_with_data_hr if x not in variables_with_data)
580 print(f'Variables with data: {variables_with_data}')
581
582 # Variables axis
583 variables_axis = list(variables_axis_lr)
584 variables_axis.extend(x for x in variables_axis_hr if x not in variables_axis)
585
586 # Joining dimensions for both resolutions
587 # Wavelength
588 wav = list(dimensions_lr['wavelength'])
589 wav.extend(x for x in dimensions_hr['wavelength'] if x not in wav)
590 dimensions['wavelength'] = wav
591 # Add LR/HR to the wavelength
592 wlr = list(dimensions_lr['wavelength'])
593 for r in range(len(wlr)):
594 wlr[r] = str(wlr[r]) + ' (LR)'
595 whr = list(dimensions_hr['wavelength'])
596 for r in range(len(whr)):
597 whr[r] = str(whr[r]) + ' (HR)'
598 dimensions['wavelength_res'] = wlr + whr
599 # Time
600 tim = list(dimensions_lr['time'])
601 tim.extend(x for x in dimensions_hr['time'] if x not in tim)
602 dimensions['time'] = tim
603 # Level
604 lev = list(dimensions_lr['level'])
605 lev.extend(x for x in dimensions_hr['level'] if x not in lev)
606 dimensions['level'] = lev
607
608 # Populate the arrays with data and errors
609 for v in variables_with_data:
610 # Create array to store the joint data
611 # data_var = np.ma.masked_all((len(dimensions['wavelength_res']), len(tim), len(lev)))
612 data_var = np.ma.zeros((len(dimensions['wavelength_res']), len(tim), len(lev)))
613 data_error_positive_var = np.ma.zeros((len(dimensions['wavelength_res']), len(tim), len(lev)))
614 data_error_negative_var = np.ma.zeros((len(dimensions['wavelength_res']), len(tim), len(lev)))
615 # ToDo check if needed
616 data_var = np.ma.masked_values(data_var, 0)
617 data_error_positive_var = np.ma.masked_values(data_error_positive_var, 0)
618 data_error_negative_var = np.ma.masked_values(data_error_negative_var, 0)
619 for w in range(len(dimensions['wavelength_res'])):
620 for t in range(len(dimensions['time'])):
621 # Incorporate data into the main array
622 print(f"{v} - Wavelength: {dimensions['wavelength_res'][w]}. Time: {dimensions['time'][t]}.")
623
624 # High resolution
625 if dimensions['wavelength_res'][w].find('HR') >= 0:
626 # Is there HR data?
627 if v in data_hr:
628 try:
629 # Find position of w and t
630 wl = float(dimensions['wavelength_res'][w].split(' ')[0])
631 wp = dimensions_hr['wavelength'].index(wl)
632 tp = dimensions_hr['time'].index(dimensions['time'][t])
633 # Check if there is data
634 a = data_hr[v][wp, tp, :]
635 d = np.average(np.ma.masked_array(a, np.isnan(a)))
636 if np.ma.min(d) is not np.ma.masked:
637 print(f'\tWe have HR data for {v}')
638 # Save data into common structure
639 data_var[w, t, :] = a
640 if np.average(np.ma.masked_array(data_error_positive_hr[v][wp, tp, :], np.isnan(
641 data_error_positive_hr[v][wp, tp, :]))) is not np.ma.masked:
642 data_error_positive_var[w, t, :] = data_error_positive_hr[v][wp, tp, :]
643 if np.average(np.ma.masked_array(data_error_negative_hr[v][wp, tp, :], np.isnan(
644 data_error_negative_hr[v][wp, tp, :]))) is not np.ma.masked:
645 data_error_negative_var[w, t, :] = data_error_negative_hr[v][wp, tp, :]
646 except ValueError:
647 pass
648
649 # Low resolution
650 if dimensions['wavelength_res'][w].find('LR') >= 0:
651 # Is there LR data?
652 if v in data_lr:
653 # Find position of w and t
654 try:
655 wl = float(dimensions['wavelength_res'][w].split(' ')[0])
656 wp = dimensions_hr['wavelength'].index(wl)
657 if wl in dimensions_lr['wavelength']:
658 wp = dimensions_lr['wavelength'].index(dimensions['wavelength'][w])
659 else:
660 wp = -1
661 # if dimensions['time'][t] in dimensions_lr['time']:
662 tp = dimensions_lr['time'].index(dimensions['time'][t])
663 # else:
664 # tp = -1
665 if wp > -1 and tp > -1:
666 # Check if there is data
667 a = data_lr[v][wp, tp, :]
668 d = np.average(np.ma.masked_array(a, np.isnan(a)))
669 if np.ma.min(d) is not np.ma.masked:
670 print(f'\tWe have LR data for {v}')
671 # Save data into common structure
672 data_var[w, t, :] = a
673 if np.average(np.ma.masked_array(data_error_positive_lr[v][wp, tp, :], np.isnan(
674 data_error_positive_lr[v][wp, tp, :]))) is not np.ma.masked:
675 data_error_positive_var[w, t, :] = data_error_positive_lr[v][wp, tp, :]
676 if np.average(np.ma.masked_array(data_error_negative_lr[v][wp, tp, :], np.isnan(
677 data_error_negative_lr[v][wp, tp, :]))) is not np.ma.masked:
678 data_error_negative_var[w, t, :] = data_error_negative_lr[v][wp, tp, :]
679 except ValueError:
680 # i.e. no 1064 wavelength in dimensions_lr
681 pass
682 # except IndexError:
683 # pass
684
685 # Store data in the global matrices
686 if variables_with_data.index(v) == 0:
687 data_all = {v: data_var}
688 data_error_positive = {v: data_error_positive_var}
689 data_error_negative = {v: data_error_negative_var}
690 else:
691 data_all[v] = data_var
692 data_error_positive[v] = data_error_positive_var
693 data_error_negative[v] = data_error_negative_var
694
695 # Plot
696 timeiter = dimensions['time']
697 # Default plotting
698 dimensions_t = dimensions
699 for t in range(len(dimensions['time'])):
700 print(f'plotting hr & lr for {timeiter[t]}')
701 dimensions_t['time'] = [timeiter[t]]
702 for vr in range(len(variables_with_data)):
703 if vr == 0:
704 data_t = {variables_with_data[vr]: data_all[variables_with_data[vr]][:, t:t + 1, :]}
705 else:
706 data_t[variables_with_data[vr]] = data_all[variables_with_data[vr]][:, t:t + 1, :]
707
708 fig = plot_vertical_profiles_plotly_allres(
709 variables=variables_with_data,
710 data=data_t,
711 dimensions=dimensions_t,
712 y_array=altitude,
713 positive_error_array=data_error_positive,
714 negative_error_array=data_error_negative,
715 xaxis_label=variables_axis,
716 yaxis_label=altitude['metadata']['long_name'] + ' [' + altitude['metadata']['units'] + ']',
717 title=station_location + " (" + station_id.upper() + ") - " + str(datetime.fromtimestamp(dimensions_t['time'][0]).strftime('%d/%m/%Y %H:%M:%S')) + " - ELDA MWL - High and low resolution")
718
719 # Show the plot (in Jupyter Notebook or Jupyter Lab)
720 fig.show()
721
722 # Save the plot
723 filename = "ELDAmwl_" + netcdf_file[0:3].upper() + "_" + datetime.fromtimestamp(
724 dimensions['time'][0]).strftime('%Y%m%d-%H%M%S') + "_all.html"
725 fig.write_html(html_path + filename)
726

mercurial