From c5954ed2a5a33458ccf16a13ec071d701be768d7 Mon Sep 17 00:00:00 2001 From: Christina Kalb Date: Mon, 10 Jun 2024 23:28:23 -0600 Subject: [PATCH 1/4] Adding phase diagrams for Stratosphere QBO --- .../stratosphere_plots.py | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py index 491e67a3..5a14f745 100644 --- a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py +++ b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py @@ -1,5 +1,6 @@ import xarray as xr # http://xarray.pydata.org/ import numpy as np +import pandas as pd import cmocean import matplotlib from matplotlib import cm @@ -55,3 +56,128 @@ def plot_polar_contour(leads,levels,pdata,outfile,ptitle,plevs,ctable): plt.savefig(outfile) plt.close() + +def plot_qbo_phase_circuits(inits,periods,rean_qbo_pcs,rfcst_qbo_pcs,outfile): + + fig = plt.figure(1) + + for i,init in enumerate(inits): + + dates = pd.date_range(init, periods=periods, freq="1D") + #Remove leap days + dates = dates[(dates.month != 2) | (dates.day != 29)] + ax = fig.add_subplot(4,7,i+1) + + # plot the QBO phase space time series + plt_handles = [] + + # green/red dots are the start/end of the fcst period + plt.plot(rfcst_qbo_pcs.sel(mode=0, time=dates), + rfcst_qbo_pcs.sel(mode=1, time=dates), linewidth=1.5) + plt.plot(rfcst_qbo_pcs.sel(mode=0, time=dates[0]), + rfcst_qbo_pcs.sel(mode=1, time=dates[0]), marker="o", color="green") + plt.plot(rfcst_qbo_pcs.sel(mode=0, time=dates[-1]), + rfcst_qbo_pcs.sel(mode=1, time=dates[-1]), marker="o", color="red") + + # plot same thing from reanalysis in black + plt.plot(rean_qbo_pcs.sel(mode=0, time=dates), + rean_qbo_pcs.sel(mode=1, time=dates), color='black', linewidth=1.5) + plt.plot(rean_qbo_pcs.sel(mode=0, time=dates[0]), + rean_qbo_pcs.sel(mode=1, time=dates[0]), marker="o", color="green") + plt.plot(rean_qbo_pcs.sel(mode=0, time=dates[-1]), + rean_qbo_pcs.sel(mode=1, time=dates[-1]), marker="o", color="red") + plt.xlim((-2.5,2.5)) + plt.ylim((-2.5,2.5)) + plt.gca().set_aspect('equal') + plt.title('Start: '+init.strftime('%Y-%m-%d'), fontsize=22) + + # plot the QBO phase lines + amp = 2.5 + ax.plot([-amp,amp],[-amp,amp], linewidth=0.5, linestyle='--', color='k', zorder=0) + ax.plot([-amp,amp],[amp,-amp], linewidth=0.5, linestyle='--', color='k', zorder=0) + ax.plot([-amp,amp],[0,0], linewidth=0.5, linestyle='--', color='k', zorder=0) + ax.plot([0,0],[-amp,amp], linewidth=0.5, linestyle='--', color='k', zorder=0) + ax.set_xticks(np.arange(-2.,2.1,1)) + ax.set_yticks(np.arange(-2.,2.1,1)) + + + fig.set_size_inches(24,16) + fig.subplots_adjust(hspace = 0.25, left=0.07, right=0.92, top=0.92, bottom=0.07) + plt.savefig(outfile, dpi=150, facecolor='white', bbox_inches="tight") + + + +def plot_qbo_phase_space(rean_qbo_pcs,eofs,plot_title,outfile): + + from mpl_toolkits.axes_grid1.inset_locator import (inset_axes, InsetPosition, mark_inset) + + fig = plt.figure(4) + + ax = fig.add_subplot(1,1,1) + ax.plot(rean_qbo_pcs.sel(mode=0), rean_qbo_pcs.sel(mode=1), alpha=0.75, linewidth=0.6) + ax.set_xlim((-2.5,2.5)) + ax.set_ylim((-2.5,2.5)) + ax.set_aspect('equal') + + amp = 2.5 + ax.plot([-amp,amp],[-amp,amp], linewidth=0.65, linestyle='--', color='k', zorder=0) + ax.plot([-amp,amp],[amp,-amp], linewidth=0.65, linestyle='--', color='k', zorder=0) + ax.plot([-amp,amp],[0,0], linewidth=0.65, linestyle='--', color='k', zorder=0) + ax.plot([0,0],[-amp,amp], linewidth=0.65, linestyle='--', color='k', zorder=0) + ax.set_xticks(np.arange(-2.,2.1,1)) + ax.set_yticks(np.arange(-2.,2.1,1)) + + ax.set_xlabel('EOF1', fontsize=20) + ax.set_ylabel('EOF2', fontsize=20) + ax.tick_params(which='major', axis='both', length=7, labelsize=18) + ax.grid(True,alpha=0.5) + + ## Plot idealized zonal wind profiles for different combinations of + ## EOF values + inset_axes = [] + axi = ax.inset_axes([2,-0.25,0.5,0.5], transform=ax.transData) + axi.plot(eofs.sel(mode=0), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([np.sqrt(2)+0.2, np.sqrt(2)+0.2, 0.5, 0.5], transform=ax.transData) + axi.plot(eofs.sel(mode=0)+eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([-0.25,2, 0.5, 0.5], transform=ax.transData) + axi.plot(eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([-np.sqrt(2)-0.2-0.5, np.sqrt(2)+0.2, 0.5, 0.5], transform=ax.transData) + axi.plot(-1*eofs.sel(mode=0)+eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([-2.5,-0.25, 0.5, 0.5], transform=ax.transData) + axi.plot(-1*eofs.sel(mode=0), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([-np.sqrt(2)-0.2-0.5, -np.sqrt(2)-0.2-0.5, 0.5, 0.5], transform=ax.transData) + axi.plot(-1*eofs.sel(mode=0)-eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([-0.25,-2.5, 0.5, 0.5], transform=ax.transData) + axi.plot(-1*eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + axi = ax.inset_axes([np.sqrt(2)+0.2, -np.sqrt(2)-0.2-0.5, 0.5, 0.5], transform=ax.transData) + axi.plot(eofs.sel(mode=0)-eofs.sel(mode=1), eofs.pres, linewidth=1.5) + inset_axes.append(axi) + + for axi in inset_axes: + axi.invert_yaxis() + axi.set_yscale('log') + axi.set_yticks([]) + axi.set_xticks([]) + axi.minorticks_off() + axi.set_xlim(-1.1,1.1) + axi.axvline(0, color='black') + axi.set_facecolor('lightgrey') + + ax.set_title(plot_title, fontsize=24, fontweight='semibold') + fig.set_size_inches(10,10) + + plt.savefig(outfile, dpi=150, facecolor='white') From 2ffa02873b36835bdebe6827216646d19ec049d6 Mon Sep 17 00:00:00 2001 From: Christina Kalb Date: Tue, 18 Jun 2024 22:19:36 -0600 Subject: [PATCH 2/4] Updating documentation --- docs/Users_Guide/stratosphere_plots.rst | 104 +++++++++++++++--- .../stratosphere_plots.py | 16 ++- 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/docs/Users_Guide/stratosphere_plots.rst b/docs/Users_Guide/stratosphere_plots.rst index afe21aa0..8fc88d6f 100644 --- a/docs/Users_Guide/stratosphere_plots.rst +++ b/docs/Users_Guide/stratosphere_plots.rst @@ -6,11 +6,11 @@ Description =========== The **stratosphere_plots.py** script contains the plotting portion for -two Stratosphere use cases, one which creates a ME plot in latitude and pressure -and another which creates ME and RMSE plots for lead time and pressure -Two METplus use cases, illustrate how to use this plot. One runs `zonal mean biases -`_ -and another creates bias and RMSE for `polar cap temperature and polar vortex U `_ +three Stratosphere use cases. One use case creates a ME plot in latitude and pressure, +another which creates ME and RMSE plots for lead time and pressure, and a third which +creates two phase diagrams and a time series of U for at 50mb and 30mb. +The three METplus use cases, illustrate how to use these plotting scripts for `zonal mean biases +`_ , creating bias and RMSE for `polar cap temperature and polar vortex U `_ and creating `phase diagrams and time series for QBO `_ These files are used by the image comparison test: @@ -32,6 +32,18 @@ These files are used by the image comparison test: * **RMSE_2018_02_polar_vortex_U.png**: Run "plot_polar_rmse" in **stratosphere_plots.py** to create this plot. +* **ERA_GFS_QBO_circuits.png**: Run "plot_qbo_phase_circuits" in **stratosphere_plots.py** + to create this plot. + +* **ERA5_QBO_PhaseSpace.png**: Run "plot_qbo_phase_space" in **stratosphere_plots.py** + to create this plot. + +* **ERA_GFS_timeseries_30mb_u_201710_201802.png**: Run "plot_u_timeseries" in **stratosphere_plots.py** + to create this plot. + +* **ERA_GFS_timeseries_50mb_u_201710_201802.png**: Run "plot_u_timeseries" in **stratosphere_plots.py** + to create this plot. + Required Packages ================= @@ -46,6 +58,8 @@ Required Packages * numpy +* xarray + * pandas * cmocean @@ -60,13 +74,13 @@ Import stratosphere_plots into the script: .. code-block:: ini - from stratosphere_plots import plot_zonal_bias,plot_polar_bias,plot_polar_rmse + from stratosphere_plots import plot_zonal_bias,plot_polar_bias,plot_polar_rmse, plot_qbo_phase_circuits,plot_qbo_phase_space,plot_u_timeseries For plot_zonal_bias ------------------- In the code, generate the following as numpy -arrays (except outfile, ptitle, and plevels). +arrays (except outfile, ptitle, and plevs). **lats:** A numpy array of the latitude values under consideration. @@ -82,14 +96,14 @@ file, a **.png** version will be written. **ptitle:** A string containing the title of the plot. -**plevels:** A list containing integers of the contour levels used in +**plevs:** A list containing integers of the contour levels used in plotting the obs climatology. For plot_polar_bias ------------------- In the code, generate the following as numpy arrays -(except wrnum, output_plotname, and plevels). +(except outfile, ptitle, and plevs). **leads:** A numpy array containing the forecast lead times. @@ -103,19 +117,19 @@ file, a **.png** version will be written. **ptitle:** A string containing the title of the plot. **plevs:** A list containing floats of the contour levels used in -plotting +plotting. For plot_polar_rmse ------------------- In the code, generate the following as numpy arrays -(except wrnum, output_plotname, and plevels). +(except outfile, ptitle, and plevs). **leads:** A numpy array containing the forecast lead times. **levels:** A numpy array of the pressure level values under consideration. -**pdata:** A numpy array containing the bias. +**pdata:** A numpy array containing the RMSE. **outfile:** The full path and filename of the output plot file, a **.png** version will be written. @@ -123,7 +137,63 @@ file, a **.png** version will be written. **ptitle:** A string containing the title of the plot. **plevs:** A list containing floats of the contour levels used in -plotting +plotting. + +For plot_qbo_phase_circuits +--------------------------- + +In the code, generate the following as numpy arrays +(except inits, periods, and outfile). + +**inits:** A listing of datetimes that are the start date for each plot. + +**periods:** An integer containing the number of days to plot from the inits. + +**rean_qbo_pcs:** An xarray dataarray containing the projected daily +zonal winds for the observations. + +**rfcst_qbo_pcs:** An xarray dataarray containing the projected +daily zonal winds for the model. + +**outfile:** The full path and filename of the output plot +file, a **.png** version will be written. + +For plot_qbo_phase_space +------------------------ + +In the code, generate the following as numpy arrays +(except ptitle and outfile). + +**rean_qbo_pcs:** An xarray dataarray containing the projected +daily zonal winds. + +**eofs:** An xarray dataarray containing the EOFs. + +**ptitle:** A string containing the title of the plot. + +**outfile:** The full path and filename of the output plot +file, a **.png** version will be written. + +For plot_u_timeseries +--------------------- + +In the code, generate the following as numpy arrays +(except ptitle and outfile). + +**obs_dt:** A numpy array of datetimes for the observations. + +**obs_u:** A numpy array containing U wind values for +the observations. + +**fcst_dt:** A numpy array of datetimes for the forecasts. + +**fcst_u:** A numpy array containing U wind values for +the forecasts. + +**ptitle:** A string containing the title of the plot. + +**outfile:** The full path and filename of the output plot +file, a **.png** version will be written. Invoke the plotting functions: @@ -135,7 +205,13 @@ Invoke the plotting functions: plot_polar_rmse(leads,levels,pdata,outfile,ptitle,plevs) + plot_qbo_phase_circuits(inits,periods,rean_qbo_pcs,rfcst_qbo_pcs,outfile) + + plot_qbo_phase_space(rean_qbo_pcs,eofs,ptitle,outfile) + + plot_u_timeseries(obs_dt,obs_u,fcst_dt,fcst_u,ptitle,outfile) + The output will be **.png** version of all requested plots and will be located based on what was specified (path and name) in the -**output_plotname**. +**outfile**. diff --git a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py index 5a14f745..8f01e473 100644 --- a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py +++ b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py @@ -107,7 +107,7 @@ def plot_qbo_phase_circuits(inits,periods,rean_qbo_pcs,rfcst_qbo_pcs,outfile): -def plot_qbo_phase_space(rean_qbo_pcs,eofs,plot_title,outfile): +def plot_qbo_phase_space(rean_qbo_pcs,eofs,ptitle,outfile): from mpl_toolkits.axes_grid1.inset_locator import (inset_axes, InsetPosition, mark_inset) @@ -177,7 +177,19 @@ def plot_qbo_phase_space(rean_qbo_pcs,eofs,plot_title,outfile): axi.axvline(0, color='black') axi.set_facecolor('lightgrey') - ax.set_title(plot_title, fontsize=24, fontweight='semibold') + ax.set_title(ptitle, fontsize=24, fontweight='semibold') fig.set_size_inches(10,10) plt.savefig(outfile, dpi=150, facecolor='white') + + +def plot_u_timeseries(obs_dt,obs_u,fcst_dt,fcst_u,plot_title,outfile): + + plt.figure(figsize=(20,10)) + plt.plot(fcst_dt,fcst_u,'r',linewidth = 2,label='model') + plt.plot(obs_dt,obs_u,'b',linewidth = 2,label='obs') + plt.title(plot_title) + plt.xlabel('Date') + plt.ylabel('Zonal Mean U (m/s)') + plt.legend() + plt.savefig(outfile,bbox_inches='tight') From ca9b70eb6309038994f5f153cf6b7d10357e6718 Mon Sep 17 00:00:00 2001 From: Christina Kalb Date: Thu, 20 Jun 2024 15:19:32 -0600 Subject: [PATCH 3/4] Adding timeseries plot --- .../stratosphere_diagnostics/stratosphere_plots.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py index 8f01e473..b4667323 100644 --- a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py +++ b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py @@ -185,11 +185,12 @@ def plot_qbo_phase_space(rean_qbo_pcs,eofs,ptitle,outfile): def plot_u_timeseries(obs_dt,obs_u,fcst_dt,fcst_u,plot_title,outfile): - plt.figure(figsize=(20,10)) + plt.figure(figsize=(16,8)) plt.plot(fcst_dt,fcst_u,'r',linewidth = 2,label='model') plt.plot(obs_dt,obs_u,'b',linewidth = 2,label='obs') - plt.title(plot_title) - plt.xlabel('Date') - plt.ylabel('Zonal Mean U (m/s)') + plt.title(plot_title,fontsize=20) + plt.xlabel('Date',fontsize=14) + plt.ylabel('Zonal Mean U (m/s)',fontsize=14) plt.legend() - plt.savefig(outfile,bbox_inches='tight') + plt.savefig(outfile) + #plt.savefig(outfile,bbox_inches='tight') From 3791d223fbeeb381eb8f887a57a96c944474bb6e Mon Sep 17 00:00:00 2001 From: Christina Kalb Date: Thu, 20 Jun 2024 16:53:41 -0600 Subject: [PATCH 4/4] Updating stratosphere plots --- .../stratosphere_diagnostics/stratosphere_plots.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py index b4667323..d95099c3 100644 --- a/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py +++ b/metplotpy/contributed/stratosphere_diagnostics/stratosphere_plots.py @@ -185,12 +185,14 @@ def plot_qbo_phase_space(rean_qbo_pcs,eofs,ptitle,outfile): def plot_u_timeseries(obs_dt,obs_u,fcst_dt,fcst_u,plot_title,outfile): - plt.figure(figsize=(16,8)) - plt.plot(fcst_dt,fcst_u,'r',linewidth = 2,label='model') - plt.plot(obs_dt,obs_u,'b',linewidth = 2,label='obs') - plt.title(plot_title,fontsize=20) - plt.xlabel('Date',fontsize=14) - plt.ylabel('Zonal Mean U (m/s)',fontsize=14) + fig = plt.figure(figsize=(16,8)) + ax = fig.add_subplot(1,1,1) + ax.plot(fcst_dt,fcst_u,'r',linewidth = 2,label='model') + ax.plot(obs_dt,obs_u,'b',linewidth = 2,label='obs') + ax.set_title(plot_title,fontsize=20) + ax.set_xlabel('Date',fontsize=14) + ax.set_ylabel('Zonal Mean U (m/s)',fontsize=14) + ax.xaxis.set_major_locator(mticker.MultipleLocator(15)) plt.legend() plt.savefig(outfile) #plt.savefig(outfile,bbox_inches='tight')