From 0dd391018a1df206cf3b07bb38e8c5cde604ef3d Mon Sep 17 00:00:00 2001 From: justin-richling Date: Thu, 3 Nov 2022 08:25:32 -0600 Subject: [PATCH 01/43] Fix accuracy in AMWG tables Set conditional based on values for different float formats going into original DataFrame Set number of significant values in adf_web.py to catch unnecessary trailing zeros in decimals. Also move most imports to beginning of script --- lib/adf_web.py | 2 +- scripts/analysis/amwg_table.py | 103 ++++++++++++++++++--------------- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/lib/adf_web.py b/lib/adf_web.py index 7c23f99fd..223d94ab1 100644 --- a/lib/adf_web.py +++ b/lib/adf_web.py @@ -568,7 +568,7 @@ def create_website(self): #which might be beneficial for colored tables and other more advance #formatting features. table_html = web_data.data.to_html(index=False, border=1, justify='center', - float_format='{:,.3g}'.format) + float_format='{:,.6g}'.format) #Construct amwg_table.html table_tmpl = jinenv.get_template('template_table.html') diff --git a/scripts/analysis/amwg_table.py b/scripts/analysis/amwg_table.py index a639af571..3c04f9fb8 100644 --- a/scripts/analysis/amwg_table.py +++ b/scripts/analysis/amwg_table.py @@ -1,3 +1,21 @@ +import numpy as np +import xarray as xr +import warnings # use to warn user about missing files. +from pathlib import Path + +#Import "special" modules: +try: + import pandas as pd +except ImportError: + print("Pandas module does not exist in python path, but is needed for amwg_table.") + print("Please install module, e.g. 'pip install pandas'.") + sys.exit(1) +try: + import scipy.stats as stats # for easy linear regression and testing +except ImportError: + print("Scipy module does not exist in python path, but is needed for amwg_table.") + print("Please install module, e.g. 'pip install scipy'.") + def amwg_table(adf): """ @@ -31,26 +49,7 @@ def amwg_table(adf): """ #Import necessary modules: - import numpy as np - import xarray as xr - from pathlib import Path from adf_base import AdfError - import warnings # use to warn user about missing files. - - #Import "special" modules: - try: - import pandas as pd - except ImportError: - print("Pandas module does not exist in python path, but is needed for amwg_table.") - print("Please install module, e.g. 'pip install pandas'.") - sys.exit(1) - - try: - import scipy.stats as stats # for easy linear regression and testing - except ImportError: - print("Scipy module does not exist in python path, but is needed for amwg_table.") - print("Please install module, e.g. 'pip install scipy'.") - #Additional information: #---------------------- @@ -219,20 +218,12 @@ def amwg_table(adf): data = data.groupby('time.year').mean(dim='time') # this should be fast b/c time series should be in memory # NOTE: data will now have a 'year' dimension instead of 'time' # Now that data is (time,), we can do our simple stats: - data_mean = data.mean() - data_sample = len(data) - data_std = data.std() - data_sem = data_std / data_sample - data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error - data_trend = stats.linregress(data.year, data.values) + stats_list = _get_row_vals(data) # These get written to our output file: # create a dataframe: cols = ['variable', 'unit', 'mean', 'sample size', 'standard dev.', 'standard error', '95% CI', 'trend', 'trend p-value'] - row_values = [var, unit_str, data_mean.data.item(), data_sample, - data_std.data.item(), data_sem.data.item(), data_ci.data.item(), - f'{data_trend.intercept : 0.3f} + {data_trend.slope : 0.3f} t', - data_trend.pvalue] + row_values = [var, unit_str] + stats_list # Format entries: dfentries = {c:[row_values[i]] for i,c in enumerate(cols)} @@ -259,20 +250,9 @@ def amwg_table(adf): data = data.groupby('time.year').mean(dim='time') # this should be fast b/c time series should be in memory # NOTE: data will now have a 'year' dimension instead of 'time' # Now that data is (time,), we can do our simple stats: - data_mean = data.mean() - data_sample = len(data) - data_std = data.std() - data_sem = data_std / data_sample - data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error - data_trend = stats.linregress(data.year, data.values) - # These get written to our output file: - # create a dataframe: - cols = ['variable', 'unit', 'mean', 'sample size', 'standard dev.', - 'standard error', '95% CI', 'trend', 'trend p-value'] - row_values = [var, restom_units, data_mean.data.item(), data_sample, - data_std.data.item(), data_sem.data.item(), data_ci.data.item(), - f'{data_trend.intercept : 0.3f} + {data_trend.slope : 0.3f} t', - data_trend.pvalue] + stats_list = _get_row_vals(data) + row_values = [var, restom_units] + stats_list + # col (column) values declared above # Format entries: dfentries = {c:[row_values[i]] for i,c in enumerate(cols)} @@ -324,16 +304,44 @@ def amwg_table(adf): ################## def _load_data(dataloc, varname): - import xarray as xr ds = xr.open_dataset(dataloc) return ds[varname] ##### +def _num_zeros(decimal_vec): + return np.floor(np.abs(np.log10(decimal_vec))) + +##### + +def _get_row_vals(data): + + # Now that data is (time,), we can do our simple stats: + data_mean = data.mean() + data_sample = len(data) + data_std = data.std() + data_sem = data_std / data_sample + data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error + data_trend = stats.linregress(data.year, data.values) + + #Check how many leading zeros are in decimals and assign formatting based off that + if (np.abs(data_mean) < 1) and (_num_zeros(np.array(np.abs(data_mean))) >= 1): + formatter = ".3g" #retain 3 significant values + else: + formatter = ".3f" #retain 3 decimal places + + data_mean_str = f'{data_mean.data.item():{formatter}}' + stdev = f'{data_std.data.item() : {formatter}}' + sem = f'{data_sem.data.item() : {formatter}}' + ci = f'{data_ci.data.item() : {formatter}}' + slope_int = f'{data_trend.intercept : {formatter}} + {data_trend.slope : {formatter}} t' + pval = f'{data_trend.pvalue : {formatter}}' + return [data_mean_str, data_sample, stdev, sem, ci, slope_int, pval] + +##### + def _spatial_average(indata): - import xarray as xr - import numpy as np - import warnings + assert 'lev' not in indata.coords assert 'ilev' not in indata.coords if 'lat' in indata.coords: @@ -354,7 +362,6 @@ def _spatial_average(indata): ##### def _df_comp_table(adf, output_location, case_names): - import pandas as pd output_csv_file_comp = output_location / "amwg_table_comp.csv" From 1b9e27967c074d4f361c726c562ca3dfa0d7c3ce Mon Sep 17 00:00:00 2001 From: justin-richling Date: Thu, 3 Nov 2022 14:10:28 -0600 Subject: [PATCH 02/43] Revert "Fix accuracy in AMWG tables" This reverts commit 0dd391018a1df206cf3b07bb38e8c5cde604ef3d. --- lib/adf_web.py | 2 +- scripts/analysis/amwg_table.py | 103 +++++++++++++++------------------ 2 files changed, 49 insertions(+), 56 deletions(-) diff --git a/lib/adf_web.py b/lib/adf_web.py index 223d94ab1..7c23f99fd 100644 --- a/lib/adf_web.py +++ b/lib/adf_web.py @@ -568,7 +568,7 @@ def create_website(self): #which might be beneficial for colored tables and other more advance #formatting features. table_html = web_data.data.to_html(index=False, border=1, justify='center', - float_format='{:,.6g}'.format) + float_format='{:,.3g}'.format) #Construct amwg_table.html table_tmpl = jinenv.get_template('template_table.html') diff --git a/scripts/analysis/amwg_table.py b/scripts/analysis/amwg_table.py index 3c04f9fb8..a639af571 100644 --- a/scripts/analysis/amwg_table.py +++ b/scripts/analysis/amwg_table.py @@ -1,21 +1,3 @@ -import numpy as np -import xarray as xr -import warnings # use to warn user about missing files. -from pathlib import Path - -#Import "special" modules: -try: - import pandas as pd -except ImportError: - print("Pandas module does not exist in python path, but is needed for amwg_table.") - print("Please install module, e.g. 'pip install pandas'.") - sys.exit(1) -try: - import scipy.stats as stats # for easy linear regression and testing -except ImportError: - print("Scipy module does not exist in python path, but is needed for amwg_table.") - print("Please install module, e.g. 'pip install scipy'.") - def amwg_table(adf): """ @@ -49,7 +31,26 @@ def amwg_table(adf): """ #Import necessary modules: + import numpy as np + import xarray as xr + from pathlib import Path from adf_base import AdfError + import warnings # use to warn user about missing files. + + #Import "special" modules: + try: + import pandas as pd + except ImportError: + print("Pandas module does not exist in python path, but is needed for amwg_table.") + print("Please install module, e.g. 'pip install pandas'.") + sys.exit(1) + + try: + import scipy.stats as stats # for easy linear regression and testing + except ImportError: + print("Scipy module does not exist in python path, but is needed for amwg_table.") + print("Please install module, e.g. 'pip install scipy'.") + #Additional information: #---------------------- @@ -218,12 +219,20 @@ def amwg_table(adf): data = data.groupby('time.year').mean(dim='time') # this should be fast b/c time series should be in memory # NOTE: data will now have a 'year' dimension instead of 'time' # Now that data is (time,), we can do our simple stats: - stats_list = _get_row_vals(data) + data_mean = data.mean() + data_sample = len(data) + data_std = data.std() + data_sem = data_std / data_sample + data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error + data_trend = stats.linregress(data.year, data.values) # These get written to our output file: # create a dataframe: cols = ['variable', 'unit', 'mean', 'sample size', 'standard dev.', 'standard error', '95% CI', 'trend', 'trend p-value'] - row_values = [var, unit_str] + stats_list + row_values = [var, unit_str, data_mean.data.item(), data_sample, + data_std.data.item(), data_sem.data.item(), data_ci.data.item(), + f'{data_trend.intercept : 0.3f} + {data_trend.slope : 0.3f} t', + data_trend.pvalue] # Format entries: dfentries = {c:[row_values[i]] for i,c in enumerate(cols)} @@ -250,9 +259,20 @@ def amwg_table(adf): data = data.groupby('time.year').mean(dim='time') # this should be fast b/c time series should be in memory # NOTE: data will now have a 'year' dimension instead of 'time' # Now that data is (time,), we can do our simple stats: - stats_list = _get_row_vals(data) - row_values = [var, restom_units] + stats_list - # col (column) values declared above + data_mean = data.mean() + data_sample = len(data) + data_std = data.std() + data_sem = data_std / data_sample + data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error + data_trend = stats.linregress(data.year, data.values) + # These get written to our output file: + # create a dataframe: + cols = ['variable', 'unit', 'mean', 'sample size', 'standard dev.', + 'standard error', '95% CI', 'trend', 'trend p-value'] + row_values = [var, restom_units, data_mean.data.item(), data_sample, + data_std.data.item(), data_sem.data.item(), data_ci.data.item(), + f'{data_trend.intercept : 0.3f} + {data_trend.slope : 0.3f} t', + data_trend.pvalue] # Format entries: dfentries = {c:[row_values[i]] for i,c in enumerate(cols)} @@ -304,44 +324,16 @@ def amwg_table(adf): ################## def _load_data(dataloc, varname): + import xarray as xr ds = xr.open_dataset(dataloc) return ds[varname] ##### -def _num_zeros(decimal_vec): - return np.floor(np.abs(np.log10(decimal_vec))) - -##### - -def _get_row_vals(data): - - # Now that data is (time,), we can do our simple stats: - data_mean = data.mean() - data_sample = len(data) - data_std = data.std() - data_sem = data_std / data_sample - data_ci = data_sem * 1.96 # https://en.wikipedia.org/wiki/Standard_error - data_trend = stats.linregress(data.year, data.values) - - #Check how many leading zeros are in decimals and assign formatting based off that - if (np.abs(data_mean) < 1) and (_num_zeros(np.array(np.abs(data_mean))) >= 1): - formatter = ".3g" #retain 3 significant values - else: - formatter = ".3f" #retain 3 decimal places - - data_mean_str = f'{data_mean.data.item():{formatter}}' - stdev = f'{data_std.data.item() : {formatter}}' - sem = f'{data_sem.data.item() : {formatter}}' - ci = f'{data_ci.data.item() : {formatter}}' - slope_int = f'{data_trend.intercept : {formatter}} + {data_trend.slope : {formatter}} t' - pval = f'{data_trend.pvalue : {formatter}}' - return [data_mean_str, data_sample, stdev, sem, ci, slope_int, pval] - -##### - def _spatial_average(indata): - + import xarray as xr + import numpy as np + import warnings assert 'lev' not in indata.coords assert 'ilev' not in indata.coords if 'lat' in indata.coords: @@ -362,6 +354,7 @@ def _spatial_average(indata): ##### def _df_comp_table(adf, output_location, case_names): + import pandas as pd output_csv_file_comp = output_location / "amwg_table_comp.csv" From 4a51633bc7ed91ba51e3a471fc9bfb5c8ed20538 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Mon, 5 Dec 2022 11:21:14 -0700 Subject: [PATCH 03/43] Update create_climo_files.py --- scripts/averaging/create_climo_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/averaging/create_climo_files.py b/scripts/averaging/create_climo_files.py index f964b3fd4..aadada94c 100644 --- a/scripts/averaging/create_climo_files.py +++ b/scripts/averaging/create_climo_files.py @@ -127,7 +127,7 @@ def create_climo_files(adf, clobber=False, search=None): #Check that time series input directory actually exists: if not input_location.is_dir(): - errmsg = f"Time series directory '{input_ts_loc}' not found. Script is exiting." + errmsg = f"Time series directory '{input_ts_locs}' not found. Script is exiting." raise AdfError(errmsg) #Check if climo directory exists, and if not, then create it: From ed3e9bf11c354e61d51816503bec6a42575c6ca1 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Fri, 12 Jul 2024 10:36:08 -0600 Subject: [PATCH 04/43] Fix incorrect plotting method names --- scripts/plotting/global_latlon_map.py | 2 +- scripts/plotting/zonal_mean.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/plotting/global_latlon_map.py b/scripts/plotting/global_latlon_map.py index 6939d98e7..a77212001 100644 --- a/scripts/plotting/global_latlon_map.py +++ b/scripts/plotting/global_latlon_map.py @@ -25,7 +25,7 @@ def my_formatwarning(msg, *args, **kwargs): return str(msg) + '\n' warnings.formatwarning = my_formatwarning -def global_latlon_map_B(adfobj): +def global_latlon_map(adfobj): """ This script/function is designed to generate global 2-D lat/lon maps of model fields with continental overlays. diff --git a/scripts/plotting/zonal_mean.py b/scripts/plotting/zonal_mean.py index a150009f1..9d3fde902 100644 --- a/scripts/plotting/zonal_mean.py +++ b/scripts/plotting/zonal_mean.py @@ -11,7 +11,7 @@ def my_formatwarning(msg, *args, **kwargs): warnings.formatwarning = my_formatwarning -def zonal_mean_B(adfobj): +def zonal_mean(adfobj): """ Plots zonal average from climatological files (annual and seasonal). From 6e5615330c28f88af338cf940676a4aae6f089b5 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Fri, 8 Nov 2024 13:39:45 -0700 Subject: [PATCH 05/43] Update default hist_str to h0a --- config_amwg_default_plots.yaml | 4 ++-- config_cam_baseline_example.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config_amwg_default_plots.yaml b/config_amwg_default_plots.yaml index fa1de3821..abe3798f2 100644 --- a/config_amwg_default_plots.yaml +++ b/config_amwg_default_plots.yaml @@ -128,7 +128,7 @@ diag_cam_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0 + hist_str: cam.h0a #Calculate climatologies? #If false, the climatology files will not be created: @@ -206,7 +206,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0 + hist_str: cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: diff --git a/config_cam_baseline_example.yaml b/config_cam_baseline_example.yaml index 8a78dc0d9..d7652f23e 100644 --- a/config_cam_baseline_example.yaml +++ b/config_cam_baseline_example.yaml @@ -128,7 +128,7 @@ diag_cam_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0 + hist_str: cam.h0a #Calculate climatologies? #If false, the climatology files will not be created: @@ -290,7 +290,7 @@ diag_cam_baseline_climo: # eg. cam.h0 or ocn.pop.h.ecosys.nday1 or hist_str: [cam.h2,cam.h0] # Only affects timeseries as everything else uses the created timeseries # Default: - hist_str: cam.h0 + hist_str: cam.h0a #Calculate cam baseline climatologies? #If false, the climatology files will not be created: From 94c3d3745810131013d9733ff30bf370e99e571b Mon Sep 17 00:00:00 2001 From: justin-richling Date: Tue, 19 Nov 2024 13:46:31 -0700 Subject: [PATCH 06/43] Update plotting_functions.py --- lib/plotting_functions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index dde8ec1e7..d9819bc48 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -1382,8 +1382,6 @@ def plot_map_and_save(wks, case_nickname, base_nickname, #Close plots: plt.close() - - print("cp_info: ",cp_info['colorbar_opt']) # # -- vertical interpolation code -- From d7a15a767f26d041ea7baf6c3ef156131d051642 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Tue, 19 Nov 2024 13:48:32 -0700 Subject: [PATCH 07/43] Revert "Update plotting_functions.py" This reverts commit 94c3d3745810131013d9733ff30bf370e99e571b. --- lib/plotting_functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index d9819bc48..dde8ec1e7 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -1382,6 +1382,8 @@ def plot_map_and_save(wks, case_nickname, base_nickname, #Close plots: plt.close() + + print("cp_info: ",cp_info['colorbar_opt']) # # -- vertical interpolation code -- From 02c2e9be5793bca55c7d801f7de0bc68f1aedd14 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Thu, 21 Nov 2024 09:45:06 -0700 Subject: [PATCH 08/43] new index template --- lib/website_templates/template_index.html | 256 ++++++++++++++---- lib/website_templates/template_index_old.html | 70 +++++ 2 files changed, 273 insertions(+), 53 deletions(-) create mode 100644 lib/website_templates/template_index_old.html diff --git a/lib/website_templates/template_index.html b/lib/website_templates/template_index.html index db49975e1..134c2cdab 100644 --- a/lib/website_templates/template_index.html +++ b/lib/website_templates/template_index.html @@ -1,14 +1,124 @@ - - - ADF Diagnostics - - - -
-
-

{{ title }}

-
+ + + + + + + CESM Unified Diagnostics CUPiD + + + + + + + + +
+

AMP Multi-Case Diagnostics

+ +
-
-

Test Case:

{{ case_name }}

- years: {{ case_yrs }}


-

Baseline Case:

{{ base_name }}

- years: {{ baseline_yrs }}

-
-
- -
-

Plot Types

-
- -
- {% for avail_type in avail_plot_types %} - {% if avail_type in plot_types.keys() %} - - {% else %} -
- {{ avail_type }} -
- {% endif %} - {% endfor %} -
- -
-

External Diagnostic Packages

-
- -
- {% for avail_type in avail_external_packages %} - {% if avail_type in external_package_links.keys() %} - - {% else %} -
- {{ avail_type }} -
- {% endif %} - {% endfor %} -
- - +
+ + +
+ + + +
+ +

+ +

+ + + + + + + + + + + + + +
+ Case Names:
+ b.e23_alpha16g.BLT1850.ne30_t232.068
+ b.e23_alpha16g.BLT1850.ne30_t232.070
+
+ Baseline Name:
+ b.e23_alpha16b.BLT1850.ne30_t232.054
+ + +
+ +
+ + Plot Types

+ +
+ +
+ Tables +
+
+ LatLon +
+ +
+ Zonal +
+
+ +
+
+ NH Polar +
+
+ SH Polar +
+
+ Special +
+ +
+ +
+
+
+ + + diff --git a/lib/website_templates/template_index_old.html b/lib/website_templates/template_index_old.html new file mode 100644 index 000000000..db49975e1 --- /dev/null +++ b/lib/website_templates/template_index_old.html @@ -0,0 +1,70 @@ + + + + ADF Diagnostics + + + +
+
+

{{ title }}

+
+ +
+
+

Test Case:

{{ case_name }}

- years: {{ case_yrs }}


+

Baseline Case:

{{ base_name }}

- years: {{ baseline_yrs }}

+
+
+ +
+

Plot Types

+
+ +
+ {% for avail_type in avail_plot_types %} + {% if avail_type in plot_types.keys() %} + + {% else %} +
+ {{ avail_type }} +
+ {% endif %} + {% endfor %} +
+ +
+

External Diagnostic Packages

+
+ +
+ {% for avail_type in avail_external_packages %} + {% if avail_type in external_package_links.keys() %} + + {% else %} +
+ {{ avail_type }} +
+ {% endif %} + {% endfor %} +
+ + + From a7518a86a68bf5f6e923f7156970f7ca10f5afd9 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Fri, 22 Nov 2024 08:29:13 -0700 Subject: [PATCH 09/43] Revert "new index template" This reverts commit 02c2e9be5793bca55c7d801f7de0bc68f1aedd14. --- lib/website_templates/template_index.html | 256 ++++-------------- lib/website_templates/template_index_old.html | 70 ----- 2 files changed, 53 insertions(+), 273 deletions(-) delete mode 100644 lib/website_templates/template_index_old.html diff --git a/lib/website_templates/template_index.html b/lib/website_templates/template_index.html index 134c2cdab..db49975e1 100644 --- a/lib/website_templates/template_index.html +++ b/lib/website_templates/template_index.html @@ -1,124 +1,14 @@ - - - - - - - CESM Unified Diagnostics CUPiD - - - - - - - - -
-

AMP Multi-Case Diagnostics

- -
+ + + ADF Diagnostics + + + +
+
+

{{ title }}

+
-
- - -
- - - -
- -

- -

- - - - - - - - - - - - - -
- Case Names:
- b.e23_alpha16g.BLT1850.ne30_t232.068
- b.e23_alpha16g.BLT1850.ne30_t232.070
-
- Baseline Name:
- b.e23_alpha16b.BLT1850.ne30_t232.054
- - -
- -
- - Plot Types

- -
- -
- Tables -
-
- LatLon -
- -
- Zonal -
-
- -
-
- NH Polar -
-
- SH Polar -
-
- Special -
- -
- -
-
-
-
- - +
+

Test Case:

{{ case_name }}

- years: {{ case_yrs }}


+

Baseline Case:

{{ base_name }}

- years: {{ baseline_yrs }}

+
+ + +
+

Plot Types

+
+ +
+ {% for avail_type in avail_plot_types %} + {% if avail_type in plot_types.keys() %} + + {% else %} +
+ {{ avail_type }} +
+ {% endif %} + {% endfor %} +
+ +
+

External Diagnostic Packages

+
+ +
+ {% for avail_type in avail_external_packages %} + {% if avail_type in external_package_links.keys() %} + + {% else %} +
+ {{ avail_type }} +
+ {% endif %} + {% endfor %} +
+ + diff --git a/lib/website_templates/template_index_old.html b/lib/website_templates/template_index_old.html deleted file mode 100644 index db49975e1..000000000 --- a/lib/website_templates/template_index_old.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - ADF Diagnostics - - - -
-
-

{{ title }}

-
- -
-
-

Test Case:

{{ case_name }}

- years: {{ case_yrs }}


-

Baseline Case:

{{ base_name }}

- years: {{ baseline_yrs }}

-
-
- -
-

Plot Types

-
- -
- {% for avail_type in avail_plot_types %} - {% if avail_type in plot_types.keys() %} - - {% else %} -
- {{ avail_type }} -
- {% endif %} - {% endfor %} -
- -
-

External Diagnostic Packages

