diff --git a/src/sounderpy/__pycache__/acars_data.cpython-312.pyc b/src/sounderpy/__pycache__/acars_data.cpython-312.pyc index 405cde3..f35fc84 100644 Binary files a/src/sounderpy/__pycache__/acars_data.cpython-312.pyc and b/src/sounderpy/__pycache__/acars_data.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/bufkit_data.cpython-312.pyc b/src/sounderpy/__pycache__/bufkit_data.cpython-312.pyc index b91c9fd..d68906b 100644 Binary files a/src/sounderpy/__pycache__/bufkit_data.cpython-312.pyc and b/src/sounderpy/__pycache__/bufkit_data.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/calc.cpython-312.pyc b/src/sounderpy/__pycache__/calc.cpython-312.pyc index aa694b1..dbd5064 100644 Binary files a/src/sounderpy/__pycache__/calc.cpython-312.pyc and b/src/sounderpy/__pycache__/calc.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/model_data.cpython-312.pyc b/src/sounderpy/__pycache__/model_data.cpython-312.pyc index f8818d4..d02130d 100644 Binary files a/src/sounderpy/__pycache__/model_data.cpython-312.pyc and b/src/sounderpy/__pycache__/model_data.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/obs_data.cpython-312.pyc b/src/sounderpy/__pycache__/obs_data.cpython-312.pyc index a6bd034..44efc16 100644 Binary files a/src/sounderpy/__pycache__/obs_data.cpython-312.pyc and b/src/sounderpy/__pycache__/obs_data.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/plot.cpython-312.pyc b/src/sounderpy/__pycache__/plot.cpython-312.pyc index 4ffeff2..4016915 100644 Binary files a/src/sounderpy/__pycache__/plot.cpython-312.pyc and b/src/sounderpy/__pycache__/plot.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/sounderpy.cpython-312.pyc b/src/sounderpy/__pycache__/sounderpy.cpython-312.pyc index 42b3964..6e7d561 100644 Binary files a/src/sounderpy/__pycache__/sounderpy.cpython-312.pyc and b/src/sounderpy/__pycache__/sounderpy.cpython-312.pyc differ diff --git a/src/sounderpy/__pycache__/utils.cpython-312.pyc b/src/sounderpy/__pycache__/utils.cpython-312.pyc index a88f2af..8192e68 100644 Binary files a/src/sounderpy/__pycache__/utils.cpython-312.pyc and b/src/sounderpy/__pycache__/utils.cpython-312.pyc differ diff --git a/src/sounderpy/acars_data.py b/src/sounderpy/acars_data.py index 200d130..a5103c3 100644 --- a/src/sounderpy/acars_data.py +++ b/src/sounderpy/acars_data.py @@ -21,7 +21,7 @@ Purpose of module: - House function for loading and parsing ACARS profiles and + House functions for loading and parsing ACARS profiles and ACARS profile data. Functions here are explicitly called by the user. diff --git a/src/sounderpy/bufkit_data.py b/src/sounderpy/bufkit_data.py index 077c70f..b045c08 100644 --- a/src/sounderpy/bufkit_data.py +++ b/src/sounderpy/bufkit_data.py @@ -17,7 +17,7 @@ Purpose of module: - House function for loading and parsing BUFKIT model forecast data. + House functions for loading and parsing BUFKIT model forecast data. Functions here are referenced by sounderpy.py diff --git a/src/sounderpy/calc.py b/src/sounderpy/calc.py index f152bb8..bae8907 100644 --- a/src/sounderpy/calc.py +++ b/src/sounderpy/calc.py @@ -139,10 +139,11 @@ def locate_bounds(arr): class sounding_params: - def __init__(self, clean_data, storm_motion='right_moving', modify_sfc=None): + def __init__(self, clean_data, storm_motion='right_moving', modify_sfc=None, include_all_parcels=False): self.clean_data = clean_data self.storm_motion = storm_motion self.modify_sfc = modify_sfc + self.include_all_parcels = include_all_parcels ###################################################################################################### @@ -394,6 +395,18 @@ def interpolate(var,hgts,step): thermo['dparcel_p'] = ma.masked thermo['dparcel_T'] = ma.masked + #--- PARCEL PROFILES ---# + # --------------------------------------------------------------- + if self.include_all_parcels: + # Calculate parcels + parcels = [parcelx(prof, pres=p[i].m, tmpc=T[i].m, dwpc=Td[i].m) for i in range(len(p))] + thermo['cape_profile'] = np.array([pcl.bplus for pcl in parcels]) + thermo['cin_profile'] = np.array([pcl.bminus for pcl in parcels]) + thermo['3cape_profile'] = np.array([pcl.b3km for pcl in parcels]) + # Interpolate + intrp['cape_profileINTRP'] = interpolate(thermo['cape_profile'], zINTRP, resolution) + intrp['cin_profileINTRP'] = interpolate(thermo['cin_profile'], zINTRP, resolution) + intrp['3cape_profileINTRP'] = interpolate(thermo['3cape_profile'], zINTRP, resolution) # ENTRAINING CAPE NOW LOCATED BELOW KINEMATICS SECTION SO diff --git a/src/sounderpy/cm1_utils.py b/src/sounderpy/cm1_utils.py index e09ba1c..975a050 100644 --- a/src/sounderpy/cm1_utils.py +++ b/src/sounderpy/cm1_utils.py @@ -94,7 +94,9 @@ def make_cm1_profile(filename, meta_data_dict): 3] # cm1 input has no surface hgt, use quadratic extrapolation to estimate sfc z else: elev = meta_data_dict['elev'] + full_z[0] = elev + full_th[0] = float(sfc_th) full_qv[0] = float(sfc_qv) / 1000. # convert to g/kg full_u[0] = 1.75 * full_u[1] - full_u[2] + 0.25 * full_u[ @@ -123,6 +125,9 @@ def make_cm1_profile(filename, meta_data_dict): check_sfc_hgt(full_z) check_latlon(meta_data_dict) + # convert hgt values to include elevation + full_z[1:] = full_z[1:] + elev + ############################################# # CONSTRUCT CLEAN_DATA DICTIONARY ############################################# diff --git a/src/sounderpy/plot.py b/src/sounderpy/plot.py index 1e5193d..be6e5e3 100644 --- a/src/sounderpy/plot.py +++ b/src/sounderpy/plot.py @@ -61,7 +61,8 @@ ########################## FULL SOUNDING ################################ def __full_sounding(clean_data, color_blind, dark_mode, storm_motion, special_parcels=None, - show_radar=True, radar_time='sounding', map_zoom=2, modify_sfc=None): + show_radar=True, radar_time='sounding', map_zoom=2, modify_sfc=None, + show_theta=False): # record process time @@ -214,7 +215,7 @@ def find_file(target_time, file_names): ws = mpcalc.wind_speed(u, v) # calculate other sounding parameters using SounderPy Calc - general, thermo, kinem, intrp = sounding_params(sounding_data, storm_motion).calc() + general, thermo, kinem, intrp = sounding_params(sounding_data, storm_motion, include_all_parcels=not show_theta).calc() ################################################################# @@ -1067,7 +1068,7 @@ def sm_str(storm_motion, speeds, directions): ################################################################# # PLOT AXIS/LOC strmws_ax = plt.axes((0.945, -0.13, 0.065, 0.23)) - plt.figtext(0.978, 0.07, f'SW ζ (%)', color=gen_txt_clr, weight='bold', fontsize=12, ha='center', alpha=0.7) + plt.figtext(0.978, 0.07, f'Streamwiseness\n of ζ (%)', color=gen_txt_clr, weight='bold', fontsize=10, ha='center', alpha=0.9) strmws_ax.spines["top"].set_color(brdr_clr) strmws_ax.spines["left"].set_color(brdr_clr) strmws_ax.spines["right"].set_color(brdr_clr) @@ -1085,20 +1086,23 @@ def sm_str(storm_motion, speeds, directions): #XTICKS strmws_ax.set_xlim(40, 102) - strmws_ax.set_xticks([50, 90]) - strmws_ax.set_xticklabels([50, 90], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) + strmws_ax.set_xticks([50, 70, 90]) + strmws_ax.set_xticklabels([50, 70, 90], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) strmws_ax.set_xlabel(' ') #HGT LABLES - strmws_ax.text(47, 502 , '0.5km', fontsize=8, alpha=0.6, color=gen_txt_clr) - strmws_ax.text(47, 1002, '1.0km', fontsize=8, alpha=0.6, color=gen_txt_clr) - strmws_ax.text(47, 1502, '1.5km', fontsize=8, alpha=0.6, color=gen_txt_clr) - strmws_ax.text(47, 2002, '2.0km', fontsize=8, alpha=0.6, color=gen_txt_clr) - strmws_ax.text(47, 2502, '2.5km', fontsize=8, alpha=0.6, color=gen_txt_clr) + strmws_ax.text(47, 502 , '.5 km', fontsize=10, weight='bold', alpha=1, color=gen_txt_clr) + strmws_ax.text(47, 1002, '1 km', fontsize=10, weight='bold', alpha=1, color=gen_txt_clr) + strmws_ax.text(47, 1502, '1.5 km', fontsize=10, weight='bold', alpha=1, color=gen_txt_clr) + strmws_ax.text(47, 2002, '2 km', fontsize=10, weight='bold', alpha=1, color=gen_txt_clr) + #strmws_ax.text(47, 2502, '2.5 km', fontsize=9, weight='bold', alpha=0.9, color=gen_txt_clr) if ma.is_masked(kinem['sm_u']) == False: - plt.plot(kinem['swv_perc'][0:11], intrp['zINTRP'][0:11], color=hodo_color[0], lw=3, clip_on=True) - plt.plot(kinem['swv_perc'][10:30], intrp['zINTRP'][10:30], color=hodo_color[1], lw=3, clip_on=True) + strmws_ax.plot(kinem['swv_perc'][0:11], intrp['zINTRP'][0:11], color=hodo_color[0], lw=3, clip_on=True) + strmws_ax.plot(kinem['swv_perc'][10:31], intrp['zINTRP'][10:31], color=hodo_color[1], lw=3, clip_on=True) + strmws_ax.fill_betweenx(intrp['zINTRP'][0:31], kinem['swv_perc'][0:31], + color='cornflowerblue', linewidth=0, alpha=0.2, clip_on=True) + if ma.is_masked(kinem['eil_z'][0]) == False: strmws_ax.fill_between(x=(40,102), y1=kinem['eil_z'][0], y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) @@ -1113,7 +1117,8 @@ def sm_str(storm_motion, speeds, directions): ### VORTICITY W/HGT ### ################################################################# vort_ax = plt.axes((1.01, -0.13, 0.066, 0.23)) - plt.figtext(1.045, 0.06, f'ζₜₒₜ & ζSW\n(/sec)', color=gen_txt_clr, weight='bold', fontsize=12, ha='center', alpha=0.7) + plt.figtext(1.043, 0.05, f'Total ζ &\n Streamwise ζ \n(/sec)', color=gen_txt_clr, weight='bold', + fontsize=12, ha='center', alpha=0.9) vort_ax.spines["top"].set_color(brdr_clr) vort_ax.spines["left"].set_color(brdr_clr) vort_ax.spines["right"].set_color(brdr_clr) @@ -1132,19 +1137,21 @@ def sm_str(storm_motion, speeds, directions): if ma.is_masked(kinem['sm_u']) == False: #XTICKS vort_ax.set_xlabel(' ') - vort_max = kinem['vort'][0:30].max()+0.005 - vort_min = kinem['vort'][0:30].min()-0.005 - vort_ax.set_xlim(vort_min-0.002, vort_max+0.002) - vort_ax.set_xticks([(vort_min+0.005),(vort_max-0.005)]) - vort_ax.set_xticklabels([(np.round(vort_min+0.002,2)),(np.round(vort_max-0.002,2))], + vort_ax.set_xlim(0, 0.06) + vort_ax.set_xticks([.01, .03, .05]) + vort_ax.set_xticklabels([".01", ".03", ".05"], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) - vort_ax.plot(kinem['swv'][0:30], intrp['zINTRP'][0:30], color='orange', linewidth=3, alpha=0.8, label='SW ζ') - vort_ax.plot(kinem['vort'][0:30], intrp['zINTRP'][0:30], color=gen_txt_clr, linewidth=4, alpha=0.4, label='Total ζ') + vort_ax.plot(kinem['swv'][0:31], intrp['zINTRP'][0:31], color='orange', linewidth=3, alpha=0.8, label='SW ζ') + vort_ax.plot(kinem['vort'][0:31], intrp['zINTRP'][0:31], color=gen_txt_clr, linewidth=4, alpha=0.4, label='Total ζ') + vort_ax.fill_betweenx(intrp['zINTRP'][0:31], kinem['vort'][0:31], where=(kinem['vort'][0:31] > kinem['swv'][0:31]), + color=gen_txt_clr, linewidth=0, alpha=0.1, clip_on=True) + vort_ax.fill_betweenx(intrp['zINTRP'][0:31], kinem['swv'][0:31], + color='orange', linewidth=0, alpha=0.2, clip_on=True) if ma.is_masked(kinem['eil_z'][0]) == False: - vort_ax.fill_between(x=(vort_min-0.002, vort_max+0.002), y1=kinem['eil_z'][0], + vort_ax.fill_between(x=(0, 0.065), y1=kinem['eil_z'][0], y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) else: warnings.warn("Total Vorticity could not be plotted (no valid storm motion/not enough data)", Warning) @@ -1158,7 +1165,7 @@ def sm_str(storm_motion, speeds, directions): ### SRW W/HGT ### ################################################################# wind_ax = plt.axes((1.0755, -0.13, 0.066, 0.23)) - plt.figtext(1.108, 0.06, f'SR Wind\n(kts)', weight='bold', color=gen_txt_clr, fontsize=12, ha='center', alpha=0.7) + plt.figtext(1.108, 0.06, f'Storm Relative\nWind (kts)', weight='bold', color=gen_txt_clr, fontsize=12, ha='center', alpha=0.9) wind_ax.spines["top"].set_color(brdr_clr) wind_ax.spines["left"].set_color(brdr_clr) wind_ax.spines["right"].set_color(brdr_clr) @@ -1175,23 +1182,30 @@ def sm_str(storm_motion, speeds, directions): wind_ax.tick_params(axis='y', length = 0) wind_ax.tick_params(axis="x",direction="in", pad=-12) + wind_ax.text(40, thermo['sb_lcl_z'], '-LCL-', fontsize=10, weight='bold', + alpha=1, color=gen_txt_clr, clip_on=True) + if thermo['mu_lfc_z'] < 2500: + wind_ax.text(40, thermo['mu_lfc_z'], '-LFC-', fontsize=10, weight='bold', + alpha=1, color=gen_txt_clr, clip_on=True) + + if ma.is_masked(kinem['sm_u']) == False: #XTICKS - wind_max = kinem['srw'][0:30].max()+1 - wind_min = kinem['srw'][0:30].min()-1 - wind_ax.set_xlim(wind_min-5, wind_max+5) - wind_ax.set_xticks([(wind_min)+2, (wind_max)-2]) - wind_ax.set_xticklabels([(int(wind_min)+2), (int(wind_max)-2)], weight='bold', + wind_ax.set_xlim(10, 50) + wind_ax.set_xticks([20, 30, 40]) + wind_ax.set_xticklabels([20, 30, 40], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) #PLOT SR WIND wind_ax.plot(kinem['srw'][0:11], intrp['zINTRP'][0:11], color=hodo_color[0], clip_on=True, linewidth=3, alpha=0.8, label='0-1 SR Wind') - wind_ax.plot(kinem['srw'][10:30], intrp['zINTRP'][10:30], color=hodo_color[1], clip_on=True, + wind_ax.plot(kinem['srw'][10:31], intrp['zINTRP'][10:31], color=hodo_color[1], clip_on=True, linewidth=3, alpha=0.8, label='1-3 SR Wind') + wind_ax.fill_betweenx(intrp['zINTRP'][0:31], kinem['srw'][0:31], + color='cornflowerblue', linewidth=0, alpha=0.2, clip_on=True) if ma.is_masked(kinem['eil_z'][0]) == False: - wind_ax.fill_between(x=(wind_min-5, wind_max+5), y1=kinem['eil_z'][0], y2=kinem['eil_z'][1], + wind_ax.fill_between(x=(5, 55), y1=kinem['eil_z'][0], y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) else: warnings.warn("Storm Relative Wind could not be plotted (no valid storm motion/not enough data)", Warning) @@ -1202,48 +1216,121 @@ def sm_str(storm_motion, speeds, directions): - ################################################################# - ### THETA & THETA E W/HGT ### - ################################################################# - #PLOT AXES/LOC - theta_ax = plt.axes((1.141, -0.13, 0.0653, 0.23)) - plt.figtext(1.175, 0.06, f'Theta-e &\nTheta (K)', weight='bold', color=gen_txt_clr, fontsize=12, ha='center', alpha=0.7) - theta_ax.spines["top"].set_color(brdr_clr) - theta_ax.spines["left"].set_color(brdr_clr) - theta_ax.spines["right"].set_color(brdr_clr) - theta_ax.spines["bottom"].set_color(brdr_clr) - theta_ax.spines["bottom"].set_color(brdr_clr) - theta_ax.set_facecolor(bckgrnd_clr) + if show_theta: + ############################################################# + ### THETA & THETA E W/HGT ### + ############################################################# + #PLOT AXES/LOC + theta_ax = plt.axes((1.141, -0.13, 0.0653, 0.23)) + plt.figtext(1.175, 0.06, f'Theta-e &\nTheta (K)', weight='bold', color=gen_txt_clr, fontsize=12, ha='center', alpha=0.9) + theta_ax.spines["top"].set_color(brdr_clr) + theta_ax.spines["left"].set_color(brdr_clr) + theta_ax.spines["right"].set_color(brdr_clr) + theta_ax.spines["bottom"].set_color(brdr_clr) + theta_ax.spines["bottom"].set_color(brdr_clr) + theta_ax.set_facecolor(bckgrnd_clr) - maxtheta = intrp['thetaeINTRP'][0:30].max() - mintheta = intrp['thetaINTRP'][0:30].min() + maxtheta = intrp['thetaeINTRP'][0:31].max() + mintheta = intrp['thetaINTRP'][0:31].min() - #YTICKS - theta_ax.set_ylim(intrp['zINTRP'][0], 3000) - theta_ax.set_yticklabels([]) - plt.ylabel(' ') - theta_ax.tick_params(axis='y', length = 0) - theta_ax.grid(True, axis='y') + #YTICKS + theta_ax.set_ylim(intrp['zINTRP'][0], 3000) + theta_ax.set_yticklabels([]) + plt.ylabel(' ') + theta_ax.tick_params(axis='y', length = 0) + theta_ax.grid(True, axis='y') - #XTICKS - theta_ax.set_xlim(mintheta - 5, maxtheta + 5) - theta_ax.set_xticks([(mintheta), (maxtheta)]) - theta_ax.set_xticklabels([int(mintheta), int(maxtheta)], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) + #XTICKS + theta_ax.set_xlim(mintheta - 5, maxtheta + 5) + theta_ax.set_xticks([(mintheta), (maxtheta)]) + theta_ax.set_xticklabels([int(mintheta), int(maxtheta)], weight='bold', alpha=0.5, fontstyle='italic', color=gen_txt_clr) - theta_ax.tick_params(axis="x", direction="in", pad=-12) - theta_ax.set_xlabel(' ') + theta_ax.tick_params(axis="x", direction="in", pad=-12) + theta_ax.set_xlabel(' ') - #PLOT THETA VS HGT - plt.plot(intrp['thetaINTRP'], intrp['zINTRP'], color='purple', linewidth=3.5, alpha=0.5, clip_on=True) - plt.plot(intrp['thetaeINTRP'], intrp['zINTRP'], color='purple', linewidth=3.5, alpha=0.8, clip_on=True) + #PLOT THETA VS HGT + plt.plot(intrp['thetaINTRP'], intrp['zINTRP'], color='purple', linewidth=3.5, alpha=0.5, clip_on=True) + plt.plot(intrp['thetaeINTRP'], intrp['zINTRP'], color='purple', linewidth=3.5, alpha=0.8, clip_on=True) - if ma.is_masked(kinem['eil_z'][0]) == False: - theta_ax.fill_between(x=(mintheta - 5, maxtheta + 5), y1=kinem['eil_z'][0], - y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) - ################################################################# + if ma.is_masked(kinem['eil_z'][0]) == False: + theta_ax.fill_between(x=(mintheta - 5, maxtheta + 5), y1=kinem['eil_z'][0], + y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) + else: + ############################################################# + ### CIN & 3CAPE W/HGT ### + ############################################################# + cin_color, cape_color = 'teal', 'tab:orange' + + mincin = intrp['cin_profileINTRP'][0:31].min() + max3cape = intrp['3cape_profileINTRP'][0:31].max() + + # PLOT AXES/LOC + inflow_ax = plt.axes((1.141, -0.13, 0.0653, 0.23)) + plt.figtext(1.173, 0.05, f'Stepwise\n CIN & CAPE\n (J/kg)', weight='bold', + color=gen_txt_clr, fontsize=12, ha='center', alpha=0.9) + inflow_ax.spines["top"].set_color(brdr_clr) + inflow_ax.spines["left"].set_color(brdr_clr) + inflow_ax.spines["right"].set_color(brdr_clr) + inflow_ax.spines["bottom"].set_color(brdr_clr) + inflow_ax.set_facecolor(bckgrnd_clr) + + ### AXIS 1 -- CIN ### + + # YAXIS PARAMS AX1 & AX2 + inflow_ax.set_ylim(intrp['zINTRP'][0], 3000) + inflow_ax.set_yticklabels([]) + inflow_ax.set_ylabel(' ') + inflow_ax.tick_params(axis='y', length=0) + inflow_ax.grid(True, axis='y') + inflow_ax.axvline(0, linestyle=':', alpha=.8) + + # XAXIS PARAMS AX1 + inflow_ax.set_xlim(-300, 300) + inflow_ax.set_xticks([-200, -100]) + inflow_ax.set_xticklabels([-200, -100], weight='bold', alpha=0.5, rotation=60, + fontstyle='italic', color=gen_txt_clr, zorder=10) + inflow_ax.tick_params(axis="x", direction="in", pad=-25) + inflow_ax.set_xlabel(' ') + plt.xticks(rotation=45) + + # PLOT CIN VS HGT + inflow_ax.fill_betweenx(intrp['zINTRP'], intrp['cin_profileINTRP'], + color=cin_color, linewidth=0, alpha=0.5, clip_on=True) + if ma.is_masked(kinem['eil_z'][0]) == False: + inflow_ax.fill_between(x=(-305, 305), y1=kinem['eil_z'][0], + y2=kinem['eil_z'][1], color='lightblue', alpha=0.2) + + ### AXIS 2 -- CAPE ### + inflow_ax2 = inflow_ax.twiny() + inflow_ax2.spines["top"].set_color(brdr_clr) + inflow_ax2.spines["left"].set_color(brdr_clr) + inflow_ax2.spines["right"].set_color(brdr_clr) + inflow_ax2.spines["bottom"].set_color(brdr_clr) + inflow_ax2.set_facecolor(bckgrnd_clr) + + # XAXIS PARAMS AX2 + inflow_ax2.set_xlim(-3000, 3000) + inflow_ax2.set_xticks([0, 1000, 2000]) + inflow_ax2.set_xticklabels(['0 ', '1k', '2k'], weight='bold', alpha=0.5, + fontstyle='italic', color=gen_txt_clr, zorder=10) + inflow_ax2.xaxis.set_ticks_position('bottom') + inflow_ax2.tick_params(axis="x", direction="in", pad=-20) + inflow_ax2.set_xlabel(' ') + plt.xticks(rotation=45) + + # YAXIS PARAMS AX2 + inflow_ax2.set_ylim(intrp['zINTRP'][0], 3000) + inflow_ax2.set_yticklabels([]) + inflow_ax2.set_ylabel(' ') + inflow_ax2.tick_params(axis="y", length=0) + inflow_ax2.grid(True, axis='y') + + # PLOT 3CAPE VS HGT + inflow_ax2.fill_betweenx(intrp['zINTRP'], intrp['cape_profileINTRP'], + color=cape_color, linewidth=0, alpha=0.8, clip_on=True) + ############################################################# - ######################################################################### ############################## TEXT PLOTS ############################### ######################################################################### @@ -1919,6 +2006,7 @@ def sm_str(storm_motion, speeds, directions): vort_ax.set_yticklabels([]) vort_ax.set_ylabel(' ') vort_ax.tick_params(axis="x",direction="in", pad=-12) + if ma.is_masked(kinem['sm_u']) == False: #XTICKS diff --git a/src/sounderpy/sounderpy.py b/src/sounderpy/sounderpy.py index b9b162a..2be01e6 100644 --- a/src/sounderpy/sounderpy.py +++ b/src/sounderpy/sounderpy.py @@ -28,7 +28,7 @@ THIS RELEASE ------- - Version: 3.0.6 | December 2024 + Version: 3.0.7 | December 2024 DOCUMENTATION @@ -50,7 +50,7 @@ citation_text = f""" ## ---------------------------------- SOUNDERPY ----------------------------------- ## ## Vertical Profile Data Retrieval and Analysis Tool For Python ## -## v3.0.6 | Dec 2024 | (C) Kyle J Gillett ## +## v3.0.7dev | Dec 2024 | (C) Kyle J Gillett ## ## Docs: https://kylejgillett.github.io/sounderpy/ ## ## --------------------- THANK YOU FOR USING THIS PACKAGE! ------------------------ ## """ @@ -206,7 +206,7 @@ def get_bufkit_data(model, station, fcst_hour, run_year=None, run_month=None, ru ######################################################################### def build_sounding(clean_data, style='full', color_blind=False, dark_mode=False, storm_motion='right_moving', special_parcels=None, show_radar=True, radar_time='sounding', map_zoom=2, modify_sfc=None, - save=False, filename='sounderpy_sounding'): + show_theta=False, save=False, filename='sounderpy_sounding'): ''' Return a full sounding plot of SounderPy data, ``plt`` @@ -223,6 +223,7 @@ def build_sounding(clean_data, style='full', color_blind=False, dark_mode=False, :type storm_motion: str or list of floats, optional :param special_parcels: a nested list of special parcels from the ``ecape_parcels`` library. The nested list should be a list of two lists (`[[a, b], [c, d]]`) where the first list should include 'highlight parcels' and second list should include 'background parcels'. For more details, see the :ref:`parcels_logic` section. :type special_parcels: nested `list` of two `lists`, optional + :param show_theta: bool, optional :param save: whether to show the plot inline or save to a file. Default is ``False`` which displays the file inline. :type save: bool, optional :param filename: the filename by which a file should be saved to if ``save = True``. Default is `sounderpy_sounding`. @@ -233,10 +234,11 @@ def build_sounding(clean_data, style='full', color_blind=False, dark_mode=False, print(f'> SOUNDING PLOTTER FUNCTION\n ---------------------------------') + plt = __full_sounding(clean_data, color_blind, dark_mode, storm_motion, special_parcels, show_radar, radar_time, map_zoom, modify_sfc, show_theta) if save: - __full_sounding(clean_data, color_blind, dark_mode, storm_motion, special_parcels, show_radar, radar_time, map_zoom, modify_sfc).savefig(filename, bbox_inches='tight') + plt.savefig(filename, bbox_inches='tight') else: - __full_sounding(clean_data, color_blind, dark_mode, storm_motion, special_parcels, show_radar, radar_time, map_zoom, modify_sfc).show() + plt.show()