diff --git a/config_cam_baseline_example.yaml b/config_cam_baseline_example.yaml
index 1dfc96bed..2293b9a97 100644
--- a/config_cam_baseline_example.yaml
+++ b/config_cam_baseline_example.yaml
@@ -65,10 +65,10 @@ user: 'USER-NAME-NOT-SET'
diag_basic_info:
#History file string to match (eg. cam.h0 or ocn.pop.h.ecosys.nday1)
- # Only affects timeseries as everything else uses timeseries
+ # Only affects timeseries as everything else uses timeseries
# Leave off trailing '.'
#Default: cam.h0
- hist_str: cam.h0
+ hist_str: cam.h0
#Is this a model vs observations comparison?
#If "false" or missing, then a model-model comparison is assumed:
@@ -151,6 +151,11 @@ diag_cam_climo:
#Name of CAM case (or CAM run name):
cam_case_name: b.e20.BHIST.f09_g17.20thC.297_05
+ #Case nickname
+ #If left blank, it will default to cam_case_name
+ # ** NOTE: if nickname starts with a zero, the string must be in quotes! **
+ case_nickname: ${diag_cam_climo.cam_case_name}
+
#Location of CAM history (h0) files:
#Example test files
cam_hist_loc: /glade/p/cesm/ADF/${diag_cam_climo.cam_case_name}
@@ -201,6 +206,10 @@ diag_cam_climo:
# - b.e20.BHIST.f09_g17.20thC.297_05
# - b1850.f19_g17.validation_mct.004
+ #case_nickname:
+ # - nickname 1
+ # - "026c"
+
#calc_cam_climo:
# - true
# - true
@@ -259,6 +268,11 @@ diag_cam_baseline_climo:
#Name of CAM baseline case:
cam_case_name: b.e20.BHIST.f09_g16.20thC.125.02
+ #Case nickname
+ #If left blank or if missing, nickname will default to baseline cam_case_name
+ # ** NOTE: if nickname starts with a zero, the string must be in quotes! **
+ case_nickname: ${diag_cam_baseline_climo.cam_case_name}
+
#Location of CAM baseline history (h0) files:
#Example test files
cam_hist_loc: /glade/p/cesm/ADF/${diag_cam_baseline_climo.cam_case_name}
@@ -377,6 +391,15 @@ diag_var_list:
#
+# Make mulit-plot comparison image for specified plots types
+# This will only run if there are more than one specified test cases declared above
+# NOTE: These plot types also need to be present above in the plotting_scripts section (for now) and variables in the diag_var_list
+# NOTE: Only global LatLon multi-case plots are available at this time - more are coming. JR
+multi_case_plots:
+ global_latlon_map:
+ - SST
+ - PSL
+
# Options for multi-case regional contour plots (./plotting/regional_map_multicase.py)
# region_multicase:
# region_spec: [slat, nlat, wlon, elon]
diff --git a/lib/adf_diag.py b/lib/adf_diag.py
index c3a5eded9..0e0327939 100644
--- a/lib/adf_diag.py
+++ b/lib/adf_diag.py
@@ -169,6 +169,9 @@ def __init__(self, config_file, debug=False):
self.expand_references(self.__cvdp_info)
#End if
+ #Add multi plots info to object:
+ self.__multi_case_plots = self.read_config_var('multi_case_plots')
+
#Add averaging script names:
self.__time_averaging_scripts = self.read_config_var('time_averaging_scripts')
@@ -197,6 +200,16 @@ def get_cvdp_info(self, var_str, required=False):
conf_dict=self.__cvdp_info,
required=required)
+ def get_multi_case_info(self, var_str, required=False):
+ """
+ Return the config variable from 'multi_case_plots' as requested by
+ the user.
+ """
+
+ return self.read_config_var(var_str,
+ conf_dict=self.__multi_case_plots,
+ required=required)
+
#########
#Script-running functions
#########
diff --git a/lib/adf_info.py b/lib/adf_info.py
index 3b39e0cd5..0ade67b94 100644
--- a/lib/adf_info.py
+++ b/lib/adf_info.py
@@ -116,6 +116,16 @@ def __init__(self, config_file, debug=False):
#Initialize "compare_obs" variable:
self.__compare_obs = self.get_basic_info('compare_obs')
+ #Case names:
+ case_names = self.get_cam_info('cam_case_name', required=True)
+
+ #Grab test case nickname(s)
+ test_nicknames = self.get_cam_info('case_nickname')
+ if test_nicknames is None:
+ #If no nicknames exist, then just set to case names
+ test_nicknames = case_names
+ #End if
+
#Check if a CAM vs AMWG obs comparison is being performed:
if self.__compare_obs:
@@ -125,6 +135,7 @@ def __init__(self, config_file, debug=False):
#Also set data name for use below:
data_name = "Obs"
+ base_nickname = "Obs"
#Set the baseline years to empty strings:
syear_baseline = ""
@@ -154,20 +165,32 @@ def __init__(self, config_file, debug=False):
base_climo_yrs = sorted(np.unique([i.stem[-7:-3] for i in files_list]))
if syear_baseline is None:
- print(f"No given start year for {data_name}, using first found year...")
+ print(f"\nNo given start year for {data_name}, using first found year...")
syear_baseline = int(base_climo_yrs[0])
#End if
if eyear_baseline is None:
- print(f"No given end year for {data_name}, using last found year...")
+ print(f"No given end year for {data_name}, using last found year...\n")
eyear_baseline = int(base_climo_yrs[-1])
#End if
#End if
+ #Grab baseline nickname
+ base_nickname = self.get_baseline_info('case_nickname')
+ if base_nickname == None:
+ base_nickname = data_name
+ #End if
+
data_name += f"_{syear_baseline}_{eyear_baseline}"
#End if
+ #Initialize case nicknames:
+ self.__test_nicknames = test_nicknames
+ self.__base_nickname = base_nickname
+
+ #Initialize baseline climo years:
self.__syear_baseline = syear_baseline
self.__eyear_baseline = eyear_baseline
+
#Create plot location variable for potential use by the website generator.
#Please note that this is also assumed to be the output location for the analyses scripts:
#-------------------------------------------------------------------------
@@ -176,9 +199,6 @@ def __init__(self, config_file, debug=False):
#Plot directory:
plot_dir = self.get_basic_info('cam_diag_plot_loc', required=True)
- #Case names:
- case_names = self.get_cam_info('cam_case_name', required=True)
-
#Start years (not currently required):
syears = self.get_cam_info('start_year')
@@ -200,7 +220,6 @@ def __init__(self, config_file, debug=False):
for case_idx, case_name in enumerate(case_names):
if syears[case_idx] is None or eyears[case_idx] is None:
- print(f"No given climo years for {case_name}...")
starting_location = Path(cam_hist_locs[case_idx])
files_list = sorted(starting_location.glob('*'+hist_str+'.*.nc'))
case_climo_yrs = sorted(np.unique([i.stem[-7:-3] for i in files_list]))
@@ -214,6 +233,7 @@ def __init__(self, config_file, debug=False):
#End if
#End if
+ #Append climo years to case directory
case_name += f"_{syears[case_idx]}_{eyears[case_idx]}"
#Set the final directory name and save it to plot_location:
@@ -224,12 +244,28 @@ def __init__(self, config_file, debug=False):
if case_idx == 0:
first_case_dir = direc_name
#End if
-
#End for
+ #Initialize case climo years:
self.__syears = syears
self.__eyears = eyears
+ #Make directoriess for multi-case diagnostics if applicable
+ if len(case_names) > 1:
+ multi_path = Path(self.get_basic_info('cam_diag_plot_loc', required=True))
+ multi_path.mkdir(parents=True, exist_ok=True)
+ main_site_path = multi_path / "main_website"
+ main_site_path.mkdir(exist_ok=True)
+ main_site_assets_path = main_site_path / "assets"
+ main_site_assets_path.mkdir(exist_ok=True)
+ main_site_img_path = main_site_path / "html_img"
+ main_site_img_path.mkdir(exist_ok=True)
+
+ #Initialize multi-case directories:
+ self.__main_site_path = main_site_path
+ self.__main_site_assets_path = main_site_assets_path
+ self.__main_site_img_path = main_site_img_path
+
#Finally add baseline case (if applicable) for use by the website table
#generator. These files will be stored in the same location as the first
#listed case.
@@ -366,6 +402,25 @@ def climo_yrs(self):
return {"syears":syears,"eyears":eyears,
"syear_baseline":self.__syear_baseline, "eyear_baseline":self.__eyear_baseline}
+ # Create property needed to return the climo start (syear) and end (eyear) years to user:
+ @property
+ def case_nicknames(self):
+ """Return the test case and baseline nicknames to the user if requested."""
+ #Note that a copy is needed in order to avoid having a script mistakenly
+ #modify this variable, as it is mutable and thus passed by reference:
+ test_nicknames = copy.copy(self.__test_nicknames)
+
+ return {"test_nicknames":test_nicknames,"base_nickname":self.__base_nickname}
+
+ # Create property needed to return the multi-case directories to scripts:
+ @property
+ def main_site_paths(self):
+ """Return the directories for multi-case diags if applicable."""
+
+ return {"main_site_path":self.__main_site_path,
+ "main_site_assets_path":self.__main_site_assets_path,
+ "main_site_img_path":self.__main_site_img_path}
+
#########
#Utility function to access expanded 'diag_basic_info' variables:
diff --git a/lib/adf_web.py b/lib/adf_web.py
index d15c2a8b3..e6e9ec064 100644
--- a/lib/adf_web.py
+++ b/lib/adf_web.py
@@ -56,6 +56,7 @@ class _WebData:
"""
def __init__(self, web_data, web_name, case_name,
+ plot_ext = None,
category = None,
season = None,
plot_type = "Special",
@@ -71,6 +72,7 @@ def __init__(self, web_data, web_name, case_name,
self.category = category
self.season = season
self.plot_type = plot_type
+ self.plot_ext = plot_ext
self.data_frame = data_frame
self.html_file = html_file
self.asset_path = asset_path
@@ -180,6 +182,7 @@ def create_html(self):
#########
def add_website_data(self, web_data, web_name, case_name,
+ plot_ext = None,
category = None,
season = None,
plot_type = "Special",
@@ -217,6 +220,7 @@ def add_website_data(self, web_data, web_name, case_name,
#Initialize Pandas data frame logical:
data_frame = False
+ html_file = []
#Check that the web_data is either a path
#or a pandas dataframe:
try:
@@ -271,7 +275,12 @@ def add_website_data(self, web_data, web_name, case_name,
#If multi-case, then save under the "multi-case" directory:
if self.num_cases > 1:
- html_file = self.__case_web_paths['multi-case']["table_pages_dir"] / html_name
+ multi_tbl_dir = self.__case_web_paths['multi-case']["table_pages_dir"]
+ #Avoid collecting individual case comparison tables
+ #Hacky - could probably use an update eventually - JR
+ if web_name != "case_comparison":
+ html_file.append(multi_tbl_dir/ html_name)
+ html_file.append(self.__case_web_paths[case_name]["table_pages_dir"] / html_name)
else:
html_file = self.__case_web_paths[case_name]["table_pages_dir"] / html_name
#End if
@@ -283,7 +292,7 @@ def add_website_data(self, web_data, web_name, case_name,
#End if
#Initialize web data object:
- web_data = _WebData(web_data, web_name, case_name,
+ web_data = _WebData(web_data, web_name, case_name, plot_ext,
category = category,
season = season,
plot_type = plot_type,
@@ -300,6 +309,9 @@ def add_website_data(self, web_data, web_name, case_name,
if plot_type not in self.__plot_type_multi:
self.__plot_type_multi.append(plot_type)
#End if
+ if plot_type not in self.__plot_type_order:
+ self.__plot_type_order.append(plot_type)
+ #End if
else: #single case plot/ADF run
if plot_type not in self.__plot_type_order:
self.__plot_type_order.append(plot_type)
@@ -332,58 +344,38 @@ def create_website(self):
#If there is more than one non-baseline case, then create new website directory:
if self.num_cases > 1:
- main_site_path = Path(self.get_basic_info('cam_diag_plot_loc', required=True))
- main_site_path = main_site_path / "main_website"
- main_site_path.mkdir(exist_ok=True)
+ #Grab all multi-case diagnostic directories
+ main_site_path = self.main_site_paths["main_site_path"]
+ main_site_assets_path = self.main_site_paths["main_site_assets_path"]
+ main_site_img_path = self.main_site_paths["main_site_img_path"]
+
case_sites = OrderedDict()
+ multi_layout = True
else:
main_site_path = "" #Set main_site_path to blank value
+ multi_layout = False
#End if
#Extract needed variables from yaml file:
case_names = self.get_cam_info('cam_case_name', required=True)
- #Time series files for unspecified climo years
- cam_ts_locs = self.get_cam_info('cam_ts_loc', required=True)
-
- #Attempt to grab case start_years (not currently required):
- ###########################################################
- # This is for the header in the html files for climo yrs
- #NOTE this may break when going to multi case...
- syear_cases = self.get_cam_info('start_year')
- eyear_cases = self.get_cam_info('end_year')
+ #Grab case climo years
+ syear_cases = self.climo_yrs["syears"]
+ eyear_cases = self.climo_yrs["eyears"]
- if (syear_cases and eyear_cases) == None:
- syear_cases = [None]*len(case_names)
- eyear_cases = [None]*len(case_names)
-
- #Loop over model cases to catch all cases that have no climo years specified:
- for case_idx, case_name in enumerate(case_names):
-
- if (syear_cases[case_idx] and eyear_cases[case_idx]) == None:
- print(f"No given climo years for {case_name}...")
- starting_location = Path(cam_ts_locs[case_idx])
- files_list = sorted(starting_location.glob('*nc'))
- #This assumes CAM file names stay with this convention
- #Better way to do this?
- syear_cases[case_idx] = int(files_list[0].stem[-13:-9])
- eyear_cases[case_idx] = int(files_list[0].stem[-6:-2])
+ #Grab baseline years (which may be empty strings if using Obs):
+ syear_baseline = self.climo_yrs["syear_baseline"]
+ eyear_baseline = self.climo_yrs["eyear_baseline"]
#Set name of comparison data, which depends on "compare_obs":
if self.compare_obs:
data_name = "Obs"
baseline_yrs = ""
+ syear_baseline = ""
+ eyear_baseline = ""
else:
data_name = self.get_baseline_info('cam_case_name', required=True)
- #Attempt to grab baseline start_years (not currently required):
- syear_baseline = self.get_baseline_info('start_year')
- eyear_baseline = self.get_baseline_info('end_year')
-
- if (syear_baseline and eyear_baseline) == None:
- syear_baseline = self.climo_yrs["syear_baseline"]
- eyear_baseline = self.climo_yrs["eyear_baseline"]
- #End if
baseline_yrs=f"{syear_baseline} - {eyear_baseline}"
#End if
@@ -393,6 +385,33 @@ def create_website(self):
#Extract variable defaults dictionary (for categories):
var_defaults_dict = self.variable_defaults
+ #Extract requested multi-case multi-plots
+ multi_case_plots = self.read_config_var('multi_case_plots')
+
+ if multi_case_plots:
+ #Grab all variables for each multi-case plot type
+ mvars = []
+ #ext are plot type extensions (keys for multi-case plots)
+ #var_list should be a list of all vars for each plot map extensions
+ #var is iterative for all plot map extensions
+ for multi_var_list in [multi_case_plots[ext] for ext in multi_case_plots]:
+ for var in multi_var_list:
+ if ((self.compare_obs) and (var in self.var_obs_dict)) or (not self.compare_obs):
+ mvars.append(var)
+
+ #Create multi-case site:
+ #Make a dictionary for plot type extensions for given plot type
+ #This can probably be populated in the for-loops during html creation...
+ #Or it should be declared somewhere higher up, like adf_info or something
+ multi_case_dict = {"global_latlon_map":"LatLon",
+ "zonal_mean":"Zonal",
+ "meridional":"Meridional",
+ "global_latlon_vect_map":"LatLon_Vector"}
+
+ #Dictionary for multi-case website plot types
+ multi_plots = {"Tables": "html_table/mean_tables.html",
+ "Special":"html_img/multi_case_mean_diag_Special.html"}
+
#Set plot type html dictionary (for Jinja templating):
plot_type_html = OrderedDict()
for plot_type in self.__plot_type_order:
@@ -412,13 +431,9 @@ def create_website(self):
"mean_tables.html")
else:
multi_plot_type_html[plot_type] = os.path.join("html_img",
- f"mean_diag_{plot_type}.html")
+ f"multi_case_mean_diag_{plot_type}.html")
#End if
#End for
- else:
- #Set to match standard plot type dict:
- multi_plot_type_html = plot_type_html
- #End if
#Set main title for website:
main_title = "CAM Diagnostics"
@@ -443,9 +458,41 @@ def create_website(self):
#so that we only had to do the web_data loop once,
#but for now this will do. -JN
mean_html_info = OrderedDict()
+ #Use this for multi-case diagnostic plots only
+ multi_mean_html_info = OrderedDict()
+ #Use this for multi-case with multi-plots
+ multi_plot_html_info = OrderedDict()
#Create another dictionary needed for HTML pages that render tables:
table_html_info = OrderedDict()
+ #Use this for multi-case diagnostic tables
+ multi_table_html_info = OrderedDict()
+
+ #If this is a multi-case instance, then copy website to "main" directory:
+ if main_site_path:
+ self.__case_web_paths["multi-case"]['img_pages_dir'].mkdir(exist_ok=True)
+
+ #Create CSS templates file path:
+ main_templates_path = main_site_path / "templates"
+
+ #Also add path to case_sites dictionary:
+ #loop over cases:
+ for idx, case_name in enumerate(case_names):
+ #Check if case name is present in plot
+ if case_name in self.__case_web_paths:
+ #Add path to case_sites dictionary:
+ case_dir_ext = f"{case_name}_{syear_cases[idx]}_{eyear_cases[idx]}"
+ if self.compare_obs:
+ base_dir_ext = f"{data_name}"
+ else:
+ base_dir_ext = f"{data_name}_{syear_baseline}_{eyear_baseline}"
+ case_sites[case_name] = [os.path.join(os.curdir,
+ f"{case_dir_ext}_vs_{base_dir_ext}",
+ "index.html"),syear_cases[idx],eyear_cases[idx]]
+
+ else:
+ #make empty list for non multi-case web generation
+ case_sites = []
#Loop over all web data objects:
for web_data in self.__website_data:
@@ -467,44 +514,46 @@ def create_website(self):
shutil.copyfile(gif_file, css_files_dir / gif_file.name)
#End for
+ #Check first for AMWG tables data frame
if web_data.data_frame:
#Create a directory that will hold table html files, if a table is present:
if self.num_cases > 1:
self.__case_web_paths['multi-case']['table_pages_dir'].mkdir(exist_ok=True)
- else:
- self.__case_web_paths[web_data.case]['table_pages_dir'].mkdir(exist_ok=True)
#End if
+ self.__case_web_paths[web_data.case]['table_pages_dir'].mkdir(exist_ok=True)
+
#Add table HTML file to dictionary:
#Note: Need to use data name instead of case name for tables.
- table_html_info[web_data.name] = web_data.html_file.name
-
- if not web_data.data_frame:
+ if len(case_names) > 1:
+ if web_data.name != "case_comparison":
+ table_html_info[web_data.name] = web_data.html_file[0].name
- #Create a directory that will hold just the html files for individual images:
- self.__case_web_paths[web_data.case]['img_pages_dir'].mkdir(exist_ok=True)
-
- #Create a directory that will hold copies of the actual images:
- self.__case_web_paths[web_data.case]['assets_dir'].mkdir(exist_ok=True)
+ multi_table_html_info[web_data.name] = web_data.html_file[0].name
+ else:
+ table_html_info[web_data.name] = web_data.html_file.name
- #Move file to assets directory:
- shutil.copy(web_data.data, web_data.asset_path)
+ #Now check all plot types
+ if not web_data.data_frame:
+ #Determine season value:
+ if web_data.season:
+ season = web_data.season
+ else:
+ season = "plot" #Just have the link be labeled "plot".
+ #End if
#Extract plot_type:
ptype = web_data.plot_type
- #Initialize Ordered Dictionary for plot type:
- if ptype not in mean_html_info:
- mean_html_info[ptype] = OrderedDict()
- #End if
+ #Extract web data name (usually the variable name):
+ var = web_data.name
#Check if category has been provided for this web data:
if web_data.category:
#If so, then just use directly:
category = web_data.category
else:
-
#Check if variable in defaults dictionary:
if web_data.name in var_defaults_dict:
#If so, then extract category from dictionary:
@@ -515,43 +564,96 @@ def create_website(self):
#End if
#End if
- if category not in mean_html_info[ptype]:
- mean_html_info[ptype][category] = OrderedDict()
- #End if
-
- #Extract web data name (usually the variable name):
- name = web_data.name
+ #Check to see if there are multiple-cases
+ if main_site_path:
+ #Check to see if the user has multi-plots enabled
+ if multi_case_plots:
+ #Loop over each variable in multi-case plot variables
+ #Check if plot ext is in requested multi-case plot types
+ if (web_data.plot_ext in multi_case_plots.keys()) and (var in mvars):
+
+ #Initialize Ordered Dictionary for multi case plot type:
+ if ptype not in multi_plot_html_info:
+ multi_plot_html_info[ptype] = OrderedDict()
+ #End if
+ #Initialize Ordered Dictionary for category:
+ if category not in multi_plot_html_info[ptype]:
+ multi_plot_html_info[ptype][category] = OrderedDict()
+ #End if
+ if var not in multi_plot_html_info[ptype][category]:
+ multi_plot_html_info[ptype][category][var] = OrderedDict()
+ #End if
+ p = f"plot_page_multi_case_{var}_{season}_{ptype}_Mean.html"
+ if season not in multi_plot_html_info[ptype][category][var]:
+ multi_plot_html_info[ptype][category][var][season] = p
+ #End if
+ #End if (variable in multi-case plot variables)
+ #End if multi-case multi-plots
+
+ #Need to isolate multi-case regular plots from the multi-case multi-plots
+ #QUESTION: Is there a better way?
+ if "multi_plot" not in str(web_data.html_file.name):
+ if ptype not in multi_mean_html_info:
+ multi_mean_html_info[ptype] = OrderedDict()
+ #End if
+ if category not in multi_mean_html_info[ptype]:
+ multi_mean_html_info[ptype][category] = OrderedDict()
+ #End if
+ if var not in multi_mean_html_info[ptype][category]:
+ multi_mean_html_info[ptype][category][var] = OrderedDict()
+ #End if
+ p = f"plot_page_multi_case_{var}_{season}_{ptype}_Mean.html"
+ if season not in multi_mean_html_info[ptype][category][var]:
+ multi_mean_html_info[ptype][category][var][season] = p
+ #End if
+ #End if (not multi-case multi-plots)
+ #End if (multi-case scenario)
+
+ #Individual cases
+ #This will be used if multi-case diagnostics as well
+ #Create a directory that will hold just the html files for individual images:
+ self.__case_web_paths[web_data.case]['img_pages_dir'].mkdir(exist_ok=True)
- #Initialize Ordered Dictionary for variable:
- if name not in mean_html_info[ptype][category]:
- mean_html_info[ptype][category][name] = OrderedDict()
- #End if
+ #Create a directory that will hold copies of the actual images:
+ self.__case_web_paths[web_data.case]['assets_dir'].mkdir(exist_ok=True)
- #Determine season value:
- if web_data.season:
- season = web_data.season
- else:
- season = "plot" #Just have the link be labeled "plot".
- #End if
+ #Move file to assets directory:
+ try:
+ shutil.copy(web_data.data, web_data.asset_path)
+ except:
+ pass
#Initialize Ordered Dictionary for season:
- mean_html_info[ptype][category][name][season] = web_data.html_file.name
-
+ #Need to ignore plots that may be generated for multi-case diags
+ #NOTE: There is probably a better way to do this - JR
+ if "multi_plot" not in str(web_data.html_file.name):
+ #Initialize Ordered Dictionary for plot type:
+ if ptype not in mean_html_info:
+ mean_html_info[ptype] = OrderedDict()
+ #End if
+ if category not in mean_html_info[ptype]:
+ mean_html_info[ptype][category] = OrderedDict()
+ #End if
+ #Initialize Ordered Dictionary for variable:
+ if var not in mean_html_info[ptype][category]:
+ mean_html_info[ptype][category][var] = OrderedDict()
+ #End if
+ mean_html_info[ptype][category][var][season] = web_data.html_file.name
+ #End if (check for multi_plot)
#End if (data-frame check)
#End for (web_data list loop)
#Loop over all web data objects again:
- for web_data in self.__website_data:
-
+ #NOTE: This will be for non multi-case diagnostics
+ for idx,web_data in enumerate(self.__website_data):
if web_data.data_frame:
-
#Create output HTML file path:
if self.num_cases > 1:
table_pages_dir = self.__case_web_paths['multi-case']['table_pages_dir']
- plot_types = multi_plot_type_html
+ table_pages_dir_indv = self.__case_web_paths[web_data.case]['table_pages_dir']
+
else:
table_pages_dir = self.__case_web_paths[web_data.case]['table_pages_dir']
- plot_types = plot_type_html
#End if
#Check if plot image already handles multiple cases,
@@ -570,22 +672,46 @@ def create_website(self):
float_format='{:6g}'.format)
#Construct amwg_table.html
+ rend_kwarg_dict = {"title": main_title,
+ "case_name": case1,
+ "case_yrs": case_yrs,
+ "base_name": data_name,
+ "baseline_yrs": baseline_yrs,
+ "amwg_tables": table_html_info,
+ "table_name": web_data.name,
+ "table_html": table_html,
+ "multi_head": False,
+ "multi": multi_layout,
+ "case_sites": case_sites}
+
table_tmpl = jinenv.get_template('template_table.html')
- table_rndr = table_tmpl.render(title=main_title,
- case1=case1,
- case2=data_name,
- case_yrs=case_yrs,
- baseline_yrs=baseline_yrs,
- amwg_tables=table_html_info,
- plot_types=plot_types,
- table_name=web_data.name,
- table_html=table_html
- )
-
- #Write mean diagnostic tables HTML file:
- with open(web_data.html_file, 'w', encoding='utf-8') as ofil:
- ofil.write(table_rndr)
- #End with
+
+ if main_site_path:
+ #Avoid single case comparison getting called here
+ #There might be a better way, but for now it works - JR
+ if web_data.name != "case_comparison":
+ rend_kwarg_dict["plot_types"] = multi_plot_type_html
+ rend_kwarg_dict["multi_head"] = "Table"
+
+ table_rndr = table_tmpl.render(rend_kwarg_dict)
+
+ #Write mean diagnostic tables HTML file:
+ html_file = web_data.html_file[0]
+ with open(html_file, 'w', encoding='utf-8') as ofil:
+ ofil.write(table_rndr)
+
+ else:
+ rend_kwarg_dict["plot_types"] = plot_type_html
+ if web_data.case == data_name:
+ rend_kwarg_dict["case_name"] = case_names[0]
+
+ table_rndr = table_tmpl.render(rend_kwarg_dict)
+
+ #Write mean diagnostic tables HTML file:
+ html_file = web_data.html_file
+ with open(html_file, 'w', encoding='utf-8') as ofil:
+ ofil.write(table_rndr)
+
#Check if the mean plot type page exists for this case (or for multi-case):
mean_table_file = table_pages_dir / "mean_tables.html"
@@ -593,102 +719,98 @@ def create_website(self):
#Construct mean_table.html
mean_table_tmpl = jinenv.get_template('template_mean_tables.html')
- mean_table_rndr = mean_table_tmpl.render(title=main_title,
- case1=case1,
- case2=data_name,
- case_yrs=case_yrs,
- baseline_yrs=baseline_yrs,
- amwg_tables=table_html_info,
- plot_types=plot_types,
- )
+
+ #Reuse the rend_kwarg_dict, but ignore certain keys
+ #since all others are the same
+ new_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'table_name', 'table_html'}}
+
+ if main_site_path:
+ plot_types = multi_plot_type_html
+ new_dict["multi_head"] = "Table"
+ else:
+ plot_types = plot_type_html
+
+ mean_table_rndr = mean_table_tmpl.render(new_dict)
#Write mean diagnostic tables HTML file:
with open(mean_table_file, 'w', encoding='utf-8') as ofil:
ofil.write(mean_table_rndr)
#End with
#End if
+ #End if (tables)
else: #Plot image
+ plot_types = plot_type_html
- #Create output HTML file path:
- img_pages_dir = self.__case_web_paths[web_data.case]['img_pages_dir']
- img_data = [os.path.relpath(web_data.asset_path, start=img_pages_dir),
- web_data.asset_path.stem]
+ #Ensure that these will ignore any multi-case pages if they exist
+ if "main_website" not in str(web_data.html_file):
+ #Create output HTML file path:
+ img_pages_dir = self.__case_web_paths[web_data.case]['img_pages_dir']
- #Check if plot image already handles multiple cases:
- if web_data.multi_case:
- case1 = "Listed in plots."
- plot_types = multi_plot_type_html
- else:
- case1 = web_data.case
- plot_types = plot_type_html
- #End if
+ img_data = [os.path.relpath(web_data.asset_path, start=img_pages_dir),
+ web_data.asset_path.stem]
- tmpl = jinenv.get_template('template.html') #Set template
- rndr = tmpl.render(title=main_title,
- var_title=web_data.name,
- season_title=web_data.season,
- plottype_title=web_data.plot_type,
- imgs=img_data,
- case1=case1,
- case2=data_name,
- case_yrs=case_yrs,
- baseline_yrs=baseline_yrs,
- mydata=mean_html_info[web_data.plot_type],
- plot_types=plot_types) #The template rendered
-
- #Write HTML file:
- with open(web_data.html_file, 'w', encoding='utf-8') as ofil:
- ofil.write(rndr)
- #End with
-
- #Check if the mean plot type page exists for this case:
- mean_ptype_file = img_pages_dir / f"mean_diag_{web_data.plot_type}.html"
- if not mean_ptype_file.exists():
-
- #Construct individual plot type mean_diag html files, if they don't
- #already exist:
- mean_tmpl = jinenv.get_template('template_mean_diag.html')
- mean_rndr = mean_tmpl.render(title=main_title,
- case1=case1,
- case2=data_name,
- case_yrs=case_yrs,
- baseline_yrs=baseline_yrs,
- mydata=mean_html_info[web_data.plot_type],
- curr_type=web_data.plot_type,
- plot_types=plot_types)
-
- #Write mean diagnostic plots HTML file:
- with open(mean_ptype_file,'w', encoding='utf-8') as ofil:
- ofil.write(mean_rndr)
+ rend_kwarg_dict = {"title": main_title,
+ "var_title": web_data.name,
+ "season_title": web_data.season,
+ "case_name": web_data.case,
+ "case_yrs": case_yrs,
+ "base_name": data_name,
+ "baseline_yrs": baseline_yrs,
+ "plottype_title": web_data.plot_type,
+ "imgs": img_data,
+ "mydata": mean_html_info[web_data.plot_type],
+ "plot_types": plot_types,
+ "multi": multi_layout}
+
+ tmpl = jinenv.get_template('template.html') #Set template
+
+ rndr = tmpl.render(rend_kwarg_dict) #The template rendered
+
+ #Write HTML file:
+ with open(web_data.html_file, 'w', encoding='utf-8') as ofil:
+ ofil.write(rndr)
#End with
- #End if (mean_ptype exists)
-
- #Check if the mean plot type and var page exists for this case:
- mean_ptype_plot_page = img_pages_dir / f"plot_page_{web_data.name}_{web_data.plot_type}.html"
- if not mean_ptype_plot_page.exists():
-
- #Construct individual plot type mean_diag html files, if they don't
- #already exist:
- plot_page_tmpl = jinenv.get_template('template_var.html')
- plot_page_rndr = plot_page_tmpl.render(title=main_title,
- var_title=web_data.name,
- season_title=web_data.season,
- plottype_title=web_data.plot_type,
- case1=case1,
- case2=data_name,
- case_yrs=case_yrs,
- baseline_yrs=baseline_yrs,
- mydata=mean_html_info[web_data.plot_type],
- curr_type=web_data.plot_type,
- plot_types=plot_types)
-
- #Write mean diagnostic plots HTML file:
- with open(mean_ptype_plot_page,'w', encoding='utf-8') as ofil:
- ofil.write(plot_page_rndr)
- #End with
- #End if (data frame)
+ #Check if the mean plot type page exists for this case:
+ mean_ptype_file = img_pages_dir / f"mean_diag_{web_data.plot_type}.html"
+ if not mean_ptype_file.exists():
+
+ #Construct individual plot type mean_diag html files, if they don't
+ #already exist:
+ mean_tmpl = jinenv.get_template('template_mean_diag.html')
+
+ #Remove keys from main dictionary for this html page
+ templ_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs', 'var_title', 'season_title'}}
+
+ mean_rndr = mean_tmpl.render(templ_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_file,'w', encoding='utf-8') as ofil:
+ ofil.write(mean_rndr)
+ #End with
+ #End if (mean_ptype exists)
+
+ #Check if the mean plot type and var page exists for this case:
+ plot_page = f"plot_page_{web_data.name}_{web_data.plot_type}.html"
+ mean_ptype_plot_page = img_pages_dir / plot_page
+ if not mean_ptype_plot_page.exists():
+
+ #Construct individual plot type mean_diag html files, if they don't
+ #already exist:
+ plot_page_tmpl = jinenv.get_template('template_var.html')
+
+ #Remove key from main dictionary for this html page
+ templ_var_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs'}}
+
+ plot_page_rndr = plot_page_tmpl.render(templ_var_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_plot_page,'w', encoding='utf-8') as ofil:
+ ofil.write(plot_page_rndr)
+ #End with
+ #End if (mean_ptype_plot_page)
+ #End if (check for multi-case diags)
#Also check if index page exists for this case:
index_html_file = \
self.__case_web_paths[web_data.case]['website_dir'] / "index.html"
@@ -698,71 +820,388 @@ def create_website(self):
plot_types = multi_plot_type_html
else:
plot_types = plot_type_html
+ plot_types = plot_type_html
#End if
#Construct index.html
index_title = "AMP Diagnostics Prototype"
index_tmpl = jinenv.get_template('template_index.html')
+
index_rndr = index_tmpl.render(title=index_title,
- case1=web_data.case,
- case2=data_name,
+ case_name=web_data.case,
+ base_name=data_name,
case_yrs=case_yrs,
baseline_yrs=baseline_yrs,
- plot_types=plot_types)
+ plot_types=plot_types,
+ multi=multi_layout)
#Write Mean diagnostics index HTML file:
with open(index_html_file, 'w', encoding='utf-8') as ofil:
ofil.write(index_rndr)
#End with
+ #End if (plot images)
#End for (web data loop)
- #If this is a multi-case instance, then copy website to "main" directory:
+ # - - - - - - - - - - - - - - - - - - - - - -
+ # --- End single-case diagnostics ---
+ # - - - - - - - - - - - - - - - - - - - - - -
+
+
+
+ # - - - - - - - - - - - - - - - - - - - - - -
+ # --- Checking for multi-case diagnostics ---
+ # - - - - - - - - - - - - - - - - - - - - - -
+
if main_site_path:
- #Add "multi-case" to start of case_names:
- case_names.insert(0, "multi-case")
+ #Loop over all web data objects AGAIN:
+ for web_data in self.__website_data:
+
+ #Create CSS templates file path:
+ main_templates_path = main_site_path / "templates"
+
+ #loop over all cases and make website directories:
+ for idx, case_name in enumerate(case_names):
+ #Check if case name is present in plot
+ if case_name in self.__case_web_paths:
+ #Extract website directory:
+ website_dir = self.__case_web_paths[case_name]['website_dir']
+ if not website_dir.is_dir():
+ website_dir.mkdir(parents=True)
+ #Copy website directory to "main site" directory:
+ shutil.copytree(website_dir, main_site_path / case_name)
+
+
+ #Starting multi-case tables if requested
+ # - - - - - - - - - - - - - - - - - - -
+ if web_data.data_frame:
+
+ #Create all individual tables for the individual websites
+
+ #Grab single case table path
+ table_pages_dir_indv = self.__case_web_paths[web_data.case]['table_pages_dir']
+
+ #Check if the mean plot type page exists for this case (or for multi-case):
+ mean_table_file = table_pages_dir_indv / "mean_tables.html"
+ table_keys = [web_data.case,data_name,"case_comparison"]
+
+ table_dict = {}
+ for key in table_keys:
+ if self.compare_obs:
+ if (key != "Obs") and (key != "case_comparison"):
+ table_dict[key] = multi_table_html_info[key]
+ else:
+ table_dict[key] = multi_table_html_info[key]
+ #End for
+
+ #Construct amwg_table.html
+ rend_kwarg_dict = {"title": main_title, "case_name": web_data.case,
+ "case_yrs": case_yrs,
+ "base_name": data_name,
+ "baseline_yrs": baseline_yrs,
+ "amwg_tables": table_dict,
+ "table_name": web_data.name,
+ "plot_types": plot_type_html,
+ "multi_head": True,
+ "multi": False,
+ "case_sites": case_sites}
+
+ if not mean_table_file.exists():
+ #Construct mean_table.html
+ mean_table_tmpl = jinenv.get_template('template_mean_tables.html')
+
+ #Remove key from main dictionary for this html page
+ tmpl_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'table_name'}}
+
+ mean_table_rndr = mean_table_tmpl.render(tmpl_rend_kwarg_dict)
+
+ #Write mean diagnostic tables HTML file:
+ with open(mean_table_file, 'w', encoding='utf-8') as ofil:
+ ofil.write(mean_table_rndr)
+ #End with
+ #End if
- #Create CSS templates file path:
- main_templates_path = main_site_path / "templates"
+ #Loop through all test cases (exclude baseline)
+ if web_data.case != data_name:
+ table_html = web_data.data.to_html(index=False, border=1, justify='center',
+ float_format='{:6g}'.format)
- #loop over cases:
- for case_name in case_names:
+ indv_html = table_pages_dir_indv / f"amwg_table_{web_data.name}.html"
- #Check if case name is present in plot
- if case_name in self.__case_web_paths:
- #Extract website directory:
- website_dir = self.__case_web_paths[case_name]['website_dir']
+ if not indv_html.exists():
+ table_tmpl = jinenv.get_template('template_table.html')
+
+ tmpl_rend_kwarg_dict = rend_kwarg_dict
+ rend_kwarg_dict["table_html"] = table_html
+
+ table_rndr = table_tmpl.render(rend_kwarg_dict)
+
+ #Write mean diagnostic tables HTML file:
+ with open(indv_html, 'w', encoding='utf-8') as ofil:
+ ofil.write(table_rndr)
+ #end if (indv_html)
+
+ #Baseline case added to all test case directories
+ # - this block should only run once when web_data is the baseline case
+ else:
+ table_html = web_data.data.to_html(index=False, border=1, justify='center',
+ float_format='{:6g}'.format)
- #Copy website directory to "main site" directory:
- shutil.copytree(website_dir, main_site_path / case_name)
+ rend_kwarg_dict["table_html"] = table_html
- #Also add path to case_sites dictionary:
- case_sites[case_name] = os.path.join(os.curdir, case_name, "index.html")
+ for case_name in case_names:
+ table_pages_dir_sp = self.__case_web_paths[case_name]['table_pages_dir']
+ table_key = [case_name,data_name,"case_comparison"]
- #Also make sure CSS template files have been copied over:
- if not main_templates_path.is_dir():
- css_files_dir = self.__case_web_paths[case_name]['css_files_dir']
- shutil.copytree(css_files_dir, main_site_path / "templates")
+ base_table_dict = {key: multi_table_html_info[key] for key in table_key}
+
+ rend_kwarg_dict["case_name"] = case_name
+ rend_kwarg_dict["amwg_tables"] = base_table_dict
+
+ sp_html = table_pages_dir_sp / f"amwg_table_{data_name}.html"
+ if not sp_html.exists():
+
+ table_tmpl = jinenv.get_template('template_table.html')
+
+ table_rndr = table_tmpl.render(rend_kwarg_dict)
+
+ with open(sp_html, 'w', encoding='utf-8') as ofil:
+ ofil.write(table_rndr)
+ #End if (sp_html)
+ #End for (case_names)
+ #End if (baseline_name)
+
+
+ #Starting multi-case plots if requested
+ # - - - - - - - - - - - - - - - - - - -
+ if not web_data.data_frame:
+
+ #Extract plot details
+ season = web_data.season
+ ptype = web_data.plot_type
+ var = web_data.name
+ ext = web_data.plot_ext
+
+ #Check if category has been provided for this web data:
+ if web_data.category:
+ #If so, then just use directly:
+ category = web_data.category
+ else:
+ #Check if variable in defaults dictionary:
+ if web_data.name in var_defaults_dict:
+ #If so, then extract category from dictionary:
+ category = var_defaults_dict[web_data.name].get("category",
+ "No category yet")
+ else:
+ category = 'No category yet'
+ #End if
#End if
- #End if
- #End for (model case loop)
- #Create multi-case site:
+ #Check for multi-case multi-plots
+ if multi_case_plots:
+ #This currently runs web_data.case for every case, but in reality
+ #it really only needs to run once since the plots are
+ #already made with all cases.
+ #So just grab the first test case:
+ case1 = self.get_cam_info('cam_case_name', required=True)[0]
+ if str(web_data.case) == str(case1):
+ #Check if variable is in desired multi-case plot
+ #and if plot_type is in given multi-case plot set:
+ if (var in mvars) and (ext in multi_case_plots):
+ #Move file to assets directory:
+ if not web_data.data.is_file():
+ shutil.copy(web_data.data, web_data.asset_path)
+
+ #Create output HTML file path:
+ img_pages_dir = self.__case_web_paths["multi-case"]['img_pages_dir']
+ multi_plot_page = f"{var}_{season}_{ptype}_multi_plot.png"
+ img_data = [os.path.relpath(main_site_assets_path / multi_plot_page,
+ start=main_site_img_path),
+ multi_plot_page]
+
+ rend_kwarg_dict = {"title": main_title,
+ "var_title": var,
+ "season_title": season,
+ "case_yrs": case_yrs,
+ "base_name": data_name,
+ "baseline_yrs": baseline_yrs,
+ "plottype_title": ptype,
+ "imgs": img_data,
+ "mydata": multi_plot_html_info[ptype],
+ "plot_types": multi_plot_type_html,
+ "multi": multi_layout,
+ "case_sites": case_sites}
+
+ multimean = f"plot_page_multi_case_{var}_{season}_{ptype}_Mean.html"
+ if not (img_pages_dir / multimean).exists():
+
+ tmpl = jinenv.get_template('template_multi_case.html')
+
+ rndr = tmpl.render(rend_kwarg_dict)
+
+ #Write HTML file:
+ with open(img_pages_dir / multimean,
+ 'w', encoding='utf-8') as ofil:
+ ofil.write(rndr)
+ #End if (multimean)
+
+ #Check if the mean plot type and var page exists for this case:
+ img_pages_dir = self.__case_web_paths["multi-case"]['img_pages_dir']
+ plot_page = f"plot_page_multi_case_{var}_{ptype}.html"
+ mean_ptype_plot_page = img_pages_dir / plot_page
+
+ if not mean_ptype_plot_page.exists():
+
+ #Remove key from main dictionary for this html page
+ templ_var_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs'}}
+
+ #Construct individual plot type mean_diag
+ #html files, if they don't already exist:
+ page_tmpl = jinenv.get_template('template_multi_case_var.html')
+
+ plot_page_rndr = page_tmpl.render(templ_var_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_plot_page,'w', encoding='utf-8') as ofil:
+ ofil.write(plot_page_rndr)
+ #End with
+ #End if (mean_ptype_plot_page exists)
+
+ multi_mean = f"multi_case_mean_diag_{ptype}.html"
+ mean_ptype_file = main_site_img_path / multi_mean
+ if not mean_ptype_file.exists():
+
+ #Remove keys from main dictionary for this html page
+ templ_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs', 'var_title', 'season_title'}}
+
+ #Construct individual plot type mean_diag
+ #html files, if they don't already exist:
+ tmp = jinenv.get_template('template_multi_case_mean_diag.html')
+
+ mean_rndr = tmp.render(templ_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_file,'w', encoding='utf-8') as ofil:
+ ofil.write(mean_rndr)
+ #End with
+ #End if (mean_ptype exists)
+
+ #Loop over any non multi-case multi-plot scenarios
+ #ie multi-case Taylor Diagrams and multi-case QBO
+ if ext not in multi_case_dict:
+ #Move file to assets directory:
+ if not web_data.data.is_file():
+ shutil.copy(web_data.data, web_data.asset_path)
+
+ #Create output HTML file path:
+ img_pages_dir = self.__case_web_paths["multi-case"]['img_pages_dir']
+ multi_plot_page = f"{var}_{season}_{ptype}_multi_plot.png"
+ img_data = [os.path.relpath(main_site_assets_path / multi_plot_page,
+ start=main_site_img_path),
+ multi_plot_page]
+
+ rend_kwarg_dict = {"title": main_title,
+ "var_title": var,
+ "season_title": season,
+ "case_yrs": case_yrs,
+ "base_name": data_name,
+ "baseline_yrs": baseline_yrs,
+ "plottype_title": ptype,
+ "imgs": img_data,
+ "mydata": multi_mean_html_info[ptype],
+ "plot_types": multi_plot_type_html,
+ "multi": multi_layout,
+ "case_sites": case_sites}
+
+ multimean = f"plot_page_multi_case_{var}_{season}_{ptype}_Mean.html"
+ if not (img_pages_dir / multimean).exists():
+ tmpl = jinenv.get_template('template_multi_case.html')
+
+ rndr = tmpl.render(rend_kwarg_dict)
+
+ #Write HTML file:
+ with open(img_pages_dir / multimean,
+ 'w', encoding='utf-8') as ofil:
+ ofil.write(rndr)
+ #End if (multimean)
+
+ #Check if the mean plot type and var page exists for this case:
+ img_pages_dir = self.__case_web_paths["multi-case"]['img_pages_dir']
+ plot_page = f"plot_page_multi_case_{var}_{ptype}.html"
+ mean_ptype_plot_page = img_pages_dir / plot_page
+
+ if not mean_ptype_plot_page.exists():
+
+ #Remove key from main dictionary for this html page
+ templ_var_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs'}}
+
+ #Construct individual plot type mean_diag
+ #html files, if they don't already exist:
+ page_tmpl = jinenv.get_template('template_multi_case_var.html')
+
+ plot_page_rndr = page_tmpl.render(templ_var_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_plot_page,'w', encoding='utf-8') as ofil:
+ ofil.write(plot_page_rndr)
+ #End with
+ #End if (mean_ptype_plot_page exists)
+
+ multi_mean = f"multi_case_mean_diag_{ptype}.html"
+ mean_ptype_file = main_site_img_path / multi_mean
+ if not mean_ptype_file.exists():
+
+ #Remove keys from main dictionary for this html page
+ templ_rend_kwarg_dict = {k: rend_kwarg_dict[k] for k in rend_kwarg_dict.keys() - {'imgs', 'var_title', 'season_title'}}
+
+ #Construct individual plot type mean_diag
+ #html files, if they don't already exist:
+ tmp = jinenv.get_template('template_multi_case_mean_diag.html')
+
+ mean_rndr = tmp.render(templ_rend_kwarg_dict)
+
+ #Write mean diagnostic plots HTML file:
+ with open(mean_ptype_file,'w', encoding='utf-8') as ofil:
+ ofil.write(mean_rndr)
+ #End with
+ #End if (mean_ptype exists)
+ #End if (ext not in multi_case_dict)
+ #End if (web_data.data_frame)
+ #End for (web_data)
+
+ #Also make sure CSS template files have been copied over:
+ if not main_templates_path.is_dir():
+ #If not, just grab the files from the first test case directory
+ css_files_dir = self.__case_web_paths[case_names[-1]]['css_files_dir']
+ shutil.copytree(css_files_dir, main_templates_path)
+ #End if
+
+ if multi_case_plots:
+ for key in multi_case_plots:
+ #Update the dictionary to add any plot types specified in the yaml file
+ mcase_plot = f"html_img/multi_case_mean_diag_{multi_case_dict[key]}.html"
+ multi_plots[multi_case_dict[key]] = mcase_plot
+ #End for
+ #End if
+
main_title = "ADF Diagnostics"
main_tmpl = jinenv.get_template('template_multi_case_index.html')
main_rndr = main_tmpl.render(title=main_title,
- case_sites=case_sites,
- )
+ case_sites=case_sites,
+ base_name=data_name,
+ baseline_yrs=baseline_yrs,
+ multi_plots=multi_plots)
#Write multi-case main HTML file:
outputfile = main_site_path / "index.html"
with open(outputfile, 'w', encoding='utf-8') as ofil:
ofil.write(main_rndr)
#End with
- #End if
+ #End if (multi case)
#Notify user that script has finishedd:
print(" ...Webpages have been generated successfully.")
+
#++++++++++++++++++++
#End Class definition
#++++++++++++++++++++
diff --git a/lib/plotting_functions.py b/lib/plotting_functions.py
index 99a373009..a1894eb57 100644
--- a/lib/plotting_functions.py
+++ b/lib/plotting_functions.py
@@ -8,6 +8,7 @@
#import statements:
from typing import Optional
+from pathlib import Path
import numpy as np
import xarray as xr
import matplotlib as mpl
@@ -1659,5 +1660,159 @@ def square_contour_difference(fld1, fld2, **kwargs):
cb2 = fig.colorbar(img3, cax=cbax_bot, orientation='horizontal')
return fig
+#####
+
+###############################
+# Multi-Case Multi-Plot Section
+###############################
+
+def multi_latlon_plots(wks, ptype, case_names, nicknames, multi_dict, web_category, adfobj):
+ """ This is a multi-case comparison of test minus baseline for each test case:
+ wks: path for saved image.
+ Should be assets directory inside of the main_website directory
+
+ ptype: ADF shortname for plot type.
+ For this plot it will be either LatLon or LatLon_Vector
+
+ case_names: list of test case names only
+
+ nicknames: list of test case nicknames
+ First entry of list will be list of test case nicknames
+ Second entry will be string object of baseline nickname
+
+ multi_dict: ordered dictionary of difference data for each var, test case, and season
+ multi_dict[var][case_name][s]
+
+ web_category:
+ variable category
+
+ adfobj: ADF object
+ Needed to test if redo_plot is called in config yaml file
+ """
+
+
+ nplots = len(nicknames[0])
+ if nplots > 2:
+ ncols = 3
+ else:
+ ncols = 2
+ #End if
+
+ #Check redo_plot. If set to True: remove old plot, if it already exists:
+ redo_plot = adfobj.get_basic_info('redo_plot')
+
+ #Determine needed matplotlib normalization function:
+ normfunc,_ = use_this_norm()
+
+ #Try and format spacing based on number of cases
+ # NOTE: ** this will have to change if figsize or dpi change **
+ if nplots < 4:
+ hspace = -1.0
+ else:
+ hspace = -0.85
+ #End if
+
+ nrows = int(np.ceil(nplots/ncols))
+ if nrows == 1:
+ y_title = 0.265
+ else:
+ y_title = 0.315
+ #End if
+
+ if nrows < 2:
+ nrows = 2
+ #End if
+
+ # specify the central longitude for the plot
+ central_longitude = get_central_longitude(adfobj)
+ proj = ccrs.PlateCarree(central_longitude=central_longitude)
+ # 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='')
+ for var in multi_dict.keys():
+ if ((adfobj.compare_obs) and (var in adfobj.var_obs_dict)) or (not adfobj.compare_obs):
+ for case in multi_dict[var].keys():
+ for season in multi_dict[var][case].keys():
+ file_name = f"{var}_{season}_{ptype}_multi_plot.png"
+ if (not redo_plot) and Path(wks / file_name).is_file():
+ #Continue to next iteration:
+ continue
+ elif (redo_plot) or (not Path(wks / file_name).is_file()):
+ fig_width = 15
+ fig_height = 15+(3*nrows) #try and dynamically create size of fig based off number of cases (therefore rows)
+ fig, axs = plt.subplots(nrows=nrows,ncols=ncols,figsize=(fig_width,fig_height), facecolor='w', edgecolor='k',
+ sharex=True,
+ sharey=True,
+ subplot_kw={"projection": proj})
+
+ #Set figure title
+ plt.suptitle(f'All Case Comparison (Test - Baseline) {var}: {season}\n', fontsize=16, y=y_title)#y=0.325 y=0.225
+
+ count = 0
+ img = []
+ titles = []
+ for r in range(0,nrows):
+ for c in range(0,ncols):
+ if count < nplots:
+ mdlfld = multi_dict[var][case_names[count]][season]["diff_data"]
+ lat = mdlfld['lat']
+ mwrap, lon = add_cyclic_point(mdlfld, coord=mdlfld['lon'])
+
+ # mesh for plots:
+ lons, lats = np.meshgrid(lon, lat)
+
+ levelsdiff = multi_dict[var][case_names[count]][season]["vres"]["diff_contour_range"]
+ levelsdiff = np.arange(levelsdiff[0],levelsdiff[1]+levelsdiff[-1],levelsdiff[-1])
+
+ # color normalization for difference
+ if (np.min(levelsdiff) < 0) and (0 < np.max(levelsdiff)):
+ 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))
+
+ cmap = multi_dict[var][case_names[count]][season]["vres"]['diff_colormap']
+
+ img.append(axs[r,c].contourf(lons, lats, mwrap, levels=levelsdiff,
+ cmap=cmap, norm=normdiff,
+ transform=proj))
+
+ #Set individual plot titles (case name/nickname)
+ titles.append(axs[r,c].set_title("$\mathbf{Test}:$"+f" {nicknames[0][count]}",loc='left',fontsize=8))
+ titles.append(axs[r,c].set_title("$\mathbf{Baseline}:$"+f" {nicknames[1]}",loc='right',fontsize=8))
+
+ axs[r,c].spines['geo'].set_linewidth(1.5) #cartopy's recommended method
+ axs[r,c].coastlines()
+ axs[r,c].set_xticks(np.linspace(-180, 120, 6), crs=proj)
+ axs[r,c].set_yticks(np.linspace(-90, 90, 7), crs=proj)
+ axs[r,c].tick_params('both', length=5, width=1.5, which='major')
+ axs[r,c].tick_params('both', length=5, width=1.5, which='minor')
+ axs[r,c].xaxis.set_major_formatter(lon_formatter)
+ axs[r,c].yaxis.set_major_formatter(lat_formatter)
+
+ else:
+ #Clear left over subplots if they don't fill the row x column matrix
+ axs[r,c].set_visible(False)
+ count = count + 1
+
+ # __COLORBARS__
+ fig.colorbar(img[-1], ax=axs.ravel().tolist(), orientation='horizontal',
+ aspect=20, shrink=.5, location="bottom",
+ anchor=(0.5,-0.3), extend='both')
+
+ #Clean up the spacing a bit
+ plt.subplots_adjust(wspace=0.3, hspace=hspace)
+
+ fig.savefig(wks / file_name, bbox_inches='tight', dpi=300)
+
+ adfobj.add_website_data(wks / file_name, file_name, case_names[0], plot_ext="global_latlon_map",
+ category=web_category, season=season, plot_type="LatLon",multi_case=True)
+
+ #Close plots:
+ plt.close()
+
+
#####################
#END HELPER FUNCTIONS
diff --git a/lib/website_templates/template.html b/lib/website_templates/template.html
index cfa488ab2..be92a6d7b 100644
--- a/lib/website_templates/template.html
+++ b/lib/website_templates/template.html
@@ -1,9 +1,7 @@
-
-
- ADF {{var_title}}
+ ADF {{ var_title }}
@@ -14,6 +12,9 @@
-
+ {% for category, var_seas in mydata.items() %}
+ {% for var_name, seas_files in var_seas.items() %}
+ {% if var_name == var_title %}
+ {% for season_name, file_name in seas_files.items() %}
+