-
- -
- {% for avail_type in avail_external_packages %} - {% if avail_type in external_package_links.keys() %} - - {% else %} -
- {{ avail_type }} -
- {% endif %} - {% endfor %} -
- - - From 72c533034a1e5b723938146280ac3cca563103d4 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Mon, 2 Dec 2024 12:22:56 -0700 Subject: [PATCH 10/43] Update adf_variable_defaults.yaml --- lib/adf_variable_defaults.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index eb7542139..60743359c 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -1406,12 +1406,16 @@ CLDICE: obs_file: "CLDICE_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDICE" + pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] + pct_diff_colormap: "PuOr_r" CLDLIQ: category: "Clouds" obs_file: "CLDLIQ_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDLIQ" + pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] + pct_diff_colormap: "PuOr_r" CLDTOT: colormap: "Oranges" From 24018b1b5f4f0ca78f42adb0bb38195cb31461d6 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Fri, 25 Apr 2025 17:14:28 -0600 Subject: [PATCH 11/43] Update conda_environment.yaml --- env/conda_environment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env/conda_environment.yaml b/env/conda_environment.yaml index 9245929fe..f53414633 100644 --- a/env/conda_environment.yaml +++ b/env/conda_environment.yaml @@ -14,5 +14,5 @@ dependencies: - xskillscore=0.0.5 - geocat-comp=2022.08.0 - python=3.11 - - xesmf=0.8.7 + - xesmf=0.8.2 prefix: /glade/work/$USER/conda-envs/adf_v0.12 From c685e4463fdfcea79fc0eca88f1601f39e3b4832 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Fri, 25 Apr 2025 17:24:40 -0600 Subject: [PATCH 12/43] add npl version of conda env --- env/npl-2024a_environment.yaml | 649 +++++++++++++++++++++++++++++++++ 1 file changed, 649 insertions(+) create mode 100644 env/npl-2024a_environment.yaml diff --git a/env/npl-2024a_environment.yaml b/env/npl-2024a_environment.yaml new file mode 100644 index 000000000..73bbda001 --- /dev/null +++ b/env/npl-2024a_environment.yaml @@ -0,0 +1,649 @@ +name: npl-2024a +channels: + - conda-forge + - r +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=2_gnu + - accessible-pygments=0.0.4=pyhd8ed1ab_0 + - affine=2.4.0=pyhd8ed1ab_0 + - aiohttp=3.9.1=py311h459d7ec_0 + - aiosignal=1.3.1=pyhd8ed1ab_0 + - alabaster=0.7.16=pyhd8ed1ab_0 + - alsa-lib=1.2.10=hd590300_0 + - annotated-types=0.6.0=pyhd8ed1ab_0 + - ansiwrap=0.8.4=py_0 + - antimeridian=0.3.5=pyhd8ed1ab_0 + - antlr-python-runtime=4.11.1=pyhd8ed1ab_0 + - anyio=4.2.0=pyhd8ed1ab_0 + - aom=3.7.1=h59595ed_0 + - appdirs=1.4.4=pyh9f0ad1d_0 + - argon2-cffi=23.1.0=pyhd8ed1ab_0 + - argon2-cffi-bindings=21.2.0=py311h459d7ec_4 + - arm_pyart=1.17.0=py311h459d7ec_0 + - arrow=1.3.0=pyhd8ed1ab_0 + - asciitree=0.3.3=py_2 + - astroid=3.0.2=py311h38be061_0 + - astropy=6.0.0=py311h1f0f07a_0 + - astropy-iers-data=0.2024.1.8.0.30.55=pyhd8ed1ab_0 + - asttokens=2.4.1=pyhd8ed1ab_0 + - async-lru=2.0.4=pyhd8ed1ab_0 + - atk-1.0=2.38.0=hd4edc92_1 + - attr=2.5.1=h166bdaf_1 + - attrs=23.2.0=pyh71513ae_0 + - aws-c-auth=0.7.5=h2acc10b_2 + - aws-c-cal=0.6.9=h0fad3b2_0 + - aws-c-common=0.9.5=hd590300_0 + - aws-c-compression=0.2.17=h3e65c2a_5 + - aws-c-event-stream=0.3.2=hc1d3383_5 + - aws-c-http=0.7.13=h858fa18_9 + - aws-c-io=0.13.35=hf90439a_7 + - aws-c-mqtt=0.9.8=hd23f6f0_1 + - aws-c-s3=0.3.22=h2de862a_1 + - aws-c-sdkutils=0.1.12=h3e65c2a_4 + - aws-checksums=0.1.17=h3e65c2a_4 + - aws-crt-cpp=0.24.4=h233f1e4_5 + - aws-sdk-cpp=1.11.182=h18c0b32_3 + - babel=2.14.0=pyhd8ed1ab_0 + - beautifulsoup4=4.12.2=pyha770c72_0 + - black=23.12.1=py311h38be061_0 + - bleach=6.1.0=pyhd8ed1ab_0 + - blosc=1.21.5=h0f2a231_0 + - bokeh=3.3.3=pyhd8ed1ab_0 + - boto3=1.34.18=pyhd8ed1ab_0 + - botocore=1.34.18=pyhd8ed1ab_0 + - bottleneck=1.3.7=py311h1f0f07a_1 + - branca=0.7.0=pyhd8ed1ab_1 + - brotli=1.1.0=hd590300_1 + - brotli-bin=1.1.0=hd590300_1 + - brotli-python=1.1.0=py311hb755f60_1 + - brunsli=0.1=h9c3ff4c_0 + - bzip2=1.0.8=hd590300_5 + - c-ares=1.25.0=hd590300_0 + - c-blosc2=2.12.0=hb4ffafa_0 + - ca-certificates=2024.2.2=hbcca054_0 + - cached-property=1.5.2=hd8ed1ab_1 + - cached_property=1.5.2=pyha770c72_1 + - cairo=1.18.0=h3faef2a_0 + - cartopy=0.22.0=py311h320fe9a_1 + - cdsapi=0.6.1=pyhd8ed1ab_0 + - celluloid=0.2.0=pyhd8ed1ab_0 + - certifi=2024.2.2=pyhd8ed1ab_0 + - cf-units=3.2.0=py311h1f0f07a_4 + - cf_xarray=0.8.7=pyhd8ed1ab_0 + - cffi=1.16.0=py311hb3a22ac_0 + - cfgrib=0.9.10.4=pyhd8ed1ab_0 + - cfitsio=4.3.0=hbdc6101_0 + - cftime=1.6.3=py311h1f0f07a_0 + - charls=2.4.2=h59595ed_0 + - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - click=8.1.7=unix_pyh707e725_0 + - click-plugins=1.1.1=py_0 + - cligj=0.7.2=pyhd8ed1ab_1 + - cloudpickle=3.0.0=pyhd8ed1ab_0 + - cmaps=2.0.1=pyhd8ed1ab_0 + - cmcrameri=1.8=pyhd8ed1ab_0 + - cmocean=3.0.3=pyhd8ed1ab_0 + - cmweather=0.3.2=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_0 + - colorcet=3.0.1=pyhd8ed1ab_0 + - colorspacious=1.1.2=pyh24bf2e0_0 + - comm=0.2.1=pyhd8ed1ab_0 + - contextily=1.5.0=pyhd8ed1ab_0 + - contourpy=1.2.0=py311h9547e67_0 + - cryptography=41.0.7=py311hcb13ee4_1 + - curl=8.4.0=hca28451_0 + - cycler=0.12.1=pyhd8ed1ab_0 + - cython=3.0.7=py311hb755f60_0 + - cytoolz=0.12.2=py311h459d7ec_1 + - dask=2024.1.0=pyhd8ed1ab_0 + - dask-core=2024.1.0=pyhd8ed1ab_0 + - dask-jobqueue=0.8.2=pyhd8ed1ab_0 + - dask-labextension=7.0.0=pyhd8ed1ab_0 + - dask-mpi=2022.4.0=pyh458ca06_2 + - dataclasses=0.8=pyhc8e2a94_3 + - datashader=0.16.0=pyhd8ed1ab_0 + - dav1d=1.2.1=hd590300_0 + - dbus=1.13.6=h5008d03_3 + - debugpy=1.8.0=py311hb755f60_1 + - decorator=5.1.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 + - descartes=1.1.0=py_4 + - dill=0.3.7=pyhd8ed1ab_0 + - distributed=2024.1.0=pyhd8ed1ab_0 + - docopt=0.6.2=py_1 + - docrep=0.3.2=pyh44b312d_0 + - docutils=0.17.1=py311h38be061_4 + - eccodes=2.32.1=h35c6de3_0 + - entrypoints=0.4=pyhd8ed1ab_0 + - eofs=1.4.1=pyhd8ed1ab_1 + - esmf=8.4.2=nompi_h9e768e6_3 + - esmpy=8.4.2=pyhc1e730c_4 + - exceptiongroup=1.2.0=pyhd8ed1ab_2 + - executing=2.0.1=pyhd8ed1ab_0 + - expat=2.5.0=hcb278e6_1 + - fasteners=0.17.3=pyhd8ed1ab_0 + - fastprogress=1.0.3=pyhd8ed1ab_0 + - ffmpeg=6.1.0=gpl_h0fd9395_104 + - findlibs=0.0.5=pyhd8ed1ab_0 + - fiona=1.9.5=py311hbac4ec9_0 + - flox=0.8.7=pyhd8ed1ab_0 + - folium=0.15.1=pyhd8ed1ab_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_1 + - fontconfig=2.14.2=h14ed4e7_0 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - fonttools=4.47.2=py311h459d7ec_0 + - fqdn=1.5.1=pyhd8ed1ab_0 + - freeglut=3.2.2=hac7e632_2 + - freetype=2.12.1=h267a509_2 + - freexl=2.0.0=h743c826_0 + - fribidi=1.0.10=h36c2ea0_0 + - frozenlist=1.4.1=py311h459d7ec_0 + - fsspec=2023.12.2=pyhca7485f_0 + - future=0.18.3=pyhd8ed1ab_0 + - gdal=3.7.2=py311h815a124_3 + - gdk-pixbuf=2.42.10=h6c15284_3 + - geocat-comp=2023.12.0=pyha770c72_0 + - geocat-viz=2023.03.0=pyhd8ed1ab_0 + - geographiclib=1.52=pyhd8ed1ab_0 + - geopandas-base=0.14.2=pyha770c72_0 + - geopy=2.4.1=pyhd8ed1ab_0 + - geos=3.12.0=h59595ed_0 + - geotiff=1.7.1=hee599c5_13 + - geoviews=1.11.0=pyhd8ed1ab_0 + - geoviews-core=1.11.0=pyha770c72_0 + - gettext=0.21.1=h27087fc_0 + - gflags=2.2.2=he1b5a44_1004 + - ghp-import=2.1.0=pyhd8ed1ab_0 + - giflib=5.2.1=h0b41bf4_3 + - glib=2.78.1=hfc55251_0 + - glib-tools=2.78.1=hfc55251_0 + - globus-cli=3.23.0=pyhd8ed1ab_0 + - globus-sdk=3.34.0=pyhd8ed1ab_0 + - glog=0.6.0=h6f12383_0 + - gmp=6.3.0=h59595ed_0 + - gnutls=3.7.9=hb077bed_0 + - graphite2=1.3.13=h58526e2_1001 + - graphviz=9.0.0=h78e8752_1 + - greenlet=3.0.3=py311hb755f60_0 + - gsl=2.7=he838d99_0 + - gst-plugins-base=1.22.7=h8e1006c_0 + - gstreamer=1.22.7=h98fc4e7_0 + - gsw=3.6.17=py311h1f0f07a_1 + - gtk2=2.24.33=h90689f9_2 + - gts=0.7.6=h977cf35_4 + - h5netcdf=1.3.0=pyhd8ed1ab_0 + - h5py=3.10.0=nompi_py311h3839ddf_100 + - harfbuzz=8.3.0=h3d44ed6_0 + - hdf4=4.2.15=h501b40f_6 + - hdf5=1.14.2=nompi_h4f84152_100 + - hdfeos2=2.20=hebf79cf_1003 + - hdfeos5=5.1.16=hf1a501a_15 + - holoviews=1.18.1=pyhd8ed1ab_0 + - hvplot=0.9.1=pyhd8ed1ab_0 + - icu=73.2=h59595ed_0 + - idna=3.6=pyhd8ed1ab_0 + - imagecodecs=2023.9.18=py311h9b38416_0 + - imageio=2.33.1=pyh8c1a49c_0 + - imagesize=1.4.1=pyhd8ed1ab_0 + - importlib-metadata=7.0.1=pyha770c72_0 + - importlib_metadata=7.0.1=hd8ed1ab_0 + - importlib_resources=6.1.1=pyhd8ed1ab_0 + - intake=0.7.0=pyhd8ed1ab_0 + - intake-esm=2023.11.10=pyhd8ed1ab_0 + - intake-xarray=0.7.0=pyhd8ed1ab_0 + - ipykernel=6.28.0=pyhd33586a_0 + - ipympl=0.9.3=pyhd8ed1ab_0 + - ipython=8.20.0=pyh707e725_0 + - ipython_genutils=0.2.0=py_1 + - ipywidgets=8.1.1=pyhd8ed1ab_0 + - iris=3.7.0=pyha770c72_0 + - isoduration=20.11.0=pyhd8ed1ab_0 + - isort=5.13.2=pyhd8ed1ab_0 + - jasper=4.0.0=h32699f2_1 + - jedi=0.19.1=pyhd8ed1ab_0 + - jinja2=3.1.3=pyhd8ed1ab_0 + - jmespath=1.0.1=pyhd8ed1ab_0 + - joblib=1.3.2=pyhd8ed1ab_0 + - json-c=0.17=h7ab15ed_0 + - json5=0.9.14=pyhd8ed1ab_0 + - jsonpointer=2.4=py311h38be061_3 + - jsonschema=4.20.0=pyhd8ed1ab_0 + - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 + - jsonschema-with-format-nongpl=4.20.0=pyhd8ed1ab_0 + - jupyter-book=0.15.1=pyhd8ed1ab_0 + - jupyter-cache=0.6.1=pyhd8ed1ab_0 + - jupyter-lsp=2.2.1=pyhd8ed1ab_0 + - jupyter-server-proxy=4.1.0=pyhd8ed1ab_0 + - jupyter_client=8.6.0=pyhd8ed1ab_0 + - jupyter_core=5.7.1=py311h38be061_0 + - jupyter_events=0.9.0=pyhd8ed1ab_0 + - jupyter_server=2.12.4=pyhd8ed1ab_0 + - jupyter_server_terminals=0.5.1=pyhd8ed1ab_0 + - jupyterlab=4.0.10=pyhd8ed1ab_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_0 + - jupyterlab_server=2.25.2=pyhd8ed1ab_0 + - jupyterlab_widgets=3.0.9=pyhd8ed1ab_0 + - jxrlib=1.1=hd590300_3 + - kealib=1.5.2=hcd42e92_1 + - keyutils=1.6.1=h166bdaf_0 + - kiwisolver=1.4.5=py311h9547e67_1 + - krb5=1.21.2=h659d440_0 + - lame=3.100=h166bdaf_1003 + - lat_lon_parser=1.3.0=pyhd8ed1ab_0 + - latexcodec=2.0.1=pyh9f0ad1d_0 + - lazy_loader=0.3=pyhd8ed1ab_0 + - lcms2=2.15=h7f713cb_2 + - ld_impl_linux-64=2.40=h41732ed_0 + - ldcpy=0.17=py311hd4cff14_1 + - lerc=4.0.0=h27087fc_0 + - libabseil=20230802.1=cxx17_h59595ed_0 + - libaec=1.1.2=h59595ed_1 + - libarchive=3.7.2=h2aa1ff5_1 + - libarrow=13.0.0=hecbb4c5_13_cpu + - libass=0.17.1=h8fe9dca_1 + - libavif16=1.0.3=hed45d22_0 + - libblas=3.9.0=20_linux64_openblas + - libboost-headers=1.84.0=ha770c72_0 + - libbrotlicommon=1.1.0=hd590300_1 + - libbrotlidec=1.1.0=hd590300_1 + - libbrotlienc=1.1.0=hd590300_1 + - libcap=2.69=h0f662aa_0 + - libcblas=3.9.0=20_linux64_openblas + - libclang=15.0.7=default_hb11cfb5_4 + - libclang13=15.0.7=default_ha2b6cf4_4 + - libcrc32c=1.1.2=h9c3ff4c_0 + - libcups=2.3.3=h4637d8d_4 + - libcurl=8.4.0=hca28451_0 + - libdeflate=1.19=hd590300_0 + - libdrm=2.4.114=h166bdaf_0 + - libedit=3.1.20191231=he28a2e2_2 + - libev=4.33=hd590300_2 + - libevent=2.1.12=hf998b51_1 + - libexpat=2.5.0=hcb278e6_1 + - libffi=3.4.2=h7f98852_5 + - libflac=1.4.3=h59595ed_0 + - libgcc-ng=13.2.0=h807b86a_3 + - libgcrypt=1.10.3=hd590300_0 + - libgd=2.3.3=he9388d3_8 + - libgdal=3.7.2=h3aa23ec_3 + - libgfortran-ng=13.2.0=h69a702a_3 + - libgfortran5=13.2.0=ha4646dd_3 + - libglib=2.78.1=hebfc3b9_0 + - libglu=9.0.0=hac7e632_1003 + - libgomp=13.2.0=h807b86a_3 + - libgoogle-cloud=2.12.0=h19a6dae_3 + - libgpg-error=1.47=h71f35ed_0 + - libgrpc=1.58.2=he06187c_0 + - libhwloc=2.9.3=default_h554bfaf_1009 + - libiconv=1.17=hd590300_2 + - libidn2=2.3.4=h166bdaf_0 + - libjpeg-turbo=2.1.5.1=hd590300_1 + - libkml=1.3.0=h01aab08_1018 + - liblapack=3.9.0=20_linux64_openblas + - liblapacke=3.9.0=20_linux64_openblas + - libllvm14=14.0.6=hcd5def8_4 + - libllvm15=15.0.7=hb3ce162_4 + - libnetcdf=4.9.2=nompi_h80fb2b6_112 + - libnghttp2=1.58.0=h47da74e_0 + - libnl=3.9.0=hd590300_0 + - libnsl=2.0.1=hd590300_0 + - libnuma=2.0.16=h0b41bf4_1 + - libogg=1.3.4=h7f98852_1 + - libopenblas=0.3.25=pthreads_h413a1c8_0 + - libopencv=4.8.1=py311h0f9022a_1 + - libopenvino=2023.1.0=h59595ed_2 + - libopenvino-auto-batch-plugin=2023.1.0=h59595ed_2 + - libopenvino-auto-plugin=2023.1.0=h59595ed_2 + - libopenvino-hetero-plugin=2023.1.0=h59595ed_2 + - libopenvino-intel-cpu-plugin=2023.1.0=h59595ed_2 + - libopenvino-intel-gpu-plugin=2023.1.0=h59595ed_2 + - libopenvino-ir-frontend=2023.1.0=h59595ed_2 + - libopenvino-onnx-frontend=2023.1.0=h59595ed_2 + - libopenvino-paddle-frontend=2023.1.0=h59595ed_2 + - libopenvino-pytorch-frontend=2023.1.0=h59595ed_2 + - libopenvino-tensorflow-frontend=2023.1.0=h59595ed_2 + - libopenvino-tensorflow-lite-frontend=2023.1.0=h59595ed_2 + - libopus=1.3.1=h7f98852_1 + - libpciaccess=0.17=h166bdaf_0 + - libpng=1.6.39=h753d276_0 + - libpq=15.5=h088ca5b_0 + - libprotobuf=4.24.3=hf27288f_1 + - libre2-11=2023.06.02=h7a70373_0 + - librsvg=2.56.3=he3f83f7_1 + - librttopo=1.1.0=hb58d41b_14 + - libsndfile=1.2.2=hc60ed4a_1 + - libsodium=1.0.18=h36c2ea0_1 + - libspatialindex=1.9.3=h9c3ff4c_4 + - libspatialite=5.1.0=h090f1da_1 + - libsqlite=3.44.2=h2797004_0 + - libssh2=1.11.0=h0841786_0 + - libstdcxx-ng=13.2.0=h7e041cc_3 + - libsystemd0=255=h3516f8a_0 + - libtasn1=4.19.0=h166bdaf_0 + - libthrift=0.19.0=hb90f79a_1 + - libtiff=4.6.0=h29866fb_1 + - libudunits2=2.2.28=h40f5838_3 + - libunistring=0.9.10=h7f98852_0 + - libutf8proc=2.8.0=h166bdaf_0 + - libuuid=2.38.1=h0b41bf4_0 + - libva=2.20.0=hd590300_0 + - libvorbis=1.3.7=h9c3ff4c_0 + - libvpx=1.13.1=h59595ed_0 + - libwebp=1.3.2=hdffd6e0_0 + - libwebp-base=1.3.2=hd590300_0 + - libxcb=1.15=h0b41bf4_0 + - libxkbcommon=1.6.0=hd429924_1 + - libxml2=2.12.4=h232c23b_1 + - libzip=1.10.1=h2629f0a_3 + - libzlib=1.2.13=hd590300_5 + - libzopfli=1.0.3=h9c3ff4c_0 + - linkify-it-py=2.0.2=pyhd8ed1ab_0 + - llvmlite=0.41.1=py311ha6695c7_0 + - locket=1.0.0=pyhd8ed1ab_0 + - looseversion=1.3.0=pyhd8ed1ab_0 + - lz4=4.3.3=py311h38e4bf4_0 + - lz4-c=1.9.4=hcb278e6_0 + - lzo=2.10=h516909a_1000 + - markdown=3.5.2=pyhd8ed1ab_0 + - markdown-it-py=2.2.0=pyhd8ed1ab_0 + - markupsafe=2.1.3=py311h459d7ec_1 + - matplotlib=3.8.2=py311h38be061_0 + - matplotlib-base=3.8.2=py311h54ef318_0 + - matplotlib-inline=0.1.6=pyhd8ed1ab_0 + - mccabe=0.7.0=pyhd8ed1ab_0 + - mdit-py-plugins=0.4.0=pyhd8ed1ab_0 + - mdurl=0.1.2=pyhd8ed1ab_0 + - mercantile=1.2.1=pyhd8ed1ab_0 + - metpy=1.6.1=pyhd8ed1ab_0 + - minizip=4.0.3=h0ab5242_0 + - mistune=3.0.2=pyhd8ed1ab_0 + - mpg123=1.32.4=h59595ed_0 + - mpi=1.0=mpich + - mpi4py=3.1.5=py311he01e52e_0 + - mpich=4.1.2=h846660c_101 + - msgpack-python=1.0.7=py311h9547e67_0 + - multidict=6.0.4=py311h459d7ec_1 + - multipledispatch=0.6.0=py_0 + - munch=4.0.0=pyhd8ed1ab_0 + - munkres=1.1.4=pyh9f0ad1d_0 + - mypy_extensions=1.0.0=pyha770c72_0 + - mysql-common=8.0.33=hf1915f5_6 + - mysql-libs=8.0.33=hca2cd23_6 + - myst-nb=0.17.2=pyhd8ed1ab_0 + - myst-parser=0.18.1=pyhd8ed1ab_0 + - nbclient=0.7.4=pyhd8ed1ab_0 + - nbconvert-core=7.14.1=pyhd8ed1ab_0 + - nbformat=5.9.2=pyhd8ed1ab_0 + - nc-time-axis=1.4.1=pyhd8ed1ab_0 + - ncar-jobqueue=2021.4.14=pyh44b312d_0 + - ncl=6.6.2=he3b17a9_50 + - nco=5.1.9=h00920e0_0 + - ncurses=6.4=h59595ed_2 + - nest-asyncio=1.5.8=pyhd8ed1ab_0 + - netcdf-fortran=4.6.1=nompi_hacb5139_103 + - netcdf4=1.6.5=nompi_py311he8ad708_100 + - nettle=3.9.1=h7ab15ed_0 + - networkx=3.2.1=pyhd8ed1ab_0 + - nomkl=1.0=h5ca1d4c_0 + - notebook-shim=0.2.3=pyhd8ed1ab_0 + - nspr=4.35=h27087fc_0 + - nss=3.96=h1d7d5a4_0 + - numba=0.58.1=py311h96b013e_0 + - numcodecs=0.12.1=py311hb755f60_0 + - numexpr=2.8.8=py311h039bad6_100 + - numpy=1.26.3=py311h64a7726_0 + - numpy_groupies=0.10.2=pyhd8ed1ab_0 + - ocgis=2.1.1=py_1 + - ocl-icd=2.3.1=h7f98852_0 + - ocl-icd-system=1.0.0=1 + - open-radar-data=0.0.7=pyhd8ed1ab_0 + - opencv=4.8.1=py311h38be061_1 + - openh264=2.4.0=h59595ed_0 + - openjpeg=2.5.0=h488ebb8_3 + - openssl=3.3.0=hd590300_0 + - orc=1.9.0=h208142c_3 + - overrides=7.4.0=pyhd8ed1ab_0 + - p11-kit=0.24.1=hc5aa10d_0 + - packaging=23.2=pyhd8ed1ab_0 + - pandas=2.1.4=py311h320fe9a_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 + - panel=1.3.6=pyhd8ed1ab_0 + - pango=1.50.14=ha41ecd1_2 + - papermill=2.4.0=pyhd8ed1ab_0 + - param=2.0.1=pyhca7485f_0 + - parso=0.8.3=pyhd8ed1ab_0 + - partd=1.4.1=pyhd8ed1ab_0 + - pathspec=0.12.1=pyhd8ed1ab_0 + - patsy=0.5.6=pyhd8ed1ab_0 + - pcre2=10.40=hc3806b6_0 + - pexpect=4.8.0=pyh1a96a4e_2 + - pickleshare=0.7.5=py_1003 + - pillow=10.0.1=py311h8aef010_1 + - pint=0.23=pyhd8ed1ab_0 + - pip=23.3.2=pyhd8ed1ab_0 + - pixman=0.43.0=h59595ed_0 + - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 + - platformdirs=4.1.0=pyhd8ed1ab_0 + - ply=3.11=py_1 + - pooch=1.8.0=pyhd8ed1ab_0 + - pop-tools=2023.6.0=pyhd8ed1ab_0 + - poppler=23.08.0=hf2349cb_2 + - poppler-data=0.4.12=hd8ed1ab_0 + - postgresql=15.5=h82ecc9d_0 + - proj=9.3.0=h1d62c97_2 + - prometheus_client=0.19.0=pyhd8ed1ab_0 + - prompt-toolkit=3.0.42=pyha770c72_0 + - properscoring=0.1=py_0 + - psutil=5.9.7=py311h459d7ec_0 + - pthread-stubs=0.4=h36c2ea0_1001 + - ptyprocess=0.7.0=pyhd3deb0d_0 + - pugixml=1.14=h59595ed_0 + - pulseaudio-client=16.1=hb77b528_5 + - pure_eval=0.2.2=pyhd8ed1ab_0 + - py-cpuinfo=9.0.0=pyhd8ed1ab_0 + - py-opencv=4.8.1=py311h781c19f_1 + - pyarrow=13.0.0=py311h39c9aba_13_cpu + - pyarrow-hotfix=0.6=pyhd8ed1ab_0 + - pybtex=0.24.0=pyhd8ed1ab_2 + - pybtex-docutils=1.0.3=py311h38be061_1 + - pycparser=2.21=pyhd8ed1ab_0 + - pyct=0.5.0=pyhd8ed1ab_0 + - pydantic=2.5.3=pyhd8ed1ab_0 + - pydantic-core=2.14.6=py311h46250e7_1 + - pydap=3.4.0=pyhd8ed1ab_0 + - pydata-sphinx-theme=0.15.1=pyhd8ed1ab_0 + - pyerfa=2.0.1.1=py311h1f0f07a_0 + - pygments=2.17.2=pyhd8ed1ab_0 + - pygraphviz=1.11=py311hbf5cbc9_2 + - pygrib=2.1.4=py311hbe899fa_8 + - pyhdf=0.11.3=py311ha36aa4f_2 + - pyjwt=2.8.0=pyhd8ed1ab_0 + - pylint=3.0.3=pyhd8ed1ab_0 + - pynco=1.1.0=pyhd8ed1ab_1 + - pyngl=1.6.1=py311hd9db0c4_6 + - pyparsing=3.1.1=pyhd8ed1ab_0 + - pyproj=3.6.1=py311h1facc83_4 + - pyqt=5.15.9=py311hf0fb5b6_5 + - pyqt5-sip=12.12.2=py311hb755f60_5 + - pyshp=2.3.1=pyhd8ed1ab_0 + - pysocks=1.7.1=pyha2e5f31_6 + - pytables=3.9.2=py311h10c7f7f_1 + - python=3.11.6=hab00c5b_0_cpython + - python-dateutil=2.8.2=pyhd8ed1ab_0 + - python-eccodes=1.6.1=py311h1f0f07a_1 + - python-fastjsonschema=2.19.1=pyhd8ed1ab_0 + - python-graphviz=0.20.1=pyh22cad53_0 + - python-json-logger=2.0.7=pyhd8ed1ab_0 + - python-tzdata=2023.4=pyhd8ed1ab_0 + - python-wget=3.2=py_0 + - python-xxhash=3.4.1=py311h459d7ec_0 + - python_abi=3.11=4_cp311 + - pytz=2023.3.post1=pyhd8ed1ab_0 + - pyviz_comms=3.0.0=pyhd8ed1ab_0 + - pywavelets=1.4.1=py311h1f0f07a_1 + - pyyaml=6.0.1=py311h459d7ec_1 + - pyzmq=25.1.2=py311h34ded2d_0 + - qt-main=5.15.8=hc47bfe8_16 + - rasterio=1.3.9=py311h40fbdff_0 + - rav1e=0.6.6=he8a937b_2 + - rdma-core=49.0=hd3aeb46_2 + - re2=2023.06.02=h2873b5e_0 + - readline=8.2=h8228510_1 + - referencing=0.32.1=pyhd8ed1ab_0 + - requests=2.31.0=pyhd8ed1ab_0 + - retrying=1.3.3=py_2 + - rfc3339-validator=0.1.4=pyhd8ed1ab_0 + - rfc3986-validator=0.1.1=pyh9f0ad1d_0 + - rpds-py=0.16.2=py311h46250e7_0 + - rtree=1.1.0=py311h3bb2b0f_0 + - s2n=1.3.56=h06160fa_0 + - s3fs=0.4.2=py_0 + - s3transfer=0.10.0=pyhd8ed1ab_0 + - scikit-image=0.22.0=py311h320fe9a_2 + - scikit-learn=1.3.2=py311hc009520_2 + - scipy=1.11.4=py311h64a7726_0 + - seaborn=0.13.1=hd8ed1ab_0 + - seaborn-base=0.13.1=pyhd8ed1ab_0 + - seawater=3.3.4=py_1 + - send2trash=1.8.2=pyh41d4057_0 + - setuptools=69.0.3=pyhd8ed1ab_0 + - setuptools-scm=8.0.4=pyhd8ed1ab_0 + - setuptools_scm=8.0.4=hd8ed1ab_0 + - shapely=2.0.2=py311he06c224_0 + - simpervisor=1.0.0=pyhd8ed1ab_0 + - sip=6.7.12=py311hb755f60_0 + - six=1.16.0=pyh6c4a22f_0 + - snappy=1.1.10=h9fff704_0 + - sniffio=1.3.0=pyhd8ed1ab_0 + - snowballstemmer=2.2.0=pyhd8ed1ab_0 + - snuggs=1.4.7=py_0 + - sortedcontainers=2.4.0=pyhd8ed1ab_0 + - soupsieve=2.5=pyhd8ed1ab_1 + - sparse=0.15.1=pyhd8ed1ab_0 + - spatialpandas=0.4.10=pyhd8ed1ab_1 + - sphinx=5.0.2=pyh6c4a22f_0 + - sphinx-book-theme=1.0.1=pyhd8ed1ab_0 + - sphinx-comments=0.0.3=pyh9f0ad1d_0 + - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 + - sphinx-design=0.3.0=pyhd8ed1ab_0 + - sphinx-external-toc=0.3.1=pyhd8ed1ab_1 + - sphinx-jupyterbook-latex=0.5.2=pyhd8ed1ab_0 + - sphinx-multitoc-numbering=0.1.3=pyhd8ed1ab_0 + - sphinx-thebe=0.2.1=pyhd8ed1ab_0 + - sphinx-togglebutton=0.3.2=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=1.0.7=pyhd8ed1ab_0 + - sphinxcontrib-bibtex=2.5.0=pyhd8ed1ab_0 + - sphinxcontrib-devhelp=1.0.5=pyhd8ed1ab_0 + - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 + - sphinxcontrib-qthelp=1.0.6=pyhd8ed1ab_0 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 + - sqlalchemy=2.0.25=py311h459d7ec_0 + - sqlite=3.44.2=h2c6b66d_0 + - stack_data=0.6.2=pyhd8ed1ab_0 + - statsmodels=0.14.1=py311h1f0f07a_0 + - svt-av1=1.7.0=h59595ed_0 + - tabulate=0.9.0=pyhd8ed1ab_1 + - tbb=2021.11.0=h00ab1b0_0 + - tblib=3.0.0=pyhd8ed1ab_0 + - tempest-remap=2.2.0=h69ec54a_2 + - tenacity=8.2.3=pyhd8ed1ab_0 + - terminado=0.18.0=pyh0d859eb_0 + - textwrap3=0.9.2=py_0 + - threadpoolctl=3.2.0=pyha21a80b_0 + - tifffile=2023.12.9=pyhd8ed1ab_0 + - tiledb=2.16.3=h8c794c1_3 + - tinycss2=1.2.1=pyhd8ed1ab_0 + - tk=8.6.13=noxft_h4845f30_101 + - tobac=1.5.2=pyhd8ed1ab_1 + - toml=0.10.2=pyhd8ed1ab_0 + - tomli=2.0.1=pyhd8ed1ab_0 + - tomlkit=0.12.3=pyha770c72_0 + - toolz=0.12.0=pyhd8ed1ab_0 + - tornado=6.3.3=py311h459d7ec_1 + - tqdm=4.66.1=pyhd8ed1ab_0 + - trackpy=0.6.1=pyhd8ed1ab_0 + - traitlets=5.14.1=pyhd8ed1ab_0 + - types-python-dateutil=2.8.19.20240106=pyhd8ed1ab_0 + - typing-extensions=4.9.0=hd8ed1ab_0 + - typing_extensions=4.9.0=pyha770c72_0 + - typing_utils=0.1.0=pyhd8ed1ab_0 + - tzcode=2023d=h3f72095_0 + - tzdata=2023d=h0c530f3_0 + - uc-micro-py=1.0.2=pyhd8ed1ab_0 + - ucx=1.15.0=h75e419f_2 + - udunits2=2.2.28=h40f5838_3 + - uri-template=1.3.0=pyhd8ed1ab_0 + - uriparser=0.9.7=hcb278e6_1 + - urllib3=1.26.18=pyhd8ed1ab_0 + - uxarray=2024.04.0=pyhd8ed1ab_0 + - versioneer=0.29=pyhd8ed1ab_0 + - wcwidth=0.2.13=pyhd8ed1ab_0 + - webcolors=1.13=pyhd8ed1ab_0 + - webencodings=0.5.1=pyhd8ed1ab_2 + - webob=1.8.7=pyhd8ed1ab_0 + - websocket-client=1.7.0=pyhd8ed1ab_0 + - wheel=0.42.0=pyhd8ed1ab_0 + - widgetsnbextension=4.0.9=pyhd8ed1ab_0 + - wrapt=1.16.0=py311h459d7ec_0 + - wrf-python=1.3.4.1=py311ha9cf758_3 + - x264=1!164.3095=h166bdaf_2 + - x265=3.5=h924138e_3 + - xarray=2023.12.0=pyhd8ed1ab_0 + - xarray-datatree=0.0.13=pyhd8ed1ab_0 + - xcb-util=0.4.0=hd590300_1 + - xcb-util-image=0.4.0=h8ee46fc_1 + - xcb-util-keysyms=0.4.0=h8ee46fc_1 + - xcb-util-renderutil=0.3.9=hd590300_1 + - xcb-util-wm=0.4.1=h8ee46fc_1 + - xerces-c=3.2.4=hac6953d_3 + - xesmf=0.8.2=pyhd8ed1ab_0 + - xgcm=0.8.1=pyhd8ed1ab_0 + - xhistogram=0.3.2=pyhd8ed1ab_0 + - xinvert=0.1.3=pyhd8ed1ab_0 + - xkeyboard-config=2.40=hd590300_0 + - xmltodict=0.13.0=pyhd8ed1ab_0 + - xorg-fixesproto=5.0=h7f98852_1002 + - xorg-imake=1.0.7=0 + - xorg-inputproto=2.3.2=h7f98852_1002 + - xorg-kbproto=1.0.7=h7f98852_1002 + - xorg-libice=1.1.1=hd590300_0 + - xorg-libsm=1.2.4=h7391055_0 + - xorg-libx11=1.8.7=h8ee46fc_0 + - xorg-libxau=1.0.11=hd590300_0 + - xorg-libxaw=1.0.14=h7f98852_1 + - xorg-libxdmcp=1.1.3=h7f98852_0 + - xorg-libxext=1.3.4=h0b41bf4_2 + - xorg-libxfixes=5.0.3=h7f98852_1004 + - xorg-libxi=1.7.10=h7f98852_0 + - xorg-libxmu=1.1.3=h7f98852_0 + - xorg-libxpm=3.5.17=hd590300_0 + - xorg-libxrender=0.9.11=hd590300_0 + - xorg-libxt=1.3.0=hd590300_1 + - xorg-makedepend=1.0.8=h59595ed_0 + - xorg-renderproto=0.11.1=h7f98852_1002 + - xorg-xextproto=7.3.0=h0b41bf4_1003 + - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 + - xorg-xproto=7.0.31=h7f98852_1007 + - xradar=0.4.2=pyhd8ed1ab_0 + - xrft=1.0.1=pyhd8ed1ab_0 + - xskillscore=0.0.24=pyhd8ed1ab_0 + - xxhash=0.8.2=hd590300_0 + - xyzservices=2023.10.1=pyhd8ed1ab_0 + - xz=5.2.6=h166bdaf_0 + - yaml=0.2.5=h7f98852_2 + - yarl=1.9.3=py311h459d7ec_0 + - zarr=2.16.1=pyhd8ed1ab_0 + - zeromq=4.3.5=h59595ed_0 + - zfp=1.0.1=h59595ed_0 + - zict=3.0.0=pyhd8ed1ab_0 + - zipp=3.17.0=pyhd8ed1ab_0 + - zlib=1.2.13=hd590300_5 + - zlib-ng=2.0.7=h0b41bf4_0 + - zstd=1.5.5=hfc55251_0 +prefix: /glade/u/apps/opt/conda/envs/npl-2024a From 3772265aba3fd869e0744567f03922848bd469a8 Mon Sep 17 00:00:00 2001 From: justin-richling Date: Fri, 25 Apr 2025 17:25:28 -0600 Subject: [PATCH 13/43] Update npl-2024a_environment.yaml --- env/npl-2024a_environment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/env/npl-2024a_environment.yaml b/env/npl-2024a_environment.yaml index 73bbda001..de2c9c1f3 100644 --- a/env/npl-2024a_environment.yaml +++ b/env/npl-2024a_environment.yaml @@ -1,4 +1,4 @@ -name: npl-2024a +name: adf_npl-2024a channels: - conda-forge - r @@ -646,4 +646,4 @@ dependencies: - zlib=1.2.13=hd590300_5 - zlib-ng=2.0.7=h0b41bf4_0 - zstd=1.5.5=hfc55251_0 -prefix: /glade/u/apps/opt/conda/envs/npl-2024a +prefix: /glade/u/apps/opt/conda/envs/adf_npl-2024a From 191f699728bd3ccfec397c7e3d7c0fce22e6e462 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 13:20:48 -0600 Subject: [PATCH 14/43] Add updated args for plotting scripts --- scripts/plotting/global_latlon_map.py | 7 +++++-- scripts/plotting/global_latlon_vect_map.py | 8 ++++++-- scripts/plotting/global_mean_timeseries.py | 2 ++ scripts/plotting/meridional_mean.py | 4 +++- scripts/plotting/polar_map.py | 5 ++++- scripts/plotting/zonal_mean.py | 6 ++++-- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/scripts/plotting/global_latlon_map.py b/scripts/plotting/global_latlon_map.py index a845c49cd..9a1bba8ab 100644 --- a/scripts/plotting/global_latlon_map.py +++ b/scripts/plotting/global_latlon_map.py @@ -101,6 +101,7 @@ def global_latlon_map(adfobj): def process_variable(adfobj, var, seasons, pres_levs, plot_type, redo_plot): vres = adfobj.variable_defaults.get(var, {}) + vres["plot_type"] = __name__ web_category = vres.get("category", None) # For global maps, also set the central longitude: @@ -378,7 +379,7 @@ def process_2d_plots(adfobj, mdata, odata, case_name, case_nickname, process_seasonal_data(mdata, odata, s) # Generate plot - pf.plot_map_and_save(plot_name, case_nickname, adfobj.data.ref_nickname, + pf.plot_map_and_save(adfobj, plot_name, case_nickname, adfobj.data.ref_nickname, [syear_case, eyear_case], [syear_baseline, eyear_baseline], mseasons[s], oseasons[s], dseasons[s], pseasons[s], @@ -412,8 +413,10 @@ def process_3d_plots(adfobj, mdata, odata, case_name, case_nickname, mseasons[s], oseasons[s], dseasons[s], pseasons[s] = \ process_seasonal_data(mdata, odata, s) + vres['lev'] = int(pres) + # Generate plot - pf.plot_map_and_save(plot_name, case_nickname, adfobj.data.ref_nickname, + pf.plot_map_and_save(adfobj, plot_name, case_nickname, adfobj.data.ref_nickname, [syear_case, eyear_case], [syear_baseline, eyear_baseline], mseasons[s].sel(lev=pres), diff --git a/scripts/plotting/global_latlon_vect_map.py b/scripts/plotting/global_latlon_vect_map.py index b0a4e02f2..375889d1f 100644 --- a/scripts/plotting/global_latlon_vect_map.py +++ b/scripts/plotting/global_latlon_vect_map.py @@ -164,6 +164,8 @@ def global_latlon_vect_map(adfobj): continue #End if + vres["plot_type"] = __name__ + #Make sure that variable is part of a vector pair: if "vector_pair" in vres: var_pair = vres["vector_pair"] @@ -405,6 +407,8 @@ def global_latlon_vect_map(adfobj): continue #End if + vres['lev'] = int(lv) + #Loop over season dictionary: for s in seasons: umseasons[s] = (utils.seasonal_mean(umdata, season=s, is_climo=True)).sel(lev=lv) @@ -444,7 +448,7 @@ def global_latlon_vect_map(adfobj): # colormap, contour_levels, diff_colormap, diff_contour_levels, tiString, tiFontSize, mpl # *Any other entries will be ignored. # NOTE: If we were doing all the plotting here, we could use whatever we want from the provided YAML file. - pf.plot_map_vect_and_save(plot_name, case_nickname, base_nickname, + pf.plot_map_vect_and_save(adfobj, plot_name, case_nickname, base_nickname, [syear_cases[case_idx],eyear_cases[case_idx]], [syear_baseline,eyear_baseline],lv, umseasons[s], vmseasons[s], @@ -506,7 +510,7 @@ def global_latlon_vect_map(adfobj): udseasons[s], vdseasons[s], obs, **vres) #Add plot to website (if enabled): - adfobj.add_website_data(plot_name, var_name, case_name, category=web_category, + adfobj.add_website_data(adfobj, plot_name, var_name, case_name, category=web_category, season=s, plot_type="LatLon_Vector") #End for diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index a166a9b66..82e3b87a7 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -51,6 +51,8 @@ def global_mean_timeseries(adfobj): vres = {} #End if + vres["plot_type"] = __name__ + # reference time series (DataArray) ref_ts_da = adfobj.data.load_reference_timeseries_da(field) diff --git a/scripts/plotting/meridional_mean.py b/scripts/plotting/meridional_mean.py index f4e058098..6891fe378 100644 --- a/scripts/plotting/meridional_mean.py +++ b/scripts/plotting/meridional_mean.py @@ -134,6 +134,8 @@ def meridional_mean(adfobj): vres = {} #End if + vres["plot_type"] = __name__ + #loop over different data sets to plot model against: for data_src in data_list: # load data (observational) comparison files @@ -231,7 +233,7 @@ def meridional_mean(adfobj): #Create new plot: - pf.plot_meridional_mean_and_save(plot_name, case_nickname, base_nickname, + pf.plot_meridional_mean_and_save(adfobj, plot_name, case_nickname, base_nickname, [syear_cases[case_idx],eyear_cases[case_idx]], [syear_baseline,eyear_baseline], mseasons[s], oseasons[s], has_lev, latbounds=slice(-5,5), obs=obs, **vres) diff --git a/scripts/plotting/polar_map.py b/scripts/plotting/polar_map.py index 976879f31..98422abe1 100644 --- a/scripts/plotting/polar_map.py +++ b/scripts/plotting/polar_map.py @@ -137,6 +137,7 @@ def polar_map(adfobj): # Get variable-specific settings vres = res.get(var, {}) web_category = vres.get("category", None) + vres["plot_type"] = __name__ # Get all plot info and check existence plot_info = [] @@ -153,8 +154,10 @@ def polar_map(adfobj): for s in seasons: for hemi_type in ["NHPolar", "SHPolar"]: + vres["hemi"] = hemi_type if pres_levs and has_lev: # 3-D variable & pressure levels specified for pres in pres_levs: + vres['lev'] = int(pres) plot_name = plot_loc / f"{var}_{pres}hpa_{s}_{hemi_type}_Mean.{plot_type}" info = { 'path': plot_name, @@ -245,7 +248,7 @@ def polar_map(adfobj): if plot['path'].exists(): plot['path'].unlink() - pf.make_polar_plot( + pf.make_polar_plot(adfobj, plot['path'], test_nicknames[case_idx], base_nickname, [syear_cases[case_idx], eyear_cases[case_idx]], [syear_baseline, eyear_baseline], diff --git a/scripts/plotting/zonal_mean.py b/scripts/plotting/zonal_mean.py index 9e034e8bf..f9ba71dd8 100644 --- a/scripts/plotting/zonal_mean.py +++ b/scripts/plotting/zonal_mean.py @@ -158,6 +158,8 @@ def zonal_mean(adfobj): vres = {} #End if + vres["plot_type"] = __name__ + # load reference data (observational or baseline) if not adfobj.compare_obs: base_name = adfobj.data.ref_case_label @@ -269,7 +271,7 @@ def zonal_mean(adfobj): if plot_name not in zonal_skip: #Create new plot: - pf.plot_zonal_mean_and_save(plot_name, case_nickname, adfobj.data.ref_nickname, + pf.plot_zonal_mean_and_save(adfobj, plot_name, case_nickname, adfobj.data.ref_nickname, [syear_cases[case_idx],eyear_cases[case_idx]], [syear_baseline,eyear_baseline], mseasons[s], oseasons[s], has_lev, log_p=False, obs=adfobj.compare_obs, **vres) @@ -281,7 +283,7 @@ def zonal_mean(adfobj): #Create log-pressure plots as well (if applicable) if (plot_name_log) and (plot_name_log not in logp_zonal_skip): - pf.plot_zonal_mean_and_save(plot_name_log, case_nickname, adfobj.data.ref_nickname, + pf.plot_zonal_mean_and_save(adfobj, plot_name_log, case_nickname, adfobj.data.ref_nickname, [syear_cases[case_idx],eyear_cases[case_idx]], [syear_baseline,eyear_baseline], mseasons[s], oseasons[s], has_lev, log_p=True, obs=adfobj.compare_obs, **vres) From 99ec62bbcb252994ba7b1d0a9bb3a82defc1d5b6 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 13:24:12 -0600 Subject: [PATCH 15/43] Bring in brianpm's changes for climo workflow --- scripts/averaging/create_climo_files.py | 109 ++++++++++++------------ 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/scripts/averaging/create_climo_files.py b/scripts/averaging/create_climo_files.py index 24d1f2098..e0aef53c1 100644 --- a/scripts/averaging/create_climo_files.py +++ b/scripts/averaging/create_climo_files.py @@ -11,7 +11,6 @@ import numpy as np import xarray as xr # module-level import so all functions can get to it. -import multiprocessing as mp def get_time_slice_by_year(time, startyear, endyear): """ @@ -224,34 +223,35 @@ def create_climo_files(adf, clobber=False, search=None): # end_diag_script(errmsg) # Previously we would kill the run here. continue - list_of_arguments.append((adf, ts_files, syr, eyr, output_file)) - - - #End of var_list loop - #-------------------- + list_of_arguments.append((adf.user, ts_files, syr, eyr, output_file)) # Parallelize the computation using multiprocessing pool: - with mp.Pool(processes=number_of_cpu) as p: - result = p.starmap(process_variable, list_of_arguments) - - #End of model case loop - #---------------------- - - #Notify user that script has ended: + print(f" --> Starting Pool with {number_of_cpu} workers for {len(list_of_arguments)} variables.") + import multiprocessing as mp + # Use 'spawn' to ensure a fresh memory space for each process + # Safer on HPC systems than the default 'fork' + context = mp.get_context('spawn') + with context.Pool(processes=number_of_cpu) as p: + results = p.starmap(process_variable, list_of_arguments) + # Print results to see if any specific variable failed + for res in results: + if "Failed" in res: + print(f"\t {res}") + print(" ... multiprocessing pool closed.") print(" ...CAM climatologies have been calculated successfully.") # # Local functions # -def process_variable(adf, ts_files, syr, eyr, output_file): +def process_variable(adf_user, ts_files, syr, eyr, output_file): ''' Compute and save the monthly climatology file. Parameters ---------- - adf - The ADF object + adf_user + The user from the ADF object ts_files : list list of paths to time series files syr : str @@ -261,46 +261,43 @@ def process_variable(adf, ts_files, syr, eyr, output_file): output_file : str or Path file path for output climatology file ''' - #Read in files via xarray (xr): - if len(ts_files) == 1: - cam_ts_data = xr.open_dataset(ts_files[0], decode_times=True) - else: - cam_ts_data = xr.open_mfdataset(ts_files, decode_times=True, combine='by_coords') - #Average time dimension over time bounds, if bounds exist: - if 'time_bnds' in cam_ts_data: - time = cam_ts_data['time'] - # NOTE: force `load` here b/c if dask & time is cftime, throws a NotImplementedError: - time = xr.DataArray(cam_ts_data['time_bnds'].load().mean(dim='nbnd').values, dims=time.dims, attrs=time.attrs) - cam_ts_data['time'] = time - cam_ts_data.assign_coords(time=time) - cam_ts_data = xr.decode_cf(cam_ts_data) - #Extract data subset using provided year bounds: - tslice = get_time_slice_by_year(cam_ts_data.time, int(syr), int(eyr)) - cam_ts_data = cam_ts_data.isel(time=tslice) - #Group time series values by month, and average those months together: - cam_climo_data = cam_ts_data.groupby('time.month').mean(dim='time') - #Rename "months" to "time": - cam_climo_data = cam_climo_data.rename({'month':'time'}) - #Set netCDF encoding method (deal with getting non-nan fill values): - enc_dv = {xname: {'_FillValue': None, 'zlib': True, 'complevel': 4} for xname in cam_climo_data.data_vars} - enc_c = {xname: {'_FillValue': None} for xname in cam_climo_data.coords} - enc = {**enc_c, **enc_dv} - - # Create a dictionary of attributes - # Convert the list to a string (join with commas) - ts_files_str = [str(path) for path in ts_files] - ts_files_str = ', '.join(ts_files_str) - attrs_dict = { - "adf_user": adf.user, - "climo_yrs": f"{syr}-{eyr}", - "time_series_files": ts_files_str, - } - cam_climo_data = cam_climo_data.assign_attrs(attrs_dict) - - #Output variable climatology to NetCDF-4 file: - cam_climo_data.to_netcdf(output_file, format='NETCDF4', encoding=enc) - return 1 # All funcs return something. Could do error checking with this if needed. - + import xarray as xr + import numpy as np + import dask + import gc + dask.config.set(scheduler='synchronous') # Disable internal dask multi-threading + try: + # Using chunks={} forces xarray to use dask, which handles memory better + # than loading everything into RAM at once via open_dataset + with xr.open_mfdataset(ts_files, decode_times=True, combine='by_coords', chunks={'time': 12}) as ds: + if 'time_bnds' in ds: + new_time = ds['time_bnds'].load().mean(dim='nbnd') + ds = ds.assign_coords(time=new_time.values) + ds = xr.decode_cf(ds) + + tslice = get_time_slice_by_year(ds.time, int(syr), int(eyr)) + ds_subset = ds.isel(time=tslice) + + climo = ds_subset.groupby('time.month').mean(dim='time') + climo = climo.rename({'month': 'time'}) + + enc_dv = {xname: {'_FillValue': None, 'zlib': True, 'complevel': 4} for xname in climo.data_vars} + enc_c = {xname: {'_FillValue': None} for xname in climo.coords} + enc = {**enc_c, **enc_dv} + + climo.attrs.update({ + "adf_user": adf_user, + "climo_yrs": f"{syr}-{eyr}", + "time_series_files": ", ".join([str(f) for f in ts_files]) + }) + + climo.to_netcdf(output_file, format='NETCDF4', encoding=enc) + return f"Success: {output_file.name}" + except Exception as e: + return f"Failed: {output_file.name} with error: {str(e)}" + finally: + # Force cleanup of memory + gc.collect() def check_averaging_interval(syear_in, eyear_in): """ From 936249ce98dfed0a9823568c845d0495c07c3794 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 17:08:39 -0600 Subject: [PATCH 16/43] Update/clean plotting utils, add NCL cmaps --- lib/plotting_utils.py | 565 +++++++++++++++++++++++++++++++++++------- 1 file changed, 482 insertions(+), 83 deletions(-) diff --git a/lib/plotting_utils.py b/lib/plotting_utils.py index d41695e7b..96bf42f4f 100644 --- a/lib/plotting_utils.py +++ b/lib/plotting_utils.py @@ -32,6 +32,13 @@ import matplotlib as mpl import matplotlib.cm as cm import cartopy.crs as ccrs +import os + +import urllib +from urllib.parse import urlparse +from urllib.request import urlretrieve +from pathlib import Path +import re from adf_diag import AdfDiag import adf_utils as utils @@ -39,6 +46,14 @@ import warnings # use to warn user about missing files. warnings.formatwarning = utils.my_formatwarning +#Set non-X-window backend for matplotlib: +mpl.use('Agg') + +#Now import pyplot: +import matplotlib.pyplot as plt + +script_name = os.path.splitext(os.path.basename(__file__))[0] + ################# #HELPER FUNCTIONS ################# @@ -307,6 +322,310 @@ def meridional_plot_preslon(ax, lon, lev, data, **kwargs): ax.set_ylim([np.max(lev), np.min(lev)]) return img, ax + +# Color Map Functions +#-------------------- + +ncl_defaults = ["ncl_default"] + +def guess_ncl_url(cmap): + return f"https://www.ncl.ucar.edu/Document/Graphics/ColorTables/Files/{cmap}.rgb" + + +def download_ncl_colormap(url, dest): + urlretrieve(url, dest) + + +def read_ncl_colormap(adfobj, fil): + # determine if fil is a URL: + # if so, we have to download it + + msg = f"{script_name}: read_ncl_colormap()" + if isinstance(fil, str): + pars = urlparse(fil) + if pars.scheme in ['http', 'https', 'ftp']: + filename = Path.cwd() / fil.split("/")[-1] + if filename.is_file(): + msg += f"\n\tFile already downloaded as {filename}" + else: + msg += f"\n\tFile will be downloaded and saved as {filename}" + download_ncl_colormap(fil, str(filename)) + else: + is_url = False + filename = Path(fil) + elif isinstance(fil, Path): + filename = fil + else: + raise ValueError(f"\tERROR: what to do with type {type(fil)}") + + # NCL's colormaps are not regularized enough to just use read_csv. + # We have to determine how many lines to skip because it varies. + # NCL has some files that have "comments" at the end + # which will look like additional columnns + # We basically are forced to just read line-by-line + + # ASSUME ALL NCL COLORMAPS ARE N rows BY 3 COLUMNS, + # AND THE VALUES ARE INTEGERS 0-255. + with open(filename) as f: + table_exists = False + for count, line in enumerate(f): + line_str = line.strip() # remove leading/trailing whitespace + if (len(line_str) == 0) or (not line_str[0].isdigit()): + continue # empty line or non-data line + # NOTE: also skips if the first value is negative (hlu_default) + else: + if re.search(r'[^\s0-9-\.]', line_str): # any non number characters ASSUMED AT END + # take the string up to the non-matching character + line_vals = line_str[:re.search(r'[^\s0-9-\.]', line_str).start()-1].strip().split() + else: + line_vals = line_str.split() + try: + row = [float(r) for r in line_vals] + except: + msg += f"\n\tERROR reading RGB file {line_vals}" + if table_exists: + table = np.vstack([table, row]) + else: + table = np.array(row) + table_exists=True + adfobj.debug_log(msg) + return table + + +def ncl_to_mpl(adfobj, nclmap, name): + msg = f"{script_name}: ncl_to_mpl()" + if nclmap.max() > 1: + try: + vals = nclmap / 255 + except: + msg += f"\n\tERROR: could not divide by 255. {type(nclmap) = }" + msg += f" {nclmap}" + adfobj.debug_log(msg) + return None + else: + msg += f"\n\t{name} seems to be 0-1" + vals = nclmap + assert vals.shape[1] == 3, 'vals.shape should be (N,3)' + ncolors = vals.shape[0] + if ncolors > 100: + my_cmap = mpl.colors.LinearSegmentedColormap.from_list(name, vals) + my_cmap_r = my_cmap.reversed() + else: + my_cmap = mpl.colors.ListedColormap(vals, name) + my_cmap_r = my_cmap.reversed() + # my_cmap, my_cmap_r from reversing a colormap + # ALLOW MPL TO KNOW ABOUT THE COLORMAP: + # mpl.colormaps.register(cmap=my_cmap) + # mpl.colormaps.register(cmap=my_cmap_r) + + adfobj.debug_log(msg) + return my_cmap, my_cmap_r + + +def choose_colormap_type(levels, threshold_symmetry=0.25): + levels = np.array(levels) + minval, maxval = np.min(levels), np.max(levels) + crosses_zero = (minval < 0) and (maxval > 0) + symmetry_ratio = abs(abs(maxval) - abs(minval)) / max(abs(maxval), abs(minval)) + is_symmetric = symmetry_ratio < threshold_symmetry + return 'diverging' if crosses_zero and is_symmetric else 'sequential' + + +def load_colormap(adfobj, cmap_name): + msg = f"{script_name}: load_colormap()" + if cmap_name in plt.colormaps(): + adfobj.debug_log(msg) + return cmap_name + else: + msg += f"\n\t{cmap_name} not a standard Matplotlib colormap. Trying NCL..." + url = guess_ncl_url(cmap_name) + locfil = Path(".") / f"{cmap_name}.rgb" + data = read_ncl_colormap(locfil,msg) if locfil.is_file() else read_ncl_colormap(url) + cm, cmr = ncl_to_mpl(adfobj, data, cmap_name) + if not cm: + msg += f"\n\tFailed to load {cmap_name}. Defaulting to 'coolwarm'." + adfobj.debug_log(msg) + return 'coolwarm' + adfobj.debug_log(msg) + return cm + + +def try_load_ncl_cmap(adfobj, cmap_case): + """Try to load an NCL colormap, fallback to PRECT special case or 'coolwarm'.""" + msg = f"{script_name}: try_load_ncl_cmap()" + msg += f"\n\tTrying {cmap_case} as an NCL color map:" + try: + url = guess_ncl_url(cmap_case) + locfil = Path(".") / f"{cmap_case}.rgb" + if locfil.is_file(): + data = read_ncl_colormap(locfil) + else: + try: + data = read_ncl_colormap(url) + except urllib.error.HTTPError: + msg += f"\n\tNCL colormap file not found" + + if isinstance(data, np.ndarray): + cm, cmr = ncl_to_mpl(data, cmap_case) + adfobj.debug_log(msg) + return cm, msg + except Exception: + pass + + adfobj.debug_log(msg) + return "coolwarm", msg + + +def get_cmap(adfobj, plotty, plot_type_dict, kwargs, polar_names): + """ + Gather colormap from variable defaults file, if applicable. + Falls back to 'viridis' (case) or 'BrBG' (diff) if none is found. + """ + + key_map = { + "diff": ("diff_colormap", "BrBG"), + "case": ("colormap", "viridis"), + } + colormap_key, default_cmap = key_map.get(plotty, ("colormap", "viridis")) + + cmap_case = None + + msg = f"{script_name}: get_cmap()" + + # Priority 1: YAML dict + if colormap_key in plot_type_dict: + cmap_entry = plot_type_dict[colormap_key] + msg += f"\n\tUser supplied cmap for {plotty}: {cmap_entry}" + + if isinstance(cmap_entry, str): + cmap_case = cmap_entry + elif isinstance(cmap_entry, dict): + resolved = resolve_hemi_level(adfobj, cmap_entry, kwargs, polar_names) + if isinstance(resolved, str): + cmap_case = resolved + + # Priority 2: kwargs dict + elif colormap_key in kwargs and isinstance(kwargs[colormap_key], str): + cmap_case = kwargs[colormap_key] + msg += f"\n\tUser supplied cmap for {plotty}: {cmap_case}" + + # Priority 3: fallback default + if not cmap_case: + msg += f"\n\tNo cmap for {plotty} found, defaulting to {default_cmap}" + cmap_case = default_cmap + + # NCL support + if cmap_case in ncl_defaults: + cmap_case, msg = try_load_ncl_cmap(adfobj, cmap_case) + + # Final check: must exist in matplotlib or NCL + if isinstance(cmap_case, str): + if (cmap_case not in plt.colormaps()) and (cmap_case not in ncl_defaults): + msg += f"\n\tInvalid cmap '{cmap_case}' for {plotty}, defaulting to {default_cmap}" + cmap_case = default_cmap + + adfobj.debug_log(msg) + + return cmap_case + + +# Conour Plot Prep Functions +#---------------------------- +def resolve_hemi_level(adfobj, data, kwargs, polar_names): + """Resolve hemisphere and/or vertical level specific values from a dict.""" + msg = f"{script_name}: resolve_hemi_level()" + hemi = kwargs.get("hemi") + lev = kwargs.get("lev") + + if hemi and polar_names.get(hemi) in data: + hemi_data = data[polar_names[hemi]] + if isinstance(hemi_data, dict) and lev in hemi_data: + msg += f"\n\tPolar {hemi} with vertical level {lev}" + adfobj.debug_log(msg) + return hemi_data[lev] + msg += f"\n\tPolar {hemi} without vertical levels" + adfobj.debug_log(msg) + return hemi_data + elif lev and lev in data: + msg += f"\n\tVertical level {lev}" + adfobj.debug_log(msg) + return data[lev] + + adfobj.debug_log(msg) + return None + + + +def resolve_levels(adfobj, plotty, plot_type_dict, kwargs, polar_names): + """Resolve contour levels based on user input and defaults.""" + levels_sim = None + msg = f"{script_name}: resolve_levels()" + + # Map keys based on plot type + key_map = { + "diff": ("diff_contour_levels", "diff_contour_range", "diff_contour_linspace"), + "case": ("contour_levels", "contour_levels_range", "contour_levels_linspace"), + } + contour_levels, contour_range, contour_linspace = key_map.get(plotty, (None, None, None)) + + def process_entry(entry, kind, msg): + """Handle lists and dicts for levels/ranges/linspace.""" + if isinstance(entry, list): + if len(entry) == 3: + if kind == "range": + msg += f"\n\tLevels specified for {plotty}: numpy.arange." + adfobj.debug_log(msg) + return np.arange(*entry) + elif kind == "linspace": + msg += f"\n\tLevels specified for {plotty}: numpy.linspace." + adfobj.debug_log(msg) + return np.linspace(*entry) + else: + msg += f"\n\tLevels specified for {plotty} as list of 3 values, please add more values." + msg += " Will get contrours from data range." + adfobj.debug_log(msg) + return None + elif len(entry) < 3: + msg += f"\n\tNot enough {kind} entries for {plotty} (<3) — ambiguous" + adfobj.debug_log(msg) + else: + adfobj.debug_log(msg) + return entry + elif isinstance(entry, dict): + resolved = resolve_hemi_level(adfobj, entry, kwargs, polar_names) + if isinstance(resolved, list) and len(resolved) == 3: + if kind == "range": + msg += f"\n\tLevels specified for {plotty}: numpy.arange." + adfobj.debug_log(msg) + return np.arange(*resolved) + elif kind == "linspace": + msg += f"\n\tLevels specified for {plotty}: numpy.linspace." + adfobj.debug_log(msg) + return np.linspace(*resolved) + adfobj.debug_log(msg) + return resolved + else: + adfobj.debug_log(msg) + return entry + + # Priority: explicit contour levels → range → linspace + for key, kind in [(contour_levels, "levels"), + (contour_range, "range"), + (contour_linspace, "linspace")]: + entry = None + if key in plot_type_dict: + entry = plot_type_dict[key] + elif key in kwargs: + entry = kwargs[key] + + if entry is not None: + levels_sim = process_entry(entry, kind, msg) + if levels_sim is not None: + break # stop once a valid setting is found + adfobj.debug_log(msg) + return levels_sim + + def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): """Preparation for making contour plots. @@ -334,14 +653,49 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): - 'contourf_opt': mpl kwargs for contourf - 'colorbar_opt': mpl kwargs for colorbar - 'diff_colorbar_opt' : mpl kwargs for difference colorbar - - 'normdiff': color normalization for difference panel - - 'cmapdiff': colormap for difference panel - - 'levelsdiff': contour levels for difference panel - - 'cmap1': color map for a and b panels - - 'norm1': color normalization for a and b panels - - 'levels1' : contour levels for a and b panels + - 'pct_colorbar_opt': mpl kwargs for percent difference colorbar + - 'norm_diff': color normalization for difference panel + - 'cmap_diff': colormap for difference panel + - 'levels_diff': contour levels for difference panel + - 'norm_pctdiff': color normalization for percent difference panel + - 'cmap_pctdiff': colormap for percent difference panel + - 'levels_pctdiff':contour levels for percent difference panel + - 'cmap_sim': color map for a and b panels + - 'norm_sim': color normalization for a and b panels + - 'levels_sim' : contour levels for a and b panels - 'plot_log_p' : true/false whether to plot log(pressure) axis + - 'extend_sim': colorbar extend for a and b panels + - 'extend_diff': colorbar extend for difference panel """ + + adfobj = kwargs["adfobj"] + + polar_names = {"NHPolar":"nh", + "SHPolar":"sh"} + + # Start color map/bar configurations + # ---------------------------------- + if "plot_type" in kwargs: + plot_type = kwargs["plot_type"] + if plot_type in kwargs: + plot_type_dict = kwargs[plot_type] + else: + plot_type_dict = kwargs + else: + plot_type = None + plot_type_dict = {} + + msg = f"{script_name}: prep_contour_plot()" + msg_detail = f"\n\n\tPreparing contour map for {adata.name}" + if "lev" in kwargs: + msg_detail += f' - {kwargs["lev"]}' + if "hemi" in kwargs: + msg_detail += f' : {kwargs["hemi"]}' + if plot_type: + msg_detail += f" for {plot_type} plot" + start_msg = msg + f"{msg_detail}\n\t{'-' * (len(msg_detail)-2)}\n" + adfobj.debug_log(start_msg) + # determine levels & color normalization: minval = np.min([np.min(adata), np.min(bdata)]) maxval = np.max([np.max(adata), np.max(bdata)]) @@ -349,100 +703,142 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): # determine norm to use (deprecate this once minimum MPL version is high enough) normfunc, mplv = use_this_norm() - if 'colormap' in kwargs: - cmap1 = kwargs['colormap'] - else: - cmap1 = 'coolwarm' - #End if - - if 'contour_levels' in kwargs: - levels1 = kwargs['contour_levels'] - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) - elif 'contour_levels_range' in kwargs: - assert len(kwargs['contour_levels_range']) == 3, \ - "contour_levels_range must have exactly three entries: min, max, step" - - levels1 = np.arange(*kwargs['contour_levels_range']) - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) + # Case/Baseline options -- Check in kwargs for colormap and levels + # COLOR MAP + #--------- + cmap_case = get_cmap(adfobj, "case", plot_type_dict, kwargs, polar_names) + msg = f"\n\tFinal case colormap: {cmap_case}\n\n" + + # CONTOUR LEVELS + #--------------- + levels_sim = resolve_levels(adfobj, "case", plot_type_dict, kwargs, polar_names) + msg += f"\n\tPre check levels: {type(levels_sim)}\n\t\t{levels_sim}\n" + if levels_sim is None: + msg += "\n\tSetting the levels from max/min" + levels_sim = np.linspace(minval, maxval, 12) + msg += f"\n\tFinal levels: {type(levels_sim)}\n\t\t{levels_sim}\n\n" + + # Check whether data exceeds limits + vmin, vmax = levels_sim[0], levels_sim[-1] + + extend = 'neither' + if minval < vmin and maxval > vmax: + extend = 'both' + elif minval < vmin: + extend = 'min' + elif maxval > vmax: + extend = 'max' + + if kwargs.get('non_linear', False): + cmap_obj = cm.get_cmap(cmap_case) + norm_sim = mpl.colors.BoundaryNorm(levels_sim, cmap_obj.N) else: - levels1 = np.linspace(minval, maxval, 12) - if ('non_linear' in kwargs) and (kwargs['non_linear']): - cmap_obj = cm.get_cmap(cmap1) - norm1 = mpl.colors.BoundaryNorm(levels1, cmap_obj.N) - else: - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) + norm_sim = mpl.colors.Normalize(vmin=min(levels_sim), vmax=max(levels_sim)) #End if #Check if the minval and maxval are actually different. If not, - #then set "levels1" to be an empty list, which will cause the + #then set "levels_sim" to be an empty list, which will cause the #plotting scripts to add a label instead of trying to plot a variable #with no contours: if minval == maxval: - levels1 = [] + levels_sim = [] #End if - if ('colormap' not in kwargs) and ('contour_levels' not in kwargs): + if ('colormap' not in plot_type_dict) and ('contour_levels' not in plot_type_dict): if ((minval < 0) and (0 < maxval)) and mplv > 2: - norm1 = normfunc(vmin=minval, vmax=maxval, vcenter=0.0) + norm_sim = normfunc(vmin=minval, vmax=maxval, vcenter=0.0) else: - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) + norm_sim = mpl.colors.Normalize(vmin=minval, vmax=maxval) #End if #End if - + # Difference options -- Check in kwargs for colormap and levels - if "diff_colormap" in kwargs: - cmapdiff = kwargs["diff_colormap"] - else: - cmapdiff = 'coolwarm' - #End if - - if "diff_contour_levels" in kwargs: - levelsdiff = kwargs["diff_contour_levels"] # a list of explicit contour levels - elif "diff_contour_range" in kwargs: - assert len(kwargs['diff_contour_range']) == 3, \ - "diff_contour_range must have exactly three entries: min, max, step" + # determine levels & color normalization: + minval = np.min(diffdata) + maxval = np.max(diffdata) + + # COLOR MAP + #---------- + cmap_diff = get_cmap(adfobj, "diff", plot_type_dict, kwargs, polar_names) + msg += f"\n\tFinal difference colormap: {cmap_diff}\n\n" + + # CONTOUR LEVELS + #--------------- + levels_diff = resolve_levels(adfobj, "diff", plot_type_dict, kwargs, polar_names) + + msg += f"\n\tPre check difference LEVELS: {type(levels_diff)}\n\t\t{levels_diff}\n" + if levels_diff is None: + msg += f"\n\tSetting the difference levels from max/min" + absmaxdif = np.max(np.abs(diffdata)) + levels_diff = np.linspace(-absmaxdif, absmaxdif, 12) + msg += f"\n\tFinal difference levels: {type(levels_diff)}\n\t\t{levels_diff}\n" + + # Check whether data exceeds limits + vmin, vmax = levels_diff[0], levels_diff[-1] + extend_diff = 'neither' + if minval < vmin and maxval > vmax: + extend_diff = 'both' + elif minval < vmin: + extend_diff = 'min' + elif maxval > vmax: + extend_diff = 'max' - levelsdiff = np.arange(*kwargs['diff_contour_range']) + # color normalization for difference + if ((np.min(levels_diff) < 0) and (0 < np.max(levels_diff))) and mplv > 2: + norm_diff = normfunc(vmin=np.min(levels_diff), vmax=np.max(levels_diff), vcenter=0.0) else: - # set a symmetric color bar for diff: - absmaxdif = np.max(np.abs(diffdata.data)) - # set levels for difference plot: - levelsdiff = np.linspace(-1*absmaxdif, absmaxdif, 12) + norm_diff = mpl.colors.Normalize(vmin=np.min(levels_diff), vmax=np.max(levels_diff)) + # Percent Difference options -- Check in kwargs for colormap and levels - if "pct_diff_colormap" in kwargs: - cmappct = kwargs["pct_diff_colormap"] + # COLOR MAP + #---------- + # determine levels & color normalization: + #minval = np.min(diffdata) + #maxval = np.max(diffdata) + if "pct_diff_colormap" in plot_type_dict: + cmap_pctdiff = plot_type_dict["pct_diff_colormap"] else: - cmappct = "PuOr_r" + cmap_pctdiff = "PuOr_r" #End if - if "pct_diff_contour_levels" in kwargs: - levelspctdiff = kwargs["pct_diff_contour_levels"] # a list of explicit contour levels - elif "pct_diff_contour_range" in kwargs: - assert len(kwargs['pct_diff_contour_range']) == 3, "pct_diff_contour_range must have exactly three entries: min, max, step" - levelspctdiff = np.arange(*kwargs['pct_diff_contour_range']) + if cmap_pctdiff not in plt.colormaps(): + msg += f"\n\tPercent Difference: {cmap_pctdiff} is not a matplotlib standard color map." + msg += f" Trying if this an NCL color map" + + url = guess_ncl_url(cmap_pctdiff) + locfil = "." / f"{cmap_pctdiff}.rgb" + if locfil.is_file(): + data = read_ncl_colormap(locfil) + else: + data = read_ncl_colormap(url) + cm, cmr = ncl_to_mpl(data, cmap_pctdiff) + #ncl_colors[cm.name] = cm + #ncl_colors[cmr.name] = cmr + + if not cm: + msg += f"\n\tPercent Difference: {cmap_pctdiff} is not a matplotlib or NCL color map." + cmap_pctdiff = 'PuOr_r' + msg += f" Defaulting to '{cmap_pctdiff}'" + adfobj.debug_log(msg) + else: + cmap_pctdiff = cm + + # CONTOUR LEVELS + #--------------- + if "pct_diff_contour_levels" in plot_type_dict: + levels_pctdiff = plot_type_dict["pct_diff_contour_levels"] # a list of explicit contour levels + elif "pct_diff_contour_range" in plot_type_dict: + assert len(plot_type_dict['pct_diff_contour_range']) == 3, "pct_diff_contour_range must have exactly three entries: min, max, step" + levels_pctdiff = np.arange(*plot_type_dict['pct_diff_contour_range']) else: - levelspctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pctnorm = mpl.colors.BoundaryNorm(levelspctdiff,256) + levels_pctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] + norm_pctdiff = mpl.colors.BoundaryNorm(levels_pctdiff,256) if "plot_log_pressure" in kwargs: plot_log_p = kwargs["plot_log_pressure"] else: plot_log_p = False - # color normalization for difference - if ((np.min(levelsdiff) < 0) and (0 < np.max(levelsdiff))) and mplv > 2: - normdiff = normfunc(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff), vcenter=0.0) - else: - normdiff = mpl.colors.Normalize(vmin=np.min(levelsdiff), vmax=np.max(levelsdiff)) - subplots_opt = {} contourf_opt = {} colorbar_opt = {} @@ -457,21 +853,24 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): diff_colorbar_opt.update(kwargs['mpl'].get('diff_colorbar',{})) pct_colorbar_opt.update(kwargs['mpl'].get('pct_diff_colorbar',{})) #End if + return {'subplots_opt': subplots_opt, 'contourf_opt': contourf_opt, 'colorbar_opt': colorbar_opt, 'diff_colorbar_opt': diff_colorbar_opt, 'pct_colorbar_opt': pct_colorbar_opt, - 'normdiff': normdiff, - 'cmapdiff': cmapdiff, - 'levelsdiff': levelsdiff, - 'pctnorm': pctnorm, - 'cmappct': cmappct, - 'levelspctdiff':levelspctdiff, - 'cmap1': cmap1, - 'norm1': norm1, - 'levels1': levels1, - 'plot_log_p': plot_log_p + 'norm_diff': norm_diff, + 'cmap_diff': cmap_diff, + 'levels_diff': levels_diff, + 'norm_pctdiff': norm_pctdiff, + 'cmap_pctdiff': cmap_pctdiff, + 'levels_pctdiff':levels_pctdiff, + 'cmap_sim': cmap_case, + 'norm_sim': norm_sim, + 'levels_sim': levels_sim, + 'plot_log_p': plot_log_p, + 'extend_sim': extend, + 'extend_diff': extend_diff } From d29fb1f4f3a31f08d94dc85837475c1d4f144f45 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 17:08:59 -0600 Subject: [PATCH 17/43] Update to new contour details --- scripts/plotting/regional_map_multicase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/plotting/regional_map_multicase.py b/scripts/plotting/regional_map_multicase.py index 43b9a46d8..8d2989adb 100644 --- a/scripts/plotting/regional_map_multicase.py +++ b/scripts/plotting/regional_map_multicase.py @@ -372,9 +372,9 @@ def regional_map_multicase_plot(adf, datadict, opt=None): popts = prep_contour_plot(datadict[xreg], datadict[xreg], datadict[xreg] - datadict[xreg], **opt) popts2 = { **popts["contourf_opt"], - "cmap": popts["cmap1"], - "norm": popts["norm1"], - "levels": popts["levels1"], + "cmap": popts["cmap_sim"], + "norm": popts["norm_sim"], + "levels": popts["levels_sim"], } cb_opt = popts.get("colorbar_opt") cntrplts.append( From 73ef882570d300b2b3717900e9e4bbbd5ac82442 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 17:09:22 -0600 Subject: [PATCH 18/43] Remove percent diff (use default) --- lib/adf_variable_defaults.yaml | 444 --------------------------------- 1 file changed, 444 deletions(-) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index ed5be6da0..72ab0ee9d 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -153,8 +153,6 @@ AODDUST: scale_factor: 1 add_offset: 0 new_unit: "" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" AODVIS: category: "Aerosols" @@ -165,8 +163,6 @@ AODVIS: scale_factor: 1 add_offset: 0 new_unit: "" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" AODVISdn: category: "Aerosols" @@ -180,8 +176,6 @@ AODVISdn: obs_file: "MOD08_M3_192x288_AOD_2001-2020_climo.nc" obs_name: "MODIS" obs_var_name: "AOD_550_Dark_Target_Deep_Blue_Combined_Mean_Mean" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" BURDENBC: category: "Aerosols" @@ -189,8 +183,6 @@ BURDENBC: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" obs_file: "BURDENBC_MERRA2_monthly_climo_1degree_200001-202506.nc" obs_var_name: "BURDENBC" @@ -204,8 +196,6 @@ BURDENDUST: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_contour_range: [-1000, 1100, 100] diff_colormap: "RdBu_r" obs_file: "BURDENDUST_CAMS_monthly_climo_1degree_200301-202412.nc" @@ -220,8 +210,6 @@ BURDENPOM: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" @@ -233,8 +221,6 @@ BURDENSEASALT: new_unit: 'g m$^{-2}$' diff_contour_range: [-200, 200, 25] diff_colormap: "RdBu_r" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" obs_file: "BURDENSEASALT_CAMS_monthly_climo_1degree_200301-202412.nc" obs_var_name: "BURDENSEASALT" obs_name: "CAMS" @@ -247,8 +233,6 @@ BURDENSO4: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" obs_file: "BURDENSO4_CAMS_monthly_climo_1degree_200301-202412.nc" obs_name: "CAMS" @@ -262,16 +246,12 @@ BURDENSOA: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" DMS: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -279,8 +259,6 @@ SO2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -288,8 +266,6 @@ SOAG: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -304,8 +280,6 @@ BC: label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["bc_a1", "bc_a4"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" POM: colormap: "RdBu_r" @@ -318,8 +292,6 @@ POM: label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["pom_a1", "pom_a4"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SO4: colormap: "RdBu_r" @@ -333,8 +305,6 @@ SO4: category: "Aerosols" derivable_from: ["so4_a1", "so4_a2", "so4_a3"] derivable_from_cam_chem: ["so4_a1", "so4_a2", "so4_a3", "so4_a5"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SOA: colormap: "RdBu_r" @@ -348,8 +318,6 @@ SOA: category: "Aerosols" derivable_from: ["soa_a1", "soa_a2"] derivable_from_cam_chem: ["soa1_a1", "soa2_a1", "soa3_a1", "soa4_a1", "soa5_a1", "soa1_a2", "soa2_a2", "soa3_a2", "soa4_a2", "soa5_a2"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" DUST: colormap: "RdBu_r" @@ -364,8 +332,6 @@ DUST: label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["dst_a1", "dst_a2", "dst_a3"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SeaSalt: colormap: "RdBu_r" @@ -384,8 +350,6 @@ SeaSalt: ticks: [-10,8,6,4,2,0,-2,-4,-6,-8,-10] category: "Aerosols" derivable_from: ["ncl_a1", "ncl_a2", "ncl_a3"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" bc_a1: category: "Aerosols" @@ -393,184 +357,138 @@ bc_a1: diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" bc_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a5: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" pom_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" pom_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" soa_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" soa_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_TROP: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_AERO: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_SULFC: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Budget @@ -652,456 +570,342 @@ CO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO01: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO02: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO03: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO04: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO05: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO06: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO07: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO08: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO09: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO10: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO11: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO12: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO13: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" O3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" N2O: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HNO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NOX: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NOY: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" BIGALK: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H6: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H6: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H7O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H7OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H8: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CCL4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC11: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC113: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC114: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC115: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC12: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH2O: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3BR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CCL3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CHO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COCH3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COCHO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CHBR3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLONO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLOX: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLOY: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO2: @@ -1109,344 +913,258 @@ CO2: #contour_levels_range: [300,450,10.0] colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000.0 new_unit: "ppmv" E90: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" GLYALD: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" GLYOXAL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2402: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2SO4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC141B: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC142B: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC22: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCL_GAS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HNO3_GAS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HO2NO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HOBR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HYAC: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HYDRALD: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOP: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPNO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACRO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACROOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MVK: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" N2O5: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NH3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NH4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" O3S: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" OCLO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" OCS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ONITR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" PAN: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" POOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" RO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ROOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" SO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" SOAE: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" TERP: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" XO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" XOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -1460,16 +1178,12 @@ CLDICE: obs_file: "CLDICE_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDICE" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDLIQ: category: "Clouds" obs_file: "CLDLIQ_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDLIQ" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDTOT: colormap: "Oranges" @@ -1483,8 +1197,6 @@ CLDTOT: obs_name: "ERAI" obs_var_name: "CLDTOT" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDLOW: colormap: "Oranges" @@ -1498,8 +1210,6 @@ CLDLOW: obs_name: "ERAI" obs_var_name: "CLDLOW" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDHGH: colormap: "Oranges" @@ -1513,8 +1223,6 @@ CLDHGH: obs_name: "ERAI" obs_var_name: "CLDHGH" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDMED: colormap: "Oranges" @@ -1528,8 +1236,6 @@ CLDMED: obs_name: "ERAI" obs_var_name: "CLDMED" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLOUD: colormap: "Blues" @@ -1543,8 +1249,6 @@ CLOUD: colorbar: label : "Percent" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CONCLD: category: "Clouds" @@ -1566,8 +1270,6 @@ TGCLDLWP: obs_var_name: "TGCLDLWP" obs_scale_factor: 1000 obs_add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TGCLDIWP: colormap: "Blues" @@ -1586,8 +1288,6 @@ TGCLDIWP: obs_var_name: "TGCLDIWP" obs_scale_factor: 1000 obs_add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CCN3: category: "Clouds" @@ -1624,8 +1324,6 @@ PRECC: colorbar: label : "mm/d" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECL: colormap: "Greens" @@ -1639,8 +1337,6 @@ PRECL: colorbar: label : "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECSC: colormap: "Greens" @@ -1654,8 +1350,6 @@ PRECSC: colorbar: label : "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECSL: colormap: "Greens" @@ -1669,8 +1363,6 @@ PRECSL: colorbar: label : "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECT: colormap: "Blues" @@ -1688,8 +1380,6 @@ PRECT: obs_var_name: "PRECT" category: "Hydrologic cycle" derivable_from: ['PRECL','PRECC'] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" QFLX: category: "Hydrologic cycle" @@ -1719,8 +1409,6 @@ PSL: obs_file: "PSL_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "PSL" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PS: colormap: "Oranges" @@ -1737,8 +1425,6 @@ PS: obs_file: "PS_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "PS" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TREFHT: category: "Surface variables" @@ -1761,8 +1447,6 @@ TS: obs_name: "ERAI" obs_var_name: "TS" category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SST: colormap: "Blues" @@ -1780,18 +1464,12 @@ SST: obs_var_name: "TS" category: "Surface variables" mask: "ocean" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" U10: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Surface_Wind_Stress: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUX: vector_pair: "TAUY" @@ -1799,8 +1477,6 @@ TAUX: category: "Surface variables" scale_factor: -1 add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUY: vector_pair: "TAUX" @@ -1808,23 +1484,15 @@ TAUY: category: "Surface variables" scale_factor: -1 add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ICEFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OCNFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LANDFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: State @@ -1842,8 +1510,6 @@ TMQ: obs_name: "ERAI" obs_var_name: "PREH2O" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" RELHUM: colormap: "Blues" @@ -1860,8 +1526,6 @@ RELHUM: obs_name: "ERAI" obs_var_name: "RELHUM" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" U: colormap: "Blues" @@ -1880,8 +1544,6 @@ U: vector_pair: "V" vector_name: "Wind" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" V: colormap: "Blues" @@ -1900,37 +1562,27 @@ V: vector_pair: "U" vector_name: "Wind" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Q: category: "State" obs_file: "Q_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "Q" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" T: category: "State" obs_file: "T_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "T" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGA: category: "State" obs_file: "OMEGA_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "OMEGA" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGA500: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 864 add_offset: 0 new_unit: "hPa d$^{-1}$" @@ -1938,23 +1590,15 @@ OMEGA500: PINT: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PMID: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Z3: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Wind: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Radiation @@ -1962,13 +1606,9 @@ Wind: QRL: category: "Radiation" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" QRS: category: "Radiation" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: TOA energy flux @@ -1987,8 +1627,6 @@ RESTOM: label : "W m$^{-2}$" category: "TOA energy flux" derivable_from: ['FLNT','FSNT'] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SWCF: colormap: "Blues" @@ -2007,8 +1645,6 @@ SWCF: obs_scale_factor: 1 obs_add_offset: 0 category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LWCF: colormap: "Oranges" @@ -2025,8 +1661,6 @@ LWCF: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_lw_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSUTOA: colormap: "Blues" @@ -2040,8 +1674,6 @@ FSUTOA: colorbar: label : "Wm$^{-2}$" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNT: colormap: "Blues" @@ -2058,23 +1690,15 @@ FSNT: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "fsnt" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNTC: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNTOA: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLUT: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNT: colormap: "Oranges" @@ -2091,8 +1715,6 @@ FLNT: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_all_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNTC: colormap: "Oranges" @@ -2109,8 +1731,6 @@ FLNTC: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_clr_t_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Surface energy flux @@ -2118,13 +1738,9 @@ FLNTC: FSDS: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSDSC: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNS: colormap: "Blues" @@ -2141,8 +1757,6 @@ FSNS: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_all_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNSC: colormap: "Blues" @@ -2159,8 +1773,6 @@ FSNSC: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_clr_t_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLDS: colormap: "Oranges" @@ -2177,23 +1789,15 @@ FLDS: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_lw_down_all_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNS: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNSC: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SHFLX: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LHFLX: colormap: "Blues" @@ -2210,8 +1814,6 @@ LHFLX: obs_name: "ERAI" obs_var_name: "LHFLX" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: COSP @@ -2219,108 +1821,66 @@ LHFLX: CLDTOT_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLIMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FISCCP1_COSP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ICE_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" IWPMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LIQ_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LWPMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANCLDALB_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANPTOP_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTAU_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTB_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTBCLR_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PCTMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" REFFCLIMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" REFFCLWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SNOW_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUTMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TOT_CLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TOT_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDTOT_CAL: colormap: "cividis" @@ -2402,15 +1962,11 @@ H2O: colorbar: label: "mol mol$^{-1}$" plot_log_pressure: True - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGAT: colormap: "PuOr_r" diff_colormap: "coolwarm" plot_log_pressure: True - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #++++++++++++++ # Category: TEM From c82f2c4580ebfc7280b335ed27eeab46571dfafb Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 17:09:42 -0600 Subject: [PATCH 19/43] Update/clean plotting scripts --- lib/plotting_functions.py | 311 +++++++++++++++++--------------------- 1 file changed, 142 insertions(+), 169 deletions(-) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index 86911759e..00709243b 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -76,7 +76,7 @@ ################# -def make_polar_plot(wks, case_nickname, +def make_polar_plot(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, @@ -175,127 +175,64 @@ def make_polar_plot(wks, case_nickname, pct_cyclic, _ = add_cyclic_point(pct, coord=pct.lon) # -- deal with optional plotting arguments that might provide variable-dependent choices + kwargs["adfobj"] = adfobj + cp_info = plot_utils.prep_contour_plot(d1, d2, dif, pct, **kwargs) - # determine levels & color normalization: - minval = np.min([np.min(d1), np.min(d2)]) - maxval = np.max([np.max(d1), np.max(d2)]) - absmaxdif = np.max(np.abs(dif)) - absmaxpct = np.max(np.abs(pct)) + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + dnorm = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] - if 'colormap' in kwargs: - cmap1 = kwargs['colormap'] - else: - cmap1 = 'coolwarm' - - if 'contour_levels' in kwargs: - levels1 = kwargs['contour_levels'] - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) - elif 'contour_levels_range' in kwargs: - assert len(kwargs['contour_levels_range']) == 3, "contour_levels_range must have exactly three entries: min, max, step" - levels1 = np.arange(*kwargs['contour_levels_range']) - norm1 = mpl.colors.Normalize(vmin=min(levels1), vmax=max(levels1)) - else: - levels1 = np.linspace(minval, maxval, 12) - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) - - if ('colormap' not in kwargs) and ('contour_levels' not in kwargs): - norm1, cmap1 = plot_utils.get_difference_colors(levels1) # maybe these are better defaults if nothing else is known. - - if "diff_contour_levels" in kwargs: - levelsdiff = kwargs["diff_contour_levels"] # a list of explicit contour levels - elif "diff_contour_range" in kwargs: - assert len(kwargs['diff_contour_range']) == 3, "diff_contour_range must have exactly three entries: min, max, step" - levelsdiff = np.arange(*kwargs['diff_contour_range']) - else: - # set levels for difference plot (with a symmetric color bar): - levelsdiff = np.linspace(-1*absmaxdif.data, absmaxdif.data, 12) - #End if - - if "pct_diff_contour_levels" in kwargs: - levelspctdiff = kwargs["pct_diff_contour_levels"] # a list of explicit contour levels - elif "pct_diff_contour_range" in kwargs: - assert len(kwargs['pct_diff_contour_range']) == 3, "pct_diff_contour_range must have exactly three entries: min, max, step" - levelspctdiff = np.arange(*kwargs['pct_diff_contour_range']) - else: - levelspctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pctnorm = mpl.colors.BoundaryNorm(levelspctdiff,256) - - #NOTE: Sometimes the contour levels chosen in the defaults file - #can result in the "contourf" software stack generating a - #'TypologyException', which should manifest itself as a - #"PredicateError", but due to bugs in the stack itself - #will also sometimes raise an AttributeError. - - #To prevent this from happening, the polar max and min values - #are calculated, and if the default contour values are significantly - #larger then the min-max values, then the min-max values are used instead: - #------------------------------- - if max(levels1) > 10*maxval: - levels1 = np.linspace(minval, maxval, 12) - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) - elif minval < 0 and min(levels1) < 10*minval: - levels1 = np.linspace(minval, maxval, 12) - norm1 = mpl.colors.Normalize(vmin=minval, vmax=maxval) - #End if + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] - if max(np.abs(levelsdiff)) > 10*absmaxdif: - levelsdiff = np.linspace(-1*absmaxdif.data, absmaxdif.data, 12) - - - #End if - #------------------------------- - - # Difference options -- Check in kwargs for colormap and levels - if "diff_colormap" in kwargs: - cmapdiff = kwargs["diff_colormap"] - dnorm, _ = plot_utils.get_difference_colors(levelsdiff) # color map output ignored - else: - dnorm, cmapdiff = plot_utils.get_difference_colors(levelsdiff) - - # Pct Difference options -- Check in kwargs for colormap and levels - if "pct_diff_colormap" in kwargs: - cmappct = kwargs["pct_diff_colormap"] - else: - cmappct = "PuOr_r" - #End if + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim'] - # -- end options lons, lats = plot_utils.transform_coordinates_for_projection(proj, lon_cyclic, d1.lat) # Explicit coordinate transform fig = plt.figure(figsize=(10,10)) gs = mpl.gridspec.GridSpec(2, 4, wspace=0.9) - ax1 = plt.subplot(gs[0, :2], projection=proj) - ax2 = plt.subplot(gs[0, 2:], projection=proj) - ax3 = plt.subplot(gs[1, :2], projection=proj) - ax4 = plt.subplot(gs[1, 2:], projection=proj) + ax1 = plt.subplot(gs[0, :2], projection=proj, **cp_info['subplots_opt']) + ax2 = plt.subplot(gs[0, 2:], projection=proj, **cp_info['subplots_opt']) + ax3 = plt.subplot(gs[1, :2], projection=proj, **cp_info['subplots_opt']) + ax4 = plt.subplot(gs[1, 2:], projection=proj, **cp_info['subplots_opt']) - levs = np.unique(np.array(levels1)) - levs_diff = np.unique(np.array(levelsdiff)) - levs_pctdiff = np.unique(np.array(levelspctdiff)) + levs = np.unique(np.array(levels_sim)) + levs_diff = np.unique(np.array(levels_diff)) + levs_pctdiff = np.unique(np.array(levels_pctdiff)) - # BPM: removing `transform=ccrs.PlateCarree()` from contourf calls & transform_first=True if len(levs) < 2: - img1 = ax1.contourf(lons, lats, d1_cyclic, colors="w", norm=norm1) + img1 = ax1.contourf(lons, lats, d1_cyclic, colors="w", norm=norm_sim) ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) - img2 = ax2.contourf(lons, lats, d2_cyclic, colors="w", norm=norm1) + img2 = ax2.contourf(lons, lats, d2_cyclic, colors="w", norm=norm_sim) ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) else: - img1 = ax1.contourf(lons, lats, d1_cyclic, cmap=cmap1, norm=norm1, levels=levels1) - img2 = ax2.contourf(lons, lats, d2_cyclic, cmap=cmap1, norm=norm1, levels=levels1) + img1 = ax1.contourf(lons, lats, d1_cyclic, + cmap=cmap_sim, norm=norm_sim, levels=levels_sim, extend=cp_info['extend_sim'] + ) + img2 = ax2.contourf(lons, lats, d2_cyclic, + cmap=cmap_sim, norm=norm_sim, levels=levels_sim, extend=cp_info['extend_sim'] + ) if len(levs_pctdiff) < 2: - img3 = ax3.contourf(lons, lats, pct_cyclic, colors="w", norm=pctnorm) + img3 = ax3.contourf(lons, lats, pct_cyclic, colors="w", norm=norm_pctdiff) ax3.text(0.4, 0.4, empty_message, transform=ax3.transAxes, bbox=props) else: - img3 = ax3.contourf(lons, lats, pct_cyclic, cmap=cmappct, norm=pctnorm, levels=levelspctdiff) + img3 = ax3.contourf(lons, lats, pct_cyclic, cmap=cmap_pctdiff, norm=norm_pctdiff, + levels=levels_pctdiff, extend=extend_sim) if len(levs_diff) < 2: img4 = ax4.contourf(lons, lats, dif_cyclic, colors="w", norm=dnorm) ax4.text(0.4, 0.4, empty_message, transform=ax4.transAxes, bbox=props) else: - img4 = ax4.contourf(lons, lats, dif_cyclic, cmap=cmapdiff, norm=dnorm, levels=levelsdiff) + img4 = ax4.contourf(lons, lats, dif_cyclic, cmap=cmap_diff, norm=dnorm, + levels=levels_diff, extend=extend_diff) #Set Main title for subplots: st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) @@ -386,7 +323,7 @@ def make_polar_plot(wks, case_nickname, ####### -def plot_map_vect_and_save(wks, case_nickname, base_nickname, +def plot_map_vect_and_save(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, plev, umdlfld_nowrap, vmdlfld_nowrap, uobsfld_nowrap, vobsfld_nowrap, @@ -443,6 +380,9 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, lat = umdlfld_nowrap['lat'] wgt = np.cos(np.radians(lat)) + kwargs["adfobj"] = adfobj + cp_info = plot_utils.prep_contour_plot(umdlfld_nowrap, uobsfld_nowrap, udiffld_nowrap, None, **kwargs) + # add cyclic longitude: umdlfld, lon = add_cyclic_point(umdlfld_nowrap, coord=umdlfld_nowrap['lon']) vmdlfld, _ = add_cyclic_point(vmdlfld_nowrap, coord=vmdlfld_nowrap['lon']) @@ -475,31 +415,6 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, # too many vectors to see well, so prune by striding through data: skip=(slice(None,None,5),slice(None,None,8)) - title_string = "Missing title!" - title_string_base = title_string - if "var_name" in kwargs: - var_name = kwargs["var_name"] - else: - var_name = "missing VAR name" - #End if - - if "case_name" in kwargs: - case_name = kwargs["case_name"] - if plev: - title_string = f"{case_name} {var_name} [{plev} hPa]" - else: - title_string = f"{case_name} {var_name}" - #End if - #End if - if "baseline" in kwargs: - data_name = kwargs["baseline"] - if plev: - title_string_base = f"{data_name} {var_name} [{plev} hPa]" - else: - title_string_base = f"{data_name} {var_name}" - #End if - #End if - # Calculate vector magnitudes. # Please note that the difference field needs # to be calculated from the model and obs fields @@ -518,19 +433,25 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, # Color normalization for difference if (min_diff_val < 0) and (0 < max_diff_val): - normdiff = mpl.colors.TwoSlopeNorm(vmin=min_diff_val, vmax=max_diff_val, vcenter=0.0) + norm_diff = mpl.colors.TwoSlopeNorm(vmin=min_diff_val, vmax=max_diff_val, vcenter=0.0) else: - normdiff = mpl.colors.Normalize(vmin=min_diff_val, vmax=max_diff_val) + norm_diff = mpl.colors.Normalize(vmin=min_diff_val, vmax=max_diff_val) #End if # Generate vector plot: # - contourf to show magnitude w/ colorbar # - vectors (colored or not) to show flow --> subjective (?) choice for how to thin out vectors to be legible - img1 = ax1.contourf(lons, lats, mdl_mag, cmap='Greys', transform=ccrs.PlateCarree(), transform_first=True,) - ax1.quiver(lons[skip], lats[skip], umdlfld[skip], vmdlfld[skip], mdl_mag.values[skip], transform=ccrs.PlateCarree(), cmap='Reds') - - img2 = ax2.contourf(lons, lats, obs_mag, cmap='Greys', transform=ccrs.PlateCarree(), transform_first=True) - ax2.quiver(lons[skip], lats[skip], uobsfld[skip], vobsfld[skip], obs_mag.values[skip], transform=ccrs.PlateCarree(), cmap='Reds') + img1 = ax1.contourf(lons, lats, mdl_mag, cmap='Greys', transform=ccrs.PlateCarree(), + transform_first=True, extend='both' + ) + ax1.quiver(lons[skip], lats[skip], umdlfld[skip], vmdlfld[skip], mdl_mag.values[skip], + transform=ccrs.PlateCarree(), cmap='Reds') + + img2 = ax2.contourf(lons, lats, obs_mag, cmap='Greys', transform=ccrs.PlateCarree(), + transform_first=True, extend='both' + ) + ax2.quiver(lons[skip], lats[skip], uobsfld[skip], vobsfld[skip], obs_mag.values[skip], + transform=ccrs.PlateCarree(), cmap='Reds') # We should think about how to do plot customization and defaults. # Here I'll just pop off a few custom ones, and then pass the rest into mpl. @@ -602,7 +523,9 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, fig.colorbar(img2, cax=cb_c2_ax) # Plot vector differences: - img3 = ax3.contourf(lons, lats, diff_mag, transform=ccrs.PlateCarree(), transform_first=True, norm=normdiff, cmap='PuOr', alpha=0.5) + img3 = ax3.contourf(lons, lats, diff_mag, transform=ccrs.PlateCarree(), transform_first=True, norm=norm_diff, + cmap='PuOr', alpha=0.5, extend='both' + ) ax3.quiver(lons[skip], lats[skip], udiffld[skip], vdiffld[skip], transform=ccrs.PlateCarree()) # Add color bar to difference plot: @@ -625,7 +548,7 @@ def plot_map_vect_and_save(wks, case_nickname, base_nickname, ####### -def plot_map_and_save(wks, case_nickname, base_nickname, +def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, mdlfld, obsfld, diffld, pctld, obs=False, **kwargs): """This plots mdlfld, obsfld, diffld in a 3-row panel plot of maps. @@ -680,6 +603,7 @@ def plot_map_and_save(wks, case_nickname, base_nickname, + This is experimental, and if you find yourself doing much with this, you probably should write a new plotting script that does not rely on this module. When these are not provided, colormap is set to 'coolwarm' and limits/levels are set by data range. """ + kwargs["adfobj"] = adfobj #nice formatting for tick labels from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter @@ -695,8 +619,6 @@ def plot_map_and_save(wks, case_nickname, base_nickname, wrap_fields = (mwrap, owrap, pwrap, dwrap) # mesh for plots: lons, lats = np.meshgrid(lon, lat) - # Note: using wrapped data makes spurious lines across plot (maybe coordinate dependent) - lon2, lat2 = np.meshgrid(mdlfld['lon'], mdlfld['lat']) # get statistics (from non-wrapped) fields = (mdlfld, obsfld, diffld, pctld) @@ -750,24 +672,29 @@ def plot_map_and_save(wks, case_nickname, base_nickname, for i, a in enumerate(wrap_fields): if i == len(wrap_fields)-1: - levels = cp_info['levelsdiff'] - cmap = cp_info['cmapdiff'] - norm = cp_info['normdiff'] + levels = cp_info['levels_diff'] + cmap = cp_info['cmap_diff'] + norm = cp_info['norm_diff'] + extend = cp_info["extend_diff"] elif i == len(wrap_fields)-2: - levels = cp_info['levelspctdiff'] - cmap = cp_info['cmappct'] - norm = cp_info['pctnorm'] + levels = cp_info['levels_pctdiff'] + cmap = cp_info['cmap_pctdiff'] + norm = cp_info['norm_pctdiff'] + extend = 'both' else: - levels = cp_info['levels1'] - cmap = cp_info['cmap1'] - norm = cp_info['norm1'] + levels = cp_info['levels_sim'] + cmap = cp_info['cmap_sim'] + norm = cp_info['norm_sim'] + extend = cp_info["extend_sim"] levs = np.unique(np.array(levels)) if len(levs) < 2: img.append(ax[i].contourf(lons,lats,a,colors="w",transform=ccrs.PlateCarree(),transform_first=True)) ax[i].text(0.4, 0.4, empty_message, transform=ax[i].transAxes, bbox=props) else: - img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, transform=ccrs.PlateCarree(), transform_first=True, **cp_info['contourf_opt'])) + img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, + transform=ccrs.PlateCarree(), transform_first=True, extend=extend, + **cp_info['contourf_opt'])) #End if ax[i].set_title("AVG: {0:.3f}".format(area_avg[i]), loc='right', fontsize=11) @@ -931,9 +858,9 @@ def meridional_plot(lon, data, ax=None, color=None, **kwargs): ####### -def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, +def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, - adata, bdata, has_lev, log_p=False, obs=False, **kwargs): + adata, bdata, has_lev, log_p, obs=False, **kwargs): """This is the default zonal mean plot @@ -970,6 +897,7 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, shrink: 0.4 ``` """ + kwargs["adfobj"] = adfobj # style the plot: # We should think about how to do plot customization and defaults. @@ -1006,38 +934,61 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, # generate dictionary of contour plot settings: cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + norm_diff = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] + + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] + + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim'] # Generate zonal plot: fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) - levs = np.unique(np.array(cp_info['levels1'])) + levs = np.unique(np.array(levels_sim)) + alat = adata['lat'] + blat = bdata['lat'] - levs_diff = np.unique(np.array(cp_info['levelsdiff'])) - levs_pct_diff = np.unique(np.array(cp_info['levelspctdiff'])) + levs_diff = np.unique(np.array(levels_diff)) + levs_pct_diff = np.unique(np.array(levels_pctdiff)) if len(levs) < 2: - img0, ax[0] = zonal_plot(adata['lat'], azm, ax=ax[0]) + img0, ax[0] = zonal_plot(alat, azm, ax=ax[0]) ax[0].text(0.4, 0.4, empty_message, transform=ax[0].transAxes, bbox=props) - img1, ax[1] = zonal_plot(bdata['lat'], bzm, ax=ax[1]) + img1, ax[1] = zonal_plot(blat, bzm, ax=ax[1]) ax[1].text(0.4, 0.4, empty_message, transform=ax[1].transAxes, bbox=props) else: - img0, ax[0] = zonal_plot(adata['lat'], azm, ax=ax[0], norm=cp_info['norm1'],cmap=cp_info['cmap1'],levels=cp_info['levels1'],**cp_info['contourf_opt']) - img1, ax[1] = zonal_plot(bdata['lat'], bzm, ax=ax[1], norm=cp_info['norm1'],cmap=cp_info['cmap1'],levels=cp_info['levels1'],**cp_info['contourf_opt']) + img0, ax[0] = zonal_plot(alat, azm, ax=ax[0], norm=norm_sim,cmap=cmap_sim, + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) + img1, ax[1] = zonal_plot(blat, bzm, ax=ax[1], norm=norm_sim,cmap=cmap_sim, + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) fig.colorbar(img0, ax=ax[0], location='right',**cp_info['colorbar_opt']) fig.colorbar(img1, ax=ax[1], location='right',**cp_info['colorbar_opt']) #End if if len(levs_diff) < 2: - img2, ax[2] = zonal_plot(adata['lat'], diff, ax=ax[2]) + img2, ax[2] = zonal_plot(alat, diff, ax=ax[2]) ax[2].text(0.4, 0.4, empty_message, transform=ax[2].transAxes, bbox=props) else: - img2, ax[2] = zonal_plot(adata['lat'], diff, ax=ax[2], norm=cp_info['normdiff'],cmap=cp_info['cmapdiff'],levels=cp_info['levelsdiff'],**cp_info['contourf_opt']) + img2, ax[2] = zonal_plot(alat, diff, ax=ax[2], norm=norm_diff,cmap=cmap_diff, + levels=levels_diff, extend=extend_diff, + **cp_info['diff_colorbar_opt']) fig.colorbar(img2, ax=ax[2], location='right',**cp_info['diff_colorbar_opt']) if len(levs_pct_diff) < 2: - img3, ax[3] = zonal_plot(adata['lat'], pct, ax=ax[3]) + img3, ax[3] = zonal_plot(alat, pct, ax=ax[3]) ax[3].text(0.4, 0.4, empty_message, transform=ax[3].transAxes, bbox=props) else: - img3, ax[3] = zonal_plot(adata['lat'], pct, ax=ax[3], norm=cp_info['pctnorm'],cmap=cp_info['cmappct'],levels=cp_info['levelspctdiff'],**cp_info['contourf_opt']) + img3, ax[3] = zonal_plot(alat, pct, ax=ax[3], norm=norm_pctdiff,cmap=cmap_pctdiff, + levels=levels_pctdiff, extend="both", + **cp_info['pct_colorbar_opt']) fig.colorbar(img3, ax=ax[3], location='right',**cp_info['pct_colorbar_opt']) ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) @@ -1110,7 +1061,7 @@ def plot_zonal_mean_and_save(wks, case_nickname, base_nickname, ####### -def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, +def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, adata, bdata, has_lev, log_p=False, latbounds=None, obs=False, **kwargs): @@ -1179,6 +1130,8 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, shrink: 0.4 ``` """ + kwargs["adfobj"] = adfobj + # apply averaging: import numbers # built-in; just checking on the latbounds input if latbounds is None: @@ -1243,12 +1196,25 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, if has_lev: # generate dictionary of contour plot settings: cp_info = plot_utils.prep_contour_plot(adata, bdata, diff, pct, **kwargs) + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + norm_diff = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] + + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] + + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim'] # generate plot objects: fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) - levs = np.unique(np.array(cp_info['levels1'])) - levs_diff = np.unique(np.array(cp_info['levelsdiff'])) - levs_pctdiff = np.unique(np.array(cp_info['levelspctdiff'])) + levs = np.unique(np.array(levels_sim)) + levs_diff = np.unique(np.array(levels_diff)) + levs_pctdiff = np.unique(np.array(levels_pctdiff)) if len(levs) < 2: img0, ax[0] = pltfunc(adata[xdim], adata, ax=ax[0]) @@ -1256,25 +1222,32 @@ def plot_meridional_mean_and_save(wks, case_nickname, base_nickname, img1, ax[1] = pltfunc(bdata[xdim], bdata, ax=ax[1]) ax[1].text(0.4, 0.4, empty_message, transform=ax[1].transAxes, bbox=props) else: - img0, ax[0] = pltfunc(adata[xdim], adata, ax=ax[0], norm=cp_info['norm1'],cmap=cp_info['cmap1'],levels=cp_info['levels1'],**cp_info['contourf_opt']) - img1, ax[1] = pltfunc(bdata[xdim], bdata, ax=ax[1], norm=cp_info['norm1'],cmap=cp_info['cmap1'],levels=cp_info['levels1'],**cp_info['contourf_opt']) - cb0 = fig.colorbar(img0, ax=ax[0], location='right',**cp_info['colorbar_opt']) - cb1 = fig.colorbar(img1, ax=ax[1], location='right',**cp_info['colorbar_opt']) + img0, ax[0] = pltfunc(adata[xdim], adata, ax=ax[0], norm=norm_sim,cmap=cmap_sim, + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) + img1, ax[1] = pltfunc(bdata[xdim], bdata, ax=ax[1], norm=norm_sim,cmap=cmap_sim, + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) + cb0 = fig.colorbar(img0, ax=ax[0], location='right', **cp_info['colorbar_opt']) + cb1 = fig.colorbar(img1, ax=ax[1], location='right', **cp_info['colorbar_opt']) #End if if len(levs_diff) < 2: img2, ax[2] = pltfunc(adata[xdim], diff, ax=ax[2]) ax[2].text(0.4, 0.4, empty_message, transform=ax[2].transAxes, bbox=props) else: - img2, ax[2] = pltfunc(adata[xdim], diff, ax=ax[2], norm=cp_info['normdiff'],cmap=cp_info['cmapdiff'],levels=cp_info['levelsdiff'],**cp_info['contourf_opt']) - cb2 = fig.colorbar(img2, ax=ax[2], location='right',**cp_info['colorbar_opt']) + img2, ax[2] = pltfunc(adata[xdim], diff, ax=ax[2], norm=norm_diff,cmap=cmap_diff, + levels=levels_diff, extend=extend_diff, + **cp_info['diff_colorbar_opt']) + cb2 = fig.colorbar(img2, ax=ax[2], location='right', **cp_info['diff_colorbar_opt']) if len(levs_pctdiff) < 2: img3, ax[3] = pltfunc(adata[xdim], pct, ax=ax[3]) ax[3].text(0.4, 0.4, empty_message, transform=ax[3].transAxes, bbox=props) else: - img3, ax[3] = pltfunc(adata[xdim], pct, ax=ax[3], norm=cp_info['pctnorm'],cmap=cp_info['cmappct'],levels=cp_info['levelspctdiff'],**cp_info['contourf_opt']) - cb3 = fig.colorbar(img3, ax=ax[3], location='right',**cp_info['colorbar_opt']) + img3, ax[3] = pltfunc(adata[xdim], pct, ax=ax[3], norm=norm_pctdiff,cmap=cmap_pctdiff, + levels=levels_pctdiff, **cp_info['pct_colorbar_opt']) + cb3 = fig.colorbar(img3, ax=ax[3], location='right',**cp_info['pct_colorbar_opt']) #Set plot titles ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) From 25e87bf720588ae12e555efb60b166ab03962efd Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 17:49:19 -0600 Subject: [PATCH 20/43] Set default colormap for temp --- image_comp_2.html | 374 +++++++++++++++++++++ lib/adf_variable_defaults.yaml | 1 + scripts/plotting/global_latlon_vect_map.py | 4 +- 3 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 image_comp_2.html diff --git a/image_comp_2.html b/image_comp_2.html new file mode 100644 index 000000000..08e89f044 --- /dev/null +++ b/image_comp_2.html @@ -0,0 +1,374 @@ + + + + Image Comparison Dashboard + + + + + + +
+

