firewxpy 2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3196 @@
1
+ """
2
+ This file hosts the function that plots observed vertical profile graphics.
3
+
4
+ Data Source: University of Wyoming.
5
+
6
+ (C) Eric J. Drewitz 2024-2026
7
+ """
8
+ import matplotlib.pyplot as _plt
9
+ import matplotlib as _mpl
10
+ import pandas as _pd
11
+ import metpy.calc as _mpcalc
12
+ import numpy as _np
13
+ import firewxpy.calc.calc as _calc
14
+
15
+ from metpy.units import units as _units
16
+ from matplotlib.ticker import MaxNLocator as _MaxNLocator
17
+ from wxdata import(
18
+ get_observed_sounding_data as _get_observed_sounding_data,
19
+ linear_anti_aliasing as _linear_anti_aliasing
20
+ )
21
+ from firewxpy.utils.standard import(
22
+ plot_creation_time as _plot_creation_time,
23
+ get_timezone_abbreviation as _get_timezone_abbreviation
24
+ )
25
+
26
+ from firewxpy.utils.directory import build_directory_branch as _build_directory_branch
27
+
28
+ _plt.rcParams["axes.labelweight"] = "bold"
29
+ _mpl.rcParams['font.weight'] = 'bold'
30
+ _pd.options.mode.copy_on_write = True
31
+ _local, _utc = _plot_creation_time()
32
+ _timezone = _get_timezone_abbreviation()
33
+
34
+ def plot_temperature_relative_humidity_wind_profile(station_id,
35
+ current=True,
36
+ custom_time=None,
37
+ proxies=None,
38
+ clear_recycle_bin=False,
39
+ path='FireWxPy Graphics/Observations/Upper Air/Temperature Relative Humidity Wind Profiles',
40
+ to_fahrenheit=False,
41
+ to_kelvin=False,
42
+ to_meters=False,
43
+ to_feet=True,
44
+ to_mph=True,
45
+ to_mps=False,
46
+ anti_aliasing=100,
47
+ temperature_colormap='coolwarm',
48
+ temperature_alpha=1,
49
+ relative_humidity_colormap='BrBG',
50
+ relative_humidity_alpha=1,
51
+ wind_colormap='rainbow',
52
+ wind_barb_length=5,
53
+ wind_barb_alpha=1,
54
+ y_bottom=0,
55
+ y_top=10000,
56
+ fig_x=15,
57
+ fig_y=8,
58
+ signature_box_x=0.85,
59
+ signature_box_y=-0.15,
60
+ signature_box_style='round',
61
+ signature_box_color='steelblue',
62
+ signature_box_alpha=0.5,
63
+ signature_fontsize=8,
64
+ signature_fontcolor='black',
65
+ x_title_position=0.015,
66
+ title_1_fontsize=14,
67
+ title_1_box_style='round',
68
+ title_1_box_color='steelblue',
69
+ title_1_box_alpha=0.5,
70
+ title_1_fontcolor='black',
71
+ title_2_fontsize=12,
72
+ title_2_box_style='round',
73
+ title_2_box_color='crimson',
74
+ title_2_box_alpha=0.5,
75
+ title_2_fontcolor='black',
76
+ title_2_y_position=1,
77
+ title_3_fontsize=12,
78
+ title_3_box_style='round',
79
+ title_3_box_color='lime',
80
+ title_3_box_alpha=0.5,
81
+ title_3_fontcolor='black',
82
+ title_3_y_position=1,
83
+ title_4_fontsize=12,
84
+ title_4_box_style='round',
85
+ title_4_box_color='orange',
86
+ title_4_box_alpha=0.5,
87
+ title_4_fontcolor='black',
88
+ title_4_y_position=1,
89
+ x_axis1_box_style='round',
90
+ x_axis1_box_color='crimson',
91
+ x_axis1_box_alpha=0.5,
92
+ x_axis2_box_style='round',
93
+ x_axis2_box_color='lime',
94
+ x_axis2_box_alpha=0.5,
95
+ x_axis3_box_style='round',
96
+ x_axis3_box_color='orange',
97
+ x_axis3_box_alpha=0.5,
98
+ x_axis_label_fontsize=12,
99
+ y_axis_label_fontsize=12,
100
+ axes_label_color='black',
101
+ xtick_color='black',
102
+ ytick_color='black',
103
+ facecolor='lavender',
104
+ df=None,
105
+ date=None,
106
+ subplot_background_color='silver'):
107
+
108
+
109
+ """
110
+ This function plots an observed temperature/relative humidity/wind profile from an atmospheric sounding.
111
+
112
+ Required Arguments:
113
+
114
+ 1) station_id (String) - The station ID for the sounding site.
115
+
116
+ Optional Arguments:
117
+
118
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
119
+ when plotting past soundings.
120
+
121
+ 2) custom_time (String) - Default=None. When plotting archived sounding data, specify the custom time as a string in the
122
+ form of 'YYYY-mm-dd:HH'.
123
+
124
+ 3) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
125
+
126
+ proxies=None ---> proxies={
127
+ 'http':'http://your-proxy-address:port',
128
+ 'https':'http://your-proxy-address:port'
129
+ }
130
+
131
+ 4) clear_recycle_bin (Boolean) - Default=False, When set to True,
132
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
133
+ This setting is to help preserve memory on the machine.
134
+
135
+ 5) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Temperature Relative Humidity Wind Profiles'. The path where
136
+ the graphic will save.
137
+
138
+ 6) to_fahrenheit (Boolean) - Default=False. Set to True for temperature in Fahrenheit.
139
+
140
+ 7) to_kelvin (Boolean) - Default=False. Set to True for temperature in Kelvin.
141
+
142
+ 8) to_meters (Boolean) - Default=False. Set to True for height in meters.
143
+
144
+ 9) to_feet (Boolean) - Default=True. Set to True for height in feet.
145
+
146
+ 10) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
147
+
148
+ 11) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
149
+
150
+ 12) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
151
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
152
+ appears as a line but is a series of colormapped scatter points.
153
+
154
+ 13) temperature_colormap (String) - Default='coolwarm'. The colormap for the temperature line.
155
+
156
+ 14) temperature_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
157
+ 0 = Completely Transparent, 1 = Completely Opaque.
158
+
159
+ 15) relative_humidity_colormap (String) - Default='BrBG'. The colormap for the relative humidity line.
160
+
161
+ 16) relative_humidity_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
162
+ 0 = Completely Transparent, 1 = Completely Opaque.
163
+
164
+ 17) wind_colormap (String) - Default='rainbow'. The colormap of the wind barbs.
165
+
166
+ 18) wind_barb_length (Integer) - Default=5. The length of the wind barb.
167
+
168
+ 19) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
169
+ 0 = Completely Transparent, 1 = Completely Opaque.
170
+
171
+ 20) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
172
+
173
+ 21) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
174
+
175
+ 22) fig_x (Integer) - Default=15. The x-length of the figure.
176
+
177
+ 23) fig_y (Integer) - Default=8. The y-length of the figure.
178
+
179
+ 24) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
180
+
181
+ 25) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
182
+
183
+ 26) signature_box_style (String) - Default='round'. The style of the text box.
184
+
185
+ 27) signature_box_color (String) - Default='steelblue'. The color of the text box.
186
+
187
+ 28) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
188
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
189
+
190
+ 29) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
191
+
192
+ 30) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
193
+
194
+ 31) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
195
+
196
+ 32) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
197
+
198
+ 33) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
199
+
200
+ 34) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
201
+
202
+ 35) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
203
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
204
+
205
+ 36) title_1_fontcolor (String) - Default='black'. Font color of the first subplot title.
206
+
207
+ 37) title_2_fontsize (Integer) - Default=12. Font size of the first subplot title.
208
+
209
+ 38) title_2_box_style (String) - Default='round'. Text box style of the first subplot text box.
210
+
211
+ 39) title_2_box_color (String) - Default='crimson'. Text box color of the first subplot text box.
212
+
213
+ 40) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
214
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
215
+
216
+ 41) title_2_fontcolor (String) - Default='black'. Font color of the first subplot title.
217
+
218
+ 42) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the second subplot text box.
219
+
220
+ 43) title_3_fontsize (Integer) - Default=12. Font size of the second subplot title.
221
+
222
+ 44) title_3_box_style (String) - Default='round'. Text box style of the second subplot text box.
223
+
224
+ 45) title_3_box_color (String) - Default='crimson'. Text box color of the second subplot text box.
225
+
226
+ 46) title_3_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
227
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
228
+
229
+ 47) title_3_fontcolor (String) - Default='black'. Font color of the second subplot title.
230
+
231
+ 48) title_3_y_position (Float or Integer) - Default=1. The y-axis positon of the second subplot text box.
232
+
233
+ 49) title_4_fontsize (Integer) - Default=12. Font size of the third subplot title.
234
+
235
+ 50) title_4_box_style (String) - Default='round'. Text box style of the third subplot text box.
236
+
237
+ 51) title_4_box_color (String) - Default='crimson'. Text box color of the third subplot text box.
238
+
239
+ 52) title_4_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
240
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
241
+
242
+ 53) title_4_fontcolor (String) - Default='black'. Font color of the third subplot title.
243
+
244
+ 54) title_4_y_position (Float or Integer) - Default=1. The y-axis positon of the third subplot text box.
245
+
246
+ 55) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
247
+
248
+ 56) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
249
+
250
+ 57) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
251
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
252
+
253
+ 58) x_axis2_box_style (String) - Default='round'. Text box style of the second subplot x-axis text box.
254
+
255
+ 59) x_axis2_box_color (String) - Default='crimson'. Text box color of the second subplot x-axis text box.
256
+
257
+ 60) x_axis2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
258
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
259
+
260
+ 61) x_axis3_box_style (String) - Default='round'. Text box style of the third subplot x-axis text box.
261
+
262
+ 62) x_axis3_box_color (String) - Default='crimson'. Text box color of the third subplot x-axis text box.
263
+
264
+ 63) x_axis3_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
265
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
266
+
267
+ 64) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
268
+
269
+ 65) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
270
+
271
+ 66) axes_label_color (String) - Default='black'. The color of the labels on each axis.
272
+
273
+ 67) xtick_color (String) - Default='black'. The color of the x-ticks.
274
+
275
+ 68) ytick_color (String) - Default='black'. The color of the y-ticks.
276
+
277
+ 70) facecolor (String) - Default='lavander'. The face color of the figure.
278
+
279
+ 71) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
280
+ and pass those data frames into the plotting function, set df=df.
281
+
282
+ 72) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
283
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
284
+ is not downloading the data within the function.
285
+
286
+ 73) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
287
+
288
+ Returns
289
+ -------
290
+
291
+ A figure of the vertical profiles saved to {path}
292
+ """
293
+
294
+ _build_directory_branch(path)
295
+
296
+ if df == None:
297
+ df, date = _get_observed_sounding_data(station_id,
298
+ current=current,
299
+ custom_time=custom_time,
300
+ comparison_24=False,
301
+ proxies=proxies,
302
+ clear_recycle_bin=clear_recycle_bin)
303
+ else:
304
+ df = df
305
+ date = date
306
+
307
+
308
+ pressure = df['PRES'].values * _units('hPa')
309
+
310
+ height = _mpcalc.pressure_to_height_std(pressure)
311
+
312
+ if to_meters == True and to_feet == False:
313
+ height = _calc.kilometers_to_meters(height)
314
+ height_symbol = f"[M]"
315
+
316
+ elif to_feet == True and to_meters == False:
317
+ height = _calc.kilometers_to_meters(height)
318
+ height = _calc.meters_to_feet(height)
319
+ height_symbol = f"[FT]"
320
+ else:
321
+ height = height
322
+ height_symbol = f"[KM]"
323
+
324
+ df['HGHT'] = height.m
325
+
326
+ if to_fahrenheit == True and to_kelvin == False:
327
+ df['TEMP'] = _calc.celsius_to_fahrenheit(df['TEMP'])
328
+ temperature_symbol = f"[°F]"
329
+ elif to_kelvin == True and to_fahrenheit == False:
330
+ df['TEMP'] = _calc.celsius_to_kelvin(df['TEMP'])
331
+ temperature_symbol = f"[K]"
332
+ else:
333
+ temperature_symbol = f"[°C]"
334
+
335
+ if to_mph == True and to_mps == False:
336
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
337
+ ws_symbol = f"[MPH]"
338
+ elif to_mph == False and to_mps == True:
339
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
340
+ ws_symbol = f"[M/S]"
341
+ else:
342
+ ws_symbol = f"[KTS]"
343
+
344
+ if title_1_box_alpha < 0.5:
345
+ title_1_box_alpha = 0.5
346
+ if title_2_box_alpha < 0.5:
347
+ title_2_box_alpha = 0.5
348
+ if title_3_box_alpha < 0.5:
349
+ title_3_box_alpha = 0.5
350
+ if title_4_box_alpha < 0.5:
351
+ title_4_box_alpha = 0.5
352
+ if signature_box_alpha < 0.5:
353
+ signature_box_alpha = 0.5
354
+ if x_axis1_box_alpha < 0.5:
355
+ x_axis1_box_alpha = 0.5
356
+ if x_axis2_box_alpha < 0.5:
357
+ x_axis2_box_alpha = 0.5
358
+ if x_axis3_box_alpha < 0.5:
359
+ x_axis3_box_alpha = 0.5
360
+
361
+ title_1_box = dict(boxstyle=title_1_box_style,
362
+ facecolor=title_1_box_color,
363
+ alpha=title_1_box_alpha)
364
+
365
+ title_2_box = dict(boxstyle=title_2_box_style,
366
+ facecolor=title_2_box_color,
367
+ alpha=title_2_box_alpha)
368
+
369
+ title_3_box = dict(boxstyle=title_3_box_style,
370
+ facecolor=title_3_box_color,
371
+ alpha=title_3_box_alpha)
372
+
373
+ title_4_box = dict(boxstyle=title_4_box_style,
374
+ facecolor=title_4_box_color,
375
+ alpha=title_4_box_alpha)
376
+
377
+ props = dict(boxstyle=signature_box_style,
378
+ facecolor=signature_box_color,
379
+ alpha=signature_box_alpha)
380
+
381
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
382
+ facecolor=x_axis1_box_color,
383
+ alpha=x_axis1_box_alpha)
384
+
385
+ x_axis2_box = dict(boxstyle=x_axis2_box_style,
386
+ facecolor=x_axis2_box_color,
387
+ alpha=x_axis2_box_alpha)
388
+
389
+ x_axis3_box = dict(boxstyle=x_axis3_box_style,
390
+ facecolor=x_axis3_box_color,
391
+ alpha=x_axis3_box_alpha)
392
+
393
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
394
+ _mpl.rcParams['xtick.color'] = xtick_color
395
+ _mpl.rcParams['ytick.color'] = ytick_color
396
+
397
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
398
+
399
+ df['HGHT']
400
+
401
+ temp_x, temp_y = _linear_anti_aliasing(df['TEMP'][mask],
402
+ df['HGHT'][mask],
403
+ anti_aliasing)
404
+
405
+ rh_x, rh_y = _linear_anti_aliasing(df['RH'][mask],
406
+ df['HGHT'][mask],
407
+ anti_aliasing)
408
+
409
+ ws_x, ws_y = _linear_anti_aliasing(df['SKNT'][mask],
410
+ df['HGHT'][mask],
411
+ anti_aliasing)
412
+
413
+ fig = _plt.figure(figsize=(fig_x, fig_y))
414
+ fig.patch.set_facecolor(facecolor)
415
+
416
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
417
+ f" | VALID: {date.strftime('%m/%d/%Y %H:00 UTC')}",
418
+ fontsize=title_1_fontsize,
419
+ fontweight='bold',
420
+ color=title_1_fontcolor,
421
+ bbox=title_1_box)
422
+
423
+ ax1 = fig.add_subplot(1,3,1)
424
+ ax1.set_facecolor(subplot_background_color)
425
+ ax1.xaxis.set_major_locator(_MaxNLocator(integer=True))
426
+ ax1.yaxis.set_major_locator(_MaxNLocator(integer=True))
427
+
428
+ ax1.set_xlim((_np.nanmin(df['TEMP'][mask]) - 5), (_np.nanmax(df['TEMP'][mask]) + 5))
429
+ ax1.set_ylim(y_bottom, y_top)
430
+
431
+ ax1.set_xlabel(f"TEMPERATURE {temperature_symbol}",
432
+ fontsize=x_axis_label_fontsize,
433
+ fontweight='bold',
434
+ bbox=x_axis1_box)
435
+
436
+ ax1.set_ylabel(f"HEIGHT {height_symbol}",
437
+ fontsize=y_axis_label_fontsize,
438
+ fontweight='bold',
439
+ bbox=title_1_box)
440
+
441
+ ax1.set_title(f"TEMPERATURE",
442
+ fontweight='bold',
443
+ loc='left',
444
+ x=x_title_position,
445
+ fontsize=title_2_fontsize,
446
+ color=title_2_fontcolor,
447
+ bbox=title_2_box,
448
+ y=title_2_y_position)
449
+
450
+ ax1.scatter(temp_x,
451
+ temp_y,
452
+ c=temp_x,
453
+ vmin=_np.nanmin(df['TEMP'][mask]),
454
+ vmax=_np.nanmax(df['TEMP'][mask]),
455
+ cmap=temperature_colormap,
456
+ alpha=temperature_alpha)
457
+
458
+ ax1.text(signature_box_x,
459
+ signature_box_y,
460
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
461
+ f"| Data Source: weather.uwyo.edu\n"
462
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
463
+ fontsize=signature_fontsize,
464
+ bbox=props,
465
+ fontweight='bold',
466
+ color=signature_fontcolor,
467
+ transform=ax1.transAxes)
468
+
469
+
470
+ ax2 = fig.add_subplot(1,3,2)
471
+ ax2.set_facecolor(subplot_background_color)
472
+ ax2.xaxis.set_major_locator(_MaxNLocator(integer=True))
473
+ ax2.yaxis.set_major_locator(_MaxNLocator(integer=True))
474
+
475
+ ax2.set_xlim(0, 100)
476
+ ax2.set_ylim(y_bottom, y_top)
477
+ ax2.set_title(f"RELATIVE HUMIDITY",
478
+ fontweight='bold',
479
+ loc='left',
480
+ x=x_title_position,
481
+ fontsize=title_3_fontsize,
482
+ color=title_3_fontcolor,
483
+ bbox=title_3_box,
484
+ y=title_3_y_position)
485
+
486
+ ax2.scatter(rh_x,
487
+ rh_y,
488
+ c=rh_x,
489
+ vmin=_np.nanmin(df['RH'][mask]),
490
+ vmax=_np.nanmax(df['RH'][mask]),
491
+ cmap=relative_humidity_colormap,
492
+ alpha=relative_humidity_alpha)
493
+
494
+ ax2.set_xlabel(f"RELATIVE HUMIDITY [%]",
495
+ fontsize=x_axis_label_fontsize,
496
+ fontweight='bold',
497
+ bbox=x_axis2_box)
498
+
499
+
500
+ ax3 = fig.add_subplot(1,3,3)
501
+ ax3.set_facecolor(subplot_background_color)
502
+ ax3.xaxis.set_major_locator(_MaxNLocator(integer=True))
503
+ ax3.yaxis.set_major_locator(_MaxNLocator(integer=True))
504
+
505
+ ax3.set_xlim((_np.nanmin(df['SKNT'][mask]) - 5), (_np.nanmax(df['SKNT'][mask]) + 5))
506
+ ax3.set_ylim(y_bottom, y_top)
507
+ ax3.set_title(f"WIND SPEED",
508
+ fontweight='bold',
509
+ loc='left',
510
+ x=x_title_position,
511
+ fontsize=title_4_fontsize,
512
+ color=title_4_fontcolor,
513
+ bbox=title_4_box,
514
+ y=title_4_y_position)
515
+
516
+ ax3.scatter(ws_x,
517
+ ws_y,
518
+ c=ws_x,
519
+ vmin=_np.nanmin(df['SKNT'][mask]),
520
+ vmax=_np.nanmax(df['SKNT'][mask]),
521
+ cmap=wind_colormap)
522
+
523
+ x_positions = []
524
+ x_position = (_np.nanmin(df['SKNT'][mask]) + _np.nanmax(df['SKNT'][mask]))/2
525
+ for i in range(0, len(df['HGHT'][mask]), 1):
526
+ x_positions.append(x_position)
527
+
528
+ x_position = _np.asarray(x_positions)
529
+
530
+
531
+ ax3.barbs(x_position,
532
+ df['HGHT'][mask],
533
+ df['U-WIND'][mask],
534
+ df['V-WIND'][mask],
535
+ df['SKNT'][mask],
536
+ cmap=wind_colormap,
537
+ length=wind_barb_length,
538
+ alpha=wind_barb_alpha)
539
+
540
+ ax3.set_xlabel(f"WIND SPEED {ws_symbol}",
541
+ fontsize=x_axis_label_fontsize,
542
+ fontweight='bold',
543
+ bbox=x_axis3_box)
544
+
545
+ fig.savefig(f"{path}/{station_id.upper()}.png",
546
+ bbox_inches='tight')
547
+
548
+ _plt.close(fig)
549
+
550
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
551
+
552
+
553
+ def plot_temperature_wind_profile(station_id,
554
+ current=True,
555
+ custom_time=None,
556
+ proxies=None,
557
+ clear_recycle_bin=False,
558
+ path='FireWxPy Graphics/Observations/Upper Air/Temperature Wind Profiles',
559
+ to_fahrenheit=True,
560
+ to_kelvin=False,
561
+ to_meters=False,
562
+ to_feet=True,
563
+ to_mph=True,
564
+ to_mps=False,
565
+ anti_aliasing=100,
566
+ temperature_colormap='coolwarm',
567
+ temperature_alpha=1,
568
+ wind_colormap='rainbow',
569
+ wind_barb_length=7,
570
+ wind_barb_alpha=1,
571
+ y_bottom=0,
572
+ y_top=10000,
573
+ fig_x=15,
574
+ fig_y=8,
575
+ signature_box_x=0.25,
576
+ signature_box_y=-0.15,
577
+ signature_box_style='round',
578
+ signature_box_color='steelblue',
579
+ signature_box_alpha=0.5,
580
+ signature_fontsize=8,
581
+ signature_fontcolor='black',
582
+ title_1_fontsize=14,
583
+ title_1_box_style='round',
584
+ title_1_box_color='steelblue',
585
+ title_1_box_alpha=0.5,
586
+ title_1_fontcolor='black',
587
+ title_2_fontsize=12,
588
+ title_2_box_style='round',
589
+ title_2_box_color='crimson',
590
+ title_2_box_alpha=0.5,
591
+ title_2_fontcolor='black',
592
+ title_2_y_position=1,
593
+ title_3_fontcolor='black',
594
+ x_axis1_box_style='round',
595
+ x_axis1_box_color='crimson',
596
+ x_axis1_box_alpha=0.5,
597
+ max_temperature_text_box_x_position=0.01,
598
+ max_temperature_text_box_y_position=0.975,
599
+ max_temperature_text_box_style='round',
600
+ max_temperature_text_box_color='crimson',
601
+ max_temperature_text_box_alpha=1,
602
+ min_temperature_text_box_x_position=0.415,
603
+ min_temperature_text_box_y_position=0.975,
604
+ min_temperature_text_box_style='round',
605
+ min_temperature_text_box_color='cyan',
606
+ min_temperature_text_box_alpha=1,
607
+ max_wind_text_box_x_position=0.75,
608
+ max_wind_text_box_y_position=0.975,
609
+ max_wind_text_box_style='round',
610
+ max_wind_text_box_color='orange',
611
+ max_wind_text_box_alpha=1,
612
+ x_axis_label_fontsize=12,
613
+ y_axis_label_fontsize=12,
614
+ axes_label_color='black',
615
+ legend_fontsize=10,
616
+ xtick_color='black',
617
+ ytick_color='black',
618
+ facecolor='lavender',
619
+ df=None,
620
+ date=None,
621
+ subplot_background_color='silver'):
622
+
623
+
624
+ """
625
+ This function plots an observed temperature/wind profile from an atmospheric sounding.
626
+
627
+ Required Arguments:
628
+
629
+ 1) station_id (String) - The station ID for the sounding site.
630
+
631
+ Optional Arguments:
632
+
633
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
634
+ when plotting past soundings.
635
+
636
+ 2) custom_time (String) - Default=None. When plotting archived sounding data, specify the custom time as a string in the
637
+ form of 'YYYY-mm-dd:HH'.
638
+
639
+ 3) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
640
+
641
+ proxies=None ---> proxies={
642
+ 'http':'http://your-proxy-address:port',
643
+ 'https':'http://your-proxy-address:port'
644
+ }
645
+
646
+ 4) clear_recycle_bin (Boolean) - Default=False, When set to True,
647
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
648
+ This setting is to help preserve memory on the machine.
649
+
650
+ 5) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Temperature Wind Profiles'. The path where
651
+ the graphic will save.
652
+
653
+ 6) to_fahrenheit (Boolean) - Default=False. Set to True for temperature in Fahrenheit.
654
+
655
+ 7) to_kelvin (Boolean) - Default=False. Set to True for temperature in Kelvin.
656
+
657
+ 8) to_meters (Boolean) - Default=False. Set to True for height in meters.
658
+
659
+ 9) to_feet (Boolean) - Default=True. Set to True for height in feet.
660
+
661
+ 10) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
662
+
663
+ 11) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
664
+
665
+ 12) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
666
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
667
+ appears as a line but is a series of colormapped scatter points.
668
+
669
+ 13) temperature_colormap (String) - Default='coolwarm'. The colormap for the temperature line.
670
+
671
+ 14) temperature_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
672
+ 0 = Completely Transparent, 1 = Completely Opaque.
673
+
674
+ 15) wind_colormap (String) - Default='rainbow'. The colormap of the wind barbs.
675
+
676
+ 16) wind_barb_length (Integer) - Default=5. The length of the wind barb.
677
+
678
+ 17) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
679
+ 0 = Completely Transparent, 1 = Completely Opaque.
680
+
681
+ 18) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
682
+
683
+ 19) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
684
+
685
+ 20) fig_x (Integer) - Default=15. The x-length of the figure.
686
+
687
+ 21) fig_y (Integer) - Default=8. The y-length of the figure.
688
+
689
+ 22) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
690
+
691
+ 23) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
692
+
693
+ 24) signature_box_style (String) - Default='round'. The style of the text box.
694
+
695
+ 25) signature_box_color (String) - Default='steelblue'. The color of the text box.
696
+
697
+ 26) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
698
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
699
+
700
+ 27) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
701
+
702
+ 28) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
703
+
704
+ 29) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
705
+
706
+ 30) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
707
+
708
+ 31) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
709
+
710
+ 32) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
711
+
712
+ 33) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
713
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
714
+
715
+ 34) title_1_fontcolor (String) - Default='black'. Font color of the figure title.
716
+
717
+ 35) title_2_fontsize (Integer) - Default=12. Font size of the first subplot title.
718
+
719
+ 36) title_2_box_style (String) - Default='round'. Text box style of the subplot title text box.
720
+
721
+ 37) title_2_box_color (String) - Default='crimson'. Text box color of the subplot title text box.
722
+
723
+ 38) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
724
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
725
+
726
+ 39) title_2_fontcolor (String) - Default='black'. Font color of the subplot title.
727
+
728
+ 40) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the subplot title text box.
729
+
730
+ 41) title_3_fontcolor (String) - Default='black'. Font color of the tertiary subplot titles.
731
+
732
+ 42) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
733
+
734
+ 43) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
735
+
736
+ 44) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
737
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
738
+
739
+ 45) x_axis1_box_style (String) - Default='round'. Text box style for the general x-axis text box.
740
+
741
+ 46) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
742
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
743
+
744
+ 47) max_temperature_text_box_x_position (Float) - Default=0.01. x-position of the maximum temperature text box
745
+ with respect to the figure axis.
746
+
747
+ 48) max_temperature_text_box_y_position (Float) - Default=0.975. y-position of the maximum temperature text box
748
+ with respect to the figure axis.
749
+
750
+ 49) max_temperature_text_box_style (String) - Default='round'. Style of the maximum temperature text box.
751
+
752
+ 50) max_temperature_text_box_color (String) - Default='crimson'. Color of the maximum temperature text box.
753
+
754
+ 51) max_temperature_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
755
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
756
+
757
+ 52) min_temperature_text_box_x_position (Float) - Default=0.415. x-position of the minimum temperature text box
758
+ with respect to the figure axis.
759
+
760
+ 53) min_temperature_text_box_y_position (Float) - Default=0.975. y-position of the minimum temperature text box
761
+ with respect to the figure axis.
762
+
763
+ 54) min_temperature_text_box_style (String) - Default='round'. Style of the minimum temperature text box.
764
+
765
+ 55) min_temperature_text_box_color (String) - Default='cyan'. Color of the minimum temperature text box.
766
+
767
+ 56) min_temperature_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
768
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
769
+
770
+ 57) max_wind_text_box_x_position (Float) - Default=0.75. x-position of the maximum wind speed text box
771
+ with respect to the figure axis.
772
+
773
+ 58) max_wind_text_box_y_position (Float) - Default=0.975. y-position of the maximum wind speed text box
774
+ with respect to the figure axis.
775
+
776
+ 59) max_wind_text_box_style (String) - Default='round'. Style of the maximum wind speed text box.
777
+
778
+ 60) max_wind_text_box_color (String) - Default='orange'. Color of the maximum wind speed text box.
779
+
780
+ 61) max_wind_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
781
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
782
+
783
+ 62) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
784
+
785
+ 63) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
786
+
787
+ 64) axes_label_color (String) - Default='black'. The color of the labels on each axis.
788
+
789
+ 65) xtick_color (String) - Default='black'. The color of the x-ticks.
790
+
791
+ 66) ytick_color (String) - Default='black'. The color of the y-ticks.
792
+
793
+ 67) facecolor (String) - Default='lavander'. The face color of the figure.
794
+
795
+ 68) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
796
+ and pass those data frames into the plotting function, set df=df.
797
+
798
+ 69) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
799
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
800
+ is not downloading the data within the function.
801
+
802
+ 70) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
803
+
804
+ Returns
805
+ -------
806
+
807
+ A figure of the vertical profiles saved to {path}
808
+ """
809
+
810
+ _build_directory_branch(path)
811
+
812
+ if df == None:
813
+ df, date = _get_observed_sounding_data(station_id,
814
+ current=current,
815
+ custom_time=custom_time,
816
+ comparison_24=False,
817
+ proxies=proxies,
818
+ clear_recycle_bin=clear_recycle_bin)
819
+ else:
820
+ df = df
821
+ date = date
822
+
823
+
824
+ pressure = df['PRES'].values * _units('hPa')
825
+
826
+ height = _mpcalc.pressure_to_height_std(pressure)
827
+
828
+ if to_meters == True and to_feet == False:
829
+ height = _calc.kilometers_to_meters(height)
830
+ height_symbol = f"[M]"
831
+
832
+ elif to_feet == True and to_meters == False:
833
+ height = _calc.kilometers_to_meters(height)
834
+ height = _calc.meters_to_feet(height)
835
+ height_symbol = f"[FT]"
836
+ else:
837
+ height = height
838
+ height_symbol = f"[KM]"
839
+
840
+ df['HGHT'] = height.m
841
+
842
+ if to_fahrenheit == True and to_kelvin == False:
843
+ df['TEMP'] = _calc.celsius_to_fahrenheit(df['TEMP'])
844
+ temperature_symbol = f"[°F]"
845
+ elif to_kelvin == True and to_fahrenheit == False:
846
+ df['TEMP'] = _calc.celsius_to_kelvin(df['TEMP'])
847
+ temperature_symbol = f"[K]"
848
+ else:
849
+ temperature_symbol = f"[°C]"
850
+
851
+ if to_mph == True and to_mps == False:
852
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
853
+ ws_symbol = f"[MPH]"
854
+ elif to_mph == False and to_mps == True:
855
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
856
+ ws_symbol = f"[M/S]"
857
+ else:
858
+ ws_symbol = f"[KTS]"
859
+
860
+ if title_1_box_alpha < 0.5:
861
+ title_1_box_alpha = 0.5
862
+ if title_2_box_alpha < 0.5:
863
+ title_2_box_alpha = 0.5
864
+ if max_temperature_text_box_alpha < 0.5:
865
+ max_temperature_text_box_alpha = 0.5
866
+ if min_temperature_text_box_alpha < 0.5:
867
+ min_temperature_text_box_alpha = 0.5
868
+ if signature_box_alpha < 0.5:
869
+ signature_box_alpha = 0.5
870
+ if x_axis1_box_alpha < 0.5:
871
+ x_axis1_box_alpha = 0.5
872
+ if max_wind_text_box_alpha < 0.5:
873
+ max_wind_text_box_alpha = 0.5
874
+
875
+ title_1_box = dict(boxstyle=title_1_box_style,
876
+ facecolor=title_1_box_color,
877
+ alpha=title_1_box_alpha)
878
+
879
+ title_2_box = dict(boxstyle=title_2_box_style,
880
+ facecolor=title_2_box_color,
881
+ alpha=title_2_box_alpha)
882
+
883
+ maxt_box = dict(boxstyle=max_temperature_text_box_style,
884
+ facecolor=max_temperature_text_box_color,
885
+ alpha=max_temperature_text_box_alpha)
886
+
887
+ mint_box = dict(boxstyle=min_temperature_text_box_style,
888
+ facecolor=min_temperature_text_box_color,
889
+ alpha=min_temperature_text_box_alpha)
890
+
891
+ maxws_box = dict(boxstyle=max_wind_text_box_style,
892
+ facecolor=max_wind_text_box_color,
893
+ alpha=max_wind_text_box_alpha)
894
+
895
+ props = dict(boxstyle=signature_box_style,
896
+ facecolor=signature_box_color,
897
+ alpha=signature_box_alpha)
898
+
899
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
900
+ facecolor=x_axis1_box_color,
901
+ alpha=x_axis1_box_alpha)
902
+
903
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
904
+ _mpl.rcParams['xtick.color'] = xtick_color
905
+ _mpl.rcParams['ytick.color'] = ytick_color
906
+
907
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
908
+
909
+ temp_x, temp_y = _linear_anti_aliasing(df['TEMP'][mask],
910
+ df['HGHT'][mask],
911
+ anti_aliasing)
912
+
913
+ min_t_height = _np.nanmax(_np.where(df['TEMP'][mask] == _np.nanmin(df['TEMP'][mask]),
914
+ df['HGHT'][mask],
915
+ 0))
916
+
917
+ max_t_height = _np.nanmax(_np.where(df['TEMP'][mask] == _np.nanmax(df['TEMP'][mask]),
918
+ df['HGHT'][mask],
919
+ 0))
920
+
921
+ max_ws_height = _np.nanmax(_np.where(df['SKNT'][mask] == _np.nanmax(df['SKNT'][mask]),
922
+ df['HGHT'][mask],
923
+ 0))
924
+
925
+ fig = _plt.figure(figsize=(fig_x, fig_y))
926
+ fig.patch.set_facecolor(facecolor)
927
+
928
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
929
+ f" | VALID: {date.strftime('%m/%d/%Y %H:00 UTC')}",
930
+ fontsize=title_1_fontsize,
931
+ fontweight='bold',
932
+ color=title_1_fontcolor,
933
+ bbox=title_1_box)
934
+
935
+ ax = fig.add_subplot(1,1,1)
936
+ ax.set_facecolor(subplot_background_color)
937
+ ax.xaxis.set_major_locator(_MaxNLocator(integer=True))
938
+ ax.yaxis.set_major_locator(_MaxNLocator(integer=True))
939
+
940
+ ax.set_xlim((_np.nanmin(df['TEMP'][mask]) - 5), (_np.nanmax(df['TEMP'][mask]) + 5))
941
+ ax.set_ylim(y_bottom, y_top)
942
+
943
+ ax.set_xlabel(f"TEMPERATURE {temperature_symbol}",
944
+ fontsize=x_axis_label_fontsize,
945
+ fontweight='bold',
946
+ bbox=x_axis1_box)
947
+
948
+ ax.set_ylabel(f"HEIGHT {height_symbol}",
949
+ fontsize=y_axis_label_fontsize,
950
+ fontweight='bold',
951
+ bbox=title_1_box)
952
+
953
+ ax.set_title(f"TEMPERATURE {temperature_symbol} & WIND SPEED {ws_symbol}",
954
+ fontweight='bold',
955
+ loc='center',
956
+ fontsize=title_2_fontsize,
957
+ color=title_2_fontcolor,
958
+ bbox=title_2_box,
959
+ y=title_2_y_position)
960
+
961
+ ax.scatter(temp_x,
962
+ temp_y,
963
+ c=temp_x,
964
+ vmin=_np.nanmin(df['TEMP'][mask]),
965
+ vmax=_np.nanmax(df['TEMP'][mask]),
966
+ cmap=temperature_colormap,
967
+ alpha=temperature_alpha)
968
+
969
+ ax.text(signature_box_x,
970
+ signature_box_y,
971
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
972
+ f"| Data Source: weather.uwyo.edu\n"
973
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
974
+ fontsize=signature_fontsize,
975
+ bbox=props,
976
+ fontweight='bold',
977
+ color=signature_fontcolor,
978
+ transform=ax.transAxes)
979
+
980
+ ax.text(max_temperature_text_box_x_position,
981
+ max_temperature_text_box_y_position,
982
+ f"MAX T: {int(round(_np.nanmax(df['TEMP'][mask]), 0))} {temperature_symbol} @ {int(round(max_t_height, 0))} {height_symbol}",
983
+ fontsize=legend_fontsize,
984
+ bbox=maxt_box,
985
+ fontweight='bold',
986
+ color=title_3_fontcolor,
987
+ transform=ax.transAxes)
988
+
989
+ ax.text(min_temperature_text_box_x_position,
990
+ min_temperature_text_box_y_position,
991
+ f"MIN T: {int(round(_np.nanmin(df['TEMP'][mask]), 0))} {temperature_symbol} @ {int(round(min_t_height, 0))} {height_symbol}",
992
+ fontsize=legend_fontsize,
993
+ bbox=mint_box,
994
+ fontweight='bold',
995
+ color=title_3_fontcolor,
996
+ transform=ax.transAxes)
997
+
998
+ ax.text(max_wind_text_box_x_position,
999
+ max_wind_text_box_y_position,
1000
+ f"MAX WIND: {int(round(_np.nanmax(df['SKNT'][mask]), 0))} {ws_symbol} @ {int(round(max_ws_height, 0))} {height_symbol}",
1001
+ fontsize=legend_fontsize,
1002
+ bbox=maxws_box,
1003
+ fontweight='bold',
1004
+ color=title_3_fontcolor,
1005
+ transform=ax.transAxes)
1006
+
1007
+ x_positions = []
1008
+ x_position = (_np.nanmin(df['TEMP'][mask]) + _np.nanmax(df['TEMP'][mask]))/2
1009
+ for i in range(0, len(df['HGHT'][mask]), 1):
1010
+ x_positions.append(x_position)
1011
+
1012
+ x_position = _np.asarray(x_positions)
1013
+
1014
+ ax.barbs(x_position,
1015
+ df['HGHT'][mask],
1016
+ df['U-WIND'][mask],
1017
+ df['V-WIND'][mask],
1018
+ df['SKNT'][mask],
1019
+ cmap=wind_colormap,
1020
+ length=wind_barb_length,
1021
+ alpha=wind_barb_alpha)
1022
+
1023
+ fig.savefig(f"{path}/{station_id.upper()}.png",
1024
+ bbox_inches='tight')
1025
+
1026
+ _plt.close(fig)
1027
+
1028
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
1029
+
1030
+
1031
+ def plot_relative_humidity_wind_profile(station_id,
1032
+ current=True,
1033
+ custom_time=None,
1034
+ proxies=None,
1035
+ clear_recycle_bin=False,
1036
+ path='FireWxPy Graphics/Observations/Upper Air/Relative Humidity Wind Profiles',
1037
+ to_meters=False,
1038
+ to_feet=True,
1039
+ to_mph=True,
1040
+ to_mps=False,
1041
+ anti_aliasing=100,
1042
+ relative_humidity_colormap='BrBG',
1043
+ relative_humidity_alpha=1,
1044
+ wind_colormap='rainbow',
1045
+ wind_barb_length=5,
1046
+ wind_barb_alpha=1,
1047
+ y_bottom=0,
1048
+ y_top=10000,
1049
+ fig_x=15,
1050
+ fig_y=8,
1051
+ signature_box_x=0.25,
1052
+ signature_box_y=-0.15,
1053
+ signature_box_style='round',
1054
+ signature_box_color='steelblue',
1055
+ signature_box_alpha=0.5,
1056
+ signature_fontsize=8,
1057
+ signature_fontcolor='black',
1058
+ title_1_fontsize=14,
1059
+ title_1_box_style='round',
1060
+ title_1_box_color='steelblue',
1061
+ title_1_box_alpha=0.5,
1062
+ title_1_fontcolor='black',
1063
+ title_2_fontsize=12,
1064
+ title_2_box_style='round',
1065
+ title_2_box_color='lime',
1066
+ title_2_box_alpha=0.5,
1067
+ title_2_fontcolor='black',
1068
+ title_2_y_position=1.02,
1069
+ x_axis1_box_style='round',
1070
+ x_axis1_box_color='lime',
1071
+ x_axis1_box_alpha=0.5,
1072
+ min_rh_height_box_style='round',
1073
+ min_rh_height_box_color='saddlebrown',
1074
+ min_rh_height_box_alpha=1,
1075
+ min_rh_height_box_x_position=0.01,
1076
+ min_rh_height_box_y_position=0.975,
1077
+ max_rh_height_box_style='round',
1078
+ max_rh_height_box_color='lime',
1079
+ max_rh_height_box_alpha=1,
1080
+ max_rh_height_box_x_position=0.25,
1081
+ max_rh_height_box_y_position=0.975,
1082
+ rh_range_height_box_style='round',
1083
+ rh_range_height_box_color='lightblue',
1084
+ rh_range_height_box_alpha=1,
1085
+ rh_range_height_box_x_position=0.525,
1086
+ rh_range_height_box_y_position=0.975,
1087
+ max_wind_height_box_style='round',
1088
+ max_wind_height_box_color='crimson',
1089
+ max_wind_height_box_alpha=1,
1090
+ max_wind_height_box_x_position=0.705,
1091
+ max_wind_height_box_y_position=0.975,
1092
+ legend_fontsize=10,
1093
+ x_axis_label_fontsize=12,
1094
+ y_axis_label_fontsize=12,
1095
+ axes_label_color='black',
1096
+ xtick_color='black',
1097
+ ytick_color='black',
1098
+ facecolor='lavender',
1099
+ df=None,
1100
+ date=None,
1101
+ subplot_background_color='silver'):
1102
+
1103
+
1104
+ """
1105
+ This function plots an observed relative humidity/wind profile from an atmospheric sounding.
1106
+
1107
+ Required Arguments:
1108
+
1109
+ 1) station_id (String) - The station ID for the sounding site.
1110
+
1111
+ Optional Arguments:
1112
+
1113
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
1114
+ when plotting past soundings.
1115
+
1116
+ 2) custom_time (String) - Default=None. When plotting archived sounding data, specify the custom time as a string in the
1117
+ form of 'YYYY-mm-dd:HH'.
1118
+
1119
+ 3) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
1120
+
1121
+ proxies=None ---> proxies={
1122
+ 'http':'http://your-proxy-address:port',
1123
+ 'https':'http://your-proxy-address:port'
1124
+ }
1125
+
1126
+ 4) clear_recycle_bin (Boolean) - Default=False, When set to True,
1127
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
1128
+ This setting is to help preserve memory on the machine.
1129
+
1130
+ 5) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Relative Humidity Wind Profiles'. The path where
1131
+ the graphic will save.
1132
+
1133
+ 8) to_meters (Boolean) - Default=False. Set to True for height in meters.
1134
+
1135
+ 9) to_feet (Boolean) - Default=True. Set to True for height in feet.
1136
+
1137
+ 10) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
1138
+
1139
+ 11) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
1140
+
1141
+ 12) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
1142
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
1143
+ appears as a line but is a series of colormapped scatter points.
1144
+
1145
+ 13) relative_humidity_colormap (String) - Default='BrBG'. The colormap for the temperature line.
1146
+
1147
+ 14) relative_humidity_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
1148
+ 0 = Completely Transparent, 1 = Completely Opaque.
1149
+
1150
+ 15) wind_colormap (String) - Default='rainbow'. The colormap of the wind barbs.
1151
+
1152
+ 16) wind_barb_length (Integer) - Default=5. The length of the wind barb.
1153
+
1154
+ 17) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
1155
+ 0 = Completely Transparent, 1 = Completely Opaque.
1156
+
1157
+ 18) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
1158
+
1159
+ 19) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
1160
+
1161
+ 20) fig_x (Integer) - Default=15. The x-length of the figure.
1162
+
1163
+ 21) fig_y (Integer) - Default=8. The y-length of the figure.
1164
+
1165
+ 22) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
1166
+
1167
+ 23) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
1168
+
1169
+ 24) signature_box_style (String) - Default='round'. The style of the text box.
1170
+
1171
+ 25) signature_box_color (String) - Default='steelblue'. The color of the text box.
1172
+
1173
+ 26) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1174
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1175
+
1176
+ 27) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
1177
+
1178
+ 28) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
1179
+
1180
+ 29) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
1181
+
1182
+ 30) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
1183
+
1184
+ 31) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
1185
+
1186
+ 32) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
1187
+
1188
+ 33) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1189
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1190
+
1191
+ 34) title_1_fontcolor (String) - Default='black'. Font color of the figure title.
1192
+
1193
+ 35) title_2_fontsize (Integer) - Default=12. Font size of the subplot title.
1194
+
1195
+ 36) title_2_box_style (String) - Default='round'. Text box style of the subplot title text box.
1196
+
1197
+ 37) title_2_box_color (String) - Default='lime'. Text box color of the subplot title text box.
1198
+
1199
+ 38) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1200
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1201
+
1202
+ 39) title_2_fontcolor (String) - Default='black'. Font color of the subplot title.
1203
+
1204
+ 40) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the subplot text box.
1205
+
1206
+ 41) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
1207
+
1208
+ 42) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
1209
+
1210
+ 43) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1211
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1212
+
1213
+ 44) x_axis1_box_style (String) - Default='round'. Text box style for the general x-axis text box.
1214
+
1215
+ 45) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1216
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1217
+
1218
+ 46) max_rh_text_box_x_position (Float) - Default=0.01. x-position of the maximum relative humidity text box
1219
+ with respect to the figure axis.
1220
+
1221
+ 47) max_rh_text_box_y_position (Float) - Default=0.975. y-position of the maximum relative humidity text box
1222
+ with respect to the figure axis.
1223
+
1224
+ 48) max_rh_text_box_style (String) - Default='round'. Style of the maximum relative humidity text box.
1225
+
1226
+ 49) max_rh_text_box_color (String) - Default='crimson'. Color of the maximum relative humidity text box.
1227
+
1228
+ 50) max_rh_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1229
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1230
+
1231
+ 51) min_rh_text_box_x_position (Float) - Default=0.415. x-position of the minimum relative humidity text box
1232
+ with respect to the figure axis.
1233
+
1234
+ 52) min_rh_text_box_y_position (Float) - Default=0.975. y-position of the minimum relative humidity text box
1235
+ with respect to the figure axis.
1236
+
1237
+ 53) min_rh_text_box_style (String) - Default='round'. Style of the minimum relative humidity text box.
1238
+
1239
+ 54) min_rh_text_box_color (String) - Default='saddlebrown'. Color of the minimum relative humidity text box.
1240
+
1241
+ 55) min_rh_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1242
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1243
+
1244
+ 56) max_wind_text_box_x_position (Float) - Default=0.75. x-position of the maximum wind speed text box
1245
+ with respect to the figure axis.
1246
+
1247
+ 57) max_wind_text_box_y_position (Float) - Default=0.975. y-position of the maximum wind speed text box
1248
+ with respect to the figure axis.
1249
+
1250
+ 58) max_wind_text_box_style (String) - Default='round'. Style of the maximum wind speed text box.
1251
+
1252
+ 59) max_wind_text_box_color (String) - Default='crimson'. Color of the maximum wind speed text box.
1253
+
1254
+ 60) max_wind_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1255
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1256
+
1257
+ 61) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
1258
+
1259
+ 62) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
1260
+
1261
+ 63) axes_label_color (String) - Default='black'. The color of the labels on each axis.
1262
+
1263
+ 64) xtick_color (String) - Default='black'. The color of the x-ticks.
1264
+
1265
+ 65) ytick_color (String) - Default='black'. The color of the y-ticks.
1266
+
1267
+ 66) facecolor (String) - Default='lavander'. The face color of the figure.
1268
+
1269
+ 67) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
1270
+ and pass those data frames into the plotting function, set df=df.
1271
+
1272
+ 68) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
1273
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
1274
+ is not downloading the data within the function.
1275
+
1276
+ 69) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
1277
+
1278
+ Returns
1279
+ -------
1280
+
1281
+ A figure of the vertical profiles saved to {path}
1282
+ """
1283
+
1284
+ _build_directory_branch(path)
1285
+
1286
+ if df == None:
1287
+ df, date = _get_observed_sounding_data(station_id,
1288
+ current=current,
1289
+ custom_time=custom_time,
1290
+ comparison_24=False,
1291
+ proxies=proxies,
1292
+ clear_recycle_bin=clear_recycle_bin)
1293
+ else:
1294
+ df = df
1295
+ date = date
1296
+
1297
+
1298
+ pressure = df['PRES'].values * _units('hPa')
1299
+
1300
+ height = _mpcalc.pressure_to_height_std(pressure)
1301
+
1302
+ if to_meters == True and to_feet == False:
1303
+ height = _calc.kilometers_to_meters(height)
1304
+ height_symbol = f"[M]"
1305
+
1306
+ elif to_feet == True and to_meters == False:
1307
+ height = _calc.kilometers_to_meters(height)
1308
+ height = _calc.meters_to_feet(height)
1309
+ height_symbol = f"[FT]"
1310
+ else:
1311
+ height = height
1312
+ height_symbol = f"[KM]"
1313
+
1314
+ df['HGHT'] = height.m
1315
+
1316
+ if to_mph == True and to_mps == False:
1317
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
1318
+ ws_symbol = f"[MPH]"
1319
+ elif to_mph == False and to_mps == True:
1320
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
1321
+ ws_symbol = f"[M/S]"
1322
+ else:
1323
+ ws_symbol = f"[KTS]"
1324
+
1325
+ if title_1_box_alpha < 0.5:
1326
+ title_1_box_alpha = 0.5
1327
+ if title_2_box_alpha < 0.5:
1328
+ title_2_box_alpha = 0.5
1329
+ if signature_box_alpha < 0.5:
1330
+ signature_box_alpha = 0.5
1331
+ if x_axis1_box_alpha < 0.5:
1332
+ x_axis1_box_alpha = 0.5
1333
+ if min_rh_height_box_alpha < 0.5:
1334
+ min_rh_height_box_alpha = 0.5
1335
+ if max_rh_height_box_alpha < 0.5:
1336
+ max_rh_height_box_alpha = 0.5
1337
+ if rh_range_height_box_alpha < 0.5:
1338
+ rh_range_height_box_alpha = 0.5
1339
+ if max_wind_height_box_alpha < 0.5:
1340
+ max_wind_height_box_alpha = 0.5
1341
+
1342
+ title_1_box = dict(boxstyle=title_1_box_style,
1343
+ facecolor=title_1_box_color,
1344
+ alpha=title_1_box_alpha)
1345
+
1346
+ title_2_box = dict(boxstyle=title_2_box_style,
1347
+ facecolor=title_2_box_color,
1348
+ alpha=title_2_box_alpha)
1349
+
1350
+ props = dict(boxstyle=signature_box_style,
1351
+ facecolor=signature_box_color,
1352
+ alpha=signature_box_alpha)
1353
+
1354
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
1355
+ facecolor=x_axis1_box_color,
1356
+ alpha=x_axis1_box_alpha)
1357
+
1358
+ min_rh_height_box = dict(boxstyle=min_rh_height_box_style,
1359
+ facecolor=min_rh_height_box_color,
1360
+ alpha=min_rh_height_box_alpha)
1361
+
1362
+ max_rh_height_box = dict(boxstyle=max_rh_height_box_style,
1363
+ facecolor=max_rh_height_box_color,
1364
+ alpha=max_rh_height_box_alpha)
1365
+
1366
+ rh_range_height_box = dict(boxstyle=rh_range_height_box_style,
1367
+ facecolor=rh_range_height_box_color,
1368
+ alpha=rh_range_height_box_alpha)
1369
+
1370
+ max_wind_height_box = dict(boxstyle=max_wind_height_box_style,
1371
+ facecolor=max_wind_height_box_color,
1372
+ alpha=max_wind_height_box_alpha)
1373
+
1374
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
1375
+ _mpl.rcParams['xtick.color'] = xtick_color
1376
+ _mpl.rcParams['ytick.color'] = ytick_color
1377
+
1378
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
1379
+
1380
+ rh_x, rh_y = _linear_anti_aliasing(df['RH'][mask],
1381
+ df['HGHT'][mask],
1382
+ anti_aliasing)
1383
+
1384
+
1385
+ min_rh_height = _np.nanmax(_np.where(df['RH'][mask] == _np.nanmin(df['RH'][mask]),
1386
+ df['HGHT'][mask],
1387
+ 0))
1388
+
1389
+ max_rh_height = _np.nanmax(_np.where(df['RH'][mask] == _np.nanmax(df['RH'][mask]),
1390
+ df['HGHT'][mask],
1391
+ 0))
1392
+
1393
+ max_ws_height = _np.nanmax(_np.where(df['SKNT'][mask] == _np.nanmax(df['SKNT'][mask]),
1394
+ df['HGHT'][mask],
1395
+ 0))
1396
+
1397
+ fig = _plt.figure(figsize=(fig_x, fig_y))
1398
+ fig.patch.set_facecolor(facecolor)
1399
+
1400
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
1401
+ f" | VALID: {date.strftime('%m/%d/%Y %H:00 UTC')}",
1402
+ fontsize=title_1_fontsize,
1403
+ fontweight='bold',
1404
+ color=title_1_fontcolor,
1405
+ bbox=title_1_box)
1406
+
1407
+
1408
+ ax = fig.add_subplot(1,1,1)
1409
+ ax.set_facecolor(subplot_background_color)
1410
+ ax.xaxis.set_major_locator(_MaxNLocator(integer=True))
1411
+ ax.yaxis.set_major_locator(_MaxNLocator(integer=True))
1412
+
1413
+ ax.text(signature_box_x,
1414
+ signature_box_y,
1415
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
1416
+ f"| Data Source: weather.uwyo.edu\n"
1417
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
1418
+ fontsize=signature_fontsize,
1419
+ bbox=props,
1420
+ fontweight='bold',
1421
+ color=signature_fontcolor,
1422
+ transform=ax.transAxes)
1423
+
1424
+ ax.set_xlim((_np.nanmin(df['RH'][mask]) -5 ), (_np.nanmax(df['RH'][mask]) + 5))
1425
+ ax.set_ylim(y_bottom, y_top)
1426
+ ax.set_title(f"RELATIVE HUMIDITY & WIND SPEED {ws_symbol}",
1427
+ fontweight='bold',
1428
+ loc='center',
1429
+ fontsize=title_2_fontsize,
1430
+ color=title_2_fontcolor,
1431
+ bbox=title_2_box,
1432
+ y=title_2_y_position)
1433
+
1434
+ ax.text(max_rh_height_box_x_position,
1435
+ max_rh_height_box_y_position,
1436
+ f"RH MAX = {int(round(_np.nanmax(df['RH'][mask]), 0))} [%] @ {int(round(max_rh_height, 0))} {height_symbol}",
1437
+ fontweight='bold',
1438
+ fontsize=legend_fontsize,
1439
+ color=title_2_fontcolor,
1440
+ bbox=max_rh_height_box,
1441
+ transform=ax.transAxes)
1442
+
1443
+ ax.text(min_rh_height_box_x_position,
1444
+ min_rh_height_box_y_position,
1445
+ f"RH MIN = {int(round(_np.nanmin(df['RH'][mask]), 0))} [%] @ {int(round(min_rh_height, 0))} {height_symbol}",
1446
+ fontweight='bold',
1447
+ fontsize=legend_fontsize,
1448
+ color=title_2_fontcolor,
1449
+ bbox=min_rh_height_box,
1450
+ transform=ax.transAxes)
1451
+
1452
+ ax.text(rh_range_height_box_x_position,
1453
+ rh_range_height_box_y_position,
1454
+ f"RH RANGE = {int(round(_np.nanmax(df['RH'][mask]), 0)) - int(round(_np.nanmin(df['RH'][mask]), 0))} [%]",
1455
+ fontweight='bold',
1456
+ fontsize=legend_fontsize,
1457
+ color=title_2_fontcolor,
1458
+ bbox=rh_range_height_box,
1459
+ transform=ax.transAxes)
1460
+
1461
+ ax.text(max_wind_height_box_x_position,
1462
+ max_wind_height_box_y_position,
1463
+ f"WIND SPEED MAX = {int(round(_np.nanmax(df['SKNT'][mask]), 0))} {ws_symbol} @ {int(round(max_ws_height, 0))} {height_symbol}",
1464
+ fontweight='bold',
1465
+ fontsize=legend_fontsize,
1466
+ color=title_2_fontcolor,
1467
+ bbox=max_wind_height_box,
1468
+ transform=ax.transAxes)
1469
+
1470
+ ax.scatter(rh_x,
1471
+ rh_y,
1472
+ c=rh_x,
1473
+ vmin=_np.nanmin(df['RH'][mask]),
1474
+ vmax=_np.nanmax(df['RH'][mask]),
1475
+ cmap=relative_humidity_colormap,
1476
+ alpha=relative_humidity_alpha)
1477
+
1478
+ ax.set_xlabel(f"RELATIVE HUMIDITY [%]",
1479
+ fontsize=x_axis_label_fontsize,
1480
+ fontweight='bold',
1481
+ bbox=x_axis1_box)
1482
+
1483
+ ax.set_ylabel(f"HEIGHT {height_symbol}",
1484
+ fontsize=y_axis_label_fontsize,
1485
+ fontweight='bold',
1486
+ bbox=title_1_box)
1487
+
1488
+ x_positions = []
1489
+ x_position = (_np.nanmin(df['RH'][mask]) + _np.nanmax(df['RH'][mask]))/2
1490
+ for i in range(0, len(df['HGHT'][mask]), 1):
1491
+ x_positions.append(x_position)
1492
+
1493
+ x_position = _np.asarray(x_positions)
1494
+
1495
+ ax.barbs(x_position,
1496
+ df['HGHT'][mask],
1497
+ df['U-WIND'][mask],
1498
+ df['V-WIND'][mask],
1499
+ df['SKNT'][mask],
1500
+ cmap=wind_colormap,
1501
+ length=wind_barb_length,
1502
+ alpha=wind_barb_alpha)
1503
+
1504
+ fig.savefig(f"{path}/{station_id.upper()}.png",
1505
+ bbox_inches='tight')
1506
+
1507
+ _plt.close(fig)
1508
+
1509
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
1510
+
1511
+ def plot_temperature_relative_humidity_wind_profile_comparison(station_id,
1512
+ current=True,
1513
+ custom_time_1=None,
1514
+ custom_time_2=None,
1515
+ proxies=None,
1516
+ clear_recycle_bin=False,
1517
+ path='FireWxPy Graphics/Observations/Upper Air/Temperature Relative Humidity Wind Profiles Comparison',
1518
+ to_fahrenheit=False,
1519
+ to_kelvin=False,
1520
+ to_meters=False,
1521
+ to_feet=True,
1522
+ to_mph=True,
1523
+ to_mps=False,
1524
+ anti_aliasing=100,
1525
+ temperature_color='red',
1526
+ temperature_comparison_color='blue',
1527
+ temperature_alpha=1,
1528
+ temperature_comparison_alpha=1,
1529
+ relative_humidity_color='darkgreen',
1530
+ relative_humidity_comparison_color='darkorange',
1531
+ relative_humidity_alpha=1,
1532
+ relative_humidity_comparison_alpha=1,
1533
+ wind_color='red',
1534
+ wind_comparison_color='blue',
1535
+ wind_barb_length=5,
1536
+ wind_barb_comparison_length=5,
1537
+ wind_barb_alpha=1,
1538
+ wind_barb_comparison_alpha=1,
1539
+ y_bottom=0,
1540
+ y_top=10000,
1541
+ fig_x=15,
1542
+ fig_y=8,
1543
+ signature_box_x=0.85,
1544
+ signature_box_y=-0.15,
1545
+ signature_box_style='round',
1546
+ signature_box_color='steelblue',
1547
+ signature_box_alpha=0.5,
1548
+ signature_fontsize=8,
1549
+ signature_fontcolor='black',
1550
+ x_title_position=0.015,
1551
+ title_1_fontsize=14,
1552
+ title_1_box_style='round',
1553
+ title_1_box_color='steelblue',
1554
+ title_1_box_alpha=0.5,
1555
+ title_1_fontcolor='black',
1556
+ title_2_fontsize=12,
1557
+ title_2_box_style='round',
1558
+ title_2_box_color='crimson',
1559
+ title_2_box_alpha=0.5,
1560
+ title_2_fontcolor='black',
1561
+ title_2_y_position=1,
1562
+ title_3_fontsize=12,
1563
+ title_3_box_style='round',
1564
+ title_3_box_color='lime',
1565
+ title_3_box_alpha=0.5,
1566
+ title_3_fontcolor='black',
1567
+ title_3_y_position=1,
1568
+ title_4_fontsize=12,
1569
+ title_4_box_style='round',
1570
+ title_4_box_color='orange',
1571
+ title_4_box_alpha=0.5,
1572
+ title_4_fontcolor='black',
1573
+ title_4_y_position=1,
1574
+ x_axis1_box_style='round',
1575
+ x_axis1_box_color='crimson',
1576
+ x_axis1_box_alpha=0.5,
1577
+ x_axis2_box_style='round',
1578
+ x_axis2_box_color='lime',
1579
+ x_axis2_box_alpha=0.5,
1580
+ x_axis3_box_style='round',
1581
+ x_axis3_box_color='orange',
1582
+ x_axis3_box_alpha=0.5,
1583
+ x_axis_label_fontsize=12,
1584
+ y_axis_label_fontsize=12,
1585
+ axes_label_color='black',
1586
+ xtick_color='black',
1587
+ ytick_color='black',
1588
+ facecolor='lavender',
1589
+ df=None,
1590
+ df_comp=None,
1591
+ date=None,
1592
+ date_comp=None,
1593
+ subplot_background_color='silver',
1594
+ barb_legend_x_position=0,
1595
+ barb_legend_y_position=0,
1596
+ barb_legend_fontsize=10,
1597
+ barb_legend_zorder=10):
1598
+
1599
+
1600
+ """
1601
+ This function plots an observed temperature/relative humidity/wind profile comparison from 2 different atmospheric soundings.
1602
+
1603
+ Required Arguments:
1604
+
1605
+ 1) station_id (String) - The station ID for the sounding site.
1606
+
1607
+ Optional Arguments:
1608
+
1609
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
1610
+ when plotting past soundings.
1611
+
1612
+ 2) custom_time_1 (String) - Default=None. When plotting archived sounding data, specify the first custom time as a string in the
1613
+ form of 'YYYY-mm-dd:HH'.
1614
+
1615
+ 3) custom_time_2 (String) - Default=None. When plotting archived sounding data, specify the second custom time as a string in the
1616
+ form of 'YYYY-mm-dd:HH'.
1617
+
1618
+ 4) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
1619
+
1620
+ proxies=None ---> proxies={
1621
+ 'http':'http://your-proxy-address:port',
1622
+ 'https':'http://your-proxy-address:port'
1623
+ }
1624
+
1625
+ 5) clear_recycle_bin (Boolean) - Default=False, When set to True,
1626
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
1627
+ This setting is to help preserve memory on the machine.
1628
+
1629
+ 6) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Temperature Relative Humidity Wind Profiles Comparison'. The path where
1630
+ the graphic will save.
1631
+
1632
+ 7) to_fahrenheit (Boolean) - Default=False. Set to True for temperature in Fahrenheit.
1633
+
1634
+ 8) to_kelvin (Boolean) - Default=False. Set to True for temperature in Kelvin.
1635
+
1636
+ 9) to_meters (Boolean) - Default=False. Set to True for height in meters.
1637
+
1638
+ 10) to_feet (Boolean) - Default=True. Set to True for height in feet.
1639
+
1640
+ 11) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
1641
+
1642
+ 12) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
1643
+
1644
+ 13) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
1645
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
1646
+ appears as a line but is a series of colormapped scatter points.
1647
+
1648
+ 14) temperature_color (String) - Default='red'. The color for the temperature line corresponding to custom_time_1.
1649
+
1650
+ 15) temperature_color_comparison (String) - Default='blue'. The color for the temperature line corresponding to custom_time_2.
1651
+
1652
+ 16) temperature_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
1653
+ 0 = Completely Transparent, 1 = Completely Opaque.
1654
+
1655
+ 17) relative_humidity_color (String) - Default='darkgreen'. The color for the relative humidity line corresponding to custom_time_1.
1656
+
1657
+ 18) relative_humidity_color_comparison (String) - Default='darkorange'. The color for the relative humidity line corresponding to custom_time_2.
1658
+
1659
+ 19) relative_humidity_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
1660
+ 0 = Completely Transparent, 1 = Completely Opaque.
1661
+
1662
+ 20) wind_color (String) - Default='red'. The color for the wind line and wind barbs corresponding to custom_time_1.
1663
+
1664
+ 21) wind_color_comparison (String) - Default='blue'. The color for the wind line and wind barbs corresponding to custom_time_2.
1665
+
1666
+ 22) wind_barb_length (Integer) - Default=5. The length of the wind barb.
1667
+
1668
+ 23) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
1669
+ 0 = Completely Transparent, 1 = Completely Opaque.
1670
+
1671
+ 24) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
1672
+
1673
+ 25) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
1674
+
1675
+ 26) fig_x (Integer) - Default=15. The x-length of the figure.
1676
+
1677
+ 27) fig_y (Integer) - Default=8. The y-length of the figure.
1678
+
1679
+ 28) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
1680
+
1681
+ 29) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
1682
+
1683
+ 30) signature_box_style (String) - Default='round'. The style of the text box.
1684
+
1685
+ 31) signature_box_color (String) - Default='steelblue'. The color of the text box.
1686
+
1687
+ 32) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1688
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1689
+
1690
+ 33) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
1691
+
1692
+ 34) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
1693
+
1694
+ 35) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
1695
+
1696
+ 36) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
1697
+
1698
+ 37) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
1699
+
1700
+ 38) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
1701
+
1702
+ 39) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1703
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1704
+
1705
+ 40) title_1_fontcolor (String) - Default='black'. Font color of the first subplot title.
1706
+
1707
+ 41) title_2_fontsize (Integer) - Default=12. Font size of the first subplot title.
1708
+
1709
+ 42) title_2_box_style (String) - Default='round'. Text box style of the first subplot text box.
1710
+
1711
+ 43) title_2_box_color (String) - Default='crimson'. Text box color of the first subplot text box.
1712
+
1713
+ 44) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1714
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1715
+
1716
+ 45) title_2_fontcolor (String) - Default='black'. Font color of the first subplot title.
1717
+
1718
+ 46) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the second subplot text box.
1719
+
1720
+ 47) title_3_fontsize (Integer) - Default=12. Font size of the second subplot title.
1721
+
1722
+ 48) title_3_box_style (String) - Default='round'. Text box style of the second subplot text box.
1723
+
1724
+ 49) title_3_box_color (String) - Default='crimson'. Text box color of the second subplot text box.
1725
+
1726
+ 50) title_3_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1727
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1728
+
1729
+ 51) title_3_fontcolor (String) - Default='black'. Font color of the second subplot title.
1730
+
1731
+ 52) title_3_y_position (Float or Integer) - Default=1. The y-axis positon of the second subplot text box.
1732
+
1733
+ 53) title_4_fontsize (Integer) - Default=12. Font size of the third subplot title.
1734
+
1735
+ 54) title_4_box_style (String) - Default='round'. Text box style of the third subplot text box.
1736
+
1737
+ 55) title_4_box_color (String) - Default='crimson'. Text box color of the third subplot text box.
1738
+
1739
+ 56) title_4_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1740
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1741
+
1742
+ 57) title_4_fontcolor (String) - Default='black'. Font color of the third subplot title.
1743
+
1744
+ 58) title_4_y_position (Float or Integer) - Default=1. The y-axis positon of the third subplot text box.
1745
+
1746
+ 59) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
1747
+
1748
+ 60) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
1749
+
1750
+ 61) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1751
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1752
+
1753
+ 62) x_axis2_box_style (String) - Default='round'. Text box style of the second subplot x-axis text box.
1754
+
1755
+ 63) x_axis2_box_color (String) - Default='crimson'. Text box color of the second subplot x-axis text box.
1756
+
1757
+ 64) x_axis2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1758
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1759
+
1760
+ 65) x_axis3_box_style (String) - Default='round'. Text box style of the third subplot x-axis text box.
1761
+
1762
+ 66) x_axis3_box_color (String) - Default='crimson'. Text box color of the third subplot x-axis text box.
1763
+
1764
+ 67) x_axis3_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
1765
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
1766
+
1767
+ 68) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
1768
+
1769
+ 69) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
1770
+
1771
+ 70) axes_label_color (String) - Default='black'. The color of the labels on each axis.
1772
+
1773
+ 71) xtick_color (String) - Default='black'. The color of the x-ticks.
1774
+
1775
+ 72) ytick_color (String) - Default='black'. The color of the y-ticks.
1776
+
1777
+ 73) facecolor (String) - Default='lavander'. The face color of the figure.
1778
+
1779
+ 74) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
1780
+ and pass those data frames into the plotting function, set df=df.
1781
+
1782
+ 75) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
1783
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
1784
+ is not downloading the data within the function.
1785
+
1786
+ 76) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
1787
+
1788
+ 77) barb_legend_x_position (Float or Integer) - Default=0. x-position of wind barb legend with respect to the figure axis.
1789
+
1790
+ 78) barb_legend_y_position (Float or Integer) - Default=0. y-position of wind barb legend with respect to the figure axis.
1791
+
1792
+ 79) barb_legend_fontsize (Integer) - Default=10. Font size of wind barb legend.
1793
+
1794
+ 80) barb_legend_zorder (Integer) - Default=10. The z-order of the borders on the image. Lower numbers send this to the back
1795
+ higher numbers bring this forward.
1796
+
1797
+ Returns
1798
+ -------
1799
+
1800
+ A figure of the vertical profiles comparison saved to {path}
1801
+ """
1802
+
1803
+ _build_directory_branch(path)
1804
+
1805
+ if df == None and current == True:
1806
+ df, df_comp, date, date_comp = _get_observed_sounding_data(station_id,
1807
+ current=current,
1808
+ comparison_24=True,
1809
+ proxies=proxies,
1810
+ clear_recycle_bin=clear_recycle_bin)
1811
+
1812
+ elif df == None and current == False:
1813
+ df, date = _get_observed_sounding_data(station_id,
1814
+ current=current,
1815
+ custom_time=custom_time_1,
1816
+ comparison_24=False,
1817
+ proxies=proxies,
1818
+ clear_recycle_bin=clear_recycle_bin)
1819
+
1820
+ df_comp, date_comp = _get_observed_sounding_data(station_id,
1821
+ current=current,
1822
+ custom_time=custom_time_2,
1823
+ comparison_24=False,
1824
+ proxies=proxies,
1825
+ clear_recycle_bin=clear_recycle_bin)
1826
+
1827
+ else:
1828
+ df = df
1829
+ df_comp = df_comp
1830
+ date = date
1831
+ date_comp = date_comp
1832
+
1833
+
1834
+ pressure = df['PRES'].values * _units('hPa')
1835
+ pressure_comp = df_comp['PRES'].values * _units('hPa')
1836
+
1837
+ height = _mpcalc.pressure_to_height_std(pressure)
1838
+ height_comp = _mpcalc.pressure_to_height_std(pressure_comp)
1839
+
1840
+ if to_meters == True and to_feet == False:
1841
+ height = _calc.kilometers_to_meters(height)
1842
+ height_comp = _calc.kilometers_to_meters(height_comp)
1843
+ height_symbol = f"[M]"
1844
+
1845
+ elif to_feet == True and to_meters == False:
1846
+ height = _calc.kilometers_to_meters(height)
1847
+ height = _calc.meters_to_feet(height)
1848
+ height_comp = _calc.kilometers_to_meters(height_comp)
1849
+ height_comp = _calc.meters_to_feet(height_comp)
1850
+ height_symbol = f"[FT]"
1851
+ else:
1852
+ height = height
1853
+ height_comp = height_comp
1854
+ height_symbol = f"[KM]"
1855
+
1856
+ df['HGHT'] = height.m
1857
+ df_comp['HGHT'] = height_comp.m
1858
+
1859
+ if to_fahrenheit == True and to_kelvin == False:
1860
+ df['TEMP'] = _calc.celsius_to_fahrenheit(df['TEMP'])
1861
+ df_comp['TEMP'] = _calc.celsius_to_fahrenheit(df_comp['TEMP'])
1862
+ temperature_symbol = f"[°F]"
1863
+ elif to_kelvin == True and to_fahrenheit == False:
1864
+ df['TEMP'] = _calc.celsius_to_kelvin(df['TEMP'])
1865
+ df_comp['TEMP'] = _calc.celsius_to_kelvin(df_comp['TEMP'])
1866
+ temperature_symbol = f"[K]"
1867
+ else:
1868
+ temperature_symbol = f"[°C]"
1869
+
1870
+ if to_mph == True and to_mps == False:
1871
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
1872
+ df_comp['SKNT'] = _calc.knots_to_mph(df_comp['SKNT'])
1873
+ ws_symbol = f"[MPH]"
1874
+ elif to_mph == False and to_mps == True:
1875
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
1876
+ df_comp['SKNT'] = _calc.knots_to_mps(df_comp['SKNT'])
1877
+ ws_symbol = f"[M/S]"
1878
+ else:
1879
+ ws_symbol = f"[KTS]"
1880
+
1881
+ if title_1_box_alpha < 0.5:
1882
+ title_1_box_alpha = 0.5
1883
+ if title_2_box_alpha < 0.5:
1884
+ title_2_box_alpha = 0.5
1885
+ if title_3_box_alpha < 0.5:
1886
+ title_3_box_alpha = 0.5
1887
+ if title_4_box_alpha < 0.5:
1888
+ title_4_box_alpha = 0.5
1889
+ if signature_box_alpha < 0.5:
1890
+ signature_box_alpha = 0.5
1891
+ if x_axis1_box_alpha < 0.5:
1892
+ x_axis1_box_alpha = 0.5
1893
+ if x_axis2_box_alpha < 0.5:
1894
+ x_axis2_box_alpha = 0.5
1895
+ if x_axis3_box_alpha < 0.5:
1896
+ x_axis3_box_alpha = 0.5
1897
+
1898
+ title_1_box = dict(boxstyle=title_1_box_style,
1899
+ facecolor=title_1_box_color,
1900
+ alpha=title_1_box_alpha)
1901
+
1902
+ title_2_box = dict(boxstyle=title_2_box_style,
1903
+ facecolor=title_2_box_color,
1904
+ alpha=title_2_box_alpha)
1905
+
1906
+ title_3_box = dict(boxstyle=title_3_box_style,
1907
+ facecolor=title_3_box_color,
1908
+ alpha=title_3_box_alpha)
1909
+
1910
+ title_4_box = dict(boxstyle=title_4_box_style,
1911
+ facecolor=title_4_box_color,
1912
+ alpha=title_4_box_alpha)
1913
+
1914
+ props = dict(boxstyle=signature_box_style,
1915
+ facecolor=signature_box_color,
1916
+ alpha=signature_box_alpha)
1917
+
1918
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
1919
+ facecolor=x_axis1_box_color,
1920
+ alpha=x_axis1_box_alpha)
1921
+
1922
+ x_axis2_box = dict(boxstyle=x_axis2_box_style,
1923
+ facecolor=x_axis2_box_color,
1924
+ alpha=x_axis2_box_alpha)
1925
+
1926
+ x_axis3_box = dict(boxstyle=x_axis3_box_style,
1927
+ facecolor=x_axis3_box_color,
1928
+ alpha=x_axis3_box_alpha)
1929
+
1930
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
1931
+ _mpl.rcParams['xtick.color'] = xtick_color
1932
+ _mpl.rcParams['ytick.color'] = ytick_color
1933
+
1934
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
1935
+ mask_comp = (df_comp['HGHT'] <= y_top) & (df_comp['HGHT'] >= y_bottom)
1936
+
1937
+ temp_x, temp_y = _linear_anti_aliasing(df['TEMP'][mask],
1938
+ df['HGHT'][mask],
1939
+ anti_aliasing)
1940
+
1941
+ temp_x_comp, temp_y_comp = _linear_anti_aliasing(df_comp['TEMP'][mask_comp],
1942
+ df_comp['HGHT'][mask_comp],
1943
+ anti_aliasing)
1944
+
1945
+ rh_x, rh_y = _linear_anti_aliasing(df['RH'][mask],
1946
+ df['HGHT'][mask],
1947
+ anti_aliasing)
1948
+
1949
+ rh_x_comp, rh_y_comp = _linear_anti_aliasing(df_comp['RH'][mask_comp],
1950
+ df_comp['HGHT'][mask_comp],
1951
+ anti_aliasing)
1952
+
1953
+ ws_x, ws_y = _linear_anti_aliasing(df['SKNT'][mask],
1954
+ df['HGHT'][mask],
1955
+ anti_aliasing)
1956
+
1957
+ ws_x_comp, ws_y_comp = _linear_anti_aliasing(df_comp['SKNT'][mask_comp],
1958
+ df_comp['HGHT'][mask_comp],
1959
+ anti_aliasing)
1960
+
1961
+ temp_mins = []
1962
+ temp_x_min = (_np.nanmin(df['TEMP'][mask]) - 5)
1963
+ temp_comp_x_min = (_np.nanmin(df_comp['TEMP'][mask_comp]) - 5)
1964
+ temp_mins.append(temp_x_min)
1965
+ temp_mins.append(temp_comp_x_min)
1966
+
1967
+ temp_maxs = []
1968
+ temp_x_max = (_np.nanmax(df['TEMP'][mask]) + 5)
1969
+ temp_comp_x_max = (_np.nanmax(df_comp['TEMP'][mask_comp]) + 5)
1970
+ temp_maxs.append(temp_x_max)
1971
+ temp_maxs.append(temp_comp_x_max)
1972
+
1973
+ ws_mins = []
1974
+ ws_x_min = (_np.nanmin(df['SKNT'][mask]))
1975
+ ws_comp_x_min = (_np.nanmin(df_comp['SKNT'][mask_comp]))
1976
+ ws_mins.append(ws_x_min)
1977
+ ws_mins.append(ws_comp_x_min)
1978
+
1979
+ ws_maxs = []
1980
+ ws_x_max = (_np.nanmax(df['SKNT'][mask]) + 5)
1981
+ ws_comp_x_max = (_np.nanmax(df_comp['SKNT'][mask_comp]) + 5)
1982
+ ws_maxs.append(ws_x_max)
1983
+ ws_maxs.append(ws_comp_x_max)
1984
+
1985
+ fig = _plt.figure(figsize=(fig_x, fig_y))
1986
+ fig.patch.set_facecolor(facecolor)
1987
+
1988
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
1989
+ f" | TIME 1: {date.strftime('%m/%d/%Y %H:00 UTC')} | TIME 2: {date_comp.strftime('%m/%d/%Y %H:00 UTC')}",
1990
+ fontsize=title_1_fontsize,
1991
+ fontweight='bold',
1992
+ color=title_1_fontcolor,
1993
+ bbox=title_1_box)
1994
+
1995
+ ax1 = fig.add_subplot(1,3,1)
1996
+ ax1.set_facecolor(subplot_background_color)
1997
+ ax1.xaxis.set_major_locator(_MaxNLocator(integer=True))
1998
+ ax1.yaxis.set_major_locator(_MaxNLocator(integer=True))
1999
+
2000
+ ax1.set_xlim(_np.nanmin(temp_mins), _np.nanmax(temp_maxs))
2001
+ ax1.set_ylim(y_bottom, y_top)
2002
+
2003
+ ax1.set_xlabel(f"{temperature_symbol}",
2004
+ fontsize=x_axis_label_fontsize,
2005
+ fontweight='bold',
2006
+ bbox=x_axis1_box)
2007
+
2008
+ ax1.set_ylabel(f"{height_symbol}",
2009
+ fontsize=y_axis_label_fontsize,
2010
+ fontweight='bold',
2011
+ bbox=title_1_box)
2012
+
2013
+ ax1.set_title(f"TEMPERATURE",
2014
+ fontweight='bold',
2015
+ loc='left',
2016
+ x=x_title_position,
2017
+ fontsize=title_2_fontsize,
2018
+ color=title_2_fontcolor,
2019
+ bbox=title_2_box,
2020
+ y=title_2_y_position)
2021
+
2022
+ ax1.scatter(temp_x,
2023
+ temp_y,
2024
+ vmin=_np.nanmin(df['TEMP'][mask]),
2025
+ vmax=_np.nanmax(df['TEMP'][mask]),
2026
+ color=temperature_color,
2027
+ alpha=temperature_alpha,
2028
+ label=f"{date.strftime('%Y-%m-%d %H:00 UTC')}")
2029
+
2030
+ ax1.scatter(temp_x_comp,
2031
+ temp_y_comp,
2032
+ vmin=_np.nanmin(df_comp['TEMP'][mask_comp]),
2033
+ vmax=_np.nanmax(df_comp['TEMP'][mask_comp]),
2034
+ color=temperature_comparison_color,
2035
+ alpha=temperature_comparison_alpha,
2036
+ label=f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}")
2037
+
2038
+ ax1.text(signature_box_x,
2039
+ signature_box_y,
2040
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
2041
+ f"| Data Source: weather.uwyo.edu\n"
2042
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
2043
+ fontsize=signature_fontsize,
2044
+ bbox=props,
2045
+ fontweight='bold',
2046
+ color=signature_fontcolor,
2047
+ transform=ax1.transAxes)
2048
+
2049
+ leg = ax1.legend(loc=(barb_legend_x_position, barb_legend_y_position), prop={'size': barb_legend_fontsize})
2050
+ leg.set_zorder(barb_legend_zorder)
2051
+
2052
+ ax2 = fig.add_subplot(1,3,2)
2053
+ ax2.set_facecolor(subplot_background_color)
2054
+ ax2.xaxis.set_major_locator(_MaxNLocator(integer=True))
2055
+ ax2.yaxis.set_major_locator(_MaxNLocator(integer=True))
2056
+
2057
+ ax2.set_xlim(0, 100)
2058
+ ax2.set_ylim(y_bottom, y_top)
2059
+ ax2.set_title(f"RELATIVE HUMIDITY",
2060
+ fontweight='bold',
2061
+ loc='left',
2062
+ x=x_title_position,
2063
+ fontsize=title_3_fontsize,
2064
+ color=title_3_fontcolor,
2065
+ bbox=title_3_box,
2066
+ y=title_3_y_position)
2067
+
2068
+ ax2.scatter(rh_x,
2069
+ rh_y,
2070
+ vmin=_np.nanmin(df['RH'][mask]),
2071
+ vmax=_np.nanmax(df['RH'][mask]),
2072
+ color=relative_humidity_color,
2073
+ alpha=relative_humidity_alpha,
2074
+ label=f"{date.strftime('%Y-%m-%d %H:00 UTC')}")
2075
+
2076
+ ax2.scatter(rh_x_comp,
2077
+ rh_y_comp,
2078
+ vmin=_np.nanmin(df_comp['RH'][mask_comp]),
2079
+ vmax=_np.nanmax(df_comp['RH'][mask_comp]),
2080
+ color=relative_humidity_comparison_color,
2081
+ alpha=relative_humidity_comparison_alpha,
2082
+ label=f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}")
2083
+
2084
+ ax2.set_xlabel(f"[%]",
2085
+ fontsize=x_axis_label_fontsize,
2086
+ fontweight='bold',
2087
+ bbox=x_axis2_box)
2088
+
2089
+ leg = ax2.legend(loc=(barb_legend_x_position, barb_legend_y_position), prop={'size': barb_legend_fontsize})
2090
+ leg.set_zorder(barb_legend_zorder)
2091
+
2092
+ ax3 = fig.add_subplot(1,3,3)
2093
+ ax3.set_facecolor(subplot_background_color)
2094
+ ax3.xaxis.set_major_locator(_MaxNLocator(integer=True))
2095
+ ax3.yaxis.set_major_locator(_MaxNLocator(integer=True))
2096
+
2097
+ ax3.set_xlim(_np.nanmin(ws_mins), _np.nanmax(ws_maxs))
2098
+ ax3.set_ylim(y_bottom, y_top)
2099
+ ax3.set_title(f"WIND SPEED",
2100
+ fontweight='bold',
2101
+ loc='left',
2102
+ x=x_title_position,
2103
+ fontsize=title_4_fontsize,
2104
+ color=title_4_fontcolor,
2105
+ bbox=title_4_box,
2106
+ y=title_4_y_position)
2107
+
2108
+ ax3.scatter(ws_x,
2109
+ ws_y,
2110
+ vmin=_np.nanmin(df['SKNT'][mask]),
2111
+ vmax=_np.nanmax(df['SKNT'][mask]),
2112
+ color=wind_color,
2113
+ label=f"{date.strftime('%Y-%m-%d %H:00 UTC')}")
2114
+
2115
+ ax3.scatter(ws_x_comp,
2116
+ ws_y_comp,
2117
+ vmin=_np.nanmin(df_comp['SKNT'][mask_comp]),
2118
+ vmax=_np.nanmax(df_comp['SKNT'][mask_comp]),
2119
+ color=wind_comparison_color,
2120
+ label=f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}")
2121
+
2122
+ x_positions = []
2123
+ x_positions_comp = []
2124
+ x_position = (_np.nanmin(df['SKNT'][mask]) + _np.nanmax(df['SKNT'][mask]))/2
2125
+ x_position_comp = (_np.nanmin(df_comp['SKNT'][mask_comp]) + _np.nanmax(df_comp['SKNT'][mask_comp]))/2
2126
+ for i in range(0, len(df['HGHT'][mask]), 1):
2127
+ x_positions.append(x_position)
2128
+
2129
+ for i in range(0, len(df_comp['HGHT'][mask_comp]), 1):
2130
+ x_positions_comp.append(x_position_comp)
2131
+
2132
+ x_position = _np.asarray(x_positions)
2133
+ x_position_comp = _np.asarray(x_positions_comp)
2134
+
2135
+ ax3.barbs(x_position,
2136
+ df['HGHT'][mask],
2137
+ df['U-WIND'][mask],
2138
+ df['V-WIND'][mask],
2139
+ df['SKNT'][mask],
2140
+ color=wind_color,
2141
+ length=wind_barb_length,
2142
+ alpha=wind_barb_alpha)
2143
+
2144
+ ax3.barbs(x_position_comp,
2145
+ df_comp['HGHT'][mask_comp],
2146
+ df_comp['U-WIND'][mask_comp],
2147
+ df_comp['V-WIND'][mask_comp],
2148
+ df_comp['SKNT'][mask_comp],
2149
+ color=wind_comparison_color,
2150
+ length=wind_barb_comparison_length,
2151
+ alpha=wind_barb_comparison_alpha)
2152
+
2153
+ ax3.set_xlabel(f"{ws_symbol}",
2154
+ fontsize=x_axis_label_fontsize,
2155
+ fontweight='bold',
2156
+ bbox=x_axis3_box)
2157
+
2158
+ leg = ax3.legend(loc=(barb_legend_x_position, barb_legend_y_position), prop={'size': barb_legend_fontsize})
2159
+ leg.set_zorder(barb_legend_zorder)
2160
+
2161
+ fig.savefig(f"{path}/{station_id.upper()}.png",
2162
+ bbox_inches='tight')
2163
+
2164
+ _plt.close(fig)
2165
+
2166
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
2167
+
2168
+
2169
+ def plot_temperature_wind_profile_comparison(station_id,
2170
+ current=True,
2171
+ custom_time_1=None,
2172
+ custom_time_2=None,
2173
+ proxies=None,
2174
+ clear_recycle_bin=False,
2175
+ path='FireWxPy Graphics/Observations/Upper Air/Temperature Wind Profiles Comparison',
2176
+ to_fahrenheit=True,
2177
+ to_kelvin=False,
2178
+ to_meters=False,
2179
+ to_feet=True,
2180
+ to_mph=True,
2181
+ to_mps=False,
2182
+ anti_aliasing=100,
2183
+ temperature_color='red',
2184
+ temperature_comp_color='blue',
2185
+ temperature_alpha=1,
2186
+ temperature_comp_alpha=1,
2187
+ wind_color='darkorange',
2188
+ wind_comp_color='purple',
2189
+ wind_barb_length=7,
2190
+ wind_comp_barb_length=7,
2191
+ wind_barb_alpha=1,
2192
+ wind_comp_barb_alpha=1,
2193
+ y_bottom=0,
2194
+ y_top=10000,
2195
+ fig_x=15,
2196
+ fig_y=8,
2197
+ signature_box_x=0.25,
2198
+ signature_box_y=-0.15,
2199
+ signature_box_style='round',
2200
+ signature_box_color='steelblue',
2201
+ signature_box_alpha=0.5,
2202
+ signature_fontsize=8,
2203
+ signature_fontcolor='black',
2204
+ title_1_fontsize=14,
2205
+ title_1_box_style='round',
2206
+ title_1_box_color='steelblue',
2207
+ title_1_box_alpha=0.5,
2208
+ title_1_fontcolor='black',
2209
+ title_2_fontsize=12,
2210
+ title_2_box_style='round',
2211
+ title_2_box_color='crimson',
2212
+ title_2_box_alpha=0.5,
2213
+ title_2_fontcolor='black',
2214
+ title_2_y_position=1,
2215
+ x_axis1_box_style='round',
2216
+ x_axis1_box_color='crimson',
2217
+ x_axis1_box_alpha=0.5,
2218
+ stats_text_box_fontcolor='black',
2219
+ stats_text_box_x_position=0.7405,
2220
+ stats_text_box_y_position=0.8495,
2221
+ stats_text_box_style='round',
2222
+ stats_text_box_color='wheat',
2223
+ stats_text_box_alpha=1,
2224
+ x_axis_label_fontsize=12,
2225
+ y_axis_label_fontsize=12,
2226
+ axes_label_color='black',
2227
+ legend_fontsize=6.5,
2228
+ xtick_color='black',
2229
+ ytick_color='black',
2230
+ facecolor='lavender',
2231
+ df=None,
2232
+ df_comp=None,
2233
+ date=None,
2234
+ date_comp=None,
2235
+ subplot_background_color='silver',
2236
+ barb_legend_fontsize=10,
2237
+ barb_legend_x_position=0,
2238
+ barb_legend_y_position=0,
2239
+ barb_legend_zorder=10):
2240
+
2241
+
2242
+ """
2243
+ This function plots an observed temperature/wind profile comparison from 2 different atmospheric soundings.
2244
+
2245
+ Required Arguments:
2246
+
2247
+ 1) station_id (String) - The station ID for the sounding site.
2248
+
2249
+ Optional Arguments:
2250
+
2251
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
2252
+ when plotting past soundings.
2253
+
2254
+ 2) custom_time_1 (String) - Default=None. When plotting archived sounding data, specify the first custom time as a string in the
2255
+ form of 'YYYY-mm-dd:HH'.
2256
+
2257
+ 3) custom_time_2 (String) - Default=None. When plotting archived sounding data, specify the second custom time as a string in the
2258
+ form of 'YYYY-mm-dd:HH'.
2259
+
2260
+ 4) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
2261
+
2262
+ proxies=None ---> proxies={
2263
+ 'http':'http://your-proxy-address:port',
2264
+ 'https':'http://your-proxy-address:port'
2265
+ }
2266
+
2267
+ 5) clear_recycle_bin (Boolean) - Default=False, When set to True,
2268
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
2269
+ This setting is to help preserve memory on the machine.
2270
+
2271
+ 6) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Temperature Wind Profiles Comparison'. The path where
2272
+ the graphic will save.
2273
+
2274
+ 7) to_fahrenheit (Boolean) - Default=False. Set to True for temperature in Fahrenheit.
2275
+
2276
+ 8) to_kelvin (Boolean) - Default=False. Set to True for temperature in Kelvin.
2277
+
2278
+ 9) to_meters (Boolean) - Default=False. Set to True for height in meters.
2279
+
2280
+ 10) to_feet (Boolean) - Default=True. Set to True for height in feet.
2281
+
2282
+ 11) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
2283
+
2284
+ 12) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
2285
+
2286
+ 13) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
2287
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
2288
+ appears as a line but is a series of colormapped scatter points.
2289
+
2290
+ 14) temperature_color (String) - Default='red'. The color for the temperature line corresponding to custom_time_1.
2291
+
2292
+ 15) temperature_color_comparison (String) - Default='blue'. The color for the temperature line corresponding to custom_time_2.
2293
+
2294
+ 16) temperature_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
2295
+ 0 = Completely Transparent, 1 = Completely Opaque.
2296
+
2297
+ 17) wind_color (String) - Default='red'. The color for the wind line and wind barbs corresponding to custom_time_1.
2298
+
2299
+ 18) wind_color_comparison (String) - Default='blue'. The color for the wind line and wind barbs corresponding to custom_time_2.
2300
+
2301
+ 19) wind_barb_length (Integer) - Default=5. The length of the wind barb.
2302
+
2303
+ 20) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
2304
+ 0 = Completely Transparent, 1 = Completely Opaque.
2305
+
2306
+ 21) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
2307
+
2308
+ 22) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
2309
+
2310
+ 23) fig_x (Integer) - Default=15. The x-length of the figure.
2311
+
2312
+ 24) fig_y (Integer) - Default=8. The y-length of the figure.
2313
+
2314
+ 25) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
2315
+
2316
+ 26) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
2317
+
2318
+ 27) signature_box_style (String) - Default='round'. The style of the text box.
2319
+
2320
+ 28) signature_box_color (String) - Default='steelblue'. The color of the text box.
2321
+
2322
+ 29) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2323
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2324
+
2325
+ 30) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
2326
+
2327
+ 31) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
2328
+
2329
+ 32) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
2330
+
2331
+ 33) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
2332
+
2333
+ 34) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
2334
+
2335
+ 35) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
2336
+
2337
+ 36) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2338
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2339
+
2340
+ 37) title_1_fontcolor (String) - Default='black'. Font color of the figure title.
2341
+
2342
+ 38) title_2_fontsize (Integer) - Default=12. Font size of the first subplot title.
2343
+
2344
+ 39) title_2_box_style (String) - Default='round'. Text box style of the subplot title text box.
2345
+
2346
+ 40) title_2_box_color (String) - Default='crimson'. Text box color of the subplot title text box.
2347
+
2348
+ 41) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2349
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2350
+
2351
+ 42) title_2_fontcolor (String) - Default='black'. Font color of the subplot title.
2352
+
2353
+ 43) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the subplot title text box.
2354
+
2355
+ 44) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
2356
+
2357
+ 45) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
2358
+
2359
+ 46) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2360
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2361
+
2362
+ 47) x_axis1_box_style (String) - Default='round'. Text box style for the general x-axis text box.
2363
+
2364
+ 48) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2365
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2366
+
2367
+ 49) stats_text_box_fontcolor (String) - Default='black'. Font color of the stats table.
2368
+
2369
+ 50) stats_text_box_x_position (Float) - Default=0.7405. The x-position of the stats table text box.
2370
+
2371
+ 51) stats_text_box_y_position (Float) - Default=0.8495. The y-position of the stats table text box.
2372
+
2373
+ 52) stats_text_box_style (String) - Default='round'. The style of the stats text box.
2374
+
2375
+ 53) stats_text_box_color (String) - Defaults='wheat'. The color of the stats text box.
2376
+
2377
+ 54) stats_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2378
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2379
+
2380
+ 55) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
2381
+
2382
+ 56) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
2383
+
2384
+ 57) axes_label_color (String) - Default='black'. The color of the labels on each axis.
2385
+
2386
+ 58) xtick_color (String) - Default='black'. The color of the x-ticks.
2387
+
2388
+ 59) ytick_color (String) - Default='black'. The color of the y-ticks.
2389
+
2390
+ 60) facecolor (String) - Default='lavander'. The face color of the figure.
2391
+
2392
+ 61) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
2393
+ and pass those data frames into the plotting function, set df=df.
2394
+
2395
+ 62) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
2396
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
2397
+ is not downloading the data within the function.
2398
+
2399
+ 63) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
2400
+
2401
+ 64) barb_legend_x_position (Float or Integer) - Default=0. x-position of wind barb legend with respect to the figure axis.
2402
+
2403
+ 65) barb_legend_y_position (Float or Integer) - Default=0. y-position of wind barb legend with respect to the figure axis.
2404
+
2405
+ 66) barb_legend_fontsize (Integer) - Default=10. Font size of wind barb legend.
2406
+
2407
+ 67) barb_legend_zorder (Integer) - Default=10. The z-order of the borders on the image. Lower numbers send this to the back
2408
+ higher numbers bring this forward.
2409
+
2410
+ Returns
2411
+ -------
2412
+
2413
+ A figure of the vertical profiles comparison saved to {path}
2414
+ """
2415
+
2416
+ _build_directory_branch(path)
2417
+
2418
+ if df == None and current == True:
2419
+ df, df_comp, date, date_comp = _get_observed_sounding_data(station_id,
2420
+ current=current,
2421
+ comparison_24=True,
2422
+ proxies=proxies,
2423
+ clear_recycle_bin=clear_recycle_bin)
2424
+
2425
+ elif df == None and current == False:
2426
+ df, date = _get_observed_sounding_data(station_id,
2427
+ current=current,
2428
+ custom_time=custom_time_1,
2429
+ comparison_24=False,
2430
+ proxies=proxies,
2431
+ clear_recycle_bin=clear_recycle_bin)
2432
+
2433
+ df_comp, date_comp = _get_observed_sounding_data(station_id,
2434
+ current=current,
2435
+ custom_time=custom_time_2,
2436
+ comparison_24=False,
2437
+ proxies=proxies,
2438
+ clear_recycle_bin=clear_recycle_bin)
2439
+
2440
+ else:
2441
+ df = df
2442
+ df_comp = df_comp
2443
+ date = date
2444
+ date_comp = date_comp
2445
+
2446
+
2447
+ pressure = df['PRES'].values * _units('hPa')
2448
+ pressure_comp = df_comp['PRES'].values * _units('hPa')
2449
+
2450
+ height = _mpcalc.pressure_to_height_std(pressure)
2451
+ height_comp = _mpcalc.pressure_to_height_std(pressure_comp)
2452
+
2453
+ if to_meters == True and to_feet == False:
2454
+ height = _calc.kilometers_to_meters(height)
2455
+ height_comp = _calc.kilometers_to_meters(height_comp)
2456
+ height_symbol = f"[M]"
2457
+
2458
+ elif to_feet == True and to_meters == False:
2459
+ height = _calc.kilometers_to_meters(height)
2460
+ height = _calc.meters_to_feet(height)
2461
+ height_comp = _calc.kilometers_to_meters(height_comp)
2462
+ height_comp = _calc.meters_to_feet(height_comp)
2463
+ height_symbol = f"[FT]"
2464
+ else:
2465
+ height = height
2466
+ height_comp = height_comp
2467
+ height_symbol = f"[KM]"
2468
+
2469
+ df['HGHT'] = height.m
2470
+ df_comp['HGHT'] = height_comp.m
2471
+
2472
+ if to_fahrenheit == True and to_kelvin == False:
2473
+ df['TEMP'] = _calc.celsius_to_fahrenheit(df['TEMP'])
2474
+ df_comp['TEMP'] = _calc.celsius_to_fahrenheit(df_comp['TEMP'])
2475
+ temperature_symbol = f"[°F]"
2476
+ elif to_kelvin == True and to_fahrenheit == False:
2477
+ df['TEMP'] = _calc.celsius_to_kelvin(df['TEMP'])
2478
+ df_comp['TEMP'] = _calc.celsius_to_kelvin(df_comp['TEMP'])
2479
+ temperature_symbol = f"[K]"
2480
+ else:
2481
+ temperature_symbol = f"[°C]"
2482
+
2483
+ if to_mph == True and to_mps == False:
2484
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
2485
+ df_comp['SKNT'] = _calc.knots_to_mph(df_comp['SKNT'])
2486
+ ws_symbol = f"[MPH]"
2487
+ elif to_mph == False and to_mps == True:
2488
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
2489
+ df_comp['SKNT'] = _calc.knots_to_mps(df_comp['SKNT'])
2490
+ ws_symbol = f"[M/S]"
2491
+ else:
2492
+ ws_symbol = f"[KTS]"
2493
+
2494
+ if title_1_box_alpha < 0.5:
2495
+ title_1_box_alpha = 0.5
2496
+ if title_2_box_alpha < 0.5:
2497
+ title_2_box_alpha = 0.5
2498
+ if stats_text_box_alpha < 0.5:
2499
+ stats_text_box_alpha = 0.5
2500
+ if signature_box_alpha < 0.5:
2501
+ signature_box_alpha = 0.5
2502
+ if x_axis1_box_alpha < 0.5:
2503
+ x_axis1_box_alpha = 0.5
2504
+
2505
+ title_1_box = dict(boxstyle=title_1_box_style,
2506
+ facecolor=title_1_box_color,
2507
+ alpha=title_1_box_alpha)
2508
+
2509
+ title_2_box = dict(boxstyle=title_2_box_style,
2510
+ facecolor=title_2_box_color,
2511
+ alpha=title_2_box_alpha)
2512
+
2513
+ stats_box = dict(boxstyle=stats_text_box_style,
2514
+ facecolor=stats_text_box_color,
2515
+ alpha=stats_text_box_alpha)
2516
+
2517
+ props = dict(boxstyle=signature_box_style,
2518
+ facecolor=signature_box_color,
2519
+ alpha=signature_box_alpha)
2520
+
2521
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
2522
+ facecolor=x_axis1_box_color,
2523
+ alpha=x_axis1_box_alpha)
2524
+
2525
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
2526
+ _mpl.rcParams['xtick.color'] = xtick_color
2527
+ _mpl.rcParams['ytick.color'] = ytick_color
2528
+
2529
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
2530
+ mask_comp = (df_comp['HGHT'] <= y_top) & (df_comp['HGHT'] >= y_bottom)
2531
+
2532
+ temp_x, temp_y = _linear_anti_aliasing(df['TEMP'][mask],
2533
+ df['HGHT'][mask],
2534
+ anti_aliasing)
2535
+
2536
+ temp_comp_x, temp_comp_y = _linear_anti_aliasing(df_comp['TEMP'][mask_comp],
2537
+ df_comp['HGHT'][mask_comp],
2538
+ anti_aliasing)
2539
+
2540
+ min_t_height = _np.nanmax(_np.where(df['TEMP'][mask] == _np.nanmin(df['TEMP'][mask]),
2541
+ df['HGHT'][mask],
2542
+ 0))
2543
+
2544
+ max_t_height = _np.nanmax(_np.where(df['TEMP'][mask] == _np.nanmax(df['TEMP'][mask]),
2545
+ df['HGHT'][mask],
2546
+ 0))
2547
+
2548
+ max_ws_height = _np.nanmax(_np.where(df['SKNT'][mask] == _np.nanmax(df['SKNT'][mask]),
2549
+ df['HGHT'][mask],
2550
+ 0))
2551
+
2552
+ min_t_height_comp = _np.nanmax(_np.where(df_comp['TEMP'][mask_comp] == _np.nanmin(df_comp['TEMP'][mask_comp]),
2553
+ df_comp['HGHT'][mask_comp],
2554
+ 0))
2555
+
2556
+ max_t_height_comp = _np.nanmax(_np.where(df_comp['TEMP'][mask_comp] == _np.nanmax(df_comp['TEMP'][mask_comp]),
2557
+ df_comp['HGHT'][mask_comp],
2558
+ 0))
2559
+
2560
+ max_ws_height_comp = _np.nanmax(_np.where(df_comp['SKNT'][mask_comp] == _np.nanmax(df_comp['SKNT'][mask_comp]),
2561
+ df_comp['HGHT'][mask_comp],
2562
+ 0))
2563
+
2564
+ temp_mins = []
2565
+ temp_x_min = (_np.nanmin(df['TEMP'][mask]) - 5)
2566
+ temp_comp_x_min = (_np.nanmin(df_comp['TEMP'][mask_comp]) - 5)
2567
+ temp_mins.append(temp_x_min)
2568
+ temp_mins.append(temp_comp_x_min)
2569
+
2570
+ temp_maxs = []
2571
+ temp_x_max = (_np.nanmax(df['TEMP'][mask]) + 5)
2572
+ temp_comp_x_max = (_np.nanmax(df_comp['TEMP'][mask_comp]) + 5)
2573
+ temp_maxs.append(temp_x_max)
2574
+ temp_maxs.append(temp_comp_x_max)
2575
+
2576
+ fig = _plt.figure(figsize=(fig_x, fig_y))
2577
+ fig.patch.set_facecolor(facecolor)
2578
+
2579
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
2580
+ f" | TIME 1: {date.strftime('%m/%d/%Y %H:00 UTC')} | TIME 2: {date_comp.strftime('%m/%d/%Y %H:00 UTC')}",
2581
+ fontsize=title_1_fontsize,
2582
+ fontweight='bold',
2583
+ color=title_1_fontcolor,
2584
+ bbox=title_1_box)
2585
+
2586
+ ax = fig.add_subplot(1,1,1)
2587
+ ax.set_facecolor(subplot_background_color)
2588
+ ax.xaxis.set_major_locator(_MaxNLocator(integer=True))
2589
+ ax.yaxis.set_major_locator(_MaxNLocator(integer=True))
2590
+
2591
+ ax.set_xlim(_np.nanmin(temp_mins), _np.nanmax(temp_maxs))
2592
+ ax.set_ylim(y_bottom, y_top)
2593
+
2594
+ ax.set_xlabel(f"{temperature_symbol}",
2595
+ fontsize=x_axis_label_fontsize,
2596
+ fontweight='bold',
2597
+ bbox=x_axis1_box)
2598
+
2599
+ ax.set_ylabel(f"{height_symbol}",
2600
+ fontsize=y_axis_label_fontsize,
2601
+ fontweight='bold',
2602
+ bbox=title_1_box)
2603
+
2604
+ ax.set_title(f"TEMPERATURE {temperature_symbol} & WIND SPEED {ws_symbol}",
2605
+ fontweight='bold',
2606
+ loc='center',
2607
+ fontsize=title_2_fontsize,
2608
+ color=title_2_fontcolor,
2609
+ bbox=title_2_box,
2610
+ y=title_2_y_position)
2611
+
2612
+ ax.scatter(temp_x,
2613
+ temp_y,
2614
+ vmin=_np.nanmin(df['TEMP'][mask]),
2615
+ vmax=_np.nanmax(df['TEMP'][mask]),
2616
+ color=temperature_color,
2617
+ alpha=temperature_alpha,
2618
+ label=f"{date.strftime('%Y-%m-%d %H:00 UTC')}")
2619
+
2620
+ ax.scatter(temp_comp_x,
2621
+ temp_comp_y,
2622
+ vmin=_np.nanmin(df_comp['TEMP'][mask_comp]),
2623
+ vmax=_np.nanmax(df_comp['TEMP'][mask_comp]),
2624
+ color=temperature_comp_color,
2625
+ alpha=temperature_comp_alpha,
2626
+ label=f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}")
2627
+
2628
+ ax.text(signature_box_x,
2629
+ signature_box_y,
2630
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
2631
+ f"| Data Source: weather.uwyo.edu\n"
2632
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
2633
+ fontsize=signature_fontsize,
2634
+ bbox=props,
2635
+ fontweight='bold',
2636
+ color=signature_fontcolor,
2637
+ transform=ax.transAxes)
2638
+
2639
+ ax.text(stats_text_box_x_position,
2640
+ stats_text_box_y_position,
2641
+ f"{date.strftime('%Y-%m-%d %H:00 UTC')}\n"
2642
+ f"MAX TEMP ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df['TEMP'][mask]), 0))} {temperature_symbol} @ {int(round(max_t_height, 0))} {height_symbol}\n"
2643
+ f"MIN TEMP ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmin(df['TEMP'][mask]), 0))} {temperature_symbol} @ {int(round(min_t_height, 0))} {height_symbol}\n"
2644
+ f"MAX WIND ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df['SKNT'][mask]), 0))} {ws_symbol} @ {int(round(max_ws_height, 0))} {height_symbol}\n\n"
2645
+ f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}\n"
2646
+ f"MAX TEMP ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df_comp['TEMP'][mask_comp]), 0))} {temperature_symbol} @ {int(round(max_t_height_comp, 0))} {height_symbol}\n"
2647
+ f"MIN TEMP ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmin(df_comp['TEMP'][mask_comp]), 0))} {temperature_symbol} @ {int(round(min_t_height_comp, 0))} {height_symbol}\n"
2648
+ f"MAX WIND ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df_comp['SKNT'][mask_comp]), 0))} {ws_symbol} @ {int(round(max_ws_height_comp, 0))} {height_symbol}",
2649
+ fontsize=legend_fontsize,
2650
+ bbox=stats_box,
2651
+ fontweight='bold',
2652
+ color=stats_text_box_fontcolor,
2653
+ transform=ax.transAxes)
2654
+
2655
+ x_positions = []
2656
+ x_position = (_np.nanmin(df['TEMP'][mask]) + _np.nanmax(df['TEMP'][mask]))/2
2657
+ for i in range(0, len(df['HGHT'][mask]), 1):
2658
+ x_positions.append(x_position)
2659
+
2660
+ x_position = _np.asarray(x_positions)
2661
+
2662
+ x_positions_comp = []
2663
+ x_position_comp = (_np.nanmin(df_comp['TEMP'][mask_comp]) + _np.nanmax(df_comp['TEMP'][mask_comp]))/2
2664
+ for i in range(0, len(df_comp['HGHT'][mask_comp]), 1):
2665
+ x_positions_comp.append(x_position_comp)
2666
+
2667
+ x_position_comp = _np.asarray(x_positions_comp)
2668
+
2669
+ ax.barbs(x_position,
2670
+ df['HGHT'][mask],
2671
+ df['U-WIND'][mask],
2672
+ df['V-WIND'][mask],
2673
+ df['SKNT'][mask],
2674
+ color=wind_color,
2675
+ length=wind_barb_length,
2676
+ alpha=wind_barb_alpha)
2677
+
2678
+ ax.barbs(x_position_comp,
2679
+ df_comp['HGHT'][mask_comp],
2680
+ df_comp['U-WIND'][mask_comp],
2681
+ df_comp['V-WIND'][mask_comp],
2682
+ df_comp['SKNT'][mask_comp],
2683
+ color=wind_comp_color,
2684
+ length=wind_comp_barb_length,
2685
+ alpha=wind_comp_barb_alpha)
2686
+
2687
+ leg = ax.legend(loc=(barb_legend_x_position, barb_legend_y_position), prop={'size': barb_legend_fontsize})
2688
+ leg.set_zorder(barb_legend_zorder)
2689
+
2690
+ fig.savefig(f"{path}/{station_id.upper()}.png",
2691
+ bbox_inches='tight')
2692
+
2693
+ _plt.close(fig)
2694
+
2695
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
2696
+
2697
+ def plot_relative_humidity_wind_profile_comparison(station_id,
2698
+ current=True,
2699
+ custom_time_1=None,
2700
+ custom_time_2=None,
2701
+ proxies=None,
2702
+ clear_recycle_bin=False,
2703
+ path='FireWxPy Graphics/Observations/Upper Air/Relative Humidity Wind Profiles Comparison',
2704
+ to_meters=False,
2705
+ to_feet=True,
2706
+ to_mph=True,
2707
+ to_mps=False,
2708
+ anti_aliasing=100,
2709
+ rh_color='red',
2710
+ rh_comp_color='blue',
2711
+ rh_alpha=1,
2712
+ rh_comp_alpha=1,
2713
+ wind_color='darkorange',
2714
+ wind_comp_color='purple',
2715
+ wind_barb_length=7,
2716
+ wind_comp_barb_length=7,
2717
+ wind_barb_alpha=1,
2718
+ wind_comp_barb_alpha=1,
2719
+ y_bottom=0,
2720
+ y_top=10000,
2721
+ fig_x=15,
2722
+ fig_y=8,
2723
+ signature_box_x=0.25,
2724
+ signature_box_y=-0.15,
2725
+ signature_box_style='round',
2726
+ signature_box_color='steelblue',
2727
+ signature_box_alpha=0.5,
2728
+ signature_fontsize=8,
2729
+ signature_fontcolor='black',
2730
+ title_1_fontsize=14,
2731
+ title_1_box_style='round',
2732
+ title_1_box_color='steelblue',
2733
+ title_1_box_alpha=0.5,
2734
+ title_1_fontcolor='black',
2735
+ title_2_fontsize=12,
2736
+ title_2_box_style='round',
2737
+ title_2_box_color='crimson',
2738
+ title_2_box_alpha=0.5,
2739
+ title_2_fontcolor='black',
2740
+ title_2_y_position=1,
2741
+ x_axis1_box_style='round',
2742
+ x_axis1_box_color='crimson',
2743
+ x_axis1_box_alpha=0.5,
2744
+ stats_text_box_fontcolor='black',
2745
+ stats_text_box_x_position=0.7405,
2746
+ stats_text_box_y_position=0.8495,
2747
+ stats_text_box_style='round',
2748
+ stats_text_box_color='wheat',
2749
+ stats_text_box_alpha=1,
2750
+ x_axis_label_fontsize=12,
2751
+ y_axis_label_fontsize=12,
2752
+ axes_label_color='black',
2753
+ legend_fontsize=6.5,
2754
+ xtick_color='black',
2755
+ ytick_color='black',
2756
+ facecolor='lavender',
2757
+ df=None,
2758
+ df_comp=None,
2759
+ date=None,
2760
+ date_comp=None,
2761
+ subplot_background_color='silver',
2762
+ barb_legend_fontsize=10,
2763
+ barb_legend_x_position=0,
2764
+ barb_legend_y_position=0,
2765
+ barb_legend_zorder=10):
2766
+
2767
+
2768
+ """
2769
+ This function plots an observed relative humidity/wind profile comparison from 2 different atmospheric soundings.
2770
+
2771
+ Required Arguments:
2772
+
2773
+ 1) station_id (String) - The station ID for the sounding site.
2774
+
2775
+ Optional Arguments:
2776
+
2777
+ 1) current (Boolean) - Default=True. When set to True, the function defaults to the latest sounding. Set to False
2778
+ when plotting past soundings.
2779
+
2780
+ 2) custom_time_1 (String) - Default=None. When plotting archived sounding data, specify the first custom time as a string in the
2781
+ form of 'YYYY-mm-dd:HH'.
2782
+
2783
+ 3) custom_time_2 (String) - Default=None. When plotting archived sounding data, specify the second custom time as a string in the
2784
+ form of 'YYYY-mm-dd:HH'.
2785
+
2786
+ 4) proxies (dict or None) - Default=None. If the user is using proxy server(s), the user must change the following:
2787
+
2788
+ proxies=None ---> proxies={
2789
+ 'http':'http://your-proxy-address:port',
2790
+ 'https':'http://your-proxy-address:port'
2791
+ }
2792
+
2793
+ 5) clear_recycle_bin (Boolean) - Default=False, When set to True,
2794
+ the contents in your recycle/trash bin will be deleted with each run of the program you are calling WxData.
2795
+ This setting is to help preserve memory on the machine.
2796
+
2797
+ 6) path (String) - Default='FireWxPy Graphics/Observations/Upper Air/Relative Humidity Wind Profiles Comparison'. The path where
2798
+ the graphic will save.
2799
+
2800
+ 7) to_meters (Boolean) - Default=False. Set to True for height in meters.
2801
+
2802
+ 8) to_feet (Boolean) - Default=True. Set to True for height in feet.
2803
+
2804
+ 9) to_mph (Boolean) - Default=True. Set to True for wind speed in miles per hour.
2805
+
2806
+ 10) to_mps (Boolean) - Default=False. Set to True for wind speed in meters per second.
2807
+
2808
+ 11) anti_aliasing (Integer) - Default=100. This is the amount of data points interpolated between observed data points.
2809
+ The higher the number the more interpolated data points. This is for those who want to have a colormapped profile that
2810
+ appears as a line but is a series of colormapped scatter points.
2811
+
2812
+ 12) rh_color (String) - Default='red'. The color for the relative humidity line corresponding to custom_time_1.
2813
+
2814
+ 13) rh_comp_color (String) - Default='blue'. The color for the relative humidity line corresponding to custom_time_2.
2815
+
2816
+ 14) rh_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
2817
+ 0 = Completely Transparent, 1 = Completely Opaque.
2818
+
2819
+ 15) wind_color (String) - Default='darkorange'. The color for the wind line and wind barbs corresponding to custom_time_1.
2820
+
2821
+ 16) wind_color_comparison (String) - Default='purple'. The color for the wind line and wind barbs corresponding to custom_time_2.
2822
+
2823
+ 17) wind_barb_length (Integer) - Default=5. The length of the wind barb.
2824
+
2825
+ 18) wind_barb_alpha (Float or Integer) - Default=1. A number between 0 and 1 that corresponds to the transparency of the line.
2826
+ 0 = Completely Transparent, 1 = Completely Opaque.
2827
+
2828
+ 19) y_bottom (Integer) - Default=0. The height in feet where the y-axis begins.
2829
+
2830
+ 20) y_top (Integer) - Default=10000. The height in feet where the y-axis ends.
2831
+
2832
+ 21) fig_x (Integer) - Default=15. The x-length of the figure.
2833
+
2834
+ 22) fig_y (Integer) - Default=8. The y-length of the figure.
2835
+
2836
+ 23) signature_box_x (Float) - Default=0.85. The x-position of the signature text box with respect to the figure axis.
2837
+
2838
+ 24) signature_box_y (Float) - Default=-0.15. The y-position of the signature text box with respect to the figure axis.
2839
+
2840
+ 25) signature_box_style (String) - Default='round'. The style of the text box.
2841
+
2842
+ 26) signature_box_color (String) - Default='steelblue'. The color of the text box.
2843
+
2844
+ 27) signature_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2845
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2846
+
2847
+ 28) signature_fontsize (Integer) - Default=8. Font size of the font in the textbox.
2848
+
2849
+ 29) signature_fontcolor (String) - Default='black'. Font color of the font in the textbox.
2850
+
2851
+ 30) x_title_position (Float) - Default=0.015. The x-position for all titles with respect to the figure axis.
2852
+
2853
+ 31) title_1_fontsize (Integer) - Default=14. Font size of the figure title.
2854
+
2855
+ 32) title_1_box_style (String) - Default='round'. Text box style of the figure title textbox.
2856
+
2857
+ 33) title_1_box_color (String) - Default='steelblue'. The color of the text box of the figure title.
2858
+
2859
+ 34) title_1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2860
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2861
+
2862
+ 35) title_1_fontcolor (String) - Default='black'. Font color of the figure title.
2863
+
2864
+ 36) title_2_fontsize (Integer) - Default=12. Font size of the subplot title.
2865
+
2866
+ 37) title_2_box_style (String) - Default='round'. Text box style of the subplot title text box.
2867
+
2868
+ 38) title_2_box_color (String) - Default='lime'. Text box color of the subplot title text box.
2869
+
2870
+ 39) title_2_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2871
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2872
+
2873
+ 40) title_2_fontcolor (String) - Default='black'. Font color of the subplot title.
2874
+
2875
+ 41) title_2_y_position (Float or Integer) - Default=1. The y-axis positon of the subplot text box.
2876
+
2877
+ 42) x_axis1_box_style (String) - Default='round'. Text box style of the first subplot x-axis text box.
2878
+
2879
+ 43) x_axis1_box_color (String) - Default='crimson'. Text box color of the first subplot x-axis text box.
2880
+
2881
+ 44) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2882
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2883
+
2884
+ 45) x_axis1_box_style (String) - Default='round'. Text box style for the general x-axis text box.
2885
+
2886
+ 46) x_axis1_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2887
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2888
+
2889
+ 47) stats_text_box_fontcolor (String) - Default='black'. Font color of the stats table.
2890
+
2891
+ 48) stats_text_box_x_position (Float) - Default=0.7405. The x-position of the stats table text box.
2892
+
2893
+ 49) stats_text_box_y_position (Float) - Default=0.8495. The y-position of the stats table text box.
2894
+
2895
+ 50) stats_text_box_style (String) - Default='round'. The style of the stats text box.
2896
+
2897
+ 51) stats_text_box_color (String) - Defaults='wheat'. The color of the stats text box.
2898
+
2899
+ 52) stats_text_box_alpha (Float or Integer) - Default=0.5. A value between 0.5 and 1.
2900
+ 0.5 = Most transparency allowed. 1 = Completely opaque.
2901
+
2902
+ 53) x_axis_label_fontsize (Integer) - Default=12. Font size of x-axis labels.
2903
+
2904
+ 54) y_axis_label_fontsize (Integer) - Default=12. Font size of y-axis labels.
2905
+
2906
+ 55) axes_label_color (String) - Default='black'. The color of the labels on each axis.
2907
+
2908
+ 56) xtick_color (String) - Default='black'. The color of the x-ticks.
2909
+
2910
+ 57) ytick_color (String) - Default='black'. The color of the y-ticks.
2911
+
2912
+ 58) facecolor (String) - Default='lavander'. The face color of the figure.
2913
+
2914
+ 59) df (Pandas.DataFrame) - Default=None. If the user wishes to download a medley of Pandas.DataFrames with WxData
2915
+ and pass those data frames into the plotting function, set df=df.
2916
+
2917
+ 60) date (Datetime) - Default=None. The datetime object associated with the Pandas.DataFrame when downloading
2918
+ the data with WxData outside of the function and passing the date into the function. Set date=date if the user
2919
+ is not downloading the data within the function.
2920
+
2921
+ 61) subplot_background_color (String) - Default='silver'. The background color of each subplot axis.
2922
+
2923
+ 62) barb_legend_x_position (Float or Integer) - Default=0. x-position of wind barb legend with respect to the figure axis.
2924
+
2925
+ 63) barb_legend_y_position (Float or Integer) - Default=0. y-position of wind barb legend with respect to the figure axis.
2926
+
2927
+ 64) barb_legend_fontsize (Integer) - Default=10. Font size of wind barb legend.
2928
+
2929
+ 65) barb_legend_zorder (Integer) - Default=10. The z-order of the borders on the image. Lower numbers send this to the back
2930
+ higher numbers bring this forward.
2931
+
2932
+ Returns
2933
+ -------
2934
+
2935
+ A figure of the vertical profiles comparison saved to {path}
2936
+ """
2937
+
2938
+ _build_directory_branch(path)
2939
+
2940
+ if df == None and current == True:
2941
+ df, df_comp, date, date_comp = _get_observed_sounding_data(station_id,
2942
+ current=current,
2943
+ comparison_24=True,
2944
+ proxies=proxies,
2945
+ clear_recycle_bin=clear_recycle_bin)
2946
+
2947
+ elif df == None and current == False:
2948
+ df, date = _get_observed_sounding_data(station_id,
2949
+ current=current,
2950
+ custom_time=custom_time_1,
2951
+ comparison_24=False,
2952
+ proxies=proxies,
2953
+ clear_recycle_bin=clear_recycle_bin)
2954
+
2955
+ df_comp, date_comp = _get_observed_sounding_data(station_id,
2956
+ current=current,
2957
+ custom_time=custom_time_2,
2958
+ comparison_24=False,
2959
+ proxies=proxies,
2960
+ clear_recycle_bin=clear_recycle_bin)
2961
+
2962
+ else:
2963
+ df = df
2964
+ df_comp = df_comp
2965
+ date = date
2966
+ date_comp = date_comp
2967
+
2968
+
2969
+ pressure = df['PRES'].values * _units('hPa')
2970
+ pressure_comp = df_comp['PRES'].values * _units('hPa')
2971
+
2972
+ height = _mpcalc.pressure_to_height_std(pressure)
2973
+ height_comp = _mpcalc.pressure_to_height_std(pressure_comp)
2974
+
2975
+ if to_meters == True and to_feet == False:
2976
+ height = _calc.kilometers_to_meters(height)
2977
+ height_comp = _calc.kilometers_to_meters(height_comp)
2978
+ height_symbol = f"[M]"
2979
+
2980
+ elif to_feet == True and to_meters == False:
2981
+ height = _calc.kilometers_to_meters(height)
2982
+ height = _calc.meters_to_feet(height)
2983
+ height_comp = _calc.kilometers_to_meters(height_comp)
2984
+ height_comp = _calc.meters_to_feet(height_comp)
2985
+ height_symbol = f"[FT]"
2986
+ else:
2987
+ height = height
2988
+ height_comp = height_comp
2989
+ height_symbol = f"[KM]"
2990
+
2991
+ df['HGHT'] = height.m
2992
+ df_comp['HGHT'] = height_comp.m
2993
+
2994
+ if to_mph == True and to_mps == False:
2995
+ df['SKNT'] = _calc.knots_to_mph(df['SKNT'])
2996
+ df_comp['SKNT'] = _calc.knots_to_mph(df_comp['SKNT'])
2997
+ ws_symbol = f"[MPH]"
2998
+ elif to_mph == False and to_mps == True:
2999
+ df['SKNT'] = _calc.knots_to_mps(df['SKNT'])
3000
+ df_comp['SKNT'] = _calc.knots_to_mps(df_comp['SKNT'])
3001
+ ws_symbol = f"[M/S]"
3002
+ else:
3003
+ ws_symbol = f"[KTS]"
3004
+
3005
+ if title_1_box_alpha < 0.5:
3006
+ title_1_box_alpha = 0.5
3007
+ if title_2_box_alpha < 0.5:
3008
+ title_2_box_alpha = 0.5
3009
+ if stats_text_box_alpha < 0.5:
3010
+ stats_text_box_alpha = 0.5
3011
+ if signature_box_alpha < 0.5:
3012
+ signature_box_alpha = 0.5
3013
+ if x_axis1_box_alpha < 0.5:
3014
+ x_axis1_box_alpha = 0.5
3015
+
3016
+ title_1_box = dict(boxstyle=title_1_box_style,
3017
+ facecolor=title_1_box_color,
3018
+ alpha=title_1_box_alpha)
3019
+
3020
+ title_2_box = dict(boxstyle=title_2_box_style,
3021
+ facecolor=title_2_box_color,
3022
+ alpha=title_2_box_alpha)
3023
+
3024
+ stats_box = dict(boxstyle=stats_text_box_style,
3025
+ facecolor=stats_text_box_color,
3026
+ alpha=stats_text_box_alpha)
3027
+
3028
+ props = dict(boxstyle=signature_box_style,
3029
+ facecolor=signature_box_color,
3030
+ alpha=signature_box_alpha)
3031
+
3032
+ x_axis1_box = dict(boxstyle=x_axis1_box_style,
3033
+ facecolor=x_axis1_box_color,
3034
+ alpha=x_axis1_box_alpha)
3035
+
3036
+ _mpl.rcParams['axes.labelcolor'] = axes_label_color
3037
+ _mpl.rcParams['xtick.color'] = xtick_color
3038
+ _mpl.rcParams['ytick.color'] = ytick_color
3039
+
3040
+ mask = (df['HGHT'] <= y_top) & (df['HGHT'] >= y_bottom)
3041
+ mask_comp = (df_comp['HGHT'] <= y_top) & (df_comp['HGHT'] >= y_bottom)
3042
+
3043
+ rh_x, rh_y = _linear_anti_aliasing(df['RH'][mask],
3044
+ df['HGHT'][mask],
3045
+ anti_aliasing)
3046
+
3047
+ rh_comp_x, rh_comp_y = _linear_anti_aliasing(df_comp['RH'][mask_comp],
3048
+ df_comp['HGHT'][mask_comp],
3049
+ anti_aliasing)
3050
+
3051
+ min_rh_height = _np.nanmax(_np.where(df['RH'][mask] == _np.nanmin(df['RH'][mask]),
3052
+ df['HGHT'][mask],
3053
+ 0))
3054
+
3055
+ max_rh_height = _np.nanmax(_np.where(df['RH'][mask] == _np.nanmax(df['RH'][mask]),
3056
+ df['RH'][mask],
3057
+ 0))
3058
+
3059
+ max_ws_height = _np.nanmax(_np.where(df['SKNT'][mask] == _np.nanmax(df['SKNT'][mask]),
3060
+ df['HGHT'][mask],
3061
+ 0))
3062
+
3063
+ min_rh_height_comp = _np.nanmax(_np.where(df_comp['RH'][mask_comp] == _np.nanmin(df_comp['RH'][mask_comp]),
3064
+ df_comp['HGHT'][mask_comp],
3065
+ 0))
3066
+
3067
+ max_rh_height_comp = _np.nanmax(_np.where(df_comp['RH'][mask_comp] == _np.nanmax(df_comp['RH'][mask_comp]),
3068
+ df_comp['HGHT'][mask_comp],
3069
+ 0))
3070
+
3071
+ max_ws_height_comp = _np.nanmax(_np.where(df_comp['SKNT'][mask_comp] == _np.nanmax(df_comp['SKNT'][mask_comp]),
3072
+ df_comp['HGHT'][mask_comp],
3073
+ 0))
3074
+
3075
+ fig = _plt.figure(figsize=(fig_x, fig_y))
3076
+ fig.patch.set_facecolor(facecolor)
3077
+
3078
+ fig.suptitle(f"{station_id.upper()} VERTICAL PROFILE"
3079
+ f" | TIME 1: {date.strftime('%m/%d/%Y %H:00 UTC')} | TIME 2: {date_comp.strftime('%m/%d/%Y %H:00 UTC')}",
3080
+ fontsize=title_1_fontsize,
3081
+ fontweight='bold',
3082
+ color=title_1_fontcolor,
3083
+ bbox=title_1_box)
3084
+
3085
+ ax = fig.add_subplot(1,1,1)
3086
+ ax.set_facecolor(subplot_background_color)
3087
+ ax.xaxis.set_major_locator(_MaxNLocator(integer=True))
3088
+ ax.yaxis.set_major_locator(_MaxNLocator(integer=True))
3089
+
3090
+ ax.set_xlim(0, 100)
3091
+ ax.set_ylim(y_bottom, y_top)
3092
+
3093
+ ax.set_xlabel(f"[%]",
3094
+ fontsize=x_axis_label_fontsize,
3095
+ fontweight='bold',
3096
+ bbox=x_axis1_box)
3097
+
3098
+ ax.set_ylabel(f"{height_symbol}",
3099
+ fontsize=y_axis_label_fontsize,
3100
+ fontweight='bold',
3101
+ bbox=title_1_box)
3102
+
3103
+ ax.set_title(f"RELATIVE HUMIDITY [%] & WIND SPEED {ws_symbol}",
3104
+ fontweight='bold',
3105
+ loc='center',
3106
+ fontsize=title_2_fontsize,
3107
+ color=title_2_fontcolor,
3108
+ bbox=title_2_box,
3109
+ y=title_2_y_position)
3110
+
3111
+ ax.scatter(rh_x,
3112
+ rh_y,
3113
+ vmin=_np.nanmin(df['TEMP'][mask]),
3114
+ vmax=_np.nanmax(df['TEMP'][mask]),
3115
+ color=rh_color,
3116
+ alpha=rh_alpha,
3117
+ label=f"{date.strftime('%Y-%m-%d %H:00 UTC')}")
3118
+
3119
+ ax.scatter(rh_comp_x,
3120
+ rh_comp_y,
3121
+ vmin=_np.nanmin(df_comp['TEMP'][mask_comp]),
3122
+ vmax=_np.nanmax(df_comp['TEMP'][mask_comp]),
3123
+ color=rh_comp_color,
3124
+ alpha=rh_comp_alpha,
3125
+ label=f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}")
3126
+
3127
+ ax.text(signature_box_x,
3128
+ signature_box_y,
3129
+ f"Plot Created With FireWxPy (C) Eric J. Drewitz 2024-{_utc.strftime('%Y')} "
3130
+ f"| Data Source: weather.uwyo.edu\n"
3131
+ f" Image Created: {_local.strftime(f'%m/%d/%Y %H:00 {_timezone}')} - {_utc.strftime(f'%m/%d/%Y %H:00 UTC')}",
3132
+ fontsize=signature_fontsize,
3133
+ bbox=props,
3134
+ fontweight='bold',
3135
+ color=signature_fontcolor,
3136
+ transform=ax.transAxes)
3137
+
3138
+ ax.text(stats_text_box_x_position,
3139
+ stats_text_box_y_position,
3140
+ f"{date.strftime('%Y-%m-%d %H:00 UTC')}\n"
3141
+ f"MAX RH ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df['RH'][mask]), 0))} [%] @ {int(round(max_rh_height, 0))} {height_symbol}\n"
3142
+ f"MIN RH ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmin(df['RH'][mask]), 0))} [%] @ {int(round(min_rh_height, 0))} {height_symbol}\n"
3143
+ f"MAX WIND ({date.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df['SKNT'][mask]), 0))} {ws_symbol} @ {int(round(max_ws_height, 0))} {height_symbol}\n\n"
3144
+ f"{date_comp.strftime('%Y-%m-%d %H:00 UTC')}\n"
3145
+ f"MAX RH ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df_comp['RH'][mask_comp]), 0))} [%] @ {int(round(max_rh_height_comp, 0))} {height_symbol}\n"
3146
+ f"MIN RH ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmin(df_comp['RH'][mask_comp]), 0))} [%] @ {int(round(min_rh_height_comp, 0))} {height_symbol}\n"
3147
+ f"MAX WIND ({date_comp.strftime('%Y-%m-%d %H:00 UTC')}): {int(round(_np.nanmax(df_comp['SKNT'][mask_comp]), 0))} {ws_symbol} @ {int(round(max_ws_height_comp, 0))} {height_symbol}",
3148
+ fontsize=legend_fontsize,
3149
+ bbox=stats_box,
3150
+ fontweight='bold',
3151
+ color=stats_text_box_fontcolor,
3152
+ transform=ax.transAxes)
3153
+
3154
+ x_positions = []
3155
+ x_position = (_np.nanmin(df['RH'][mask]) + _np.nanmax(df['RH'][mask]))/2
3156
+ for i in range(0, len(df['HGHT'][mask]), 1):
3157
+ x_positions.append(x_position)
3158
+
3159
+ x_position = _np.asarray(x_positions)
3160
+
3161
+ x_positions_comp = []
3162
+ x_position_comp = (_np.nanmin(df_comp['RH'][mask_comp]) + _np.nanmax(df_comp['RH'][mask_comp]))/2
3163
+ for i in range(0, len(df_comp['HGHT'][mask_comp]), 1):
3164
+ x_positions_comp.append(x_position_comp)
3165
+
3166
+ x_position_comp = _np.asarray(x_positions_comp)
3167
+
3168
+ ax.barbs(x_position,
3169
+ df['HGHT'][mask],
3170
+ df['U-WIND'][mask],
3171
+ df['V-WIND'][mask],
3172
+ df['SKNT'][mask],
3173
+ color=wind_color,
3174
+ length=wind_barb_length,
3175
+ alpha=wind_barb_alpha)
3176
+
3177
+ ax.barbs(x_position_comp,
3178
+ df_comp['HGHT'][mask_comp],
3179
+ df_comp['U-WIND'][mask_comp],
3180
+ df_comp['V-WIND'][mask_comp],
3181
+ df_comp['SKNT'][mask_comp],
3182
+ color=wind_comp_color,
3183
+ length=wind_comp_barb_length,
3184
+ alpha=wind_comp_barb_alpha)
3185
+
3186
+ leg = ax.legend(loc=(barb_legend_x_position, barb_legend_y_position), prop={'size': barb_legend_fontsize})
3187
+ leg.set_zorder(barb_legend_zorder)
3188
+
3189
+ fig.savefig(f"{path}/{station_id.upper()}.png",
3190
+ bbox_inches='tight')
3191
+
3192
+ _plt.close(fig)
3193
+
3194
+ print(f"Saved {station_id.upper()}.png profiles to {path}.")
3195
+
3196
+