Image Comparison Dashboard

+
+ +
+ + +

Directories

+
+ + +
+ + +

Images to Compare

+
+ + +

+ + + +
+ +
+ +
+ + + + + + + + diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 72ab0ee9d..e687c848c 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -1570,6 +1570,7 @@ Q: obs_var_name: "Q" T: + colormap: "RdBu_r" category: "State" obs_file: "T_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" diff --git a/scripts/plotting/global_latlon_vect_map.py b/scripts/plotting/global_latlon_vect_map.py index 375889d1f..f1fd21ebe 100644 --- a/scripts/plotting/global_latlon_vect_map.py +++ b/scripts/plotting/global_latlon_vect_map.py @@ -502,7 +502,7 @@ def global_latlon_vect_map(adfobj): # colormap, contour_levels, diff_colormap, diff_contour_levels, tiString, tiFontSize, mpl # *Any other entries will be ignored. # NOTE: If we were doing all the plotting here, we could use whatever we want from the provided YAML file. - pf.plot_map_vect_and_save(plot_name, case_nickname, base_nickname, + pf.plot_map_vect_and_save(adfobj, plot_name, case_nickname, base_nickname, [syear_cases[case_idx],eyear_cases[case_idx]], [syear_baseline,eyear_baseline], None, umseasons[s], vmseasons[s], @@ -510,7 +510,7 @@ def global_latlon_vect_map(adfobj): udseasons[s], vdseasons[s], obs, **vres) #Add plot to website (if enabled): - adfobj.add_website_data(adfobj, plot_name, var_name, case_name, category=web_category, + adfobj.add_website_data(plot_name, var_name, case_name, category=web_category, season=s, plot_type="LatLon_Vector") #End for From a19181239a3d5987687684461193abd028c79585 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 22:32:56 -0600 Subject: [PATCH 21/43] remove unused code --- lib/adf_variable_defaults.yaml | 98 ++-------------------------------- 1 file changed, 3 insertions(+), 95 deletions(-) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index e687c848c..7615f7996 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -275,9 +275,6 @@ BC: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["bc_a1", "bc_a4"] @@ -287,9 +284,6 @@ POM: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["pom_a1", "pom_a4"] @@ -299,9 +293,6 @@ SO4: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["so4_a1", "so4_a2", "so4_a3"] derivable_from_cam_chem: ["so4_a1", "so4_a2", "so4_a3", "so4_a5"] @@ -312,9 +303,6 @@ SOA: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["soa_a1", "soa_a2"] derivable_from_cam_chem: ["soa1_a1", "soa2_a1", "soa3_a1", "soa4_a1", "soa5_a1", "soa1_a2", "soa2_a2", "soa3_a2", "soa4_a2", "soa5_a2"] @@ -327,9 +315,6 @@ DUST: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["dst_a1", "dst_a2", "dst_a3"] @@ -343,10 +328,8 @@ SeaSalt: new_unit: '$\mu$g/m3' mpl: colorbar: - label : '$\mu$g/m3' ticks: [0.05,0.2,0.4,1,2,6,24,90] diff_colorbar: - label : '$\mu$g/m3' ticks: [-10,8,6,4,2,0,-2,-4,-6,-8,-10] category: "Aerosols" derivable_from: ["ncl_a1", "ncl_a2", "ncl_a3"] @@ -1245,9 +1228,6 @@ CLOUD: scale_factor: 100 add_offset: 0 new_unit: "Percent" - mpl: - colorbar: - label : "Percent" category: "Clouds" CONCLD: @@ -1261,9 +1241,6 @@ TGCLDLWP: scale_factor: 1000 add_offset: 0 new_unit: "g m$^{-2}$" - mpl: - colorbar: - label : "g m$^{-2}$" category: "Clouds" obs_file: "TGCLDLWP_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -1279,9 +1256,6 @@ TGCLDIWP: scale_factor: 1000 add_offset: 0 new_unit: "g m$^{-2}$" - mpl: - colorbar: - label : "g m$^{-2}$" category: "Clouds" obs_file: "TGCLDIWP_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -1320,9 +1294,6 @@ PRECC: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm/d" category: "Hydrologic cycle" PRECL: @@ -1333,9 +1304,6 @@ PRECL: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" PRECSC: @@ -1346,9 +1314,6 @@ PRECSC: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" PRECSL: @@ -1359,9 +1324,6 @@ PRECSL: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" PRECT: @@ -1372,9 +1334,6 @@ PRECT: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "PRECT" @@ -1402,9 +1361,6 @@ PSL: scale_factor: 0.01 add_offset: 0 new_unit: "hPa" - mpl: - colorbar: - label : "hPa" category: "Surface variables" obs_file: "PSL_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -1418,9 +1374,6 @@ PS: scale_factor: 0.01 add_offset: 0 new_unit: "hPa" - mpl: - colorbar: - label : "hPa" category: "Surface variables" obs_file: "PS_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -1440,9 +1393,6 @@ TS: scale_factor: 1 add_offset: 0 new_unit: "K" - mpl: - colorbar: - label : "K" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "TS" @@ -1456,9 +1406,6 @@ SST: scale_factor: 1 add_offset: 0 new_unit: "K" - mpl: - colorbar: - label : "K" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "TS" @@ -1519,9 +1466,6 @@ RELHUM: scale_factor: 1 add_offset: 0 new_unit: "Fraction" - mpl: - colorbar: - label : "Fraction" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "RELHUM" @@ -1535,9 +1479,6 @@ U: scale_factor: 1 add_offset: 0 new_unit: "ms$^{-1}$" - mpl: - colorbar: - label : "ms$^{-1}$" obs_file: "U_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "U" @@ -1553,9 +1494,6 @@ V: scale_factor: 1 add_offset: 0 new_unit: "ms$^{-1}$" - mpl: - colorbar: - label : "ms$^{-1}$" obs_file: "V_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "V" @@ -1564,6 +1502,9 @@ V: category: "State" Q: + scale_factor: 1000 + add_offset: 0 + new_unit: "g/kg" category: "State" obs_file: "Q_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -1623,9 +1564,6 @@ RESTOM: scale_factor: 1 add_offset: 0 new_unit: "W m$^{-2}$" - mpl: - colorbar: - label : "W m$^{-2}$" category: "TOA energy flux" derivable_from: ['FLNT','FSNT'] @@ -1637,9 +1575,6 @@ SWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_sw_mon" @@ -1655,9 +1590,6 @@ LWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_lw_mon" @@ -1671,9 +1603,6 @@ FSUTOA: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" category: "TOA energy flux" FSNT: @@ -1684,9 +1613,6 @@ FSNT: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "fsnt" @@ -1709,9 +1635,6 @@ FLNT: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_all_mon" @@ -1725,9 +1648,6 @@ FLNTC: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_clr_t_mon" @@ -1751,9 +1671,6 @@ FSNS: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_all_mon" @@ -1767,9 +1684,6 @@ FSNSC: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_clr_t_mon" @@ -1783,9 +1697,6 @@ FLDS: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_lw_down_all_mon" @@ -1808,9 +1719,6 @@ LHFLX: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "LHFLX" From d641bfbb0ae4b7f414a2505e707187e719f1a937 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 22:33:22 -0600 Subject: [PATCH 22/43] Fix lost units after xarray calcs --- lib/adf_dataset.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/adf_dataset.py b/lib/adf_dataset.py index 2cb326cb0..1398a113a 100644 --- a/lib/adf_dataset.py +++ b/lib/adf_dataset.py @@ -323,14 +323,15 @@ def load_da(self, fils, variablename, **kwargs): warnings.warn(f"\t WARNING: Load failed for {variablename}") return None da = (ds[variablename]).squeeze() + raw_units = da.attrs.get('units', '--') scale_factor = kwargs.get('scale_factor', 1) add_offset = kwargs.get('add_offset', 0) da = da * scale_factor + add_offset if variablename in self.adf.variable_defaults: vres = self.adf.variable_defaults[variablename] - da.attrs['units'] = vres.get("new_unit", da.attrs.get('units', 'none')) + da.attrs['units'] = vres.get("new_unit", raw_units) else: - da.attrs['units'] = 'none' + da.attrs['units'] = raw_units return da # Get variable conversion defaults, if applicable From a27498ca96ac91932aaaf9df00107eb251739de8 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Mon, 6 Apr 2026 22:35:28 -0600 Subject: [PATCH 23/43] Add unit handling to contour dict --- lib/plotting_utils.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/plotting_utils.py b/lib/plotting_utils.py index 96bf42f4f..409610346 100644 --- a/lib/plotting_utils.py +++ b/lib/plotting_utils.py @@ -666,6 +666,7 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): - 'plot_log_p' : true/false whether to plot log(pressure) axis - 'extend_sim': colorbar extend for a and b panels - 'extend_diff': colorbar extend for difference panel + - 'units': ADF cleaned units string for labeling colorbars """ adfobj = kwargs["adfobj"] @@ -754,8 +755,8 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): # Difference options -- Check in kwargs for colormap and levels # determine levels & color normalization: - minval = np.min(diffdata) - maxval = np.max(diffdata) + minval = np.nanmin(diffdata) + maxval = np.nanmax(diffdata) # COLOR MAP #---------- @@ -834,6 +835,18 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): levels_pctdiff = [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] norm_pctdiff = mpl.colors.BoundaryNorm(levels_pctdiff,256) + vmin, vmax = levels_pctdiff[0], levels_pctdiff[-1] + extend_pctdiff = 'neither' + if pctdata is not None: + minval = np.nanmin(pctdata) + maxval = np.nanmax(pctdata) + if minval < vmin and maxval > vmax: + extend_pctdiff = 'both' + elif minval < vmin: + extend_pctdiff = 'min' + elif maxval > vmax: + extend_pctdiff = 'max' + if "plot_log_pressure" in kwargs: plot_log_p = kwargs["plot_log_pressure"] else: @@ -854,6 +867,11 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): pct_colorbar_opt.update(kwargs['mpl'].get('pct_diff_colorbar',{})) #End if + if "units" in kwargs: + units = kwargs["units"] + else: + units = adata.units + return {'subplots_opt': subplots_opt, 'contourf_opt': contourf_opt, 'colorbar_opt': colorbar_opt, @@ -870,7 +888,9 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): 'levels_sim': levels_sim, 'plot_log_p': plot_log_p, 'extend_sim': extend, - 'extend_diff': extend_diff + 'extend_diff': extend_diff, + 'extend_pctdiff': extend_pctdiff, + 'units': units } From 487b966f328396b44fd65e7bc953070de643bd5a Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Wed, 8 Apr 2026 11:03:32 -0600 Subject: [PATCH 24/43] Add units to Wind Stress vars --- lib/adf_variable_defaults.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 7615f7996..3e22890a2 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -1416,9 +1416,11 @@ U10: category: "Surface variables" Surface_Wind_Stress: + new_unit: "N m$^{-2}$" category: "Surface variables" TAUX: + new_unit: "N m$^{-2}$" vector_pair: "TAUY" vector_name: "Surface_Wind_Stress" category: "Surface variables" @@ -1426,6 +1428,7 @@ TAUX: add_offset: 0 TAUY: + new_unit: "N m$^{-2}$" vector_pair: "TAUX" vector_name: "Surface_Wind_Stress" category: "Surface variables" From 1ce7ddbfb95064c9ef363d9a4e5275f229e9729e Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Wed, 8 Apr 2026 11:09:17 -0600 Subject: [PATCH 25/43] Clean up 1deg config yaml --- lib/adf_variable_defaults_era5-1deg.yaml | 101 +---------------------- 1 file changed, 3 insertions(+), 98 deletions(-) diff --git a/lib/adf_variable_defaults_era5-1deg.yaml b/lib/adf_variable_defaults_era5-1deg.yaml index b138e31e7..f4adabb8e 100644 --- a/lib/adf_variable_defaults_era5-1deg.yaml +++ b/lib/adf_variable_defaults_era5-1deg.yaml @@ -299,9 +299,6 @@ BC: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["bc_a1", "bc_a4"] pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] @@ -313,9 +310,6 @@ POM: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["pom_a1", "pom_a4"] pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] @@ -327,9 +321,6 @@ SO4: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["so4_a1", "so4_a2", "so4_a3"] derivable_from_cam_chem: ["so4_a1", "so4_a2", "so4_a3", "so4_a5"] @@ -342,9 +333,6 @@ SOA: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["soa_a1", "soa_a2"] derivable_from_cam_chem: ["soa1_a1", "soa2_a1", "soa3_a1", "soa4_a1", "soa5_a1", "soa1_a2", "soa2_a2", "soa3_a2", "soa4_a2", "soa5_a2"] @@ -359,9 +347,6 @@ DUST: scale_factor: 1000000000 add_offset: 0 new_unit: '$\mu$g/m3' - mpl: - colorbar: - label : '$\mu$g/m3' category: "Aerosols" derivable_from: ["dst_a1", "dst_a2", "dst_a3"] pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] @@ -377,10 +362,8 @@ SeaSalt: new_unit: '$\mu$g/m3' mpl: colorbar: - label : '$\mu$g/m3' ticks: [0.05,0.2,0.4,1,2,6,24,90] diff_colorbar: - label : '$\mu$g/m3' ticks: [-10,8,6,4,2,0,-2,-4,-6,-8,-10] category: "Aerosols" derivable_from: ["ncl_a1", "ncl_a2", "ncl_a3"] @@ -1539,9 +1522,6 @@ CLOUD: scale_factor: 100 add_offset: 0 new_unit: "Percent" - mpl: - colorbar: - label : "Percent" category: "Clouds" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -1557,9 +1537,6 @@ TGCLDLWP: scale_factor: 1000 add_offset: 0 new_unit: "g m$^{-2}$" - mpl: - colorbar: - label : "g m$^{-2}$" category: "Clouds" obs_file: "TGCLDLWP_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" @@ -1577,9 +1554,6 @@ TGCLDIWP: scale_factor: 1000 add_offset: 0 new_unit: "g m$^{-2}$" - mpl: - colorbar: - label : "g m$^{-2}$" category: "Clouds" obs_file: "TGCLDIWP_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" @@ -1620,9 +1594,6 @@ PRECC: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm/d" category: "Hydrologic cycle" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -1635,9 +1606,6 @@ PRECL: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -1650,9 +1618,6 @@ PRECSC: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -1665,9 +1630,6 @@ PRECSL: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" category: "Hydrologic cycle" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -1680,9 +1642,6 @@ PRECT: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "PRECT" @@ -1712,9 +1671,6 @@ PSL: scale_factor: 0.01 add_offset: 0 new_unit: "hPa" - mpl: - colorbar: - label : "hPa" category: "Surface variables" obs_file: "PSL_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" @@ -1730,9 +1686,6 @@ PS: scale_factor: 0.01 add_offset: 0 new_unit: "hPa" - mpl: - colorbar: - label : "hPa" category: "Surface variables" obs_file: "PS_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" @@ -1754,9 +1707,6 @@ TS: scale_factor: 1 add_offset: 0 new_unit: "K" - mpl: - colorbar: - label : "K" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "TS" @@ -1772,9 +1722,6 @@ SST: scale_factor: 1 add_offset: 0 new_unit: "K" - mpl: - colorbar: - label : "K" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "TS" @@ -1789,11 +1736,13 @@ U10: pct_diff_colormap: "PuOr_r" Surface_Wind_Stress: + new_unit: "N m$^{-2}$" category: "Surface variables" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" TAUX: + new_unit: "N m$^{-2}$" vector_pair: "TAUY" vector_name: "Surface_Wind_Stress" category: "Surface variables" @@ -1806,6 +1755,7 @@ TAUX: obs_var_name: "TAUX" TAUY: + new_unit: "N m$^{-2}$" vector_pair: "TAUX" vector_name: "Surface_Wind_Stress" category: "Surface variables" @@ -1859,9 +1809,6 @@ RELHUM: scale_factor: 1 add_offset: 0 new_unit: "Fraction" - mpl: - colorbar: - label : "Fraction" obs_file: "RELHUM_ERA5_monthly_climo_1degree_197901-202212.nc" obs_name: "ERA5" obs_var_name: "RELHUM" @@ -1877,9 +1824,6 @@ U: scale_factor: 1 add_offset: 0 new_unit: "ms$^{-1}$" - mpl: - colorbar: - label : "ms$^{-1}$" obs_file: "U_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "U" @@ -1897,9 +1841,6 @@ V: scale_factor: 1 add_offset: 0 new_unit: "ms$^{-1}$" - mpl: - colorbar: - label : "ms$^{-1}$" obs_file: "V_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "V" @@ -1988,9 +1929,6 @@ RESTOM: scale_factor: 1 add_offset: 0 new_unit: "W m$^{-2}$" - mpl: - colorbar: - label : "W m$^{-2}$" category: "TOA energy flux" derivable_from: ['FLNT','FSNT'] pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] @@ -2004,9 +1942,6 @@ SWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_sw_mon" @@ -2024,9 +1959,6 @@ LWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_lw_mon" @@ -2042,9 +1974,6 @@ FSUTOA: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" category: "TOA energy flux" pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" @@ -2057,9 +1986,6 @@ FSNT: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "fsnt" @@ -2090,9 +2016,6 @@ FLNT: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_all_mon" @@ -2108,9 +2031,6 @@ FLNTC: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_clr_t_mon" @@ -2140,9 +2060,6 @@ FSNS: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_all_mon" @@ -2158,9 +2075,6 @@ FSNSC: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_clr_t_mon" @@ -2176,9 +2090,6 @@ FLDS: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_lw_down_all_mon" @@ -2209,9 +2120,6 @@ LHFLX: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "LHFLX" @@ -2404,9 +2312,6 @@ H2O: scale_factor: 1 add_offset: 0 new_unit: "mol mol$^{-1}$" - mpl: - colorbar: - label: "mol mol$^{-1}$" plot_log_pressure: True pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] pct_diff_colormap: "PuOr_r" From b6e48a670cc093f9dcad122a582b0ef17e772477 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Wed, 8 Apr 2026 16:11:07 -0600 Subject: [PATCH 26/43] Modify lat lon vector plot to reuse `plot_map_and_save` --- scripts/plotting/global_latlon_vect_map.py | 57 +++++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/scripts/plotting/global_latlon_vect_map.py b/scripts/plotting/global_latlon_vect_map.py index f1fd21ebe..451822326 100644 --- a/scripts/plotting/global_latlon_vect_map.py +++ b/scripts/plotting/global_latlon_vect_map.py @@ -165,6 +165,7 @@ def global_latlon_vect_map(adfobj): #End if vres["plot_type"] = __name__ + vres["vector"] = True #Make sure that variable is part of a vector pair: if "vector_pair" in vres: @@ -390,7 +391,9 @@ def global_latlon_vect_map(adfobj): uoseasons = {} voseasons = {} udseasons = {} # hold the differences - vdseasons = {} # hold the differences + vdseasons = {} + upseasons = {} # hold the percent differences + vpseasons = {} if has_lev: @@ -419,6 +422,20 @@ def global_latlon_vect_map(adfobj): udseasons[s] = umseasons[s] - uoseasons[s] vdseasons[s] = vmseasons[s] - voseasons[s] + upseasons[s] = (umseasons[s] - uoseasons[s]) / np.abs(uoseasons[s]) * 100.0 + upseasons[s] = upseasons[s].where(np.isfinite(upseasons[s]), np.nan) + vpseasons[s] = (vmseasons[s] - voseasons[s]) / np.abs(voseasons[s]) * 100.0 + vpseasons[s] = vpseasons[s].where(np.isfinite(vpseasons[s]), np.nan) + + vres["umdlfld_nowrap"] = umseasons[s] + vres["vmdlfld_nowrap"] = vmseasons[s] + vres["uobsfld_nowrap"] = uoseasons[s] + vres["vobsfld_nowrap"] = voseasons[s] + vres["udiffld_nowrap"] = udseasons[s] + vres["vdiffld_nowrap"] = vdseasons[s] + vres["upctdiffld_nowrap"] = upseasons[s] + vres["vpctdiffld_nowrap"] = vpseasons[s] + # time to make plot; here we'd probably loop over whatever plots we want for this variable # I'll just call this one "LatLon_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? plot_name = plot_loc / f"{var_name}_{lv}hpa_{s}_LatLon_Vector_Mean.{plot_type}" @@ -448,12 +465,12 @@ def global_latlon_vect_map(adfobj): # colormap, contour_levels, diff_colormap, diff_contour_levels, tiString, tiFontSize, mpl # *Any other entries will be ignored. # NOTE: If we were doing all the plotting here, we could use whatever we want from the provided YAML file. - pf.plot_map_vect_and_save(adfobj, plot_name, case_nickname, base_nickname, - [syear_cases[case_idx],eyear_cases[case_idx]], - [syear_baseline,eyear_baseline],lv, - umseasons[s], vmseasons[s], - uoseasons[s], voseasons[s], - udseasons[s], vdseasons[s], obs, **vres) + pf.plot_map_and_save(adfobj, plot_name, case_nickname, base_nickname, + [syear_cases[case_idx],eyear_cases[case_idx]], + [syear_baseline,eyear_baseline], + umseasons[s], uoseasons[s], + udseasons[s], upseasons[s], + obs=obs, **vres) #Add plot to website (if enabled): adfobj.add_website_data(plot_name, f"{var_name}_{lv}hpa", case_name, category=web_category, @@ -473,6 +490,20 @@ def global_latlon_vect_map(adfobj): udseasons[s] = umseasons[s] - uoseasons[s] vdseasons[s] = vmseasons[s] - voseasons[s] + upseasons[s] = (umseasons[s] - uoseasons[s]) / np.abs(uoseasons[s]) * 100.0 + upseasons[s] = upseasons[s].where(np.isfinite(upseasons[s]), np.nan) + vpseasons[s] = (vmseasons[s] - voseasons[s]) / np.abs(voseasons[s]) * 100.0 + vpseasons[s] = vpseasons[s].where(np.isfinite(vpseasons[s]), np.nan) + + vres["umdlfld_nowrap"] = umseasons[s] + vres["vmdlfld_nowrap"] = vmseasons[s] + vres["uobsfld_nowrap"] = uoseasons[s] + vres["vobsfld_nowrap"] = voseasons[s] + vres["udiffld_nowrap"] = udseasons[s] + vres["vdiffld_nowrap"] = vdseasons[s] + vres["upctdiffld_nowrap"] = upseasons[s] + vres["vpctdiffld_nowrap"] = vpseasons[s] + # time to make plot; here we'd probably loop over whatever plots we want for this variable # I'll just call this one "LatLon_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? plot_name = plot_loc / f"{var_name}_{s}_LatLon_Vector_Mean.{plot_type}" @@ -502,12 +533,12 @@ def global_latlon_vect_map(adfobj): # colormap, contour_levels, diff_colormap, diff_contour_levels, tiString, tiFontSize, mpl # *Any other entries will be ignored. # NOTE: If we were doing all the plotting here, we could use whatever we want from the provided YAML file. - pf.plot_map_vect_and_save(adfobj, plot_name, case_nickname, base_nickname, - [syear_cases[case_idx],eyear_cases[case_idx]], - [syear_baseline,eyear_baseline], None, - umseasons[s], vmseasons[s], - uoseasons[s], voseasons[s], - udseasons[s], vdseasons[s], obs, **vres) + pf.plot_map_and_save(adfobj, plot_name, case_nickname, base_nickname, + [syear_cases[case_idx],eyear_cases[case_idx]], + [syear_baseline,eyear_baseline], + umseasons[s], uoseasons[s], + udseasons[s], upseasons[s], + obs=obs, **vres) #Add plot to website (if enabled): adfobj.add_website_data(plot_name, var_name, case_name, category=web_category, From 5cbe4b85ad3ab0e1305d6aeb0cd57857257ca7ba Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Wed, 8 Apr 2026 20:19:03 -0600 Subject: [PATCH 27/43] Add variable default dict function --- scripts/plotting/adf_histogram.py | 4 ++++ scripts/plotting/global_mean_timeseries.py | 4 ++-- scripts/plotting/meridional_mean.py | 2 ++ scripts/plotting/polar_map.py | 2 ++ scripts/plotting/zonal_mean.py | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/plotting/adf_histogram.py b/scripts/plotting/adf_histogram.py index f41d5716d..19b5466ea 100644 --- a/scripts/plotting/adf_histogram.py +++ b/scripts/plotting/adf_histogram.py @@ -29,6 +29,7 @@ import warnings # use to warn user about missing files. import adf_utils as utils +import plotting_utils as plot_utils warnings.formatwarning = utils.my_formatwarning # @@ -120,6 +121,7 @@ def get_load_args(adfobj, case, variablename): adfobj.debug_log(f"adf_histogram: Found variable defaults for {var}") else: vres = {} + vres = plot_utils.add_var_to_vres(adfobj, var, vres) # probably have to make sure no "lev" dim (but gets confused about other dimensions) da = load_ref_func(*get_load_args(adfobj, adfobj.data.ref_case_label, var)) @@ -150,6 +152,8 @@ def get_load_args(adfobj, case, variablename): adfobj.debug_log(f"adf_histogram: Found variable defaults for {var}") else: vres = {} + vres = plot_utils.add_var_to_vres(adfobj, var, vres) + hist_file = plot_loc / f"{case_name}_{var}_{plot_name_string}.nc" histogram_file_exists = hist_file.is_file() if (not histogram_file_exists) or (redo_histogram_files): diff --git a/scripts/plotting/global_mean_timeseries.py b/scripts/plotting/global_mean_timeseries.py index 82e3b87a7..08400f7c3 100644 --- a/scripts/plotting/global_mean_timeseries.py +++ b/scripts/plotting/global_mean_timeseries.py @@ -12,7 +12,7 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as ticker - +import plotting_utils as plot_utils import adf_utils as utils import warnings # use to warn user about missing files. @@ -50,7 +50,7 @@ def global_mean_timeseries(adfobj): else: vres = {} #End if - + vres = plot_utils.add_var_to_vres(adfobj, field, vres) vres["plot_type"] = __name__ # reference time series (DataArray) diff --git a/scripts/plotting/meridional_mean.py b/scripts/plotting/meridional_mean.py index 6891fe378..39339801f 100644 --- a/scripts/plotting/meridional_mean.py +++ b/scripts/plotting/meridional_mean.py @@ -2,6 +2,7 @@ import numpy as np import xarray as xr import plotting_functions as pf +import plotting_utils as plot_utils import adf_utils as utils import warnings # use to warn user about missing files. @@ -134,6 +135,7 @@ def meridional_mean(adfobj): vres = {} #End if + vres = plot_utils.add_var_to_vres(adfobj, var, vres) vres["plot_type"] = __name__ #loop over different data sets to plot model against: diff --git a/scripts/plotting/polar_map.py b/scripts/plotting/polar_map.py index 98422abe1..ddfb089fc 100644 --- a/scripts/plotting/polar_map.py +++ b/scripts/plotting/polar_map.py @@ -4,6 +4,7 @@ # ADF library import plotting_functions as pf +import plotting_utils as plot_utils import adf_utils as utils def get_hemisphere(hemi_type): @@ -136,6 +137,7 @@ def polar_map(adfobj): # Get variable-specific settings vres = res.get(var, {}) + vres = plot_utils.add_var_to_vres(adfobj, var, vres) web_category = vres.get("category", None) vres["plot_type"] = __name__ diff --git a/scripts/plotting/zonal_mean.py b/scripts/plotting/zonal_mean.py index f9ba71dd8..0e5fe6a2a 100644 --- a/scripts/plotting/zonal_mean.py +++ b/scripts/plotting/zonal_mean.py @@ -2,6 +2,7 @@ import numpy as np import xarray as xr import plotting_functions as pf +import plotting_utils as plot_utils import adf_utils as utils import warnings # use to warn user about missing files. @@ -158,6 +159,7 @@ def zonal_mean(adfobj): vres = {} #End if + vres = plot_utils.add_var_to_vres(adfobj, var, vres) vres["plot_type"] = __name__ # load reference data (observational or baseline) From cdcb6e24a2147b11745ea063e99cc657910f85d7 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 17:53:17 -0600 Subject: [PATCH 28/43] Bring meridional plots up to speed with zonal --- scripts/plotting/meridional_mean.py | 358 ++++++++++++++++------------ 1 file changed, 202 insertions(+), 156 deletions(-) diff --git a/scripts/plotting/meridional_mean.py b/scripts/plotting/meridional_mean.py index 39339801f..874ac8e27 100644 --- a/scripts/plotting/meridional_mean.py +++ b/scripts/plotting/meridional_mean.py @@ -17,61 +17,53 @@ def meridional_mean(adfobj): the function that calculates the average can take any range of latitudes. Compare CAM climatologies against other climatological data (observations or baseline runs). + Compare CAM climatologies against + other climatological data (observations or baseline runs). + + Parameters + ---------- + adfobj : AdfDiag + The diagnostics object that contains all the configuration information + + Returns + ------- + None + Does not return value, produces files. + + Notes + ----- + Uses AdfData for loading data described by adfobj. + + Directly uses adfobj for the following: + diag_var_list, climo_yrs, variable_defaults, read_config_var, + get_basic_info, add_website_data, debug_log + + Determines whether `lev` dimension is present. If not, makes + a line plot, but if so it makes a contour plot. + TODO: There's a flag to plot linear vs log pressure, but no + method to infer what the user wants. """ #Notify user that script has started: msg = "\n Generating meridional mean plots..." print(f"{msg}\n {'-' * (len(msg)-3)}") - #Extract needed quantities from ADF object: - #----------------------------------------- var_list = adfobj.diag_var_list - model_rgrid_loc = adfobj.get_basic_info("cam_regrid_loc", required=True) #Special ADF variable which contains the output paths for #all generated plots and tables: plot_locations = adfobj.plot_location - #CAM simulation variables (this is always assumed to be a list): - case_names = adfobj.get_cam_info("cam_case_name", required=True) - #Grab case years syear_cases = adfobj.climo_yrs["syears"] eyear_cases = adfobj.climo_yrs["eyears"] - # CAUTION: - # "data" here refers to either obs or a baseline simulation, - # Until those are both treated the same (via intake-esm or similar) - # we will do a simple check and switch options as needed: - if adfobj.get_basic_info("compare_obs"): - #Set obs call for observation details for plot titles - obs = True - - #Extract variable-obs dictionary: - var_obs_dict = adfobj.var_obs_dict - - #If dictionary is empty, then there are no observations to regrid to, - #so quit here: - if not var_obs_dict: - print("\t No observations found to plot against, so no meridional-mean maps will be generated.") - return - else: - obs = False - data_name = adfobj.get_baseline_info("cam_case_name", required=True) # does not get used, is just here as a placemarker - data_list = [data_name] # gets used as just the name to search for climo files HAS TO BE LIST - data_loc = model_rgrid_loc #Just use the re-gridded model data path - #End if - #Grab baseline years (which may be empty strings if using Obs): syear_baseline = adfobj.climo_yrs["syear_baseline"] eyear_baseline = adfobj.climo_yrs["eyear_baseline"] - #Grab all case nickname(s) - test_nicknames = adfobj.case_nicknames["test_nicknames"] - base_nickname = adfobj.case_nicknames["base_nickname"] - res = adfobj.variable_defaults # will be dict of variable-specific plot preferences - # or an empty dictionary if use_defaults was not specified in the config YAML file. + # or an empty dictionary if use_defaults was not specified in YAML. #Set plot file type: # -- this should be set in basic_info_dict, but is not required @@ -85,12 +77,6 @@ def meridional_mean(adfobj): print(f"\t NOTE: redo_plot is set to {redo_plot}") #----------------------------------------- - #Set data path variables: - #----------------------- - mclimo_rg_loc = Path(model_rgrid_loc) - if not adfobj.compare_obs: - dclimo_loc = Path(data_loc) - #----------------------- #Set seasonal ranges: seasons = {"ANN": np.arange(1,13,1), @@ -99,37 +85,80 @@ def meridional_mean(adfobj): "MAM": [3, 4, 5], "SON": [9, 10, 11]} + #Check if plots already exist and redo_plot boolean + #If redo_plot is false and file exists, keep track and attempt to skip calcs to + #speed up preformance a bit if re-running the ADF + meridional_skip = [] + logp_meridional_skip = [] + + #Loop over model cases: + for case_idx, case_name in enumerate(adfobj.data.case_names): + #Set output plot location: + plot_loc = Path(plot_locations[case_idx]) + + #Check if plot output directory exists, and if not, then create it: + if not plot_loc.is_dir(): + print(f" {plot_loc} not found, making new directory") + plot_loc.mkdir(parents=True) + #End if + + #Loop over the variables for each season + for var in var_list: + for s in seasons: + #Check meridional log-p: + plot_name_log = plot_loc / f"{var}_{s}_Meridional_logp_Mean.{plot_type}" + + # Check redo_plot. If set to True: remove old plot, if it already exists: + if (not redo_plot) and plot_name_log.is_file(): + logp_meridional_skip.append(plot_name_log) + #Continue to next iteration: + adfobj.add_website_data(plot_name_log, f"{var}_logp", case_name, season=s, + plot_type="Meridional", category=web_category) + pass + + elif (redo_plot) and plot_name_log.is_file(): + plot_name_log.unlink() + #End if + + #Check regular meridional + plot_name = plot_loc / f"{var}_{s}_Meridional_Mean.{plot_type}" + # Check redo_plot. If set to True: remove old plot, if it already exists: + if (not redo_plot) and plot_name.is_file(): + meridional_skip.append(plot_name) + #Add already-existing plot to website (if enabled): + adfobj.add_website_data(plot_name, var, case_name, season=s, + plot_type="Meridional") + + continue + elif (redo_plot) and plot_name.is_file(): + plot_name.unlink() + #End if + #End for (seasons) + #End for (variables) + #End for (cases) + # + # End redo plots check + # + + # + # Setup Plotting + # #Loop over variables: for var in var_list: #Notify user of variable being plotted: print(f"\t - meridional mean plots for {var}") - if adfobj.compare_obs: - #Check if obs exist for the variable: - if var in var_obs_dict: - #Note: In the future these may all be lists, but for - #now just convert the target_list. - #Extract target file: - dclimo_loc = var_obs_dict[var]["obs_file"] - #Extract target list (eventually will be a list, for now need to convert): - data_list = [var_obs_dict[var]["obs_name"]] - #Extract target variable name: - data_var = var_obs_dict[var]["obs_var"] - else: - dmsg = f"No obs found for variable `{var}`, meridional mean plotting skipped." - adfobj.debug_log(dmsg) - continue - #End if - else: - #Set "data_var" for consistent use below: - data_var = var - #End if + if var not in adfobj.data.ref_var_nam: + dmsg = f"\t WARNING: No reference data found for variable `{var}`, meridional mean plotting skipped." + adfobj.debug_log(dmsg) + print(dmsg) + continue # Check res for any variable specific options that need to be used BEFORE going to the plot: if var in res: vres = res[var] #If found then notify user, assuming debug log is enabled: - adfobj.debug_log(f"meridional_mean: Found variable defaults for {var}") + adfobj.debug_log(f"\t INFO: meridional_mean: Found variable defaults for {var}") else: vres = {} @@ -137,126 +166,143 @@ def meridional_mean(adfobj): vres = plot_utils.add_var_to_vres(adfobj, var, vres) vres["plot_type"] = __name__ + #Extract category (if available): + web_category = vres.get("category", None) - #loop over different data sets to plot model against: - for data_src in data_list: - # load data (observational) comparison files - # (we should explore intake as an alternative to having this kind of repeated code): - if adfobj.compare_obs: - #For now, only grab one file (but convert to list for use below) - oclim_fils = [dclimo_loc] - else: - oclim_fils = sorted(dclimo_loc.glob(f"{data_src}_{var}_baseline.nc")) - #End if - oclim_ds = utils.load_dataset(oclim_fils) + # load reference data (observational or baseline) + if not adfobj.compare_obs: + base_name = adfobj.data.ref_case_label + else: + base_name = adfobj.data.ref_labels[var] + + # Gather reference variable data + odata = adfobj.data.load_reference_regrid_da(base_name, var) + + #Check if regridded file exists, if not skip zonal plot for this var + if odata is None: + dmsg = f"\t WARNING: No regridded baseline file for {base_name} for variable `{var}`, zonal mean plotting skipped." + adfobj.debug_log(dmsg) + continue + + #Check meridional mean dimensions + lat_lev_ref = utils.validate_dims(odata, ['lat', 'lev']) + #Check if reference file has vertical levels + #Notify user of level dimension: + if lat_lev_ref['has_lev']: + print(f"\t INFO: {var} has lev dimension.") + has_lev_ref = True + else: + has_lev_ref = False - #Loop over model cases: - for case_idx, case_name in enumerate(case_names): + #Loop over model cases: + for case_idx, case_name in enumerate(adfobj.data.case_names): - #Set case nickname: - case_nickname = test_nicknames[case_idx] + #Set case nickname: + case_nickname = adfobj.data.test_nicknames[case_idx] - #Set output plot location: - plot_loc = Path(plot_locations[case_idx]) + #Set output plot location: + plot_loc = Path(plot_locations[case_idx]) - #Check if plot output directory exists, and if not, then create it: - if not plot_loc.is_dir(): - print(f" {plot_loc} not found, making new directory") - plot_loc.mkdir(parents=True) + # load re-gridded model files: + mdata = adfobj.data.load_regrid_da(case_name, var) - # load re-gridded model files: - mclim_fils = sorted(mclimo_rg_loc.glob(f"{data_src}_{case_name}_{var}_*.nc")) - mclim_ds = utils.load_dataset(mclim_fils) + if mdata is None: + dmsg = f"\t WARNING: No regridded test file for {case_name} for variable `{var}`, zonal mean plotting skipped." + adfobj.debug_log(dmsg) + continue - # stop if data is invalid: - if (oclim_ds is None) or (mclim_ds is None): - warnings.warn(f"invalid data, skipping meridional mean plot of {var}") - continue + # determine whether it's 2D or 3D + # 3D triggers search for surface pressure + # check data dimensions: + #has_lat, has_lev = utils.zm_validate_dims(mdata) + lat_lev = utils.validate_dims(mdata, ['lat', 'lev']) + + #Check if reference file has vertical levels + #Notify user of level dimension: + if lat_lev['has_lev']: + print(f"\t INFO: {var} has lev dimension.") + has_lev = True + else: + has_lev = False - #Extract variable of interest - odata = oclim_ds[data_var].squeeze() # squeeze in case of degenerate dimensions - mdata = mclim_ds[var].squeeze() - - # APPLY UNITS TRANSFORMATION IF SPECIFIED: - # NOTE: looks like our climo files don't have all their metadata - mdata = mdata * vres.get("scale_factor",1) + vres.get("add_offset", 0) - # update units - mdata.attrs['units'] = vres.get("new_unit", mdata.attrs.get('units', 'none')) - - # Do the same for the baseline case if need be: - if not adfobj.compare_obs: - odata = odata * vres.get("scale_factor",1) + vres.get("add_offset", 0) - # update units - odata.attrs['units'] = vres.get("new_unit", odata.attrs.get('units', 'none')) - # Or for observations - else: - odata = odata * vres.get("obs_scale_factor",1) + vres.get("obs_add_offset", 0) - # Note: we are going to assume that the specification ensures the conversion makes the units the same. - # Doesn't make sense to add a different unit. - - # determine whether it's 2D or 3D - # 3D triggers search for surface pressure - validate_lat_lev = utils.validate_dims(mdata, ['lat', 'lev']) # keys=> 'has_lat', 'has_lev', with T/F values - - #Notify user of level dimension: - if validate_lat_lev['has_lev']: - print(f"\t INFO: {var} has lev dimension.") - has_lev = True - else: - has_lev = False + #Check to make sure each case has vertical levels if one of the cases does + if (has_lev) and (not has_lev_ref): + print(f"\t WARNING: expecting lev boolean for both case: {has_lev} and ref: {has_lev_ref}") + continue + if (has_lev_ref) and (not has_lev): + print(f"\t WARNING: expecting lev boolean for both case: {has_lev} and ref: {has_lev_ref}") + continue - # - # Seasonal Averages - # Note: xarray can do seasonal averaging, but depends on having time accessor, - # which these prototype climo files don't. + # + # Seasonal Averages + # + + #Create new dictionaries: + mseasons = {} + oseasons = {} + + #Loop over season dictionary: + for s in seasons: + vres["season"] = s + + # time to make plot; here we'd probably loop over whatever plots we want for this variable + # I'll just call this one "Zonal_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? + # NOTE: Up to this point, nothing really differs from global_latlon_map, + # so we could have made one script instead of two. + # Merging would make overall timing better because looping twice will double I/O steps. # - #Create new dictionaries: - mseasons = {} - oseasons = {} + # difference: each entry should be (lat, lon) or (plev, lat, lon) + # dseasons[s] = mseasons[s] oseasons[s] + # difference will be calculated in plot_zonal_mean_and_save; + # because we can let any pressure-level interpolation happen there + # This could be re-visited for efficiency or improved code structure. - #Loop over season dictionary: - for s in seasons: - plot_name = plot_loc / f"{var}_{s}_Meridional_Mean.{plot_type}" + #Seasonal Averages + mseasons[s] = utils.seasonal_mean(mdata, season=s, is_climo=True) + oseasons[s] = utils.seasonal_mean(odata, season=s, is_climo=True) - # Check redo_plot. If set to True: remove old plot, if it already exists: - if (not redo_plot) and plot_name.is_file(): - #Add already-existing plot to website (if enabled): - adfobj.debug_log(f"'{plot_name}' exists and clobber is false.") - adfobj.add_website_data(plot_name, var, case_name, season=s, - plot_type="Meridional") - #Continue to next iteration: - continue - elif (redo_plot) and plot_name.is_file(): - plot_name.unlink() + #Set the file name + plot_name = plot_loc / f"{var}_{s}_Meridional_Mean.{plot_type}" + plot_name_log = None - mseasons[s] = utils.seasonal_mean(mdata, season=s, is_climo=True) - oseasons[s] = utils.seasonal_mean(odata, season=s, is_climo=True) + if has_lev: + #Set the file name for log-pressure plots + plot_name_log = plot_loc / f"{var}_logp_{s}_Meridional_Mean.{plot_type}" + #End if + #Create plots + if plot_name not in meridional_skip: #Create new plot: - pf.plot_meridional_mean_and_save(adfobj, plot_name, case_nickname, base_nickname, - [syear_cases[case_idx],eyear_cases[case_idx]], - [syear_baseline,eyear_baseline], - mseasons[s], oseasons[s], has_lev, latbounds=slice(-5,5), obs=obs, **vres) + pf.plot_meridional_mean_and_save(adfobj, plot_name, case_nickname, adfobj.data.ref_nickname, + [syear_cases[case_idx],eyear_cases[case_idx]], + [syear_baseline,eyear_baseline], + mseasons[s], oseasons[s], has_lev, log_p=False, obs=adfobj.compare_obs, **vres) #Add plot to website (if enabled): - adfobj.add_website_data(plot_name, var, case_name, season=s, - plot_type="Meridional") + adfobj.add_website_data(plot_name, var, case_name, season=s, plot_type="Meridional") + #End if + + #Create log-pressure plots as well (if applicable) + if (plot_name_log) and (plot_name_log not in logp_meridional_skip): - #End for (seasons loop) - #End for (case names loop) - #End for (obs/baseline loop) + pf.plot_meridional_mean_and_save(adfobj, plot_name_log, case_nickname, adfobj.data.ref_nickname, + [syear_cases[case_idx],eyear_cases[case_idx]], + [syear_baseline,eyear_baseline], + mseasons[s], oseasons[s], has_lev, log_p=True, obs=adfobj.compare_obs, **vres) + + #Add plot to website (if enabled): + adfobj.add_website_data(plot_name_log, f"{var}_logp", case_name, season=s, plot_type="Meridional", category=web_category) + #End if + + #End for (seasons loop) + #End for (case names loop) #End for (variables loop) #Notify user that script has ended: print(" ...Meridional mean plots have been generated successfully.") -######### -# Helpers -######### - - ############## #END OF SCRIPT \ No newline at end of file From 7109b06f5d8cdaa2f35e2fdeb3f227d21c3720db Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:15:42 -0600 Subject: [PATCH 29/43] Add `vres` updates for plotting --- scripts/plotting/global_latlon_map.py | 5 +++++ scripts/plotting/global_latlon_vect_map.py | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/plotting/global_latlon_map.py b/scripts/plotting/global_latlon_map.py index 9a1bba8ab..a3bb3ff58 100644 --- a/scripts/plotting/global_latlon_map.py +++ b/scripts/plotting/global_latlon_map.py @@ -102,6 +102,7 @@ def global_latlon_map(adfobj): def process_variable(adfobj, var, seasons, pres_levs, plot_type, redo_plot): vres = adfobj.variable_defaults.get(var, {}) vres["plot_type"] = __name__ + vres = plot_utils.add_var_to_vres(adfobj, var, vres) web_category = vres.get("category", None) # For global maps, also set the central longitude: @@ -373,6 +374,8 @@ def process_2d_plots(adfobj, mdata, odata, case_name, case_nickname, plot_name = plot_loc / f"{var}_{s}_LatLon_Mean.{plot_type}" if doplot[plot_name] is None: continue + + vres["season"] = s # Calculate seasonal means and differences mseasons[s], oseasons[s], dseasons[s], pseasons[s] = \ @@ -408,6 +411,8 @@ def process_3d_plots(adfobj, mdata, odata, case_name, case_nickname, plot_name = plot_loc / f"{var}_{pres}hpa_{s}_LatLon_Mean.{plot_type}" if doplot[plot_name] is None: continue + + vres["season"] = s # Calculate seasonal means and differences mseasons[s], oseasons[s], dseasons[s], pseasons[s] = \ diff --git a/scripts/plotting/global_latlon_vect_map.py b/scripts/plotting/global_latlon_vect_map.py index 451822326..6a09f9b0c 100644 --- a/scripts/plotting/global_latlon_vect_map.py +++ b/scripts/plotting/global_latlon_vect_map.py @@ -153,6 +153,7 @@ def global_latlon_vect_map(adfobj): # Check res for any variable specific options that need to be used BEFORE going to the plot: if var in res: vres = res[var] + vres = plot_utils.add_var_to_vres(adfobj, var, vres) #If found then notify user, assuming debug log is enabled: adfobj.debug_log(f"global_latlon_vect_map: Found variable defaults for {var}") @@ -168,14 +169,22 @@ def global_latlon_vect_map(adfobj): vres["vector"] = True #Make sure that variable is part of a vector pair: - if "vector_pair" in vres: + """if "vector_pair" in vres: var_pair = vres["vector_pair"] var_name = vres["vector_name"] else: adfobj.debug_log(f"variable '{var}' not a vector pair") continue + #End if""" + + if "vector_pair" not in vres: + adfobj.debug_log(f"variable '{var}' not a vector pair") + continue #End if + var_pair = vres["vector_pair"] + var_name = vres["vector_name"] + #Notify user of variable being plotted: print(f"\t - lat/lon vector maps for {var},{var_pair}") @@ -436,6 +445,8 @@ def global_latlon_vect_map(adfobj): vres["upctdiffld_nowrap"] = upseasons[s] vres["vpctdiffld_nowrap"] = vpseasons[s] + vres["season"] = s + # time to make plot; here we'd probably loop over whatever plots we want for this variable # I'll just call this one "LatLon_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? plot_name = plot_loc / f"{var_name}_{lv}hpa_{s}_LatLon_Vector_Mean.{plot_type}" @@ -456,7 +467,7 @@ def global_latlon_vect_map(adfobj): # pass in casenames vres["case_name"] = case_name vres["baseline"] = data_src - vres["var_name"] = var_name + #vres["var_name"] = var_name #Create new plot: # NOTE: send vres as kwarg dictionary. --> ONLY vres, not the full res @@ -504,6 +515,8 @@ def global_latlon_vect_map(adfobj): vres["upctdiffld_nowrap"] = upseasons[s] vres["vpctdiffld_nowrap"] = vpseasons[s] + vres["season"] = s + # time to make plot; here we'd probably loop over whatever plots we want for this variable # I'll just call this one "LatLon_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? plot_name = plot_loc / f"{var_name}_{s}_LatLon_Vector_Mean.{plot_type}" @@ -524,7 +537,7 @@ def global_latlon_vect_map(adfobj): # pass in casenames vres["case_name"] = case_name vres["baseline"] = data_src - vres["var_name"] = var_name + #vres["var_name"] = var_name #Create new plot: # NOTE: send vres as kwarg dictionary. --> ONLY vres, not the full res From da04b97ebc29266afd29892484d2fa22d3452efc Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:16:17 -0600 Subject: [PATCH 30/43] Keep attrs after mean call --- lib/adf_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/adf_utils.py b/lib/adf_utils.py index 179051011..5c8ca330e 100644 --- a/lib/adf_utils.py +++ b/lib/adf_utils.py @@ -700,7 +700,8 @@ def zonal_mean_xr(fld): davgovr = [dim for dim in d if dim not in ('lev','lat')] else: raise IOError("zonal_mean_xr requires Xarray DataArray input.") - return fld.mean(dim=davgovr) + fld = fld.mean(dim=davgovr, keep_attrs=True) + return fld ##################### #END HELPER FUNCTIONS \ No newline at end of file From 318ea3986109b6822e6cbe2595b464506923a6aa Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:16:56 -0600 Subject: [PATCH 31/43] Keep log-p plots as same category --- scripts/plotting/zonal_mean.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/plotting/zonal_mean.py b/scripts/plotting/zonal_mean.py index 0e5fe6a2a..cb6a106fe 100644 --- a/scripts/plotting/zonal_mean.py +++ b/scripts/plotting/zonal_mean.py @@ -108,7 +108,7 @@ def zonal_mean(adfobj): logp_zonal_skip.append(plot_name_log) #Continue to next iteration: adfobj.add_website_data(plot_name_log, f"{var}_logp", case_name, season=s, - plot_type="Zonal", category="Log-P") + plot_type="Zonal", category=web_category) pass elif (redo_plot) and plot_name_log.is_file(): @@ -161,6 +161,8 @@ def zonal_mean(adfobj): vres = plot_utils.add_var_to_vres(adfobj, var, vres) vres["plot_type"] = __name__ + #Extract category (if available): + web_category = vres.get("category", None) # load reference data (observational or baseline) if not adfobj.compare_obs: @@ -242,6 +244,7 @@ def zonal_mean(adfobj): #Loop over season dictionary: for s in seasons: + vres["season"] = s # time to make plot; here we'd probably loop over whatever plots we want for this variable # I'll just call this one "Zonal_Mean" ... would this work as a pattern [operation]_[AxesDescription] ? @@ -291,7 +294,7 @@ def zonal_mean(adfobj): mseasons[s], oseasons[s], has_lev, log_p=True, obs=adfobj.compare_obs, **vres) #Add plot to website (if enabled): - adfobj.add_website_data(plot_name_log, f"{var}_logp", case_name, season=s, plot_type="Zonal", category="Log-P") + adfobj.add_website_data(plot_name_log, f"{var}_logp", case_name, season=s, plot_type="Zonal", category=web_category) #End if #End for (seasons loop) From abfb7275e7ab7f0886d67e883b39798a2d9c2b4b Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:17:05 -0600 Subject: [PATCH 32/43] Add `vres` updates for plotting --- scripts/plotting/polar_map.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/plotting/polar_map.py b/scripts/plotting/polar_map.py index ddfb089fc..47d07bbd8 100644 --- a/scripts/plotting/polar_map.py +++ b/scripts/plotting/polar_map.py @@ -213,6 +213,7 @@ def polar_map(adfobj): case_name = plot['case'] case_idx = plot['case_idx'] + vres["season"] = plot['season'] plot_loc = Path(plot_locations[case_idx]) # Ensure plot directory exists @@ -234,6 +235,7 @@ def polar_map(adfobj): continue mdata = mdata.sel(lev=plot['pressure']) odata_level = odata.sel(lev=plot['pressure']) + vres["lev"] = plot['pressure'] else: if not utils.lat_lon_validate_dims(mdata): continue From 4fee7f12b420d5f72d30b1804d91a29821ae8628 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:18:44 -0600 Subject: [PATCH 33/43] Add suite of plot detail updates. Also test code for colored line plot and lat/lon vector percent diff --- lib/plotting_functions.py | 1112 +++++++++++++++++++++---------------- 1 file changed, 637 insertions(+), 475 deletions(-) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index 00709243b..6f64f1cd8 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -43,6 +43,7 @@ from cartopy.util import add_cyclic_point from mpl_toolkits.axes_grid1.inset_locator import inset_axes from matplotlib.lines import Line2D +from matplotlib.ticker import MaxNLocator from adf_base import AdfError import plotting_utils as plot_utils @@ -70,6 +71,8 @@ "SON": [9, 10, 11] } +cbar_size = 8 +cbar_labelpad = 5 ################# #HELPER FUNCTIONS @@ -174,145 +177,159 @@ def make_polar_plot(adfobj, wks, case_nickname, dif_cyclic, _ = add_cyclic_point(dif, coord=dif.lon) pct_cyclic, _ = add_cyclic_point(pct, coord=pct.lon) + wrap_fields = (d1_cyclic, d2_cyclic, pct_cyclic, dif_cyclic) + # -- deal with optional plotting arguments that might provide variable-dependent choices kwargs["adfobj"] = adfobj cp_info = plot_utils.prep_contour_plot(d1, d2, dif, pct, **kwargs) - - levels_diff = cp_info['levels_diff'] - cmap_diff = cp_info['cmap_diff'] - dnorm = cp_info['norm_diff'] - extend_diff = cp_info['extend_diff'] - - levels_pctdiff = cp_info['levels_pctdiff'] - cmap_pctdiff = cp_info['cmap_pctdiff'] - norm_pctdiff = cp_info['norm_pctdiff'] - - levels_sim = cp_info['levels_sim'] - cmap_sim = cp_info['cmap_sim'] - norm_sim = cp_info['norm_sim'] - extend_sim = cp_info['extend_sim'] + units = cp_info['units'] lons, lats = plot_utils.transform_coordinates_for_projection(proj, lon_cyclic, d1.lat) # Explicit coordinate transform fig = plt.figure(figsize=(10,10)) gs = mpl.gridspec.GridSpec(2, 4, wspace=0.9) - ax1 = plt.subplot(gs[0, :2], projection=proj, **cp_info['subplots_opt']) - ax2 = plt.subplot(gs[0, 2:], projection=proj, **cp_info['subplots_opt']) - ax3 = plt.subplot(gs[1, :2], projection=proj, **cp_info['subplots_opt']) - ax4 = plt.subplot(gs[1, 2:], projection=proj, **cp_info['subplots_opt']) + ax1 = plt.subplot(gs[0, :2], projection=proj) + ax2 = plt.subplot(gs[0, 2:], projection=proj) + ax3 = plt.subplot(gs[1, :2], projection=proj) + ax4 = plt.subplot(gs[1, 2:], projection=proj) + axs = [ax1,ax2,ax3,ax4] - levs = np.unique(np.array(levels_sim)) - levs_diff = np.unique(np.array(levels_diff)) - levs_pctdiff = np.unique(np.array(levels_pctdiff)) + means = [] + mins = [] + maxs = [] - if len(levs) < 2: - img1 = ax1.contourf(lons, lats, d1_cyclic, colors="w", norm=norm_sim) - ax1.text(0.4, 0.4, empty_message, transform=ax1.transAxes, bbox=props) + # determine levels & color normalization: + minval = np.min([np.min(d1), np.min(d2)]) + maxval = np.max([np.max(d1), np.max(d2)]) + absmaxdif = np.max(np.abs(dif)) + absmaxpct = np.max(np.abs(pct)) - img2 = ax2.contourf(lons, lats, d2_cyclic, colors="w", norm=norm_sim) - ax2.text(0.4, 0.4, empty_message, transform=ax2.transAxes, bbox=props) - else: - img1 = ax1.contourf(lons, lats, d1_cyclic, - cmap=cmap_sim, norm=norm_sim, levels=levels_sim, extend=cp_info['extend_sim'] - ) - img2 = ax2.contourf(lons, lats, d2_cyclic, - cmap=cmap_sim, norm=norm_sim, levels=levels_sim, extend=cp_info['extend_sim'] - ) + means.extend([d1_region_mean,d2_region_mean, pct_region_mean, dif_region_mean]) + mins.extend([d1_region_min,d2_region_min, pct_region_min, dif_region_min]) + maxs.extend([d1_region_max,d2_region_max, pct_region_max, dif_region_max]) - if len(levs_pctdiff) < 2: - img3 = ax3.contourf(lons, lats, pct_cyclic, colors="w", norm=norm_pctdiff) - ax3.text(0.4, 0.4, empty_message, transform=ax3.transAxes, bbox=props) - else: - img3 = ax3.contourf(lons, lats, pct_cyclic, cmap=cmap_pctdiff, norm=norm_pctdiff, - levels=levels_pctdiff, extend=extend_sim) + pctdiff_idx = 2 + diff_idx = 3 + imgs = [] + + # Loop over data arrays to make plots + for i, a in enumerate(wrap_fields): + if i == diff_idx: + levels = cp_info['levels_diff'] + cmap = cp_info['cmap_diff'] + norm = cp_info['norm_diff'] + extend = cp_info['extend_diff'] + elif i == pctdiff_idx: + levels = cp_info['levels_pctdiff'] + cmap = cp_info['cmap_pctdiff'] + norm = cp_info['norm_pctdiff'] + extend = cp_info['extend_pctdiff'] + else: + levels = cp_info['levels_sim'] + cmap = cp_info['cmap_sim'] + norm = cp_info['norm_sim'] + extend = cp_info['extend_sim'] + + levs = np.unique(np.array(levels)) + if len(levs) < 2: + imgs.append(axs[i].contourf(lons,lats,a,colors="w")) + axs[i].text(0.4, 0.4, empty_message, transform=axs[i].transAxes, bbox=props) + else: + imgs.append(axs[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, + extend=extend, + **cp_info['contourf_opt'])) + + # Set stats for title + stat_mean = f"Mean: {means[i]:5.2f}" + stat_max = f"Max: {maxs[i]:5.2f}" + stat_min = f"Min: {mins[i]:5.2f}" + stats = f"{stat_mean}\n{stat_max}\n{stat_min}" + #axs[i].set_title(stats, loc='right', fontsize=8) + axs[i].text(-0.05, 0.0, stats, transform=axs[i].transAxes,fontsize=cbar_size) + #axs[i].text(0.8, 0.925, stats, transform=axs[i].transAxes,fontsize=cbar_size) + + #End for - if len(levs_diff) < 2: - img4 = ax4.contourf(lons, lats, dif_cyclic, colors="w", norm=dnorm) - ax4.text(0.4, 0.4, empty_message, transform=ax4.transAxes, bbox=props) - else: - img4 = ax4.contourf(lons, lats, dif_cyclic, cmap=cmap_diff, norm=dnorm, - levels=levels_diff, extend=extend_diff) - #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) + var_name = kwargs['var_name'] + if "lev" in kwargs: + lev = kwargs["lev"] + var_name = f"{var_name} at {lev} hPa" + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=14, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) st.set_y(0.95) #Set plot titles case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" - ax1.set_title(case_title, loc='left', fontsize=6) #fontsize=tiFontSize + axs[0].set_title(case_title, loc='left', fontsize=8) #fontsize=tiFontSize if obs: obs_var = kwargs["obs_var_name"] obs_title = kwargs["obs_file"][:-3] base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" - ax2.set_title(base_title, loc='left', fontsize=6) #fontsize=tiFontSize + axs[1].set_title(base_title, loc='left', fontsize=8) #fontsize=tiFontSize else: base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" - ax2.set_title(base_title, loc='left', fontsize=6) - - ax1.text(-0.2, -0.10, f"Mean: {d1_region_mean:5.2f}\nMax: {d1_region_max:5.2f}\nMin: {d1_region_min:5.2f}", transform=ax1.transAxes) + axs[1].set_title(base_title, loc='left', fontsize=8) - ax2.text(-0.2, -0.10, f"Mean: {d2_region_mean:5.2f}\nMax: {d2_region_max:5.2f}\nMin: {d2_region_min:5.2f}", transform=ax2.transAxes) + axs[2].set_title("Test % Diff Baseline", loc='left', fontsize=8,fontweight="bold") + axs[3].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=8) - ax3.text(-0.2, -0.10, f"Mean: {pct_region_mean:5.2f}\nMax: {pct_region_max:5.2f}\nMin: {pct_region_min:5.2f}", transform=ax3.transAxes) - ax3.set_title("Test % diff Baseline", loc='left', fontsize=8) - - ax4.text(-0.2, -0.10, f"Mean: {dif_region_mean:5.2f}\nMax: {dif_region_max:5.2f}\nMin: {dif_region_min:5.2f}", transform=ax4.transAxes) - ax4.set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=8) - - if "units" in kwargs: - ax2.set_ylabel(kwargs["units"]) - ax4.set_ylabel(kwargs["units"]) - else: - ax2.set_ylabel(f"{d1.units}") - ax4.set_ylabel(f"{d1.units}") - - [a.set_extent(domain, ccrs.PlateCarree()) for a in [ax1, ax2, ax3, ax4]] - [a.coastlines() for a in [ax1, ax2, ax3, ax4]] - - # __Follow the cartopy gallery example to make circular__: - # Compute a circle in axes coordinates, which we can use as a boundary - # for the map. We can pan/zoom as much as we like - the boundary will be - # permanently circular. - theta = np.linspace(0, 2*np.pi, 100) - center, radius = [0.5, 0.5], 0.5 - verts = np.vstack([np.sin(theta), np.cos(theta)]).T - circle = mpl.path.Path(verts * radius + center) - [a.set_boundary(circle, transform=a.transAxes) for a in [ax1, ax2, ax3, ax4]] + for a in axs: + a.coastlines() + a.set_extent(domain, ccrs.PlateCarree()) + # __Follow the cartopy gallery example to make circular__: + # Compute a circle in axes coordinates, which we can use as a boundary + # for the map. We can pan/zoom as much as we like - the boundary will be + # permanently circular. + theta = np.linspace(0, 2*np.pi, 100) + center, radius = [0.5, 0.5], 0.5 + verts = np.vstack([np.sin(theta), np.cos(theta)]).T + circle = mpl.path.Path(verts * radius + center) + a.set_boundary(circle, transform=a.transAxes) + a.gridlines(draw_labels=False, crs=ccrs.PlateCarree(), + lw=1, color="gray",y_inline=True, + xlocs=range(-180,180,90), ylocs=range(0,90,10)) # __COLORBARS__ - cb_mean_ax = inset_axes(ax2, - width="5%", # width = 5% of parent_bbox width + cb_mean_ax = inset_axes(axs[1], + width="5%", height="90%", # height : 90% loc='lower left', bbox_to_anchor=(1.05, 0.05, 1, 1), bbox_transform=ax2.transAxes, borderpad=0, ) - fig.colorbar(img1, cax=cb_mean_ax) + cbar = fig.colorbar(imgs[0], cax=cb_mean_ax) + cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad, loc='left') + cbar.ax.tick_params(labelsize=cbar_size) - cb_pct_ax = inset_axes(ax3, - width="5%", # width = 5% of parent_bbox width + cb_pct_ax = inset_axes(axs[2], + width="5%", height="90%", # height : 90% loc='lower left', bbox_to_anchor=(1.05, 0.05, 1, 1), bbox_transform=ax3.transAxes, borderpad=0, - ) + ) - cb_diff_ax = inset_axes(ax4, - width="5%", # width = 5% of parent_bbox width + cb_diff_ax = inset_axes(axs[3], + width="5%", height="90%", # height : 90% loc='lower left', bbox_to_anchor=(1.05, 0.05, 1, 1), bbox_transform=ax4.transAxes, borderpad=0, - ) + ) - fig.colorbar(img3, cax=cb_pct_ax) + pctdiff_cbar = fig.colorbar(imgs[2], cax=cb_pct_ax) + pctdiff_cbar.ax.set_title("%", fontsize=cbar_size, pad=cbar_labelpad, loc='left') + pctdiff_cbar.ax.tick_params(labelsize=cbar_size) - fig.colorbar(img4, cax=cb_diff_ax) + diff_cbar = fig.colorbar(imgs[3], cax=cb_diff_ax) + diff_cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad, loc='left') + diff_cbar.ax.tick_params(labelsize=cbar_size) # Save files fig.savefig(wks, bbox_inches='tight', dpi=300) @@ -320,233 +337,8 @@ def make_polar_plot(adfobj, wks, case_nickname, # Close figures to avoid memory issues: plt.close(fig) - ####### -def plot_map_vect_and_save(adfobj, wks, case_nickname, base_nickname, - case_climo_yrs, baseline_climo_yrs, - plev, umdlfld_nowrap, vmdlfld_nowrap, - uobsfld_nowrap, vobsfld_nowrap, - udiffld_nowrap, vdiffld_nowrap, obs=False, **kwargs): - - """This plots a vector plot. - - Vector fields constructed from x- and y-components (u, v). - - Parameters - ---------- - wks : str or Path - output file path - case_nickname : str - short name for case - base_nickname : str - short name for base case - case_climo_yrs : list - list of years in case climatology, used for annotation - baseline_climo_yrs : list - list of years in base case climatology, used for annotation - plev : str or float or None - if not None, label denoting the pressure level - umdlfld_nowrap, vmdlfld_nowrap : xarray.DataArray - input data for case, the x- and y- components of the vectors - uobsfld_nowrap, vobsfld_nowrap : xarray.DataArray - input data for base case, the x- and y- components of the vectors - udiffld_nowrap, vdiffld_nowrap : xarray.DataArray - input difference data, the x- and y- components of the vectors - kwargs : dict, optional - variable-specific options, See Notes - - Notes - ----- - kwargs expected to be a variable-specific section, - possibly provided by an ADF Variable Defaults YAML file. - Currently it is inspected for: - - `central_longitude` - - `var_name` - - `case_name` - - `baseline` - - `tiString` - - `tiFontSize` - - `units` - - _Note_ The title string constructed by kwargs appears to not be used. - """ - - # specify the central longitude for the plot: - cent_long = kwargs.get('central_longitude', 180) - - # generate projection: - proj = ccrs.PlateCarree(central_longitude=cent_long) - lat = umdlfld_nowrap['lat'] - wgt = np.cos(np.radians(lat)) - - kwargs["adfobj"] = adfobj - cp_info = plot_utils.prep_contour_plot(umdlfld_nowrap, uobsfld_nowrap, udiffld_nowrap, None, **kwargs) - - # add cyclic longitude: - umdlfld, lon = add_cyclic_point(umdlfld_nowrap, coord=umdlfld_nowrap['lon']) - vmdlfld, _ = add_cyclic_point(vmdlfld_nowrap, coord=vmdlfld_nowrap['lon']) - uobsfld, _ = add_cyclic_point(uobsfld_nowrap, coord=uobsfld_nowrap['lon']) - vobsfld, _ = add_cyclic_point(vobsfld_nowrap, coord=vobsfld_nowrap['lon']) - udiffld, _ = add_cyclic_point(udiffld_nowrap, coord=udiffld_nowrap['lon']) - vdiffld, _ = add_cyclic_point(vdiffld_nowrap, coord=vdiffld_nowrap['lon']) - - # create mesh for plots: - lons, lats = np.meshgrid(lon, lat) - - # create figure: - fig = plt.figure(figsize=(14,10)) - - # LAYOUT WITH GRIDSPEC - gs = mpl.gridspec.GridSpec(3, 6, wspace=0.5, hspace=0.0) - gs.tight_layout(fig) - ax1 = plt.subplot(gs[0:2, :3], projection=proj) - ax2 = plt.subplot(gs[0:2, 3:], projection=proj) - ax3 = plt.subplot(gs[2, 1:5], projection=proj) - ax = [ax1,ax2,ax3] - - # formatting for tick labels - lon_formatter = LongitudeFormatter(number_format='0.0f', - degree_symbol='', - dateline_direction_label=False) - lat_formatter = LatitudeFormatter(number_format='0.0f', - degree_symbol='') - - # too many vectors to see well, so prune by striding through data: - skip=(slice(None,None,5),slice(None,None,8)) - - # Calculate vector magnitudes. - # Please note that the difference field needs - # to be calculated from the model and obs fields - # in order to get the correct sign: - mdl_mag_ma = np.sqrt(umdlfld**2 + vmdlfld**2) - obs_mag_ma = np.sqrt(uobsfld**2 + vobsfld**2) - - #Convert vector magnitudes to xarray DataArrays: - mdl_mag = xr.DataArray(mdl_mag_ma) - obs_mag = xr.DataArray(obs_mag_ma) - diff_mag = mdl_mag - obs_mag - - # Get difference limits, in order to plot the correct range: - min_diff_val = np.min(diff_mag) - max_diff_val = np.max(diff_mag) - - # Color normalization for difference - if (min_diff_val < 0) and (0 < max_diff_val): - norm_diff = mpl.colors.TwoSlopeNorm(vmin=min_diff_val, vmax=max_diff_val, vcenter=0.0) - else: - norm_diff = mpl.colors.Normalize(vmin=min_diff_val, vmax=max_diff_val) - #End if - - # Generate vector plot: - # - contourf to show magnitude w/ colorbar - # - vectors (colored or not) to show flow --> subjective (?) choice for how to thin out vectors to be legible - img1 = ax1.contourf(lons, lats, mdl_mag, cmap='Greys', transform=ccrs.PlateCarree(), - transform_first=True, extend='both' - ) - ax1.quiver(lons[skip], lats[skip], umdlfld[skip], vmdlfld[skip], mdl_mag.values[skip], - transform=ccrs.PlateCarree(), cmap='Reds') - - img2 = ax2.contourf(lons, lats, obs_mag, cmap='Greys', transform=ccrs.PlateCarree(), - transform_first=True, extend='both' - ) - ax2.quiver(lons[skip], lats[skip], uobsfld[skip], vobsfld[skip], obs_mag.values[skip], - transform=ccrs.PlateCarree(), cmap='Reds') - - # We should think about how to do plot customization and defaults. - # Here I'll just pop off a few custom ones, and then pass the rest into mpl. - if 'tiString' in kwargs: - tiString = kwargs.pop("tiString") - else: - tiString = '' - if 'tiFontSize' in kwargs: - tiFontSize = kwargs.pop('tiFontSize') - else: - tiFontSize = 8 - #End if - - #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) - st.set_y(0.85) - - #Set plot titles - case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" - ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) - - if obs: - obs_var = kwargs["obs_var_name"] - obs_title = kwargs["obs_file"][:-3] - base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" - ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) - else: - base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" - ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) - - #Set stats: area_avg - ax[0].set_title(f"Mean: {mdl_mag.weighted(wgt).mean().item():5.2f}\nMax: {mdl_mag.max():5.2f}\nMin: {mdl_mag.min():5.2f}", loc='right', - fontsize=tiFontSize) - ax[1].set_title(f"Mean: {obs_mag.weighted(wgt).mean().item():5.2f}\nMax: {obs_mag.max():5.2f}\nMin: {obs_mag.min():5.2f}", loc='right', - fontsize=tiFontSize) - ax[-1].set_title(f"Mean: {diff_mag.weighted(wgt).mean().item():5.2f}\nMax: {diff_mag.max():5.2f}\nMin: {diff_mag.min():5.2f}", loc='right', - fontsize=tiFontSize) - - # set rmse title: - ax[-1].set_title(f"RMSE: ", fontsize=tiFontSize) - ax[-1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) - - if "units" in kwargs: - ax[1].set_ylabel(f"[{kwargs['units']}]") - ax[-1].set_ylabel(f"[{kwargs['units']}]") - #End if - - # Add cosmetic plot features: - for a in ax: - a.spines['geo'].set_linewidth(1.5) #cartopy's recommended method - a.coastlines() - a.set_xticks(np.linspace(-180, 120, 6), crs=ccrs.PlateCarree()) - a.set_yticks(np.linspace(-90, 90, 7), crs=ccrs.PlateCarree()) - a.tick_params('both', length=5, width=1.5, which='major') - a.tick_params('both', length=5, width=1.5, which='minor') - a.xaxis.set_major_formatter(lon_formatter) - a.yaxis.set_major_formatter(lat_formatter) - #End for - - # Add colorbar to vector plot: - cb_c2_ax = inset_axes(ax2, - width="5%", # width = 5% of parent_bbox width - height="100%", # height : 100% - loc='lower left', - bbox_to_anchor=(1.05, 0, 1, 1), - bbox_transform=ax2.transAxes, - borderpad=0, - ) - fig.colorbar(img2, cax=cb_c2_ax) - - # Plot vector differences: - img3 = ax3.contourf(lons, lats, diff_mag, transform=ccrs.PlateCarree(), transform_first=True, norm=norm_diff, - cmap='PuOr', alpha=0.5, extend='both' - ) - ax3.quiver(lons[skip], lats[skip], udiffld[skip], vdiffld[skip], transform=ccrs.PlateCarree()) - - # Add color bar to difference plot: - cb_d_ax = inset_axes(ax3, - width="5%", # width = 5% of parent_bbox width - height="100%", # height : 100% - loc='lower left', - bbox_to_anchor=(1.05, 0, 1, 1), - bbox_transform=ax3.transAxes, - borderpad=0 - ) - fig.colorbar(img3, cax=cb_d_ax) - - # Write final figure to file - fig.savefig(wks, bbox_inches='tight', dpi=300) - - #Close plots: - plt.close() - - -####### def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, case_climo_yrs, baseline_climo_yrs, @@ -607,33 +399,80 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, #nice formatting for tick labels from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter - - # preprocess - # - assume all three fields have same lat/lon - lat = obsfld['lat'] - wgt = np.cos(np.radians(lat)) - mwrap, lon = add_cyclic_point(mdlfld, coord=mdlfld['lon']) - owrap, _ = add_cyclic_point(obsfld, coord=obsfld['lon']) - dwrap, _ = add_cyclic_point(diffld, coord=diffld['lon']) - pwrap, _ = add_cyclic_point(pctld, coord=pctld['lon']) - wrap_fields = (mwrap, owrap, pwrap, dwrap) - # mesh for plots: - lons, lats = np.meshgrid(lon, lat) - - # get statistics (from non-wrapped) - fields = (mdlfld, obsfld, diffld, pctld) - area_avg = [utils.spatial_average(x, weights=wgt, spatial_dims=None) for x in fields] - - d_rmse = utils.wgt_rmse(mdlfld, obsfld, wgt) # correct weighted RMSE for (lat,lon) fields. - - # We should think about how to do plot customization and defaults. - # Here I'll just pop off a few custom ones, and then pass the rest into mpl. - if 'tiString' in kwargs: - tiString = kwargs.pop("tiString") + if "vector" in kwargs: + + # too many vectors to see well, so prune by striding through data: + skip=(slice(None,None,5),slice(None,None,8)) + + umdlfld_nowrap = kwargs["umdlfld_nowrap"] + vmdlfld_nowrap = kwargs["vmdlfld_nowrap"] + uobsfld_nowrap = kwargs["uobsfld_nowrap"] + vobsfld_nowrap = kwargs["vobsfld_nowrap"] + udiffld_nowrap = kwargs["udiffld_nowrap"] + vdiffld_nowrap = kwargs["vdiffld_nowrap"] + upctdiffld_nowrap = kwargs["upctdiffld_nowrap"] + vpctdiffld_nowrap = kwargs["vpctdiffld_nowrap"] + + lat = umdlfld_nowrap['lat'] + + # add cyclic longitude: + umdlfld, lon = add_cyclic_point(umdlfld_nowrap, coord=umdlfld_nowrap['lon']) + vmdlfld, _ = add_cyclic_point(vmdlfld_nowrap, coord=vmdlfld_nowrap['lon']) + uobsfld, _ = add_cyclic_point(uobsfld_nowrap, coord=uobsfld_nowrap['lon']) + vobsfld, _ = add_cyclic_point(vobsfld_nowrap, coord=vobsfld_nowrap['lon']) + udiffld, _ = add_cyclic_point(udiffld_nowrap, coord=udiffld_nowrap['lon']) + vdiffld, _ = add_cyclic_point(vdiffld_nowrap, coord=vdiffld_nowrap['lon']) + upctdiffld, _ = add_cyclic_point(upctdiffld_nowrap, coord=upctdiffld_nowrap['lon']) + vpctdiffld, _ = add_cyclic_point(vpctdiffld_nowrap, coord=vpctdiffld_nowrap['lon']) + + # create mesh for plots: + lons, lats = np.meshgrid(lon, lat) + + # Calculate vector magnitudes. + # Please note that the difference field needs + # to be calculated from the model and obs fields + # in order to get the correct sign: + mdl_mag_ma = np.sqrt(umdlfld**2 + vmdlfld**2) + obs_mag_ma = np.sqrt(uobsfld**2 + vobsfld**2) + + #Convert vector magnitudes to xarray DataArrays: + mdl_mag = xr.DataArray(mdl_mag_ma) + obs_mag = xr.DataArray(obs_mag_ma) + sim_mags = [mdl_mag, obs_mag] + diff_mag = mdl_mag - obs_mag + pctdiff_mag = diff_mag / np.abs(obs_mag) * 100.0 + #pctdiff_mag = diff_mag / np.abs((mdl_mag + obs_mag)/2) * 100.0 + pctdiff_mag = pctdiff_mag.where(np.isfinite(pctdiff_mag), np.nan) + pctdiff_mag = pctdiff_mag.fillna(0.0) + + wrap_fields = (umdlfld, uobsfld, udiffld, upctdiffld) + + # get statistics (from non-wrapped) + fields = (mdl_mag, obs_mag, pctdiff_mag, diff_mag) + wgt = np.cos(np.radians(lat)) + #area_avg = [utils.spatial_average(x, weights=wgt, spatial_dims=None) for x in fields] + #area_avg = [400 for x in fields] + d_rmse = utils.wgt_rmse(mdl_mag, obs_mag, wgt) # correct weighted RMSE for (lat,lon) fields else: - tiString = '' - #End if + # preprocess + # - assume all three fields have same lat/lon + lat = obsfld['lat'] + wgt = np.cos(np.radians(lat)) + mwrap, lon = add_cyclic_point(mdlfld, coord=mdlfld['lon']) + owrap, _ = add_cyclic_point(obsfld, coord=obsfld['lon']) + dwrap, _ = add_cyclic_point(diffld, coord=diffld['lon']) + pwrap, _ = add_cyclic_point(pctld, coord=pctld['lon']) + wrap_fields = (mwrap, owrap, pwrap, dwrap) + # mesh for plots: + lons, lats = np.meshgrid(lon, lat) + + # get statistics (from non-wrapped) + fields = (mdlfld, obsfld, diffld, pctld) + area_avg = [utils.spatial_average(x, weights=wgt, spatial_dims=None) for x in fields] + + d_rmse = utils.wgt_rmse(mdlfld, obsfld, wgt) # correct weighted RMSE for (lat,lon) fields. + # We should think about how to do plot customization and defaults. if 'tiFontSize' in kwargs: tiFontSize = kwargs.pop('tiFontSize') else: @@ -642,6 +481,7 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, # generate dictionary of contour plot settings: cp_info = plot_utils.prep_contour_plot(mdlfld, obsfld, diffld, pctld, **kwargs) + units = cp_info['units'] # specify the central longitude for the plot central_longitude = kwargs.get('central_longitude', 180) @@ -650,14 +490,29 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, fig = plt.figure(figsize=(14,10)) # LAYOUT WITH GRIDSPEC - gs = mpl.gridspec.GridSpec(3, 6, wspace=2.0,hspace=0.0) # 2 rows, 4 columns, but each map will take up 2 columns + wspace = 1.66 + hspace = -0.25 + """if "vector" in kwargs: + hspace = 0 + else: + hspace = -0.25""" + gs = mpl.gridspec.GridSpec(3, 6, wspace=wspace, hspace=hspace) # 2 rows, 4 columns, but each map will take up 2 columns proj = ccrs.PlateCarree(central_longitude=central_longitude) ax1 = plt.subplot(gs[0:2, :3], projection=proj, **cp_info['subplots_opt']) ax2 = plt.subplot(gs[0:2, 3:], projection=proj, **cp_info['subplots_opt']) + #Keep this for later in case percent diff is desired in vector plots ax3 = plt.subplot(gs[2, :3], projection=proj, **cp_info['subplots_opt']) ax4 = plt.subplot(gs[2, 3:], projection=proj, **cp_info['subplots_opt']) ax = [ax1,ax2,ax3,ax4] + """if "vector" in kwargs: + ax3 = plt.subplot(gs[2, 1:5], projection=proj, **cp_info['subplots_opt']) + ax = [ax1,ax2,ax3] + else: + ax3 = plt.subplot(gs[2, :3], projection=proj, **cp_info['subplots_opt']) + ax4 = plt.subplot(gs[2, 3:], projection=proj, **cp_info['subplots_opt']) + ax = [ax1,ax2,ax3,ax4]""" + img = [] # contour plots cs = [] # contour lines cb = [] # color bars @@ -669,19 +524,44 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, lat_formatter = LatitudeFormatter(number_format='0.0f', degree_symbol='') - for i, a in enumerate(wrap_fields): + """if "vector" in kwargs: #ignore percent diff for now, think about picking back up later + diff_idx = 2 + else: + pctdiff_idx = 2 + diff_idx = 3""" - if i == len(wrap_fields)-1: + pctdiff_idx = 2 + diff_idx = 3 + for i, a in enumerate(wrap_fields): + if i == diff_idx: levels = cp_info['levels_diff'] cmap = cp_info['cmap_diff'] - norm = cp_info['norm_diff'] extend = cp_info["extend_diff"] - elif i == len(wrap_fields)-2: + if "vector" in kwargs: + # Get difference limits, in order to plot the correct range: + min_diff_val = np.min(diff_mag) + max_diff_val = np.max(diff_mag) + + # Color normalization for difference + if (min_diff_val < 0) and (0 < max_diff_val): + norm = mpl.colors.TwoSlopeNorm(vmin=min_diff_val, vmax=max_diff_val, vcenter=0.0) + else: + norm = mpl.colors.Normalize(vmin=min_diff_val, vmax=max_diff_val) + #End if + else: + norm = cp_info['norm_diff'] + if i == pctdiff_idx: levels = cp_info['levels_pctdiff'] cmap = cp_info['cmap_pctdiff'] + extend = cp_info['extend_pctdiff'] norm = cp_info['norm_pctdiff'] - extend = 'both' - else: + """if "vector" not in kwargs: #non vector lat/lon gets percent diff as third (2) index For now, JR + if i == pctdiff_idx: + levels = cp_info['levels_pctdiff'] + cmap = cp_info['cmap_pctdiff'] + extend = cp_info['extend_pctdiff'] + norm = cp_info['norm_pctdiff']""" + if i in [0,1]: levels = cp_info['levels_sim'] cmap = cp_info['cmap_sim'] norm = cp_info['norm_sim'] @@ -692,11 +572,40 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, img.append(ax[i].contourf(lons,lats,a,colors="w",transform=ccrs.PlateCarree(),transform_first=True)) ax[i].text(0.4, 0.4, empty_message, transform=ax[i].transAxes, bbox=props) else: - img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, + if "vector" in kwargs: + if i == diff_idx: + img.append(ax[i].contourf(lons, lats, diff_mag, transform=ccrs.PlateCarree(), + transform_first=True, norm=norm, + cmap='PuOr', alpha=0.5, extend=extend + )) + ax[i].quiver(lons[skip], lats[skip], udiffld[skip], vdiffld[skip], + transform=ccrs.PlateCarree()) + + + if i == pctdiff_idx: + img.append(ax[i].contourf(lons, lats, pctdiff_mag, transform=ccrs.PlateCarree(), + transform_first=True, norm=norm, + cmap='PuOr', extend=extend + )) + #ax[i].quiver(lons[skip], lats[skip], upctdiffld[skip], vpctdiffld[skip], + # transform=ccrs.PlateCarree()) + + + if i in [0,1]: + img.append(ax[i].contourf(lons, lats, sim_mags[i], cmap='Greys', + transform=ccrs.PlateCarree(), + transform_first=True, extend=extend + )) + ax[i].quiver(lons[skip], lats[skip], umdlfld[skip], vmdlfld[skip], mdl_mag.values[skip], + transform=ccrs.PlateCarree(), cmap='Reds') + ax[i].quiver(lons[skip], lats[skip], uobsfld[skip], vobsfld[skip], obs_mag.values[skip], + transform=ccrs.PlateCarree(), cmap='Reds') + else: + img.append(ax[i].contourf(lons, lats, a, levels=levels, cmap=cmap, norm=norm, transform=ccrs.PlateCarree(), transform_first=True, extend=extend, **cp_info['contourf_opt'])) #End if - ax[i].set_title("AVG: {0:.3f}".format(area_avg[i]), loc='right', fontsize=11) + #ax[i].set_title("AVG: {0:.3f}".format(area_avg[i]), loc='right', fontsize=11) # add contour lines <- Unused for now -JN # TODO: add an option to turn this on -BM @@ -705,8 +614,13 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, #ax[i].text( 10, -140, "CONTOUR FROM {} to {} by {}".format(min(cs[i].levels), max(cs[i].levels), cs[i].levels[1]-cs[i].levels[0]), #bbox=dict(facecolor='none', edgecolor='black'), fontsize=tiFontSize-2) - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=18) - st.set_y(0.85) + var_name = kwargs['var_name'] + if "lev" in kwargs: + lev = kwargs["lev"] + var_name = f"{var_name} at {lev} hPa" + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=14, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) + st.set_y(0.825) #Set plot titles case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" @@ -726,17 +640,28 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, fontsize=tiFontSize) ax[1].set_title(f"Mean: {obsfld.weighted(wgt).mean().item():5.2f}\nMax: {obsfld.max():5.2f}\nMin: {obsfld.min():5.2f}", loc='right', fontsize=tiFontSize) - ax[2].set_title(f"Mean: {pctld.weighted(wgt).mean().item():5.2f}\nMax: {pctld.max():5.2f}\nMin: {pctld.min():5.2f}", loc='right', - fontsize=tiFontSize) - ax[3].set_title(f"Mean: {diffld.weighted(wgt).mean().item():5.2f}\nMax: {diffld.max():5.2f}\nMin: {diffld.min():5.2f}", loc='right', - fontsize=tiFontSize) + """if "vector" not in kwargs: + ax[pctdiff_idx].set_title(f"Mean: {pctld.weighted(wgt).mean().item():5.2f}\nMax: {pctld.max():5.2f}\nMin: {pctld.min():5.2f}", loc='right', + fontsize=tiFontSize) + ax[diff_idx].set_title(f"Mean: {diffld.weighted(wgt).mean().item():5.2f}\nMax: {diffld.max():5.2f}\nMin: {diffld.min():5.2f}", loc='right', + fontsize=tiFontSize) + ax[pctdiff_idx].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") + ax[diff_idx].set_title(f"RMSE: {d_rmse:.3f}", fontsize=tiFontSize) + ax[diff_idx].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) + else: + ax[diff_idx].set_title(f"Mean: {diffld.weighted(wgt).mean().item():5.2f}\nMax: {diffld.max():5.2f}\nMin: {diffld.min():5.2f}", loc='right', + fontsize=tiFontSize) + ax[diff_idx].set_title(f"RMSE: {d_rmse:.3f}", fontsize=tiFontSize) + ax[diff_idx].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize)""" - # set rmse title: - ax[3].set_title(f"RMSE: {d_rmse:.3f}", fontsize=tiFontSize) - ax[3].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) - ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") + ax[diff_idx].set_title(f"Mean: {diffld.weighted(wgt).mean().item():5.2f}\nMax: {diffld.max():5.2f}\nMin: {diffld.min():5.2f}", loc='right', + fontsize=tiFontSize) + ax[pctdiff_idx].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") + ax[diff_idx].set_title(f"RMSE: {d_rmse:.3f}", fontsize=tiFontSize) + ax[diff_idx].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) for a in ax: + a.tick_params(axis='both', labelsize=8) a.spines['geo'].set_linewidth(1.5) #cartopy's recommended method a.coastlines() a.set_xticks(np.linspace(-180, 120, 6), crs=ccrs.PlateCarree()) @@ -747,37 +672,54 @@ def plot_map_and_save(adfobj, wks, case_nickname, base_nickname, a.yaxis.set_major_formatter(lat_formatter) # __COLORBARS__ - cb_mean_ax = inset_axes(ax2, - width="5%", # width = 5% of parent_bbox width - height="100%", # height : 100% + cb_mean_ax = inset_axes(ax[1], + width="5%", + height="100%", loc='lower left', - bbox_to_anchor=(1.05, 0, 1, 1), + bbox_to_anchor=(1.02, 0, 1, 1), bbox_transform=ax2.transAxes, borderpad=0, ) - fig.colorbar(img[1], cax=cb_mean_ax, **cp_info['colorbar_opt']) + cbar = fig.colorbar(img[1], cax=cb_mean_ax, **cp_info['colorbar_opt']) + cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad, loc='left') + cbar.ax.tick_params(labelsize=cbar_size) + + """if "vector" not in kwargs: + cb_pct_ax = inset_axes(ax[pctdiff_idx], + width="5%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax3.transAxes, + borderpad=0, + ) + pctdiff_cbar = fig.colorbar(img[pctdiff_idx], cax=cb_pct_ax, **cp_info['pct_colorbar_opt']) + pctdiff_cbar.ax.set_title("%", fontsize=cbar_size, pad=cbar_labelpad, loc='left') + pctdiff_cbar.ax.tick_params(labelsize=cbar_size)""" + cb_pct_ax = inset_axes(ax[pctdiff_idx], + width="5%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax3.transAxes, + borderpad=0, + ) + pctdiff_cbar = fig.colorbar(img[pctdiff_idx], cax=cb_pct_ax, **cp_info['pct_colorbar_opt']) + pctdiff_cbar.ax.set_title("%", fontsize=cbar_size, pad=cbar_labelpad, loc='left') + pctdiff_cbar.ax.tick_params(labelsize=cbar_size) - cb_pct_ax = inset_axes(ax3, - width="5%", # width = 5% of parent_bbox width - height="100%", # height : 100% - loc='lower left', - bbox_to_anchor=(1.05, 0, 1, 1), - bbox_transform=ax3.transAxes, - borderpad=0, - ) - PCT_CB = fig.colorbar(img[2], cax=cb_pct_ax, **cp_info['colorbar_opt']) - PCT_CB.ax.set_ylabel="%" - - cb_diff_ax = inset_axes(ax4, - width="5%", # width = 5% of parent_bbox width - height="100%", # height : 100% + cb_diff_ax = inset_axes(ax[diff_idx], + width="5%", + height="100%", loc='lower left', - bbox_to_anchor=(1.05, 0, 1, 1), - bbox_transform=ax4.transAxes, + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[diff_idx].transAxes, borderpad=0, ) - fig.colorbar(img[3], cax=cb_diff_ax, **cp_info['colorbar_opt']) + diff_cbar = fig.colorbar(img[diff_idx], cax=cb_diff_ax, **cp_info['diff_colorbar_opt']) + diff_cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad, loc='left') + diff_cbar.ax.tick_params(labelsize=cbar_size) # Write final figure to file fig.savefig(wks, bbox_inches='tight', dpi=300) @@ -908,6 +850,34 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, tiFontSize = 8 #End if + azm = utils.zonal_mean_xr(adata) + bzm = utils.zonal_mean_xr(bdata) + diff = azm - bzm + + # calculate the percent change + pct = (azm - bzm) / np.abs(bzm) * 100.0 + #check if pct has NaN's or Inf values and if so set them to 0 to prevent plotting errors + pct = pct.where(np.isfinite(pct), np.nan) + pct = pct.fillna(0.0) + + # generate dictionary of contour plot settings: + cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) + units = cp_info['units'] + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + norm_diff = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] + + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] + extend_pctdiff = cp_info['extend_pctdiff'] + + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim'] + #Set plot titles case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" @@ -932,8 +902,9 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, pct = pct.where(np.isfinite(pct), np.nan) pct = pct.fillna(0.0) - # generate dictionary of contour plot settings: + """# generate dictionary of contour plot settings: cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) + levels_diff = cp_info['levels_diff'] cmap_diff = cp_info['cmap_diff'] norm_diff = cp_info['norm_diff'] @@ -942,21 +913,23 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, levels_pctdiff = cp_info['levels_pctdiff'] cmap_pctdiff = cp_info['cmap_pctdiff'] norm_pctdiff = cp_info['norm_pctdiff'] + extend_pctdiff = cp_info['extend_pctdiff'] levels_sim = cp_info['levels_sim'] cmap_sim = cp_info['cmap_sim'] norm_sim = cp_info['norm_sim'] - extend_sim = cp_info['extend_sim'] + extend_sim = cp_info['extend_sim']""" # Generate zonal plot: - fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) + fig, ax = plt.subplots(figsize=(8,10),nrows=4, constrained_layout=True, + sharex=True, sharey=True,**cp_info['subplots_opt']) levs = np.unique(np.array(levels_sim)) alat = adata['lat'] blat = bdata['lat'] levs_diff = np.unique(np.array(levels_diff)) levs_pct_diff = np.unique(np.array(levels_pctdiff)) - + cbar_labelpad_zonal = 3 if len(levs) < 2: img0, ax[0] = zonal_plot(alat, azm, ax=ax[0]) ax[0].text(0.4, 0.4, empty_message, transform=ax[0].transAxes, bbox=props) @@ -969,8 +942,30 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, img1, ax[1] = zonal_plot(blat, bzm, ax=ax[1], norm=norm_sim,cmap=cmap_sim, levels=levels_sim, extend=extend_sim, **cp_info['contourf_opt']) - fig.colorbar(img0, ax=ax[0], location='right',**cp_info['colorbar_opt']) - fig.colorbar(img1, ax=ax[1], location='right',**cp_info['colorbar_opt']) + + cb_mean_ax = inset_axes(ax[0], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[0].transAxes, + borderpad=0, + ) + cbar0 = fig.colorbar(img0, cax=cb_mean_ax, location='right',**cp_info['colorbar_opt']) + cbar0.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + cbar0.ax.tick_params(labelsize=cbar_size) + + cb_mean_ax = inset_axes(ax[1], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[1].transAxes, + borderpad=0, + ) + cbar1 = fig.colorbar(img1, cax=cb_mean_ax, location='right',**cp_info['colorbar_opt']) + cbar1.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + cbar1.ax.tick_params(labelsize=cbar_size) #End if if len(levs_diff) < 2: @@ -980,41 +975,67 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, img2, ax[2] = zonal_plot(alat, diff, ax=ax[2], norm=norm_diff,cmap=cmap_diff, levels=levels_diff, extend=extend_diff, **cp_info['diff_colorbar_opt']) - fig.colorbar(img2, ax=ax[2], location='right',**cp_info['diff_colorbar_opt']) + diffcb_mean_ax = inset_axes(ax[2], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[2].transAxes, + borderpad=0, + ) + diff_cbar = fig.colorbar(img2, cax=diffcb_mean_ax, location='right',**cp_info['colorbar_opt']) + diff_cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + diff_cbar.ax.tick_params(labelsize=cbar_size) if len(levs_pct_diff) < 2: img3, ax[3] = zonal_plot(alat, pct, ax=ax[3]) ax[3].text(0.4, 0.4, empty_message, transform=ax[3].transAxes, bbox=props) else: img3, ax[3] = zonal_plot(alat, pct, ax=ax[3], norm=norm_pctdiff,cmap=cmap_pctdiff, - levels=levels_pctdiff, extend="both", + levels=levels_pctdiff, extend=extend_pctdiff, **cp_info['pct_colorbar_opt']) - fig.colorbar(img3, ax=ax[3], location='right',**cp_info['pct_colorbar_opt']) + pctdiffcb_mean_ax = inset_axes(ax[3], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[3].transAxes, + borderpad=0, + ) + pctdiff_cbar = fig.colorbar(img3, cax=pctdiffcb_mean_ax, location='right',**cp_info['colorbar_opt']) + pctdiff_cbar.ax.set_title("%", fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + pctdiff_cbar.ax.tick_params(labelsize=cbar_size) ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) ax[2].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) ax[3].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") - # style the plot: #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=15) + var_name = kwargs['var_name'] + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=14, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) st.set_y(0.85) - ax[-1].set_xlabel("LATITUDE") + ax[-1].set_xlabel("LATITUDE", fontsize=tiFontSize) + + for a in ax: + a.tick_params('both', length=5, width=1.5, which='major') + a.tick_params('both', length=5, width=1.5, which='minor') if log_p: [a.set_yscale("log") for a in ax] fig.text(-0.03, 0.5, 'PRESSURE [hPa]', va='center', rotation='vertical') else: - line = Line2D([0], [0], label="$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", + line = Line2D([0], [0], label="$\mathbf{Test}:$"+case_nickname, color="#1f77b4") # #1f77b4 -> matplotlib standard blue - - line2 = Line2D([0], [0], label=base_title, + line2 = Line2D([0], [0], label="$\mathbf{Baseline}:$"+base_nickname, color="#ff7f0e") # #ff7f0e -> matplotlib standard orange + byears = f"years: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + tyears = f"years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" - azm = utils.zonal_mean_xr(adata) + """azm = utils.zonal_mean_xr(adata) bzm = utils.zonal_mean_xr(bdata) diff = azm - bzm @@ -1024,32 +1045,84 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, pct = pct.where(np.isfinite(pct), np.nan) pct = pct.fillna(0.0) - fig, ax = plt.subplots(nrows=3) - ax = [ax[0],ax[1],ax[2]] + # generate dictionary of contour plot settings: + cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) + units = cp_info['units'] + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + norm_diff = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] + + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] + extend_pctdiff = cp_info['extend_pctdiff'] + + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim']""" + + + fig, ax = plt.subplots(nrows=3)#figsize=(6,8), + ax[0].set_title(f"{tyears}\n{byears}", loc='right', fontsize=6) #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=15) - st.set_y(1.02) + var_name = kwargs['var_name'] + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=12, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) + st.set_y(1) zonal_plot(adata['lat'], azm, ax=ax[0],color="#1f77b4") # #1f77b4 -> matplotlib standard blue zonal_plot(bdata['lat'], bzm, ax=ax[0],color="#ff7f0e") # #ff7f0e -> matplotlib standard orange - fig.legend(handles=[line,line2],bbox_to_anchor=(-0.15, 0.87, 1.05, .102),loc="right", - borderaxespad=0.0,fontsize=6,frameon=False) - - zonal_plot(adata['lat'], diff, ax=ax[1], color="k") - ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) - - zonal_plot(adata['lat'], pct, ax=ax[2], color="k") - ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=10,fontweight="bold") + fig.legend(handles=[line,line2],bbox_to_anchor=(0.125, 0.84, 1.05, .102),loc="upper left", + borderaxespad=0.0,fontsize=6,frameon=False,labelspacing=0.3) + + zonal_plot( + adata['lat'], diff, + ax=ax[1], + use_cmap=True, + cmap=cmap_diff, + norm=norm_diff + ) + ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=6) + ax[1].set_ylabel(units, fontsize=6) + + zonal_plot( + adata['lat'], pct, + ax=ax[2], + use_cmap=True, + cmap=cmap_pctdiff, + norm=norm_pctdiff + ) + ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=6,fontweight="bold") + ax[2].set_ylabel("%", fontsize=6) + + ax[-1].set_xlabel("LATITUDE", fontsize=6) for a in ax: - try: - a.label_outer() - except: - pass - #End except + a.tick_params('both', length=3, width=1, which='major') + a.tick_params('both', length=3, width=1, which='minor') + a.tick_params(axis='both', labelsize=6) + # Set the maximum number of ticks desired + #a.xaxis.set_major_locator(MaxNLocator(nbins=5)) + a.yaxis.set_major_locator(MaxNLocator(nbins=8)) + a.grid(True) #End for + + plt.subplots_adjust(wspace= 0.01, hspace= 0.5, right=0.85) + + # Create colorbar axes (same width for both) + cax1 = fig.add_axes([0.86, 0.4, 0.02, 0.1925]) # [left, bottom, width, height] + cax2 = fig.add_axes([0.86, 0.11, 0.02, 0.1925]) + ax[1].set_facecolor("0.5") # dark gray + ax[2].set_facecolor("0.5") + + diff_cbar = fig.colorbar(ax[1]._last_linecollection, cax=cax1) + diff_cbar.ax.tick_params(labelsize=6) + pctdiff_cbar = fig.colorbar(ax[2]._last_linecollection, cax=cax2) + pctdiff_cbar.ax.tick_params(labelsize=6) #End if #Write the figure to provided workspace/file: @@ -1129,7 +1202,7 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, colorbar: shrink: 0.4 ``` - """ + """ kwargs["adfobj"] = adfobj # apply averaging: @@ -1171,6 +1244,10 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, if len(adata.dims) > 2: print(f"ERROR: plot_meridonal_mean_and_save - AFTER averaging, there are too many dimensions: {adata.dims}") return None + + # plot-controlling parameters: + xdim = 'lon' # the name used for the x-axis dimension + pltfunc = meridional_plot # the plotting function ... maybe we can generalize to get zonal/meridional into one function (?) diff = adata - bdata @@ -1180,10 +1257,26 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, pct = pct.where(np.isfinite(pct), np.nan) pct = pct.fillna(0.0) - # plot-controlling parameters: - xdim = 'lon' # the name used for the x-axis dimension - pltfunc = meridional_plot # the plotting function ... maybe we can generalize to get zonal/meridional into one function (?) + # generate dictionary of contour plot settings: + cp_info = plot_utils.prep_contour_plot(adata, bdata, diff, pct, **kwargs) + units = cp_info['units'] + + levels_diff = cp_info['levels_diff'] + cmap_diff = cp_info['cmap_diff'] + norm_diff = cp_info['norm_diff'] + extend_diff = cp_info['extend_diff'] + levels_pctdiff = cp_info['levels_pctdiff'] + cmap_pctdiff = cp_info['cmap_pctdiff'] + norm_pctdiff = cp_info['norm_pctdiff'] + extend_pctdiff = cp_info['extend_pctdiff'] + + levels_sim = cp_info['levels_sim'] + cmap_sim = cp_info['cmap_sim'] + norm_sim = cp_info['norm_sim'] + extend_sim = cp_info['extend_sim'] + + #Set plot titles case_title = "$\mathbf{Test}:$"+f"{case_nickname}\nyears: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" if obs: @@ -1192,30 +1285,16 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, base_title = "$\mathbf{Baseline}:$"+obs_title+"\n"+"$\mathbf{Variable}:$"+f"{obs_var}" else: base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" - if has_lev: - # generate dictionary of contour plot settings: - cp_info = plot_utils.prep_contour_plot(adata, bdata, diff, pct, **kwargs) - levels_diff = cp_info['levels_diff'] - cmap_diff = cp_info['cmap_diff'] - norm_diff = cp_info['norm_diff'] - extend_diff = cp_info['extend_diff'] - levels_pctdiff = cp_info['levels_pctdiff'] - cmap_pctdiff = cp_info['cmap_pctdiff'] - norm_pctdiff = cp_info['norm_pctdiff'] - - levels_sim = cp_info['levels_sim'] - cmap_sim = cp_info['cmap_sim'] - norm_sim = cp_info['norm_sim'] - extend_sim = cp_info['extend_sim'] + # Generate zonal plot: + fig, ax = plt.subplots(figsize=(8,10),nrows=4, constrained_layout=True, + sharex=True, sharey=True,**cp_info['subplots_opt']) - # generate plot objects: - fig, ax = plt.subplots(figsize=(10,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) levs = np.unique(np.array(levels_sim)) levs_diff = np.unique(np.array(levels_diff)) - levs_pctdiff = np.unique(np.array(levels_pctdiff)) - + levs_pct_diff = np.unique(np.array(levels_pctdiff)) + cbar_labelpad_zonal = 3 if len(levs) < 2: img0, ax[0] = pltfunc(adata[xdim], adata, ax=ax[0]) ax[0].text(0.4, 0.4, empty_message, transform=ax[0].transAxes, bbox=props) @@ -1223,13 +1302,35 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, ax[1].text(0.4, 0.4, empty_message, transform=ax[1].transAxes, bbox=props) else: img0, ax[0] = pltfunc(adata[xdim], adata, ax=ax[0], norm=norm_sim,cmap=cmap_sim, - levels=levels_sim, extend=extend_sim, - **cp_info['contourf_opt']) + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) img1, ax[1] = pltfunc(bdata[xdim], bdata, ax=ax[1], norm=norm_sim,cmap=cmap_sim, - levels=levels_sim, extend=extend_sim, - **cp_info['contourf_opt']) - cb0 = fig.colorbar(img0, ax=ax[0], location='right', **cp_info['colorbar_opt']) - cb1 = fig.colorbar(img1, ax=ax[1], location='right', **cp_info['colorbar_opt']) + levels=levels_sim, extend=extend_sim, + **cp_info['contourf_opt']) + + cb_mean_ax = inset_axes(ax[0], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[0].transAxes, + borderpad=0, + ) + cbar0 = fig.colorbar(img0, cax=cb_mean_ax, location='right',**cp_info['colorbar_opt']) + cbar0.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + cbar0.ax.tick_params(labelsize=cbar_size) + + cb_mean_ax = inset_axes(ax[1], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[1].transAxes, + borderpad=0, + ) + cbar1 = fig.colorbar(img1, cax=cb_mean_ax, location='right',**cp_info['colorbar_opt']) + cbar1.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + cbar1.ax.tick_params(labelsize=cbar_size) #End if if len(levs_diff) < 2: @@ -1237,67 +1338,129 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, ax[2].text(0.4, 0.4, empty_message, transform=ax[2].transAxes, bbox=props) else: img2, ax[2] = pltfunc(adata[xdim], diff, ax=ax[2], norm=norm_diff,cmap=cmap_diff, - levels=levels_diff, extend=extend_diff, - **cp_info['diff_colorbar_opt']) - cb2 = fig.colorbar(img2, ax=ax[2], location='right', **cp_info['diff_colorbar_opt']) + levels=levels_diff, extend=extend_diff, + **cp_info['diff_colorbar_opt']) + diffcb_mean_ax = inset_axes(ax[2], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[2].transAxes, + borderpad=0, + ) + diff_cbar = fig.colorbar(img2, cax=diffcb_mean_ax, location='right',**cp_info['colorbar_opt']) + diff_cbar.ax.set_title(units, fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + diff_cbar.ax.tick_params(labelsize=cbar_size) - if len(levs_pctdiff) < 2: + if len(levs_pct_diff) < 2: img3, ax[3] = pltfunc(adata[xdim], pct, ax=ax[3]) ax[3].text(0.4, 0.4, empty_message, transform=ax[3].transAxes, bbox=props) else: img3, ax[3] = pltfunc(adata[xdim], pct, ax=ax[3], norm=norm_pctdiff,cmap=cmap_pctdiff, - levels=levels_pctdiff, **cp_info['pct_colorbar_opt']) - cb3 = fig.colorbar(img3, ax=ax[3], location='right',**cp_info['pct_colorbar_opt']) + levels=levels_pctdiff, extend=extend_pctdiff, + **cp_info['pct_colorbar_opt']) + pctdiffcb_mean_ax = inset_axes(ax[3], + width="2%", + height="100%", + loc='lower left', + bbox_to_anchor=(1.02, 0, 1, 1), + bbox_transform=ax[3].transAxes, + borderpad=0, + ) + pctdiff_cbar = fig.colorbar(img3, cax=pctdiffcb_mean_ax, location='right',**cp_info['colorbar_opt']) + pctdiff_cbar.ax.set_title("%", fontsize=cbar_size, pad=cbar_labelpad_zonal, loc='left') + pctdiff_cbar.ax.tick_params(labelsize=cbar_size) - #Set plot titles ax[0].set_title(case_title, loc='left', fontsize=tiFontSize) ax[1].set_title(base_title, loc='left', fontsize=tiFontSize) ax[2].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=tiFontSize) - ax[3].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize, fontweight = "bold") + ax[3].set_title("Test % Diff Baseline", loc='left', fontsize=tiFontSize,fontweight="bold") # style the plot: #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=15) + var_name = kwargs['var_name'] + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=14, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) st.set_y(0.85) - ax[-1].set_xlabel("LONGITUDE") - if cp_info['plot_log_p']: + ax[-1].set_xlabel("LONGITUDE", fontsize=tiFontSize) + + for a in ax: + a.tick_params('both', length=5, width=1.5, which='major') + a.tick_params('both', length=5, width=1.5, which='minor') + + if log_p: [a.set_yscale("log") for a in ax] - fig.text(-0.03, 0.5, 'PRESSURE [hPa]', va='center', rotation='vertical') + fig.text(-0.03, 0.5, 'PRESSURE [hPa]', va='center', rotation='vertical') else: - line = Line2D([0], [0], label="$\mathbf{Test}:$"+f"{case_nickname} - years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}", + line = Line2D([0], [0], label="$\mathbf{Test}:$"+case_nickname, color="#1f77b4") # #1f77b4 -> matplotlib standard blue - - line2 = Line2D([0], [0], label=base_title, + line2 = Line2D([0], [0], label="$\mathbf{Baseline}:$"+base_nickname, color="#ff7f0e") # #ff7f0e -> matplotlib standard orange - - + byears = f"years: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" + tyears = f"years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" fig, ax = plt.subplots(nrows=3) - ax = [ax[0],ax[1],ax[2]] + ax[0].set_title(f"{tyears}\n{byears}", loc='right', fontsize=6) + + #Set Main title for subplots: + var_name = kwargs['var_name'] + st = fig.suptitle(f"{var_name}: {kwargs['season']}", fontsize=12, + fontfamily=["DejaVu Sans", "Liberation Sans", "sans-serif"]) + st.set_y(1) pltfunc(adata[xdim], adata, ax=ax[0],color="#1f77b4") # #1f77b4 -> matplotlib standard blue pltfunc(bdata[xdim], bdata, ax=ax[0],color="#ff7f0e") # #ff7f0e -> matplotlib standard orange - pltfunc(adata[xdim], diff, ax=ax[1], color="k") - pltfunc(adata[xdim], pct, ax=ax[2], color="k") - ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=10) - ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=10, fontweight = "bold") + fig.legend(handles=[line,line2],bbox_to_anchor=(0.125, 0.84, 1.05, .102),loc="upper left", + borderaxespad=0.0,fontsize=6,frameon=False,labelspacing=0.3) - #Set Main title for subplots: - st = fig.suptitle(wks.stem[:-5].replace("_"," - "), fontsize=15) - st.set_y(1.02) + pltfunc( + adata[xdim], diff, + ax=ax[1], + use_cmap=True, + cmap="RdBu_r", + norm=norm_diff + ) + + ax[1].set_title("$\mathbf{Test} - \mathbf{Baseline}$", loc='left', fontsize=6) + ax[1].set_ylabel(units, fontsize=6) + + pltfunc( + adata[xdim], pct, + ax=ax[2], + use_cmap=True, + cmap="PuOr", + norm=norm_pctdiff + ) + + ax[2].set_title("Test % Diff Baseline", loc='left', fontsize=6,fontweight="bold") + ax[2].set_ylabel("%", fontsize=6) - fig.legend(handles=[line,line2],bbox_to_anchor=(-0.15, 0.87, 1.05, .102),loc="right", - borderaxespad=0.0,fontsize=6,frameon=False) + ax[-1].set_xlabel("LONGITUDE", fontsize=6) for a in ax: - try: - a.label_outer() - except: - pass - #End except + a.tick_params('both', length=3, width=1, which='major') + a.tick_params('both', length=3, width=1, which='minor') + a.tick_params(axis='both', labelsize=6) + # Set the maximum number of ticks desired + #a.xaxis.set_major_locator(MaxNLocator(nbins=5)) + a.yaxis.set_major_locator(MaxNLocator(nbins=8)) + a.grid(True) #End for + + plt.subplots_adjust(wspace= 0.01, hspace= 0.5, right=0.85) + + # Create colorbar axes (same width for both) + cax1 = fig.add_axes([0.86, 0.4, 0.02, 0.1925]) # [left, bottom, width, height] + cax2 = fig.add_axes([0.86, 0.11, 0.02, 0.1925]) + ax[1].set_facecolor("0.5") # dark gray + ax[2].set_facecolor("0.5") + + diff_cbar = fig.colorbar(ax[1]._last_linecollection, cax=cax1) + diff_cbar.ax.tick_params(labelsize=6) + pctdiff_cbar = fig.colorbar(ax[2]._last_linecollection, cax=cax2) + pctdiff_cbar.ax.tick_params(labelsize=6) #End if #Write the figure to provided workspace/file: @@ -1306,7 +1469,6 @@ def plot_meridional_mean_and_save(adfobj, wks, case_nickname, base_nickname, #Close plots: plt.close() - ####### def square_contour_difference(fld1, fld2, **kwargs): From ab260c3d6f78fb3f60b3f2efd84aa486fc14dd60 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:19:18 -0600 Subject: [PATCH 34/43] Add nick name option for variables --- lib/adf_variable_defaults.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/adf_variable_defaults.yaml b/lib/adf_variable_defaults.yaml index 3e22890a2..439b7930c 100644 --- a/lib/adf_variable_defaults.yaml +++ b/lib/adf_variable_defaults.yaml @@ -1416,6 +1416,7 @@ U10: category: "Surface variables" Surface_Wind_Stress: + nickname: "Surface Wind Stress" new_unit: "N m$^{-2}$" category: "Surface variables" From 2271bb7c0090d9ad3982f7f5a420d04c53fb2ab3 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:20:03 -0600 Subject: [PATCH 35/43] Remove percent diff vals (now stored as defaults) --- lib/adf_variable_defaults_era5-1deg.yaml | 444 ----------------------- 1 file changed, 444 deletions(-) diff --git a/lib/adf_variable_defaults_era5-1deg.yaml b/lib/adf_variable_defaults_era5-1deg.yaml index f4adabb8e..aba523d8c 100644 --- a/lib/adf_variable_defaults_era5-1deg.yaml +++ b/lib/adf_variable_defaults_era5-1deg.yaml @@ -153,8 +153,6 @@ AODDUST: scale_factor: 1 add_offset: 0 new_unit: "" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" AODVIS: category: "Aerosols" @@ -165,8 +163,6 @@ AODVIS: scale_factor: 1 add_offset: 0 new_unit: "" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" AODVISdn: category: "Aerosols" @@ -180,8 +176,6 @@ AODVISdn: obs_file: "MOD08_M3_192x288_AOD_2001-2020_climo.nc" obs_name: "MODIS" obs_var_name: "AOD_550_Dark_Target_Deep_Blue_Combined_Mean_Mean" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" BURDENBC: category: "Aerosols" @@ -189,8 +183,6 @@ BURDENBC: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" obs_file: "BURDENBC_MERRA2_monthly_climo_1degree_200001-202506.nc" obs_var_name: "BURDENBC" @@ -204,8 +196,6 @@ BURDENDUST: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_contour_range: [-1000, 1100, 100] diff_colormap: "RdBu_r" obs_file: "BURDENDUST_CAMS_monthly_climo_1degree_200301-202412.nc" @@ -220,8 +210,6 @@ BURDENPOM: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" @@ -233,8 +221,6 @@ BURDENSEASALT: new_unit: 'g m$^{-2}$' diff_contour_range: [-200, 200, 25] diff_colormap: "RdBu_r" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" obs_file: "BURDENSEASALT_CAMS_monthly_climo_1degree_200301-202412.nc" obs_var_name: "BURDENSEASALT" obs_name: "CAMS" @@ -247,8 +233,6 @@ BURDENSO4: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" obs_file: "BURDENSO4_CAMS_monthly_climo_1degree_200301-202412.nc" obs_name: "CAMS" @@ -262,16 +246,12 @@ BURDENSOA: scale_factor: 1000000 add_offset: 0 new_unit: 'g m$^{-2}$' - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" diff_colormap: "RdBu_r" DMS: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -279,8 +259,6 @@ SO2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -288,8 +266,6 @@ SOAG: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -301,8 +277,6 @@ BC: new_unit: '$\mu$g/m3' category: "Aerosols" derivable_from: ["bc_a1", "bc_a4"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" POM: colormap: "RdBu_r" @@ -312,8 +286,6 @@ POM: new_unit: '$\mu$g/m3' category: "Aerosols" derivable_from: ["pom_a1", "pom_a4"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SO4: colormap: "RdBu_r" @@ -324,8 +296,6 @@ SO4: category: "Aerosols" derivable_from: ["so4_a1", "so4_a2", "so4_a3"] derivable_from_cam_chem: ["so4_a1", "so4_a2", "so4_a3", "so4_a5"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SOA: colormap: "RdBu_r" @@ -336,8 +306,6 @@ SOA: category: "Aerosols" derivable_from: ["soa_a1", "soa_a2"] derivable_from_cam_chem: ["soa1_a1", "soa2_a1", "soa3_a1", "soa4_a1", "soa5_a1", "soa1_a2", "soa2_a2", "soa3_a2", "soa4_a2", "soa5_a2"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" DUST: colormap: "RdBu_r" @@ -349,8 +317,6 @@ DUST: new_unit: '$\mu$g/m3' category: "Aerosols" derivable_from: ["dst_a1", "dst_a2", "dst_a3"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SeaSalt: colormap: "RdBu_r" @@ -367,8 +333,6 @@ SeaSalt: ticks: [-10,8,6,4,2,0,-2,-4,-6,-8,-10] category: "Aerosols" derivable_from: ["ncl_a1", "ncl_a2", "ncl_a3"] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" bc_a1: category: "Aerosols" @@ -376,184 +340,138 @@ bc_a1: diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" bc_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" dst_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ncl_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" num_a5: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" pom_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" pom_a4: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" so4_a3: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" soa_a1: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" soa_a2: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0e-9 new_unit: "ug/kg" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_TROP: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_AERO: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SAD_SULFC: category: "Aerosols" colormap: "jet" diff_colormap: "gist_ncar" scale_factor: 1.0 new_unit: "cm2/cm3" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Budget @@ -635,456 +553,342 @@ CO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO01: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO02: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO03: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO04: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO05: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO06: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO07: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO08: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO09: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO10: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO11: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO12: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO13: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" O3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" N2O: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HNO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NOX: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" NOY: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000000.0 new_unit: "pptv" BIGALK: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H5OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C2H6: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H6: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H7O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H7OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" C3H8: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CCL4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC11: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC113: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC114: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC115: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CFC12: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH2O: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3BR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CCL3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CHO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3CO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COCH3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COCHO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3COOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3OH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH3OOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CH4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CHBR3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLONO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLOX: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CLOY: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" CO2: @@ -1092,344 +896,258 @@ CO2: #contour_levels_range: [300,450,10.0] colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000.0 new_unit: "ppmv" E90: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" GLYALD: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" GLYOXAL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2402: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2O2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" H2SO4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC141B: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC142B: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCFC22: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCL: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HCL_GAS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HNO3_GAS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HO2NO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HOBR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HYAC: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" HYDRALD: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOP: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPNO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ISOPOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACRO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MACROOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" MVK: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" N2O5: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NH3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NH4: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" NO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" O3S: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" OCLO: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" OCS: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ONITR: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" PAN: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" POOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" RO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" ROOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" SO3: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" SOAE: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" TERP: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" XO2: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" XOOH: category: "Composition" colormap: "jet" diff_colormap: "gist_ncar" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 1000000000.0 new_unit: "ppbv" @@ -1443,16 +1161,12 @@ CLDICE: obs_file: "CLDICE_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDICE" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDLIQ: category: "Clouds" obs_file: "CLDLIQ_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "CLDLIQ" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDTOT: colormap: "Oranges" @@ -1466,8 +1180,6 @@ CLDTOT: obs_name: "ERAI" obs_var_name: "CLDTOT" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDLOW: colormap: "Oranges" @@ -1481,8 +1193,6 @@ CLDLOW: obs_name: "ERAI" obs_var_name: "CLDLOW" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDHGH: colormap: "Oranges" @@ -1496,8 +1206,6 @@ CLDHGH: obs_name: "ERAI" obs_var_name: "CLDHGH" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDMED: colormap: "Oranges" @@ -1511,8 +1219,6 @@ CLDMED: obs_name: "ERAI" obs_var_name: "CLDMED" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLOUD: colormap: "Blues" @@ -1523,8 +1229,6 @@ CLOUD: add_offset: 0 new_unit: "Percent" category: "Clouds" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CONCLD: category: "Clouds" @@ -1543,8 +1247,6 @@ TGCLDLWP: obs_var_name: "TGCLDLWP" obs_scale_factor: 1000 obs_add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TGCLDIWP: colormap: "Blues" @@ -1560,8 +1262,6 @@ TGCLDIWP: obs_var_name: "TGCLDIWP" obs_scale_factor: 1000 obs_add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CCN3: category: "Clouds" @@ -1595,8 +1295,6 @@ PRECC: add_offset: 0 new_unit: "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECL: colormap: "Greens" @@ -1607,8 +1305,6 @@ PRECL: add_offset: 0 new_unit: "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECSC: colormap: "Greens" @@ -1619,8 +1315,6 @@ PRECSC: add_offset: 0 new_unit: "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECSL: colormap: "Greens" @@ -1631,8 +1325,6 @@ PRECSL: add_offset: 0 new_unit: "mm d$^{-1}$" category: "Hydrologic cycle" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PRECT: colormap: "Blues" @@ -1647,8 +1339,6 @@ PRECT: obs_var_name: "PRECT" category: "Hydrologic cycle" derivable_from: ['PRECL','PRECC'] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" QFLX: category: "Hydrologic cycle" @@ -1675,8 +1365,6 @@ PSL: obs_file: "PSL_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "PSL" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PS: colormap: "Oranges" @@ -1690,8 +1378,6 @@ PS: obs_file: "PS_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "PS" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TREFHT: category: "Surface variables" @@ -1711,8 +1397,6 @@ TS: obs_name: "ERAI" obs_var_name: "TS" category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SST: colormap: "Blues" @@ -1727,19 +1411,13 @@ SST: obs_var_name: "TS" category: "Surface variables" mask: "ocean" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" U10: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Surface_Wind_Stress: new_unit: "N m$^{-2}$" category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUX: new_unit: "N m$^{-2}$" @@ -1748,8 +1426,6 @@ TAUX: category: "Surface variables" scale_factor: -1 add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" obs_file: "TAUX_ERA5_monthly_climo_1degree_197901-202212.nc" obs_name: "ERA5" obs_var_name: "TAUX" @@ -1761,23 +1437,15 @@ TAUY: category: "Surface variables" scale_factor: -1 add_offset: 0 - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ICEFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OCNFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LANDFRAC: category: "Surface variables" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" obs_file: "ERA5_LSM_1deg_conservativeregrid.nc" obs_name: "ERA5" obs_var_name: "LANDFRAC" @@ -1798,8 +1466,6 @@ TMQ: obs_name: "ERAI" obs_var_name: "PREH2O" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" RELHUM: colormap: "Blues" @@ -1813,8 +1479,6 @@ RELHUM: obs_name: "ERA5" obs_var_name: "RELHUM" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" U: colormap: "Blues" @@ -1830,8 +1494,6 @@ U: vector_pair: "V" vector_name: "Wind" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" V: colormap: "Blues" @@ -1847,37 +1509,27 @@ V: vector_pair: "U" vector_name: "Wind" category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Q: category: "State" obs_file: "Q_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "Q" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" T: category: "State" obs_file: "T_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "T" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGA: category: "State" obs_file: "OMEGA_ERA5_monthly_climo_1degree_197901-202112.nc" obs_name: "ERA5" obs_var_name: "OMEGA" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGA500: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" scale_factor: 864 add_offset: 0 new_unit: "hPa d$^{-1}$" @@ -1885,23 +1537,15 @@ OMEGA500: PINT: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PMID: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Z3: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" Wind: category: "State" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Radiation @@ -1909,13 +1553,9 @@ Wind: QRL: category: "Radiation" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" QRS: category: "Radiation" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: TOA energy flux @@ -1931,8 +1571,6 @@ RESTOM: new_unit: "W m$^{-2}$" category: "TOA energy flux" derivable_from: ['FLNT','FSNT'] - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SWCF: colormap: "Blues" @@ -1948,8 +1586,6 @@ SWCF: obs_scale_factor: 1 obs_add_offset: 0 category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LWCF: colormap: "Oranges" @@ -1963,8 +1599,6 @@ LWCF: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_lw_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSUTOA: colormap: "Blues" @@ -1975,8 +1609,6 @@ FSUTOA: add_offset: 0 new_unit: "Wm$^{-2}$" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNT: colormap: "Blues" @@ -1990,23 +1622,15 @@ FSNT: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "fsnt" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNTC: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNTOA: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLUT: category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNT: colormap: "Oranges" @@ -2020,8 +1644,6 @@ FLNT: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_all_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNTC: colormap: "Oranges" @@ -2035,8 +1657,6 @@ FLNTC: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_lw_clr_t_mon" category: "TOA energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: Surface energy flux @@ -2044,13 +1664,9 @@ FLNTC: FSDS: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSDSC: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNS: colormap: "Blues" @@ -2064,8 +1680,6 @@ FSNS: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_all_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FSNSC: colormap: "Blues" @@ -2079,8 +1693,6 @@ FSNSC: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_net_sw_clr_t_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLDS: colormap: "Oranges" @@ -2094,23 +1706,15 @@ FLDS: obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "sfc_lw_down_all_mon" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNS: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FLNSC: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SHFLX: category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LHFLX: colormap: "Blues" @@ -2124,8 +1728,6 @@ LHFLX: obs_name: "ERAI" obs_var_name: "LHFLX" category: "Sfc energy flux" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #+++++++++++++++++ # Category: COSP @@ -2133,108 +1735,66 @@ LHFLX: CLDTOT_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLIMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" FISCCP1_COSP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" ICE_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" IWPMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LIQ_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" LWPMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANCLDALB_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANPTOP_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTAU_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTB_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" MEANTBCLR_ISCCP: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" PCTMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" REFFCLIMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" REFFCLWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" SNOW_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUTMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TAUWMODIS: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TOT_CLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" TOT_ICLD_VISTAU: category: "COSP" - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" CLDTOT_CAL: colormap: "cividis" @@ -2313,15 +1873,11 @@ H2O: add_offset: 0 new_unit: "mol mol$^{-1}$" plot_log_pressure: True - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" OMEGAT: colormap: "PuOr_r" diff_colormap: "coolwarm" plot_log_pressure: True - pct_diff_contour_levels: [-100,-75,-50,-40,-30,-20,-10,-8,-6,-4,-2,0,2,4,6,8,10,20,30,40,50,75,100] - pct_diff_colormap: "PuOr_r" #++++++++++++++ # Category: TEM From 9658adab92628448e1169341eb2172b98fc16fcc Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:20:46 -0600 Subject: [PATCH 36/43] Add test yaml for examples of new features --- lib/adf_variable_defaults_test.yaml | 214 ++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 lib/adf_variable_defaults_test.yaml diff --git a/lib/adf_variable_defaults_test.yaml b/lib/adf_variable_defaults_test.yaml new file mode 100644 index 000000000..e32cb21dc --- /dev/null +++ b/lib/adf_variable_defaults_test.yaml @@ -0,0 +1,214 @@ +#+++++++++++++ +# Available ADF Default Plot Types +#+++++++++++++ +default_ptypes: ["Tables","LatLon","LatLon_Vector","Zonal","Meridional", + "NHPolar","SHPolar","TimeSeries","Special"] + +PBLH: + contour_levels: [0, 13, 26] + category: "Surface variables" + obs_file: "PBLH_ERA5_monthly_climo_197901-202112.nc" + obs_name: "ERA5" + obs_var_name: "PBLH" + +PRECT: + #colormap: "GnBu" + # test the new colormap building method with 'fakemap', check if in matplotlib, + # if not check NCL, if nothing after that, default to viridis + #colormap: "fakemap" + polar_map: + colormap: "fakemap" + #nh: "fakemap" + #sh: "GnBu" + global_latlon_map: + colormap: "BrBG" + contour_levels_range: [0, 13, 1] + diff_colormap: "seismic" + diff_contour_range: [-10, 10.1, 0.5] + scale_factor: 86400000 + add_offset: 0 + new_unit: "mm d$^{-1}$" + mpl: + colorbar: + label : "mm d$^{-1}$" + obs_file: "ERAI_all_climo.nc" + obs_name: "ERAI" + obs_var_name: "PRECT" + category: "Hydrologic cycle" + derivable_from: ['PRECL','PRECC'] + + +SWCF: + colormap: "Reds" + polar_map: + colormap: + nh: "fakemap" + sh: "Blues" + contour_levels_range: [-150, 51, 10] + diff_colormap: "BrBG" + diff_contour_range: [-20, 21, 2] + scale_factor: 1 + add_offset: 0 + new_unit: "Wm$^{-2}$" + mpl: + colorbar: + label : "Wm$^{-2}$" + obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" + obs_name: "CERES_EBAF_Ed4.1" + obs_var_name: "toa_cre_sw_mon" + obs_scale_factor: 1 + obs_add_offset: 0 + category: "TOA energy flux" + + +LWCF: + colormap: "Oranges" + contour_levels_range: [-10, 101, 5] + diff_colormap: "BrBG" + diff_contour_range: [-15, 16, 1] + scale_factor: 1 + add_offset: 0 + new_unit: "Wm$^{-2}$" + mpl: + colorbar: + label : "Wm$^{-2}$" + obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" + obs_name: "CERES_EBAF_Ed4.1" + obs_var_name: "toa_cre_lw_mon" + category: "TOA energy flux" + + +PSL: + colormap: "Oranges" + polar_map: + colormap: "rainbow" + contour_levels_range: [1000, 1023, 1] + #contour_levels_range: [980, 1053, 4] + diff_contour_range: [-9, 9.1, 0.5] + scale_factor: 0.01 + add_offset: 0 + new_unit: "hPa" + mpl: + colorbar: + label : "hPa" + category: "Surface variables" + obs_file: "PSL_ERA5_monthly_climo_197901-202112.nc" + obs_name: "ERA5" + obs_var_name: "PSL" + + +# Here are some examples of specifiying features like colormap, contour level values, difference values, etc. +# based on plot type and if 3d, the vertical level (in model levels). +# These are new features to the configuration and plotting routines. +U: + global_latlon_map: + colormap: # if not specified, default to viridis for any missing values nested (levs, ie 850) or not + 200: "ncl_default" + #850: "Spectral" + contour_levels_range: + 200: [-10, 51, 2.5] + 850: [-10, 31, 2.5] + diff_contour_range: + 200: [-15, 16, 2] + 850: [-5, 5.1, 0.5] + polar_map: + colormap: + nh: "terrain" + sh: "HoobaDoopFloppityFloop" + contour_levels_range: + nh: + 200: [-10, 31, 2.5] + 850: [-10, 13, 1] + sh: + 200: [-10, 51, 5] + 850: [-10, 31, 2.5] + diff_contour_range: + 200: [-10, 10, 1] + 850: [-5, 5.1, 0.5] + #nh: + # 200: [-15, 16, 2] + # 850: [-5, 5.1, 0.5] + #sh: + # 200: [-15, 16, 2] + # 850: [-5, 5.1, 0.5] + zonal_mean: + colormap: "ncl_default" + contour_levels_linspace: [-10, 30, 15] # These will be applied to all zonal 3d mean plots + #diff_contour_range: # default to figuring our the contour levels from difference from max/min + scale_factor: 1 + add_offset: 0 + new_unit: "ms$^{-1}$" + mpl: + colorbar: + label : "ms$^{-1}$" + obs_file: "U_ERA5_monthly_climo_197901-202112.nc" + obs_name: "ERA5" + obs_var_name: "U" + vector_pair: "V" + vector_name: "Wind" + category: "State" + + +Q: # example of no specific values for plotting, so it will default all values to using max and min, not suggested... + #global_latlon_map: + # colormap: + polar_map: + colormap: + nh: "terrain" + sh: "nipy_spectral" + category: "State" + obs_file: "Q_ERA5_monthly_climo_197901-202112.nc" + obs_name: "ERA5" + obs_var_name: "Q" + + +T: + global_latlon_map: # example of specifying values equally across feature, ie colormap is the same for all levels + colormap: "plasma" #Apply this to all latlon maps + #200: "terrain" + #850: "Spectral" + contour_levels_range: [200, 301, 5] # This range will be applied to all levels in global lat/lon + polar_map: # example of changing multiple features for both vertical levels + colormap: + # In theory these should plot both hemispheres with these colorbars at these levels... + 200: "terrain" + 850: "Spectral" + contour_levels_range: + 200: [200, 231, 1] + 850: [250, 302, 2.5] + diff_contour_range: + 200: [-5, 6.1, 0.25] + 850: [-5, 5.1, 0.5] + zonal_mean: + colormap: "ncl_default" + contour_levels: [200, 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300] + # These will be applied to all zonal mean plots? + category: "State" + obs_file: "T_ERA5_monthly_climo_197901-202112.nc" + obs_name: "ERA5" + obs_var_name: "T" + + +RELHUM: + colormap: "Oranges" + polar_map: + colormap: "Blues" + #nh: "terrain" + #200: "terrain" + #850: "Spectral" + #sh: "nipy_spectral" + #200: "scipy_spectral" + #850: "HoobaDoopFloppityFloop" + contour_levels_range: [0, 105, 5] + diff_colormap: "BrBG" + diff_contour_range: [-15, 16, 2] + scale_factor: 1 + add_offset: 0 + new_unit: "Fraction" + mpl: + colorbar: + label : "Fraction" + obs_file: "ERAI_all_climo.nc" + obs_name: "ERAI" + obs_var_name: "RELHUM" + category: "State" \ No newline at end of file From e1fac61cba761c0708079abc5bfaa2a71e7ab147 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 18:21:49 -0600 Subject: [PATCH 37/43] Update with `vres` function and experimental colored line plot --- lib/plotting_utils.py | 77 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/lib/plotting_utils.py b/lib/plotting_utils.py index 409610346..2f0e6bfbd 100644 --- a/lib/plotting_utils.py +++ b/lib/plotting_utils.py @@ -243,7 +243,7 @@ def get_central_longitude(*args): # -- zonal & meridional mean code -- # -def _plot_line(axobject, xdata, ydata, color, **kwargs): +'''def _plot_line(axobject, xdata, ydata, color, **kwargs): """Create a generic line plot and check for some ways to annotate.""" if color != None: @@ -258,6 +258,58 @@ def _plot_line(axobject, xdata, ydata, color, **kwargs): axobject.set_ylabel("[{units}]".format(kwargs["units"])) #End if + return axobject''' + + + +def _plot_line(axobject, xdata, ydata, color=None, **kwargs): + """Create a generic line plot and check for some ways to annotate.""" + + use_cmap = kwargs.pop("use_cmap", False) + cmap = kwargs.pop("cmap", "viridis") + norm = kwargs.pop("norm", None) + vmin = kwargs.pop("vmin", None) + vmax = kwargs.pop("vmax", None) + + if use_cmap: + from matplotlib.collections import LineCollection + + x = np.asarray(xdata) + y = np.asarray(ydata) + + points = np.array([x, y]).T.reshape(-1, 1, 2) + segments = np.concatenate([points[:-1], points[1:]], axis=1) + + lc = LineCollection(segments, cmap=cmap) + + if norm is not None: + lc.set_norm(norm) + else: + if vmin is None: + vmin = np.nanmin(y) + if vmax is None: + vmax = np.nanmax(y) + lc.set_clim(vmin, vmax) + + lc.set_array(y) + + axobject.add_collection(lc) + axobject.autoscale() + + axobject._last_linecollection = lc + + else: + if color is not None: + axobject.plot(xdata, ydata, c=color, **kwargs) + else: + axobject.plot(xdata, ydata, **kwargs) + + # Y label logic + if hasattr(ydata, "units"): + axobject.set_ylabel("[{units}]".format(units=getattr(ydata, "units"))) + elif "units" in kwargs: + axobject.set_ylabel("[{units}]".format(kwargs["units"])) + return axobject def meridional_plot_line(ax, lon, data, color, **kwargs): @@ -268,9 +320,8 @@ def meridional_plot_line(ax, lon, data, color, **kwargs): # # annotate # - ax.set_xlabel("LONGITUDE") if hasattr(data, "units"): - ax.set_ylabel("{units}".format(units=getattr(data,"units"))) + ax.set_ylabel("{units}".format(units=getattr(data,"units")),fontsize=6) elif "units" in kwargs: ax.set_ylabel("{units}".format(kwargs["units"])) return ax @@ -282,9 +333,8 @@ def zonal_plot_line(ax, lat, data, color, **kwargs): # # annotate # - ax.set_xlabel("LATITUDE") if hasattr(data, "units"): - ax.set_ylabel("{units}".format(units=getattr(data,"units"))) + ax.set_ylabel("{units}".format(units=getattr(data,"units")),fontsize=6) elif "units" in kwargs: ax.set_ylabel("{units}".format(kwargs["units"])) return ax @@ -894,5 +944,22 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): } +def add_var_to_vres(adfobj, var, vres): + if 'vector_name' in vres: + vect_var_name = vres['vector_name'] + vec_vres = adfobj.variable_defaults.get(vect_var_name, {}) + if 'nickname' in vec_vres: + vres["var_name"] = vec_vres['nickname'] + else: + vres["var_name"] = vect_var_name + else: + + if 'nickname' in vres: + vres["var_name"] = vres['nickname'] + else: + vres["var_name"] = var + return vres + + ##################### #END HELPER FUNCTIONS \ No newline at end of file From 98304997594ded3d9013035dbb49396e322c4523 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 20:19:14 -0600 Subject: [PATCH 38/43] Rename vars to fix hemi defaults bug --- scripts/plotting/polar_map.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/scripts/plotting/polar_map.py b/scripts/plotting/polar_map.py index 47d07bbd8..2294693fc 100644 --- a/scripts/plotting/polar_map.py +++ b/scripts/plotting/polar_map.py @@ -156,10 +156,8 @@ def polar_map(adfobj): for s in seasons: for hemi_type in ["NHPolar", "SHPolar"]: - vres["hemi"] = hemi_type - if pres_levs and has_lev: # 3-D variable & pressure levels specified + if pres_levs and has_lev: # 3-D variable & lev levels specified for pres in pres_levs: - vres['lev'] = int(pres) plot_name = plot_loc / f"{var}_{pres}hpa_{s}_{hemi_type}_Mean.{plot_type}" info = { 'path': plot_name, @@ -167,8 +165,8 @@ def polar_map(adfobj): 'case': case_name, 'case_idx': case_idx, 'season': s, - 'type': hemi_type, - 'pressure': pres, + 'hemi': hemi_type, + 'lev': pres, 'exists': plot_name.is_file() } plot_info.append(info) @@ -186,7 +184,7 @@ def polar_map(adfobj): 'case': case_name, 'case_idx': case_idx, 'season': s, - 'type': hemi_type, + 'hemi': hemi_type, 'exists': plot_name.is_file() } plot_info.append(info) @@ -214,6 +212,7 @@ def polar_map(adfobj): case_name = plot['case'] case_idx = plot['case_idx'] vres["season"] = plot['season'] + vres["hemi"] = plot['hemi'] plot_loc = Path(plot_locations[case_idx]) # Ensure plot directory exists @@ -230,12 +229,12 @@ def polar_map(adfobj): else: has_lev = False - if has_lev and pres_levs and plot.get('pressure'): + if has_lev and pres_levs and plot.get('lev'): if not all(dim in mdata.dims for dim in ['lat', 'lev']): continue - mdata = mdata.sel(lev=plot['pressure']) - odata_level = odata.sel(lev=plot['pressure']) - vres["lev"] = plot['pressure'] + mdata = mdata.sel(lev=plot['lev']) + odata_level = odata.sel(lev=plot['lev']) + vres["lev"] = plot['lev'] else: if not utils.lat_lon_validate_dims(mdata): continue @@ -257,7 +256,7 @@ def polar_map(adfobj): [syear_cases[case_idx], eyear_cases[case_idx]], [syear_baseline, eyear_baseline], mseason, oseason, dseason, pseason, - hemisphere=get_hemisphere(plot['type']), + hemisphere=get_hemisphere(plot['hemi']), obs=adfobj.compare_obs, **vres ) @@ -265,7 +264,7 @@ def polar_map(adfobj): adfobj.add_website_data( plot['path'], plot['var'], case_name, category=web_category, season=plot['season'], - plot_type=plot['type'] + plot_type=plot['hemi'] ) print(" ...polar maps have been generated successfully.") From c79bf4587496531ac30399e1549466c421a0a7f3 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 20:25:22 -0600 Subject: [PATCH 39/43] Fix NCL and other cmap bugs --- lib/plotting_utils.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/plotting_utils.py b/lib/plotting_utils.py index 2f0e6bfbd..51a104d63 100644 --- a/lib/plotting_utils.py +++ b/lib/plotting_utils.py @@ -490,12 +490,12 @@ def load_colormap(adfobj, cmap_name): msg += f"\n\t{cmap_name} not a standard Matplotlib colormap. Trying NCL..." url = guess_ncl_url(cmap_name) locfil = Path(".") / f"{cmap_name}.rgb" - data = read_ncl_colormap(locfil,msg) if locfil.is_file() else read_ncl_colormap(url) + data = read_ncl_colormap(adfobj, locfil,msg) if locfil.is_file() else read_ncl_colormap(adfobj, url) cm, cmr = ncl_to_mpl(adfobj, data, cmap_name) if not cm: msg += f"\n\tFailed to load {cmap_name}. Defaulting to 'coolwarm'." adfobj.debug_log(msg) - return 'coolwarm' + return 'viridis' adfobj.debug_log(msg) return cm @@ -508,23 +508,24 @@ def try_load_ncl_cmap(adfobj, cmap_case): url = guess_ncl_url(cmap_case) locfil = Path(".") / f"{cmap_case}.rgb" if locfil.is_file(): - data = read_ncl_colormap(locfil) + data = read_ncl_colormap(adfobj, locfil) else: try: - data = read_ncl_colormap(url) + data = read_ncl_colormap(adfobj, url) except urllib.error.HTTPError: - msg += f"\n\tNCL colormap file not found" + msg += "\n\tNCL colormap file not found" if isinstance(data, np.ndarray): - cm, cmr = ncl_to_mpl(data, cmap_case) + cm, cmr = ncl_to_mpl(adfobj, data, cmap_case) adfobj.debug_log(msg) return cm, msg - except Exception: - pass - - adfobj.debug_log(msg) - return "coolwarm", msg + adfobj.debug_log(msg) + return "viridis", msg + except Exception: + msg + "Something went wrong trying to load NCL colormap. Defaulting to 'viridis'." + adfobj.debug_log(msg) + return "viridis", msg def get_cmap(adfobj, plotty, plot_type_dict, kwargs, polar_names): """ @@ -559,15 +560,15 @@ def get_cmap(adfobj, plotty, plot_type_dict, kwargs, polar_names): cmap_case = kwargs[colormap_key] msg += f"\n\tUser supplied cmap for {plotty}: {cmap_case}" - # Priority 3: fallback default + # Priority 3: NCL support + if cmap_case in ncl_defaults: + cmap_case, msg = try_load_ncl_cmap(adfobj, cmap_case) + + # Last attempt fallback default if not cmap_case: msg += f"\n\tNo cmap for {plotty} found, defaulting to {default_cmap}" cmap_case = default_cmap - # NCL support - if cmap_case in ncl_defaults: - cmap_case, msg = try_load_ncl_cmap(adfobj, cmap_case) - # Final check: must exist in matplotlib or NCL if isinstance(cmap_case, str): if (cmap_case not in plt.colormaps()) and (cmap_case not in ncl_defaults): @@ -859,10 +860,10 @@ def prep_contour_plot(adata, bdata, diffdata, pctdata, **kwargs): url = guess_ncl_url(cmap_pctdiff) locfil = "." / f"{cmap_pctdiff}.rgb" if locfil.is_file(): - data = read_ncl_colormap(locfil) + data = read_ncl_colormap(adfobj, locfil) else: - data = read_ncl_colormap(url) - cm, cmr = ncl_to_mpl(data, cmap_pctdiff) + data = read_ncl_colormap(adfobj, url) + cm, cmr = ncl_to_mpl(adfobj, data, cmap_pctdiff) #ncl_colors[cm.name] = cm #ncl_colors[cmr.name] = cmr From 957b862b1613b60e35f8ba870c7ab3d25afde157 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 20:26:14 -0600 Subject: [PATCH 40/43] update yaml --- lib/adf_variable_defaults_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/adf_variable_defaults_test.yaml b/lib/adf_variable_defaults_test.yaml index e32cb21dc..cd47a7f07 100644 --- a/lib/adf_variable_defaults_test.yaml +++ b/lib/adf_variable_defaults_test.yaml @@ -114,7 +114,7 @@ U: polar_map: colormap: nh: "terrain" - sh: "HoobaDoopFloppityFloop" + sh: "fake_cmap" contour_levels_range: nh: 200: [-10, 31, 2.5] From 36f05fb5276f3dc0a17380ad27d322b0f0b419f0 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 20:27:32 -0600 Subject: [PATCH 41/43] Ignore NCL RGB files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index bfe7abc69..0f812e59c 100644 --- a/.gitignore +++ b/.gitignore @@ -111,5 +111,8 @@ GitHub.sublime-settings !.vscode/extensions.json .history +#NCL RGB files +*.rgb + From b4db66d30ac2d00e222b8eee27bb9f54df2ef105 Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 21:01:38 -0600 Subject: [PATCH 42/43] Clean up old code --- lib/plotting_functions.py | 63 --------------------------------------- 1 file changed, 63 deletions(-) diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py index 6f64f1cd8..e9c9daa30 100644 --- a/lib/plotting_functions.py +++ b/lib/plotting_functions.py @@ -888,38 +888,6 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, else: base_title = "$\mathbf{Baseline}:$"+f"{base_nickname}\nyears: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" if has_lev: - - # calculate zonal average: - azm = utils.zonal_mean_xr(adata) - bzm = utils.zonal_mean_xr(bdata) - - # calculate difference: - diff = azm - bzm - - # calculate the percent change - pct = (azm - bzm) / np.abs(bzm) * 100.0 - #check if pct has NaN's or Inf values and if so set them to 0 to prevent plotting errors - pct = pct.where(np.isfinite(pct), np.nan) - pct = pct.fillna(0.0) - - """# generate dictionary of contour plot settings: - cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) - - levels_diff = cp_info['levels_diff'] - cmap_diff = cp_info['cmap_diff'] - norm_diff = cp_info['norm_diff'] - extend_diff = cp_info['extend_diff'] - - levels_pctdiff = cp_info['levels_pctdiff'] - cmap_pctdiff = cp_info['cmap_pctdiff'] - norm_pctdiff = cp_info['norm_pctdiff'] - extend_pctdiff = cp_info['extend_pctdiff'] - - levels_sim = cp_info['levels_sim'] - cmap_sim = cp_info['cmap_sim'] - norm_sim = cp_info['norm_sim'] - extend_sim = cp_info['extend_sim']""" - # Generate zonal plot: fig, ax = plt.subplots(figsize=(8,10),nrows=4, constrained_layout=True, sharex=True, sharey=True,**cp_info['subplots_opt']) @@ -1035,35 +1003,6 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, byears = f"years: {baseline_climo_yrs[0]}-{baseline_climo_yrs[-1]}" tyears = f"years: {case_climo_yrs[0]}-{case_climo_yrs[-1]}" - """azm = utils.zonal_mean_xr(adata) - bzm = utils.zonal_mean_xr(bdata) - diff = azm - bzm - - # calculate the percent change - pct = (azm - bzm) / np.abs(bzm) * 100.0 - #check if pct has NaN's or Inf values and if so set them to 0 to prevent plotting errors - pct = pct.where(np.isfinite(pct), np.nan) - pct = pct.fillna(0.0) - - # generate dictionary of contour plot settings: - cp_info = plot_utils.prep_contour_plot(azm, bzm, diff, pct, **kwargs) - units = cp_info['units'] - levels_diff = cp_info['levels_diff'] - cmap_diff = cp_info['cmap_diff'] - norm_diff = cp_info['norm_diff'] - extend_diff = cp_info['extend_diff'] - - levels_pctdiff = cp_info['levels_pctdiff'] - cmap_pctdiff = cp_info['cmap_pctdiff'] - norm_pctdiff = cp_info['norm_pctdiff'] - extend_pctdiff = cp_info['extend_pctdiff'] - - levels_sim = cp_info['levels_sim'] - cmap_sim = cp_info['cmap_sim'] - norm_sim = cp_info['norm_sim'] - extend_sim = cp_info['extend_sim']""" - - fig, ax = plt.subplots(nrows=3)#figsize=(6,8), ax[0].set_title(f"{tyears}\n{byears}", loc='right', fontsize=6) @@ -1105,8 +1044,6 @@ def plot_zonal_mean_and_save(adfobj, wks, case_nickname, base_nickname, a.tick_params('both', length=3, width=1, which='major') a.tick_params('both', length=3, width=1, which='minor') a.tick_params(axis='both', labelsize=6) - # Set the maximum number of ticks desired - #a.xaxis.set_major_locator(MaxNLocator(nbins=5)) a.yaxis.set_major_locator(MaxNLocator(nbins=8)) a.grid(True) #End for From 415bcc556d900b1703b32329ba2fdd0fd1650b8e Mon Sep 17 00:00:00 2001 From: Justin Richling Date: Thu, 9 Apr 2026 21:12:11 -0600 Subject: [PATCH 43/43] Remove old code --- lib/adf_variable_defaults_test.yaml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/lib/adf_variable_defaults_test.yaml b/lib/adf_variable_defaults_test.yaml index cd47a7f07..ba12a4086 100644 --- a/lib/adf_variable_defaults_test.yaml +++ b/lib/adf_variable_defaults_test.yaml @@ -28,9 +28,6 @@ PRECT: scale_factor: 86400000 add_offset: 0 new_unit: "mm d$^{-1}$" - mpl: - colorbar: - label : "mm d$^{-1}$" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "PRECT" @@ -50,9 +47,6 @@ SWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_sw_mon" @@ -69,9 +63,6 @@ LWCF: scale_factor: 1 add_offset: 0 new_unit: "Wm$^{-2}$" - mpl: - colorbar: - label : "Wm$^{-2}$" obs_file: "CERES_EBAF_Ed4.1_2001-2020.nc" obs_name: "CERES_EBAF_Ed4.1" obs_var_name: "toa_cre_lw_mon" @@ -88,9 +79,6 @@ PSL: scale_factor: 0.01 add_offset: 0 new_unit: "hPa" - mpl: - colorbar: - label : "hPa" category: "Surface variables" obs_file: "PSL_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" @@ -138,9 +126,6 @@ U: scale_factor: 1 add_offset: 0 new_unit: "ms$^{-1}$" - mpl: - colorbar: - label : "ms$^{-1}$" obs_file: "U_ERA5_monthly_climo_197901-202112.nc" obs_name: "ERA5" obs_var_name: "U" @@ -205,9 +190,6 @@ RELHUM: scale_factor: 1 add_offset: 0 new_unit: "Fraction" - mpl: - colorbar: - label : "Fraction" obs_file: "ERAI_all_climo.nc" obs_name: "ERAI" obs_var_name: "RELHUM"