diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 702a7ec89..5d0c04f5c 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -70,41 +70,4 @@ jobs: - name: Test with pytest run: | - cd test - cd scatter - pytest test_scatter.py - cd ../bar - pytest test_bar.py - cd ../box - pytest test_box.py - cd ../contour - pytest test_contour.py - cd ../eclv - pytest test_eclv.py - cd ../ens_ss - pytest test_ens_ss.py - cd ../equivalence_testing_bounds - pytest test_equivalence_testing_bounds.py - cd ../line - pytest test_line_groups_plot.py - pytest test_line_plot.py - cd ../mpr_plot - pytest test_mpr_plot.py - cd ../performance_diagram - pytest test_performance_diagram.py - cd ../reliability_diagram - pytest test_reliability_diagram.py - cd ../roc_diagram - pytest test_roc_diagram.py - cd ../taylor_diagram - pytest test_taylor_diagram.py - cd ../wind_rose - pytest test_wind_rose.py - cd ../histogram - pytest test_prob_hist.py - pytest test_rank_hist.py - pytest test_rel_hist.py - cd ../tcmpr_plots - pytest --capture=fd test_tcmpr_plots.py - - + pytest diff --git a/.idea/METplotpy.iml b/.idea/METplotpy.iml index 2d40d0241..d5edc0586 100644 --- a/.idea/METplotpy.iml +++ b/.idea/METplotpy.iml @@ -2,7 +2,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index c58198b34..23fec60ae 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/metplotpy/plots/bar/bar.py b/metplotpy/plots/bar/bar.py index cb8818866..77f3dab5f 100644 --- a/metplotpy/plots/bar/bar.py +++ b/metplotpy/plots/bar/bar.py @@ -452,8 +452,9 @@ def _remove_html(self) -> None: Removes previously made HTML file. """ - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" + # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -465,9 +466,8 @@ def write_html(self) -> None: """ if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -498,10 +498,11 @@ def write_output_file(self) -> None: filename = filename + '.points1' + # create directory if needed + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as f: for series in self.series_list: f.write(f"{series.series_points['dbl_med']}\n") - f.close() def main(config_filename=None): diff --git a/metplotpy/plots/base_plot.py b/metplotpy/plots/base_plot.py index 03a84ef15..6925ce646 100644 --- a/metplotpy/plots/base_plot.py +++ b/metplotpy/plots/base_plot.py @@ -387,8 +387,7 @@ def save_to_file(self): # Create the directory for the output plot if it doesn't already exist dirname = os.path.dirname(os.path.abspath(image_name)) - if not os.path.exists(dirname): - os.mkdir(dirname) + os.makedirs(dirname, exist_ok=True) if self.figure: try: self.figure.write_image(image_name) diff --git a/metplotpy/plots/box/box.py b/metplotpy/plots/box/box.py index 6c41762a6..35e9f522f 100644 --- a/metplotpy/plots/box/box.py +++ b/metplotpy/plots/box/box.py @@ -569,9 +569,8 @@ def write_html(self) -> None: # is_create = self.config_obj.create_html if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -605,6 +604,9 @@ def write_output_file(self) -> None: filename = filename + '.points1' if os.path.exists(filename): os.remove(filename) + # create directory if needed + os.makedirs(os.path.dirname(filename), exist_ok=True) + for series in self.series_list: for indy_val in self.config_obj.indy_vals: if calc_util.is_string_integer(indy_val): diff --git a/metplotpy/plots/config.py b/metplotpy/plots/config.py index 9f1f9f7f2..88d02d4cc 100644 --- a/metplotpy/plots/config.py +++ b/metplotpy/plots/config.py @@ -490,6 +490,9 @@ def _get_show_legend(self) -> list: """ show_legend_settings = self.get_config_value('show_legend') + if show_legend_settings is None: + raise ValueError("ERROR: show_legend parameter is not provided.") + # Support all variations of setting the show_legend: '1', 1, "true" (any combination of cases), True (boolean) updated_show_legend_settings = [] for legend_setting in show_legend_settings: @@ -499,10 +502,6 @@ def _get_show_legend(self) -> list: else: updated_show_legend_settings.append(int(0)) - - if show_legend_settings is None: - raise ValueError("ERROR: show_legend parameter is not provided.") - return self.create_list_by_series_ordering(list(updated_show_legend_settings)) def _get_markers(self): diff --git a/metplotpy/plots/contour/contour.py b/metplotpy/plots/contour/contour.py index 353a1d72c..233b6e47e 100644 --- a/metplotpy/plots/contour/contour.py +++ b/metplotpy/plots/contour/contour.py @@ -365,8 +365,9 @@ def _remove_html(self) -> None: Removes previously made HTML file. """ - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" + # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -377,9 +378,8 @@ def write_html(self) -> None: """ if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -408,6 +408,7 @@ def write_output_file(self) -> None: filename = self.config_obj.points_path + os.path.sep + filename filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as file: writer = csv.writer(file, delimiter='\t') diff --git a/metplotpy/plots/eclv/eclv.py b/metplotpy/plots/eclv/eclv.py index 5860b572b..358539d65 100644 --- a/metplotpy/plots/eclv/eclv.py +++ b/metplotpy/plots/eclv/eclv.py @@ -362,6 +362,7 @@ def write_output_file(self) -> None: filename = self.config_obj.points_path + os.path.sep + filename filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as file: writer = csv.writer(file, delimiter='\t') diff --git a/metplotpy/plots/ens_ss/ens_ss.py b/metplotpy/plots/ens_ss/ens_ss.py index d6d153ee5..f74d56378 100644 --- a/metplotpy/plots/ens_ss/ens_ss.py +++ b/metplotpy/plots/ens_ss/ens_ss.py @@ -475,8 +475,9 @@ def _remove_html(self) -> None: Removes previously made HTML file. """ - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" + # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -487,9 +488,8 @@ def write_html(self) -> None: """ if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -525,6 +525,7 @@ def write_output_file(self) -> None: # filename = 'points' filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as file: while i < len(self.series_list): diff --git a/metplotpy/plots/equivalence_testing_bounds/equivalence_testing_bounds.py b/metplotpy/plots/equivalence_testing_bounds/equivalence_testing_bounds.py index 5d3798c0f..7cb366fab 100644 --- a/metplotpy/plots/equivalence_testing_bounds/equivalence_testing_bounds.py +++ b/metplotpy/plots/equivalence_testing_bounds/equivalence_testing_bounds.py @@ -488,9 +488,9 @@ def _remove_html(self) -> None: """ Removes previously made HTML file. """ + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -504,9 +504,9 @@ def write_html(self) -> None: self.logger.info(f"Write html file: {datetime.now()}") if self.config_obj.create_html is True: - # construct the fle name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + # construct the file name from plot_filename + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -556,6 +556,7 @@ def write_output_file(self) -> None: filename = self.config_obj.points_path + os.path.sep + filename filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) # save points self._save_points(ci_tost_df.values.tolist(), filename) diff --git a/metplotpy/plots/histogram/hist.py b/metplotpy/plots/histogram/hist.py index a3012a5c7..fe12d96ef 100644 --- a/metplotpy/plots/histogram/hist.py +++ b/metplotpy/plots/histogram/hist.py @@ -437,9 +437,8 @@ def write_html(self) -> None: if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -472,6 +471,7 @@ def write_output_file(self) -> None: filename = self.config_obj.points_path + os.path.sep + filename filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as file: for series in self.series_list: diff --git a/metplotpy/plots/histogram_2d/histogram_2d.py b/metplotpy/plots/histogram_2d/histogram_2d.py index 3f22aa068..b7f35159d 100644 --- a/metplotpy/plots/histogram_2d/histogram_2d.py +++ b/metplotpy/plots/histogram_2d/histogram_2d.py @@ -109,15 +109,16 @@ def save_to_file(self): self.logger.info(f"Saving plot to file {image_name}: {datetime.now()} ") if self.figure: try: + os.makedirs(os.path.dirname(image_name), exist_ok=True) self.figure.write_image(image_name) except FileNotFoundError: self.logger.error(f"FileNotFoundError: Can't save to file {image_name}") - except ValueError: + except ValueError as err: self.logger.error(f"ValueError: Some other error occurred " - f"{datetime.now()}") + f"{datetime.now()}: {err}") else: - self.logger.error(f"The figure was not created. Cannot save file.") + self.logger.error("The figure was not created. Cannot save file.") self.logger.info(f"Finished saving plot to file: {datetime.now()}") @@ -128,46 +129,8 @@ def write_output_file(self): :return: """ - self.logger.info(f"Begin writing plot to output file: {datetime.now()}") - self.logger.info(f"No intermediate points1 file created. This plot type is not " - "integrated into METviewer: {datetime.now()}") - - # if points_path parameter doesn't exist, - # open file, name it based on the stat_input config setting, - # (the input data file) except replace the .data - # extension with .points1 extension - # otherwise use points_path path - match = re.match(r'(.*)(.data)', self.config_obj.parameters['stat_input']) - if self.config_obj.dump_points_1 is True and match: - filename = match.group(1) - # replace the default path with the custom - if self.config_obj.points_path is not None: - # get the file name - path = filename.split(os.path.sep) - if len(path) > 0: - filename = path[-1] - else: - filename = '.' + os.path.sep - filename = self.config_obj.points_path + os.path.sep + filename - - output_file = filename + '.points1' - - # make sure this file doesn't already - # exist, delete it if it does - self.logger.info(f"Check if file exists, delete if it does. " - f"{datetime.now()}") - try: - if os.stat(output_file).st_size == 0: - open(output_file, 'a') - else: - os.remove(output_file) - except FileNotFoundError: - # OK if no file was found - self.logger.info(f"FileNotFound while checking if output file exists. " - f" This is OK:{datetime.now()}") - pass - - self.logger.info(f"Finished writing plot to output file: {datetime.now()}") + self.logger.info("No intermediate points1 file created. This plot type is not " + f"integrated into METviewer: {datetime.now()}") def _read_input_data(self): """ diff --git a/metplotpy/plots/hovmoeller/hovmoeller.py b/metplotpy/plots/hovmoeller/hovmoeller.py index b189a903c..89145be36 100644 --- a/metplotpy/plots/hovmoeller/hovmoeller.py +++ b/metplotpy/plots/hovmoeller/hovmoeller.py @@ -17,15 +17,14 @@ __author__ = 'David Fillmore' __version__ = '0.1.0' -import metcalcpy.util.read_env_vars_in_config - """ Import standard modules """ +import os from datetime import datetime import getpass import sys -import yaml + import numpy as np import xarray as xr import plotly.graph_objects as go @@ -208,8 +207,8 @@ def write_html(self) -> None: self.logger.info(f"Begin writing html output: {datetime.now()}") if self.config_obj.create_html is True: # construct the fle name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) diff --git a/metplotpy/plots/line/line.py b/metplotpy/plots/line/line.py index c49c3614a..b978049c2 100644 --- a/metplotpy/plots/line/line.py +++ b/metplotpy/plots/line/line.py @@ -76,8 +76,8 @@ def __init__(self, parameters: dict) -> None: "curves is inconsistent with the number of settings " "required for describing each series. Please check " "the number of your configuration file's plot_ci, " - "plot_disp, series_order, user_legend " - "colors, series_symbols, show_legend settings.") + "plot_disp, series_order, user_legend, " + "colors, series_symbols, and show_legend settings.") self.logger.error(f"ValueError: {error_msg}: {datetime.now()}") raise ValueError(error_msg) @@ -712,8 +712,9 @@ def _remove_html(self) -> None: Removes previously made HTML file. """ - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" + # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -728,9 +729,8 @@ def write_html(self) -> None: logger.info(f"Begin writing to html file: {datetime.now()}") if self.config_obj.create_html is True: # construct the file name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - name_arr[-1] = 'html' - html_name = ".".join(name_arr) + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) diff --git a/metplotpy/plots/line/line_config.py b/metplotpy/plots/line/line_config.py index d4acbe88b..39149d967 100644 --- a/metplotpy/plots/line/line_config.py +++ b/metplotpy/plots/line/line_config.py @@ -383,7 +383,7 @@ def _get_plot_stat(self) -> str: def _config_consistency_check(self) -> bool: """ Checks that the number of settings defined for plot_ci, - plot_disp, series_order, user_legend colors, and series_symbols + plot_disp, series_order, user_legend, colors, and series_symbols are consistent. Args: @@ -399,24 +399,29 @@ def _config_consistency_check(self) -> bool: # permutations from the series_var setting in the # config file - # Numbers of values for other settings for series - num_ci_settings = len(self.plot_ci) - num_plot_disp = len(self.plot_disp) - num_markers = len(self.marker_list) - num_series_ord = len(self.series_ordering) - num_colors = len(self.colors_list) - num_legends = len(self.user_legends) - num_line_widths = len(self.linewidth_list) - num_linestyles = len(self.linestyles_list) - num_show_legend = len(self.show_legend) - num_con_series = len(self.con_series) - status = False - - if (self.num_series == num_plot_disp == \ - num_markers == num_series_ord == num_colors \ - == num_legends == num_line_widths == num_linestyles == num_ci_settings \ - == num_show_legend == num_con_series): - status = True + lists_to_check = { + "plot_ci": self.plot_ci, + "plot_disp": self.plot_disp, + "marker_list": self.marker_list, + "series_ordering": self.series_ordering, + "colors_list": self.colors_list, + "user_legends": self.user_legends, + "linewidth_list": self.linewidth_list, + "linestyles_list": self.linestyles_list, + "show_legend": self.show_legend, + "con_series": self.con_series, + } + status = True + for name, list_to_check in lists_to_check.items(): + + if len(list_to_check) == self.num_series: + continue + + self.logger.error( + f"number of series ({self.num_series}) does not match {name} ({len(list_to_check)})" + ) + status = False + return status def _get_plot_ci(self) -> list: diff --git a/metplotpy/plots/mpr_plot/mpr_plot.py b/metplotpy/plots/mpr_plot/mpr_plot.py index 329d5b279..90a77fccf 100644 --- a/metplotpy/plots/mpr_plot/mpr_plot.py +++ b/metplotpy/plots/mpr_plot/mpr_plot.py @@ -13,7 +13,7 @@ """ __author__ = 'Tatiana Burek' - +import os from datetime import datetime import pandas as pd import numpy as np @@ -562,13 +562,14 @@ def save_to_file(self) -> None: Returns: """ - self.logger.info(f"Saving to file") + self.logger.info("Saving to file") image_name = self.get_config_value('plot_filename') pio.kaleido.scope.default_format = "png" pio.kaleido.scope.default_height = self.config_obj.height pio.kaleido.scope.default_width = self.config_obj.width if self.figure: try: + os.makedirs(os.path.dirname(image_name), exist_ok=True) self.figure.write_image(image_name) except FileNotFoundError: self.logger.error(f"FileNotFoundError: {image_name}") diff --git a/metplotpy/plots/performance_diagram/performance_diagram.py b/metplotpy/plots/performance_diagram/performance_diagram.py index e5f92ed28..a9d96d305 100644 --- a/metplotpy/plots/performance_diagram/performance_diagram.py +++ b/metplotpy/plots/performance_diagram/performance_diagram.py @@ -425,36 +425,26 @@ def write_output_file(self): filename = self.config_obj.points_path + os.path.sep + filename output_file = filename + '.points1' + os.makedirs(os.path.dirname(output_file), exist_ok=True) + if os.path.exists(output_file): + os.remove(output_file) + + with open(output_file, 'a') as fileobj: + header_str = "1-far\t pody\n" + fileobj.write(header_str) + all_pody = [] + all_sr = [] + for series in self.series_list: + pody_points = series.series_points[1] + sr_points = series.series_points[0] + all_pody.extend(pody_points) + all_sr.extend(sr_points) + + all_points = zip(all_sr, all_pody) + for idx, pts in enumerate(all_points): + data_str = str(pts[0]) + "\t" + str(pts[1]) + "\n" + fileobj.write(data_str) - # make sure this file doesn't already - # exist, delete it if it does - try: - if os.stat(output_file).st_size == 0: - fileobj = open(output_file, 'a') - else: - os.remove(output_file) - except FileNotFoundError: - # OK if no file was found - self.logger.error("FileNotFoundError: OK to ignore, deleting files " - "and the file to delete is not found") - - fileobj = open(output_file, 'a') - header_str = "1-far\t pody\n" - fileobj.write(header_str) - all_pody = [] - all_sr = [] - for series in self.series_list: - pody_points = series.series_points[1] - sr_points = series.series_points[0] - all_pody.extend(pody_points) - all_sr.extend(sr_points) - - all_points = zip(all_sr, all_pody) - for idx, pts in enumerate(all_points): - data_str = str(pts[0]) + "\t" + str(pts[1]) + "\n" - fileobj.write(data_str) - - fileobj.close() self.logger.info(f"Finished writing output file: {datetime.now()}") diff --git a/metplotpy/plots/reliability_diagram/reliability.py b/metplotpy/plots/reliability_diagram/reliability.py index b83f95720..fc928af71 100644 --- a/metplotpy/plots/reliability_diagram/reliability.py +++ b/metplotpy/plots/reliability_diagram/reliability.py @@ -600,8 +600,9 @@ def _remove_html(self) -> None: Removes previously made HTML file. """ - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" + # remove the old file if it exist if os.path.exists(html_name): os.remove(html_name) @@ -613,8 +614,8 @@ def write_html(self) -> None: self.logger.info("Writing html file.") if self.config_obj.create_html is True: # construct the fle name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) @@ -712,6 +713,7 @@ def _save_points(points: list, output_file: str) -> None: else: formatted_row.append("%.6f" % val) all_points_formatted.append(formatted_row) + os.makedirs(os.path.dirname(output_file), exist_ok=True) with open(output_file, "w+") as my_csv: csv_writer = csv.writer(my_csv, delimiter=' ') csv_writer.writerows(all_points_formatted) diff --git a/metplotpy/plots/revision_box/revision_box.py b/metplotpy/plots/revision_box/revision_box.py index d9336712e..bfca2af43 100644 --- a/metplotpy/plots/revision_box/revision_box.py +++ b/metplotpy/plots/revision_box/revision_box.py @@ -268,6 +268,7 @@ def write_output_file(self) -> None: filename = self.config_obj.points_path + os.path.sep + filename filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) if os.path.exists(filename): os.remove(filename) for series in self.series_list: diff --git a/metplotpy/plots/revision_series/revision_series.py b/metplotpy/plots/revision_series/revision_series.py index acf7621e9..03e6cafdb 100644 --- a/metplotpy/plots/revision_series/revision_series.py +++ b/metplotpy/plots/revision_series/revision_series.py @@ -17,7 +17,6 @@ from typing import Union -import yaml import numpy as np import plotly.graph_objects as go @@ -280,6 +279,7 @@ def write_output_file(self) -> None: filename = 'points' filename = filename + '.points1' + os.makedirs(os.path.dirname(filename), exist_ok=True) with open(filename, 'w') as file: for series in self.series_list: file.writelines( diff --git a/metplotpy/plots/roc_diagram/roc_diagram.py b/metplotpy/plots/roc_diagram/roc_diagram.py index c728e0c3a..01bcdd811 100644 --- a/metplotpy/plots/roc_diagram/roc_diagram.py +++ b/metplotpy/plots/roc_diagram/roc_diagram.py @@ -507,35 +507,26 @@ def write_output_file(self): filename = self.config_obj.points_path + os.path.sep + filename output_file = filename + '.points1' + os.makedirs(os.path.dirname(output_file), exist_ok=True) + if os.path.exists(output_file): + os.remove(output_file) + + with open(output_file, 'a') as fileobj: + header_str = "pofd\t pody\n" + fileobj.write(header_str) + all_pody = [] + all_pofd = [] + for series in self.series_list: + pody_points = series.series_points[1] + pofd_points = series.series_points[0] + all_pody.extend(pody_points) + all_pofd.extend(pofd_points) + + all_points = zip(all_pofd, all_pody) + for idx, pts in enumerate(all_points): + data_str = str(pts[0]) + "\t" + str(pts[1]) + "\n" + fileobj.write(data_str) - # make sure this file doesn't already - # exit, delete it if it does - try: - if os.stat(output_file).st_size == 0: - fileobj = open(output_file, 'a') - else: - os.remove(output_file) - except FileNotFoundError as fnfe: - # OK if no file was found - pass - - fileobj = open(output_file, 'a') - header_str = "pofd\t pody\n" - fileobj.write(header_str) - all_pody = [] - all_pofd = [] - for series in self.series_list: - pody_points = series.series_points[1] - pofd_points = series.series_points[0] - all_pody.extend(pody_points) - all_pofd.extend(pofd_points) - - all_points = zip(all_pofd, all_pody) - for idx, pts in enumerate(all_points): - data_str = str(pts[0]) + "\t" + str(pts[1]) + "\n" - fileobj.write(data_str) - - fileobj.close() def write_html(self) -> None: """ @@ -545,8 +536,8 @@ def write_html(self) -> None: self.logger.info("Writing HTML file") if self.config_obj.create_html is True: # construct the fle name from plot_filename - name_arr = self.get_config_value('plot_filename').split('.') - html_name = name_arr[0] + ".html" + base_name, _ = os.path.splitext(self.get_config_value('plot_filename')) + html_name = f"{base_name}.html" # save html self.figure.write_html(html_name, include_plotlyjs=False) diff --git a/metplotpy/plots/skew_t/skew_t.py b/metplotpy/plots/skew_t/skew_t.py index 3861edafa..1c171f571 100644 --- a/metplotpy/plots/skew_t/skew_t.py +++ b/metplotpy/plots/skew_t/skew_t.py @@ -66,7 +66,7 @@ def extract_sounding_data(input_file, output_directory): txt_file.write("".join(line) + "\n") # Read in the current sounding data file, replacing any 9999 values with NaN. - df_raw: pandas.DataFrame = pd.read_csv(sounding_data_file, sep='/s+', skiprows=1, engine='python') + df_raw: pandas.DataFrame = pd.read_csv(sounding_data_file, sep=r'\s+', skiprows=1, engine='python') df_raw.replace('9999', 'NA', inplace=True) # Rename some columns so they are more descriptive diff --git a/metplotpy/plots/taylor_diagram/taylor_diagram.py b/metplotpy/plots/taylor_diagram/taylor_diagram.py index 904b64df1..b6b7bc54c 100644 --- a/metplotpy/plots/taylor_diagram/taylor_diagram.py +++ b/metplotpy/plots/taylor_diagram/taylor_diagram.py @@ -19,6 +19,7 @@ """ __author__ = 'Minna Win' +import os import warnings from datetime import datetime import matplotlib.pyplot as plt @@ -333,6 +334,7 @@ def _create_figure(self) -> None: # Save the figure, based on whether we are displaying only positive # correlations or all # correlations. + os.makedirs(os.path.dirname(self.config_obj.output_image), exist_ok=True) if pos_correlation_only: # Setting the bbox_inches keeps the legend box always within the plot # boundaries. This *may* result diff --git a/metplotpy/plots/tcmpr_plots/tcmpr.py b/metplotpy/plots/tcmpr_plots/tcmpr.py index 9988e0640..41ddfb957 100755 --- a/metplotpy/plots/tcmpr_plots/tcmpr.py +++ b/metplotpy/plots/tcmpr_plots/tcmpr.py @@ -585,7 +585,7 @@ def create_plot(config_obj: dict) -> None: quotechar='"', skipinitialspace=True, encoding='utf-8') logger = util.get_common_logger(config_obj.log_level, config_obj.log_filename) -\ + for plot_type in config_obj.plot_type_list: # Apply event equalization, if requested diff --git a/metplotpy/plots/wind_rose/wind_rose.py b/metplotpy/plots/wind_rose/wind_rose.py index fea5d5689..34e4c1f1f 100644 --- a/metplotpy/plots/wind_rose/wind_rose.py +++ b/metplotpy/plots/wind_rose/wind_rose.py @@ -317,14 +317,15 @@ def save_to_file(self) -> None: image_name = self.get_config_value('plot_filename') if self.figure: try: + os.makedirs(os.path.dirname(image_name), exist_ok=True) self.figure.write_image(image_name) except FileNotFoundError: - print("Can't save to file " + image_name) + self.logger.error("Can't save to file " + image_name) except ValueError as ex: - print(ex) + self.logger.error(ex) else: - print("Oops! The figure was not created. Can't save.") + self.logger.error("Oops! The figure was not created. Can't save.") @staticmethod def _boundary_filter(boundary_lower_speed: float, diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..46c8ed0dd --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +test_output/ diff --git a/test/bar/bar_with_nones.yaml b/test/bar/bar_with_nones.yaml index a120bf448..1ddb42d2c 100644 --- a/test/bar/bar_with_nones.yaml +++ b/test/bar/bar_with_nones.yaml @@ -1,3 +1,6 @@ +stat_input: !ENV '${TEST_DIR}/bar_with_nones.data' +plot_filename: !ENV '${TEST_OUTPUT}/bar_with_nones.png' + alpha: 0.05 caption_align: 0.0 caption_col: '#333333' @@ -94,12 +97,6 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -points_path: - random_seed: null series_order: @@ -163,8 +160,5 @@ ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 -stat_input: ./bar_with_nones.data -plot_filename: ./bar_with_nones.png - show_legend: -True \ No newline at end of file diff --git a/test/bar/custom_bar.yaml b/test/bar/custom_bar.yaml index 3361c2c7a..eb9df890e 100644 --- a/test/bar/custom_bar.yaml +++ b/test/bar/custom_bar.yaml @@ -66,11 +66,7 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -#points_path: /dir_to_save_points1_file +points_path: !ENV '${TEST_OUTPUT}/intermed_files' random_seed: null @@ -136,7 +132,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/bar.data' -plot_filename: !ENV '${TEST_DIR}/bar.png' +plot_filename: !ENV '${TEST_OUTPUT}/bar.png' # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have # permissions to the directory you specify. The default, as specified in the default config file is stdout. diff --git a/test/bar/custom_defaultpoints1_bar.yaml b/test/bar/custom_defaultpoints1_bar.yaml deleted file mode 100644 index ba7343521..000000000 --- a/test/bar/custom_defaultpoints1_bar.yaml +++ /dev/null @@ -1,137 +0,0 @@ -alpha: 0.05 -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -circular_block_bootstrap: 'True' -colors: -- '#ff0000' -- '#8000ff' -con_series: -- 1 -- 1 -create_html: 'False' -derived_series_1: [] -dump_points_1: 'True' -# allow points1 file to be saved to the default location -#points_path: './intermed_files' -eqbound_high: 0.001 -eqbound_low: -0.001 -event_equal: 'False' -fcst_var_val_1: - TMP: - - ME -fixed_vars_vals_input: {} -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -indy_label: -- '12' -- '24' -indy_vals: -- '120000' -- '240000' -indy_var: fcst_lead -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: None -list_stat_1: -- ME -mar: -- 8 -- 4 -- 5 -- 4 -method: bca -mgp: -- 1 -- 1 -- 0 -num_iterations: 1 -num_threads: -1 -plot_caption: '' -plot_disp: -- 'True' -- 'True' -plot_height: 8.5 -plot_res: 72 -plot_stat: median -plot_type: png16m -plot_units: in -plot_width: 11.0 -random_seed: null - -series_order: -- 1 -- 2 - - -series_val_1: - model: - - AFWAOCv3.5.1_d01 - - NoahMPv3.5.1_d01 -series_val_2: {} -show_nstats: 'True' - -sync_yaxes: 'False' -title: test title -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] -vert_plot: 'False' -x2lab_align: 0.5 -x2lab_offset: -0.5 -x2lab_size: 0.8 -x2lab_weight: 1 -x2tlab_horiz: 0.5 -x2tlab_orient: 1 -x2tlab_perp: 1 -x2tlab_size: 0.8 -xaxis: test x_label -xaxis_reverse: 'True' -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 -y2lab_align: 0.5 -y2lab_offset: 1 -y2lab_size: 1 -y2lab_weight: 1 -y2lim: [] -y2tlab_horiz: 0.5 -y2tlab_orient: 1 -y2tlab_perp: 1 -y2tlab_size: 1.0 -yaxis_1: test y_label -yaxis_2: '' -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 - -stat_input: !ENV '${TEST_DIR}/bar.data' -plot_filename: !ENV '${TEST_DIR}/bar_defaultpoints1.png' -show_legend: - -True - -True \ No newline at end of file diff --git a/test/bar/custom_points1_bar.yaml b/test/bar/custom_points1_bar.yaml deleted file mode 100644 index bfc23987e..000000000 --- a/test/bar/custom_points1_bar.yaml +++ /dev/null @@ -1,137 +0,0 @@ -alpha: 0.05 -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -circular_block_bootstrap: 'True' -colors: -- '#ff0000' -- '#8000ff' -con_series: -- 1 -- 1 -create_html: 'False' -derived_series_1: [] -dump_points_1: 'True' -points_path: !ENV '${TEST_DIR}/intermed_files' -eqbound_high: 0.001 -eqbound_low: -0.001 -event_equal: 'False' -fcst_var_val_1: - TMP: - - ME -fixed_vars_vals_input: {} -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -indy_label: -- '12' -- '24' -indy_vals: -- '120000' -- '240000' -indy_var: fcst_lead -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: None -list_stat_1: -- ME -mar: -- 8 -- 4 -- 5 -- 4 -method: bca -mgp: -- 1 -- 1 -- 0 -num_iterations: 1 -num_threads: -1 -plot_caption: '' -plot_disp: -- 'True' -- 'True' -plot_height: 8.5 -plot_res: 72 -plot_stat: median -plot_type: png16m -plot_units: in -plot_width: 11.0 -random_seed: null - -series_order: -- 1 -- 2 - - -series_val_1: - model: - - AFWAOCv3.5.1_d01 - - NoahMPv3.5.1_d01 -series_val_2: {} -show_nstats: 'True' - -sync_yaxes: 'False' -title: test title -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] -vert_plot: 'False' -x2lab_align: 0.5 -x2lab_offset: -0.5 -x2lab_size: 0.8 -x2lab_weight: 1 -x2tlab_horiz: 0.5 -x2tlab_orient: 1 -x2tlab_perp: 1 -x2tlab_size: 0.8 -xaxis: test x_label -xaxis_reverse: 'True' -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 -y2lab_align: 0.5 -y2lab_offset: 1 -y2lab_size: 1 -y2lab_weight: 1 -y2lim: [] -y2tlab_horiz: 0.5 -y2tlab_orient: 1 -y2tlab_perp: 1 -y2tlab_size: 1.0 -yaxis_1: test y_label -yaxis_2: '' -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 - -stat_input: !ENV '${TEST_DIR}/bar.data' -plot_filename: !ENV '${TEST_DIR}/bar_points1.png' - -show_legend: - -True - -True diff --git a/test/bar/test_bar.py b/test/bar/test_bar.py index eb0c5feee..03cc1db94 100644 --- a/test/bar/test_bar.py +++ b/test/bar/test_bar.py @@ -3,159 +3,35 @@ import pytest from metplotpy.plots.bar import bar -# from metcalcpy.compare_images import CompareImages -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['bar.png', 'bar.points1'] +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_bar.yaml", ["bar.png", "intermed_files/bar.points1"]), + ("bar_with_nones.yaml", ["bar_with_nones.png"]), + ("threshold_bar.yaml", ["threshold_bar.png"]), +]) +def test_bar(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_bar.yaml" + remove_files(os.environ['TEST_OUTPUT'], expected_files) - # Invoke the command to generate a Bar plot based on - # the custom_bar.yaml custom config file. - bar.main(custom_config_filename) + bar.main(f"{os.environ['TEST_DIR']}/{input_yaml}") + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") -@pytest.fixture -def setup_nones(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/bar_with_nones.yaml" + if input_yaml == "custom_bar.yaml": + check_custom_bar_nans() - # Invoke the command to generate a Bar plot based on - # the custom_bar.yaml custom config file. - bar.main(custom_config_filename) - -def test_files_exist(setup, remove_files): - """ - Checking that the plot and data files are getting created - """ - check_files = ('bar.png', 'bar.points1') - for test_input in check_files: - print(f'Checking if {cwd}/{test_input} is found') - assert os.path.isfile(f"{cwd}/{test_input}") - remove_files(cwd, check_files) - - -def test_no_nans_in_points_file(setup, remove_files): - """ - Checking that the points1 intermediate file does not - have any NaN's. This is indicative of a problem with the _create_series_points() method. - """ - - # Check for NaN's in the intermediate files, line.points1 and line.points2 - # Fail if there are any NaN's-this indicates something went wrong with the - # line_series.py module's _create_series_points() method. - nans_found = False - with open(f"{cwd}/bar.points1", "r") as f: +def check_custom_bar_nans(): + """Checking that there are no NaNs in the data file. + Check for NaNs in a file that is known to have NaNs to ensure check works as expected.""" + with open(f"{os.environ['TEST_OUTPUT']}/intermed_files/bar.points1", "r") as f: data = f.read() - if "NaN" in data: - nans_found = True - - assert not nans_found + assert "NaN" not in data # Verify that the nan.points1 file does indeed trigger a "nans_found" - with open(f"{cwd}/nan.points1", "r") as f: + with open(f"{os.environ['TEST_DIR']}/nan.points1", "r") as f: data = f.read() - if "NaN" in data: - nans_found = True - - assert nans_found - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("fails on linux host machines") -def test_images_match(setup, remove_files): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/bar_expected.png', f'{cwd}/bar.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("fails on linux host machines") -def test_none_data_images_match(setup_nones): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/expected_with_nones.png', f'{cwd}/bar_with_nones.png') - assert comparison.mssim == 1 - - try: - plot_file = f'{cwd}/bar_with_nones.png' - os.remove(plot_file) - except OSError: - pass - - -def test_point_and_plot_files_exist(setup_env, remove_files): - """ - Checking that the plot and (specified location) intermediate file are getting created - """ - check_files = ("bar_points1.png", "intermed_files/bar.points1") - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_points1_bar.yaml" - intermed_dir = os.path.join(cwd, 'intermed_files') - try: - os.mkdir(intermed_dir) - except FileExistsError: - pass - - # Invoke the command to generate a Bar plot based on - # the custom_bar.yaml custom config file. - bar.main(custom_config_filename) - - for test_input in check_files: - assert os.path.isfile(f"{cwd}/{test_input}") - remove_files(cwd, check_files) - - -def test_point_and_plot_files_exist_default(setup_env, remove_files): - """ - Checking that the plot and (specified location) intermediate file are getting created - """ - check_files = ("bar_defaultpoints1.png", "bar.points1") - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_defaultpoints1_bar.yaml" - - # Invoke the command to generate a Bar plot based on - # the custom_bar.yaml custom config file. - bar.main(custom_config_filename) - - for test_input in check_files: - assert os.path.isfile(f"{cwd}/{test_input}") - - # remove the .png and .points files - remove_files(cwd, check_files) - - -@pytest.mark.skip("fails on linux host machines") -def test_threshold_plotting(setup_env, remove_files): - """ - Verify that the bar plot using data with thresholds is correct. - - """ - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/threshold_bar.yaml" - - # Invoke the command to generate a Bar plot based on - # the custom_bar.yaml custom config file. - bar.main(custom_config_filename) - - comparison = CompareImages(f'{cwd}/expected_threshold.png', f'{cwd}/threshold_bar.png') - assert comparison.mssim == 1 - remove_files(cwd, ['threshold_bar.png']) + assert "NaN" in data diff --git a/test/bar/threshold_bar.yaml b/test/bar/threshold_bar.yaml index 36efd5917..561d7ccd1 100644 --- a/test/bar/threshold_bar.yaml +++ b/test/bar/threshold_bar.yaml @@ -84,7 +84,7 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/threshold_bar.png' +plot_filename: !ENV '${TEST_OUTPUT}/threshold_bar.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -165,3 +165,5 @@ ytlab_horiz: 0.65 ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 3 +show_legend: + -True diff --git a/test/box/custom_box.yaml b/test/box/custom_box.yaml index bd2a1b61d..a3749b9bd 100644 --- a/test/box/custom_box.yaml +++ b/test/box/custom_box.yaml @@ -102,12 +102,7 @@ plot_type: png16m plot_units: in plot_width: 11.0 - -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -#points_path: /dir_to_save_points1_file +points_path: !ENV '${TEST_OUTPUT}/intermed_files' random_seed: null @@ -181,7 +176,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/box.data' -plot_filename: !ENV '${TEST_DIR}/box.png' +plot_filename: !ENV '${TEST_OUTPUT}/box.png' # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have # permissions to the directory you specify. The default, as specified in the default config file is stdout. diff --git a/test/box/custom_box_defaultpoints1.yaml b/test/box/custom_box_defaultpoints1.yaml index 597204572..07e02eb78 100644 --- a/test/box/custom_box_defaultpoints1.yaml +++ b/test/box/custom_box_defaultpoints1.yaml @@ -175,7 +175,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/box.data' -plot_filename: !ENV '${TEST_DIR}/box_defaultpoints1.png' +plot_filename: !ENV '${TEST_OUTPUT}/box_defaultpoints1.png' show_legend: -True -True diff --git a/test/box/custom_box_points1.yaml b/test/box/custom_box_points1.yaml index c6be626ea..4de9ece4d 100644 --- a/test/box/custom_box_points1.yaml +++ b/test/box/custom_box_points1.yaml @@ -101,7 +101,7 @@ plot_stat: median plot_type: png16m plot_units: in plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' random_seed: null @@ -174,7 +174,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/box.data' -plot_filename: !ENV '${TEST_DIR}/box_points1.png' +plot_filename: !ENV '${TEST_OUTPUT}/box_points1.png' show_legend: -True -True diff --git a/test/box/simple_box.yaml b/test/box/simple_box.yaml index c1fc33aaf..8dbb9d7ee 100644 --- a/test/box/simple_box.yaml +++ b/test/box/simple_box.yaml @@ -113,7 +113,7 @@ xaxis: FCST_LEAD xaxis_reverse: 'False' stat_input: !ENV '${TEST_DIR}/box.data' -plot_filename: !ENV '${TEST_DIR}/default_box.png' +plot_filename: !ENV '${TEST_OUTPUT}/default_box.png' show_legend: -True diff --git a/test/box/test_box.py b/test/box/test_box.py index 25ab21c41..83bb9e2a3 100644 --- a/test/box/test_box.py +++ b/test/box/test_box.py @@ -1,116 +1,17 @@ import pytest import os from metplotpy.plots.box import box -#from metcalcpy.compare_images import CompareImages -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['box.png', 'box.points1'] -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_box.yaml" +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_box.yaml", ["box.png", "intermed_files/box.points1"]), +]) +def test_box(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - box.main(custom_config_filename) + remove_files(os.environ['TEST_OUTPUT'], expected_files) + box.main(f"{os.environ['TEST_DIR']}/{input_yaml}") -@pytest.mark.parametrize("test_input, expected", - (["box.png", True], ["box.points1", True])) -def test_files_exist(setup, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/box_expected.png', f'{cwd}/box.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.parametrize("test_input, expected", - (["box_expected.png", True], ["box_points1.png", True], ["intermed_files/box.points1", True])) -def test_points1_file_exist(setup_env, test_input, expected, remove_files): - """ - Checking that the plot is created and points1 output files is created - where specified in the custom_box_points1.yaml file - """ - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_box_points1.yaml" - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a box plot based on - # the custom_box_points1.yaml custom config file. - box.main(custom_config_filename) - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, ['box_points1.png']) - - -@pytest.mark.parametrize("test_input, expected", - (["box_defaultpoints1.png", True], ["box.points1", True])) -def test_defaultpoints1_file_exist(setup_env, test_input, expected, remove_files): - """ - Checking that the plot is created and points1 output files is created - in the default location (i.e. the current working dir, where the box.data file resides) - """ - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_box_defaultpoints1.yaml" - - # Invoke the command to generate a box plot based on - # the custom_box_defaultpoints1.yaml custom config file. - box.main(custom_config_filename) - assert os.path.isfile(f"{cwd}/{test_input}") == expected - - # remove the created plot and intermediate .points1 file - remove_files(cwd, ['box_defaultpoints1.png', 'box.points1']) - - -def test_no_nans_in_points_file(setup, remove_files): - """ - Checking that the points1 file does not contain NaN's - """ - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - custom_config_filename = f"{cwd}/custom_box_defaultpoints1.yaml" - - # Invoke the command to generate a box plot based on - # the custom_box_defaultpoints1.yaml custom config file. - box.main(custom_config_filename) - - # Check for NaN's in the intermediate files, line.points1 and line.points2 - # Fail if there are any NaN's-this indicates something went wrong with the - # line_series.py module's _create_series_points() method. - nans_found = False - with open(f"{cwd}/box.points1", "r") as f: - data = f.read() - if "NaN" in data: - nans_found = True - - assert not nans_found - remove_files(cwd, CLEANUP_FILES) - - # Verify that the nan.points1 file does indeed trigger a "nans_found" - with open(f"{cwd}/nan.points1", "r") as f: - data = f.read() - if "NaN" in data: - nans_found = True - - # assert - assert nans_found - - # remove the created plot and intermediate .points1 file - remove_files(cwd, ['box_defaultpoints1.png', 'box.points1']) + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/conftest.py b/test/conftest.py index 264258c21..97f294c78 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,14 +1,24 @@ import pytest import os from unittest.mock import patch +import sys +from pathlib import Path import shutil +import logging import json import xarray as xr from pandas import DatetimeIndex +# add METplotpy directory to path so the package can be found +metplotpy_dir = str(Path(__file__).parents[1]) +sys.path.insert(0, os.path.abspath(metplotpy_dir)) + +# set METPLOTPY_BASE to the root of the repo as well +os.environ['METPLOTPY_BASE'] = metplotpy_dir + # This fixture temporarily sets the working directory # to the dir containing the test file. This means -# realative file locations can be used for each test +# relative file locations can be used for each test # file. # NOTE: autouse=True means this applies to ALL tests. # Code that updates the cwd inside test is now redundant @@ -73,20 +83,37 @@ def compare_json(fig, expected_json_file): return compare_json -@pytest.fixture -def setup_env(): - def set_environ(test_dir): - print("Setting up environment") - os.environ['METPLOTPY_BASE'] = f"{test_dir}/../../" - os.environ['TEST_DIR'] = test_dir - return set_environ +@pytest.fixture(scope="module") +def module_setup_env(request): + """Module-scoped fixture that sets up environment variables once per test module. + + This fixture automatically determines the test directory from the test module's location. + """ + test_dir = request.fspath.dirname + print("Setting up environment") + os.environ['TEST_DIR'] = test_dir + # write test output under METPLOTPY_TEST_OUTPUT if set, otherwise write to test/test_output + # write to a subdirectory named after the plot type + output_dir = os.environ.get('METPLOTPY_TEST_OUTPUT', os.path.join(test_dir, os.pardir)) + output_dir = os.path.join(output_dir, 'test_output', os.path.basename(test_dir)) + + # remove output directory for plot type if it already exists to ensure clean test environment + if os.path.exists(output_dir): + print(f"Removing existing output directory: {output_dir}") + shutil.rmtree(output_dir) + + os.environ['TEST_OUTPUT'] = output_dir + yield + # Optional: cleanup after all tests in the module complete @pytest.fixture() def remove_files(): def remove_the_files(test_dir, file_list): - print("Removing the files") + print("Removing files") # loop over list of files under test_dir and remove them + if isinstance(file_list, str): + file_list = [file_list] for file in file_list: try: os.remove(os.path.join(test_dir, file)) @@ -94,11 +121,12 @@ def remove_the_files(test_dir, file_list): pass # also remove intermed_files directory if it exists - print("Removing intermed_files directory if it exists") - try: - shutil.rmtree(f"{test_dir}/intermed_files") - except FileNotFoundError: - pass + if os.path.isdir(f"{test_dir}/intermed_files"): + print("Removing intermed_files directory") + try: + shutil.rmtree(f"{test_dir}/intermed_files") + except FileNotFoundError: + pass return remove_the_files @@ -133,3 +161,6 @@ def nc_test_file(tmp_path_factory): TEST_NC_DATA.to_netcdf(file_name) return file_name +@pytest.fixture(autouse=True) +def setup_logging(caplog): + caplog.set_level(logging.INFO) diff --git a/test/contour/custom_contour.yaml b/test/contour/custom_contour.yaml index b53e5a71e..d33ccf190 100644 --- a/test/contour/custom_contour.yaml +++ b/test/contour/custom_contour.yaml @@ -151,7 +151,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/contour.data' -plot_filename: !ENV '${TEST_DIR}/contour.png' +plot_filename: !ENV '${TEST_OUTPUT}/contour.png' # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have # permissions to the directory you specify. The default, as specified in the default config file is stdout. diff --git a/test/contour/test_contour.py b/test/contour/test_contour.py index 7aff0c56f..c1843d543 100644 --- a/test/contour/test_contour.py +++ b/test/contour/test_contour.py @@ -1,54 +1,17 @@ import pytest import os from metplotpy.plots.contour import contour -#from metcalcpy.compare_images import CompareImages -cwd = os.path.dirname(__file__) -@pytest.fixture -def setup(): - # Cleanup the plotfile output file from any previous run - cleanup() - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_contour.yaml", ["contour.png"]), +]) +def test_contour(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" - # Invoke the command to generate a contour plot based on - # the config yaml files. + remove_files(os.environ['TEST_OUTPUT'], expected_files) - contour.main(f"{cwd}/custom_contour.yaml") + contour.main(f"{os.environ['TEST_DIR']}/{input_yaml}") - - -def cleanup(): - # remove the previously created files - try: - plot_file = 'contour.png' - os.remove(os.path.join(cwd, plot_file)) - except OSError as e: - # Typically, when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.parametrize("test_input, expected", - ([f"{cwd}/contour_expected.png", True], [f"{cwd}/contour.png", True] - )) -def test_files_exist(setup, test_input, expected): - """ - Checking that the plot files are getting created - """ - assert os.path.isfile(test_input) == expected - cleanup() - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup): - """ - Compare an expected plots with the - newly created plots to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/contour_expected.png', f'{cwd}/contour.png') - assert comparison.mssim == 1 - cleanup() + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/difficulty_index/test_difficulty_index_plotting.py b/test/difficulty_index/test_difficulty_index_plotting.py index 5dfe50c88..d92bd7988 100755 --- a/test/difficulty_index/test_difficulty_index_plotting.py +++ b/test/difficulty_index/test_difficulty_index_plotting.py @@ -1,23 +1,23 @@ import os +import math + from . import example_difficulty_index as edi cwd = os.path.dirname(__file__) def test_difficulty_index_plot(): - """ - Compare difficulty index values to ensure correctness. - """ + """Compare difficulty index values to ensure correctness.""" file1 = f'{cwd}/swh_North_Pacific_5dy_ensemble.npz' lats, lons, fieldijn = edi.load_data(file1) muij, sigmaij = edi.compute_stats(fieldijn) - assert 6.988188171386719 == muij[0][10] + assert math.isclose(6.988188171386719, muij[0][10]) - assert 6.3287403106689455 == muij[18][65] + assert math.isclose(6.3287403106689455, muij[18][65]) - assert 9.475065612792969 == muij[25][100] + assert math.isclose(9.475065612792969, muij[25][100]) if __name__ == "__main__": diff --git a/test/eclv/custom_eclv.yaml b/test/eclv/custom_eclv.yaml index 18ddd739b..c79150f3f 100644 --- a/test/eclv/custom_eclv.yaml +++ b/test/eclv/custom_eclv.yaml @@ -113,7 +113,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/eclv.data' -plot_filename: !ENV '${TEST_DIR}/eclv.png' +plot_filename: !ENV '${TEST_OUTPUT}/eclv.png' # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have # permissions to the directory you specify. The default, as specified in the default config file is stdout. diff --git a/test/eclv/custom_eclv_ctc.yaml b/test/eclv/custom_eclv_ctc.yaml index 80d7c731b..dfae7fea5 100644 --- a/test/eclv/custom_eclv_ctc.yaml +++ b/test/eclv/custom_eclv_ctc.yaml @@ -112,7 +112,7 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/eclv_ctc.data' -plot_filename: !ENV '${TEST_DIR}/eclv_ctc.png' +plot_filename: !ENV '${TEST_OUTPUT}/eclv_ctc.png' show_legend: -True diff --git a/test/eclv/custom_eclv_pct.yaml b/test/eclv/custom_eclv_pct.yaml index bc6e3a4aa..bb8a3dc66 100644 --- a/test/eclv/custom_eclv_pct.yaml +++ b/test/eclv/custom_eclv_pct.yaml @@ -103,6 +103,6 @@ ytlab_perp: 0.5 ytlab_size: 1 stat_input: !ENV '${TEST_DIR}/eclv_pct.data' -plot_filename: !ENV '${TEST_DIR}/eclv_pct.png' +plot_filename: !ENV '${TEST_OUTPUT}/eclv_pct.png' show_legend: -True \ No newline at end of file diff --git a/test/eclv/test_eclv.py b/test/eclv/test_eclv.py index 37bf24b63..3812f24c2 100644 --- a/test/eclv/test_eclv.py +++ b/test/eclv/test_eclv.py @@ -1,67 +1,19 @@ import pytest import os from metplotpy.plots.eclv import eclv -#from metcalcpy.compare_images import CompareImages -cwd = os.path.dirname(__file__) -@pytest.fixture -def setup(): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - - # Invoke the command to generate a ECLV plots based on - # the config yaml files. - - eclv.main(f"{cwd}/custom_eclv_pct.yaml") - eclv.main(f"{cwd}/custom_eclv.yaml") - eclv.main(f"{cwd}/custom_eclv_ctc.yaml") - - -def cleanup(): - # remove the previously created files - try: - plot_file = 'eclv_pct.png' - os.remove(os.path.join(cwd, plot_file)) - plot_file = 'eclv.png' - os.remove(os.path.join(cwd, plot_file)) - plot_file = 'eclv_ctc.png' - os.remove(os.path.join(cwd, plot_file)) - - except OSError as e: - # Typically, when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.parametrize("test_input, expected", - ([f"{cwd}/eclv_pct_expected.png", True], [f"{cwd}/eclv_pct.png", True], - [f"{cwd}/eclv_ctc_expected.png", True], [f"{cwd}/eclv_ctc.png", True], - [f"{cwd}/eclv_expected.png", True], [f"{cwd}/eclv.png", True])) -def test_files_exist(setup, test_input, expected): +@pytest.mark.parametrize( + "yaml_file, expected_output", [ + ("custom_eclv.yaml", "eclv.png"), + ("custom_eclv_pct.yaml", "eclv_pct.png"), + ("custom_eclv_ctc.yaml", "eclv_ctc.png"), + ] +) +def test_files_exist(module_setup_env, remove_files, yaml_file, expected_output): """ Checking that the plot files are getting created """ - assert os.path.isfile(test_input) == expected - cleanup() - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup): - """ - Compare an expected plots with the - newly created plots to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/eclv_pct_expected.png', './eclv_pct.png') - assert comparison.mssim == 1 - - comparison = CompareImages(f'{cwd}/eclv_expected.png', './eclv.png') - assert comparison.mssim == 1 - - comparison = CompareImages(f'{cwd}/eclv_ctc_expected.png', './eclv_ctc.png') - assert comparison.mssim == 1 - cleanup() + remove_files(os.environ['TEST_OUTPUT'], expected_output) + eclv.main(f"{os.environ['TEST_DIR']}/{yaml_file}") + assert os.path.isfile(os.path.join(os.environ['TEST_OUTPUT'], expected_output)) diff --git a/test/ens_ss/custom2_ens_ss.yaml b/test/ens_ss/custom2_ens_ss.yaml deleted file mode 100644 index a01d1cbd0..000000000 --- a/test/ens_ss/custom2_ens_ss.yaml +++ /dev/null @@ -1,120 +0,0 @@ -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -colors: -- '#ff0000' -- '#8000ff' - -create_html: 'False' -dump_points_1: 'True' -ensss_pts: -1 -ensss_pts_disp: 'True' -event_equal: 'True' -fcst_var_val_1: - TMP: - - MSE -fixed_vars_vals_input: {} -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -indy_label: [] -indy_vals: [] -indy_var: '' -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: None -list_stat_1: -- MSE -mar: -- 8 -- 4 -- 5 -- 4 -mgp: -- 1 -- 1 -- 0 -plot_caption: '' - -plot_disp: -- 'True' -- 'True' -plot_height: 8.5 -plot_res: 72 -plot_type: png16m -plot_units: in -plot_width: 11.0 -series_line_style: -- '-' -- '-' -series_line_width: -- 1 -- 1 -series_order: -- 1 -- 2 -series_symbols: -- . -- . -series_type: -- b -- b -series_val_1: - model: - - WRF -title: test title -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] - -xaxis: test x_label -xaxis_reverse: 'False' -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 - -yaxis_1: test y_label -yaxis_2: '' -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 -y2lab_align: 0.5 -y2lab_offset: 1 -y2lab_size: 1 -y2lab_weight: 1 -y2lim: [] -y2tlab_horiz: 0.5 -y2tlab_orient: 1 -y2tlab_perp: 1 -y2tlab_size: 1.0 - -stat_input: !ENV '${TEST_DIR}/ens_ss.data' -plot_filename: !ENV '${TEST_DIR}/intermed_files/ens_ss.png' -points_path: !ENV '${TEST_DIR}/intermed_files' -show_legend: - -True - -True \ No newline at end of file diff --git a/test/ens_ss/custom_ens_ss.yaml b/test/ens_ss/custom_ens_ss.yaml index 3bfe05850..5d4dd0034 100644 --- a/test/ens_ss/custom_ens_ss.yaml +++ b/test/ens_ss/custom_ens_ss.yaml @@ -54,11 +54,7 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -#points_path: /dir_to_save_points1_file +points_path: !ENV '${TEST_OUTPUT}/intermed_files' series_line_style: - '-' @@ -120,7 +116,7 @@ y2tlab_perp: 1 y2tlab_size: 1.0 stat_input: !ENV '${TEST_DIR}/ens_ss.data' -plot_filename: !ENV '${TEST_DIR}/ens_ss.png' +plot_filename: !ENV '${TEST_OUTPUT}/ens_ss.png' # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have # permissions to the directory you specify. The default, as specified in the default config file is stdout. diff --git a/test/ens_ss/test_ens_ss.py b/test/ens_ss/test_ens_ss.py index 9962fc569..744e2dcb2 100644 --- a/test/ens_ss/test_ens_ss.py +++ b/test/ens_ss/test_ens_ss.py @@ -1,88 +1,18 @@ import os import pytest -#from metcalcpy.compare_images import CompareImages -from metplotpy.plots.ens_ss import ens_ss - -cwd = os.path.dirname(__file__) - -@pytest.fixture -def setup(): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_ens_ss.yaml" - - # Invoke the command to generate a Bar plot based on - # the custom_ens_ss.yaml custom config file. - ens_ss.main(custom_config_filename) +from metplotpy.plots.ens_ss import ens_ss -def cleanup(): - # remove the .png and .points files - # from any previous runs - try: - plot_file = 'ens_ss.png' - points_file_1 = 'ens_ss.points1' - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(cwd, points_file_1)) - except OSError as er: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.parametrize("test_input, expected", - ([f"{cwd}/ens_ss.png", True],[f"{cwd}/ens_ss.png", True],[f"{cwd}/ens_ss.points1", True])) -def test_files_exist( setup, test_input, expected): - """ - Checking that the plot and data files are getting created - """ - assert os.path.isfile(test_input) == expected - cleanup() - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/ens_ss_expected.png', f'{cwd}/ens_ss.png') - assert comparison.mssim == 1 - cleanup() +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_ens_ss.yaml", ["ens_ss.png", "intermed_files/ens_ss.points1"]), +]) +def test_ens_ss(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" -@pytest.mark.parametrize("test_input, expected", - ([f"{cwd}/intermed_files/ens_ss.png", True], [f"{cwd}/intermed_files/ens_ss.points1", True])) -def test_files_exist(test_input, expected): - """ - Checking that the plot and data files are getting created - """ - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError as e: - pass - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom2_ens_ss.yaml" + remove_files(os.environ['TEST_OUTPUT'], expected_files) - # Invoke the command to generate a Bar plot based on - # the custom_ens_ss.yaml custom config file. - ens_ss.main(custom_config_filename) - assert os.path.isfile(test_input) == expected - cleanup() - try: - subdir = os.path.join(cwd, "intermed_files") - plot_file = 'ens_ss.png' - points_file_1 = 'ens_ss.points1' - os.remove(os.path.join(subdir, plot_file)) - os.remove(os.path.join(subdir, points_file_1)) - os.rmdir(subdir) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass + ens_ss.main(f"{os.environ['TEST_DIR']}/{input_yaml}") + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/equivalence_testing_bounds/.html b/test/equivalence_testing_bounds/.html deleted file mode 100644 index 4804a2c58..000000000 --- a/test/equivalence_testing_bounds/.html +++ /dev/null @@ -1,24 +0,0 @@ - - - -
- - -
- -
- - \ No newline at end of file diff --git a/test/equivalence_testing_bounds/custom_equivalence_testing_bounds.yaml b/test/equivalence_testing_bounds/custom_equivalence_testing_bounds.yaml index ffec3e5d0..0ac728408 100644 --- a/test/equivalence_testing_bounds/custom_equivalence_testing_bounds.yaml +++ b/test/equivalence_testing_bounds/custom_equivalence_testing_bounds.yaml @@ -163,7 +163,8 @@ ytlab_horiz: 0.5 ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 -plot_filename: !ENV '${TEST_DIR}/equivalence_testing_bounds.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' +plot_filename: !ENV '${TEST_OUTPUT}/equivalence_testing_bounds.png' stat_input: !ENV '${TEST_DIR}/equivalence_testing_bounds.data' show_legend: - 'True' diff --git a/test/equivalence_testing_bounds/custom_equivalence_testing_bounds2.yaml b/test/equivalence_testing_bounds/custom_equivalence_testing_bounds2.yaml deleted file mode 100644 index f087c6b8c..000000000 --- a/test/equivalence_testing_bounds/custom_equivalence_testing_bounds2.yaml +++ /dev/null @@ -1,172 +0,0 @@ -alpha: 0.05 -box_avg: 'False' -box_boxwex: 0.2 -box_notch: 'False' -box_outline: 'True' -box_pts: 'False' -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -colors: -- '#ff0000' -- '#8000ff' -- '#00ff7f' -con_series: -- 1 -- 1 -- 1 -create_html: 'True' -derived_series_1: -- - ARWref_hrconus_control DPT ME - - ARWref_hrconus_experiment1 DPT ME - - ETB -derived_series_2: [] -dump_points_1: 'True' -dump_points_2: 'False' -event_equal: 'True' -fcst_var_val_1: - DPT: - - ME -fcst_var_val_2: {} -fixed_vars_vals_input: {} -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -high_eqbound: 0.001 -indy_label: [] -indy_stagger_1: 'False' -indy_stagger_2: 'False' -indy_vals: [] -indy_var: fcst_lead -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: sl1l2 -list_stat_1: -- ME -list_stat_2: [] -list_static_val: - fcst_var: DPT -low_eqbound: -0.001 -mar: -- 8 -- 4 -- 5 -- 4 -method: bca -mgp: -- 1 -- 1 -- 0 -num_iterations: 1 -num_threads: -1 -plot_caption: '' -plot_ci: -- none -- none -- none -plot_disp: -- 'True' -- 'True' -- 'True' -plot_height: 8.5 -plot_res: 72 -plot_stat: median -plot_type: png16m -plot_units: in -plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' -random_seed: null -series_line_style: -- '-' -- '-' -- '-' -series_line_width: -- 1 -- 1 -- 1 -series_order: -- 1 -- 2 -- 3 -series_symbols: -- . -- . -- . -series_type: -- b -- b -- b -series_val_1: - model: - - ARWref_hrconus_control - - ARWref_hrconus_experiment1 -series_val_2: {} -show_nstats: 'False' -show_signif: -- 'False' -- 'False' -- 'False' -sync_yaxes: 'False' -title: test title -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] -variance_inflation_factor: 'False' -vert_plot: 'False' -x2lab_align: 0.5 -x2lab_offset: -0.5 -x2lab_size: 0.8 -x2lab_weight: 1 -x2tlab_horiz: 0.5 -x2tlab_orient: 1 -x2tlab_perp: 1 -x2tlab_size: 0.8 -xaxis: test x_label -xaxis_reverse: 'False' -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 -y2lab_align: 0.5 -y2lab_offset: 1 -y2lab_size: 1 -y2lab_weight: 1 -y2lim: [] -y2tlab_horiz: 0.5 -y2tlab_orient: 1 -y2tlab_perp: 1 -y2tlab_size: 1.0 -yaxis_1: test y_label -yaxis_2: '' -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 -plot_filename: !ENV '${TEST_DIR}/intermed_files/equivalence_testing_bounds.png' -stat_input: !ENV '${TEST_DIR}/equivalence_testing_bounds.data' -show_legend: -- 'True' -- 'True' -- 'True' diff --git a/test/equivalence_testing_bounds/test_equivalence_testing_bounds.py b/test/equivalence_testing_bounds/test_equivalence_testing_bounds.py index e7e849e69..2c563b31e 100644 --- a/test/equivalence_testing_bounds/test_equivalence_testing_bounds.py +++ b/test/equivalence_testing_bounds/test_equivalence_testing_bounds.py @@ -1,74 +1,20 @@ import pytest import os -from metplotpy.plots.equivalence_testing_bounds import equivalence_testing_bounds as etb -#from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['equivalence_testing_bounds.png', 'equivalence_testing_bounds.points1'] - -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_equivalence_testing_bounds.yaml" - - # Invoke the command to generate an equivalence testing boundary plot based on - # the custom config file. - etb.main(custom_config_filename) - -@pytest.mark.parametrize("test_input,expected", - (["equivalence_testing_bounds.png", True], - ["equivalence_testing_bounds.points1", True])) -def test_files_exist(setup, test_input, expected, remove_files): - ''' - Checking that the plot and data files are getting created - ''' - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("skimage differences causing failure") -def test_images_match(setup, remove_files): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - plot_file = 'equivalence_testing_bounds.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/equivalence_testing_bounds_expected.png', actual_file) - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.parametrize("test_input,expected", - (["intermed_files/equivalence_testing_bounds.png", True], - ["intermed_files/equivalence_testing_bounds.points1", True])) -def test_files_exist(setup_env, test_input, expected, remove_files): - ''' - Checking that the plot and data files are getting created - ''' +from metplotpy.plots.equivalence_testing_bounds import equivalence_testing_bounds as etb - intermed_dir = os.path.join(cwd, 'intermed_files') - try: - os.mkdir(intermed_dir) - except FileExistsError: - pass +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_equivalence_testing_bounds.yaml", [ + "equivalence_testing_bounds.png", + "intermed_files/equivalence_testing_bounds.points1", + ]), +]) +def test_equivalence_testing_bounds(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_equivalence_testing_bounds2.yaml" + remove_files(os.environ['TEST_OUTPUT'], expected_files) - # Invoke the command to generate an equivalence testing boundary plot based on - # the custom config file. - etb.main(custom_config_filename) + etb.main(f"{os.environ['TEST_DIR']}/{input_yaml}") - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, ['intermed_files/equivalence_testing_bounds.png', - 'intermed_files/equivalence_testing_bounds.points1', - 'intermed_files/equivalence_testing_bounds.html']) - try: - os.rmdir(intermed_dir) - except OSError: - pass + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/histogram/prob_hist.yaml b/test/histogram/prob_hist.yaml index 1b72e5c22..f4610ca00 100644 --- a/test/histogram/prob_hist.yaml +++ b/test/histogram/prob_hist.yaml @@ -1,5 +1,5 @@ stat_input: !ENV '${TEST_DIR}/prob_hist.data' -plot_filename: !ENV '${TEST_DIR}/prob_hist.png' +plot_filename: !ENV '${TEST_OUTPUT}/prob_hist.png' caption_align: 0.0 caption_col: '#333333' diff --git a/test/histogram/rank_hist.yaml b/test/histogram/rank_hist.yaml index 8cf23ec95..f1899b450 100644 --- a/test/histogram/rank_hist.yaml +++ b/test/histogram/rank_hist.yaml @@ -1,5 +1,5 @@ stat_input: !ENV '${TEST_DIR}/rank_hist.data' -plot_filename: !ENV '${TEST_DIR}/rank_hist.png' +plot_filename: !ENV '${TEST_OUTPUT}/rank_hist.png' caption_align: 0.0 caption_col: '#333333' diff --git a/test/histogram/rel_hist.yaml b/test/histogram/rel_hist.yaml index ebb76e031..e68063075 100644 --- a/test/histogram/rel_hist.yaml +++ b/test/histogram/rel_hist.yaml @@ -1,4 +1,4 @@ -plot_filename: !ENV '${TEST_DIR}/rel_hist.png' +plot_filename: !ENV '${TEST_OUTPUT}/rel_hist.png' stat_input: !ENV '${TEST_DIR}/rel_hist.data' diff --git a/test/histogram/test_prob_hist.py b/test/histogram/test_prob_hist.py index fc9b3ab43..41fb9bcf9 100644 --- a/test/histogram/test_prob_hist.py +++ b/test/histogram/test_prob_hist.py @@ -1,15 +1,13 @@ import pytest import os from metplotpy.plots.histogram import prob_hist -#from metcalcpy.compare_images import CompareImages cwd = os.path.dirname(__file__) @pytest.fixture -def setup(setup_env): +def setup(module_setup_env): cleanup() - setup_env(cwd) custom_config_filename = f"{cwd}/prob_hist.yaml" prob_hist.main(custom_config_filename) @@ -20,29 +18,13 @@ def cleanup(): # from any previous runs try: plot_file = 'prob_hist.png' - os.remove(os.path.join(cwd, plot_file)) + os.remove(os.path.join(os.environ['TEST_OUTPUT'], plot_file)) except OSError: pass -@pytest.mark.parametrize("test_input, expected", - (["prob_hist_expected.png", True], - ["prob_hist.png", True])) -def test_files_exist(setup, test_input, expected): +def test_files_exist(setup): """ Checking that the plot and data files are getting created """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - cleanup() - -@pytest.mark.skip("Image comparisons fail during Github Actions checks.") -def test_images_match(setup): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f"{cwd}/prob_hist_expected.png", - f"{cwd}/prob_hist.png") - assert comparison.mssim == 1 - cleanup() + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/prob_hist.png") diff --git a/test/histogram/test_rank_hist.py b/test/histogram/test_rank_hist.py index 4b9d5b08e..75f19bdea 100644 --- a/test/histogram/test_rank_hist.py +++ b/test/histogram/test_rank_hist.py @@ -1,16 +1,13 @@ import pytest import os from metplotpy.plots.histogram import rank_hist -#from metcalcpy.compare_images import CompareImages cwd = os.path.dirname(__file__) @pytest.fixture -def setup(setup_env): +def setup(module_setup_env): cleanup() - setup_env(cwd) - custom_config_filename = f"{cwd}/rank_hist.yaml" rank_hist.main(custom_config_filename) @@ -20,30 +17,13 @@ def cleanup(): # from any previous runs try: plot_file = 'rank_hist.png' - os.remove(os.path.join(cwd, plot_file)) + os.remove(os.path.join(os.environ['TEST_OUTPUT'], plot_file)) except OSError: pass -@pytest.mark.parametrize("test_input, expected", - (["rank_hist_expected.png", True], - ["rank_hist.png", True])) -def test_files_exist(setup, test_input, expected): +def test_files_exist(setup): """ Checking that the plot and data files are getting created """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - cleanup() - - -@pytest.mark.skip("Image comparisons fail during Github Actions checks.") -def test_images_match(setup): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f"{cwd}/rank_hist_expected.png", - f"{cwd}/rank_hist.png") - assert comparison.mssim == 1 - cleanup() + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/rank_hist.png") diff --git a/test/histogram/test_rel_hist.py b/test/histogram/test_rel_hist.py index a491283c1..04ea70830 100644 --- a/test/histogram/test_rel_hist.py +++ b/test/histogram/test_rel_hist.py @@ -1,20 +1,15 @@ import pytest import os from metplotpy.plots.histogram import rel_hist -#from metcalcpy.compare_images import CompareImages cwd = os.path.dirname(__file__) @pytest.fixture -def setup(setup_env): - # Cleanup the plotfile output file from any previous run +def setup(module_setup_env): + # Cleanup the plotfile output file from any previous run cleanup() - setup_env(cwd) custom_config_filename = f"{cwd}/rel_hist.yaml" - - # Invoke the command to generate a histogram based on - # the rel_hist.yaml custom config file. rel_hist.main(custom_config_filename) @@ -23,30 +18,13 @@ def cleanup(): # from any previous runs try: plot_file = 'rel_hist.png' - os.remove(os.path.join(cwd, plot_file)) + os.remove(os.path.join(os.environ['TEST_OUTPUT'], plot_file)) except OSError: pass -@pytest.mark.parametrize("test_input, expected", - (["rel_hist_expected.png", True], - ["rel_hist.png", True])) -def test_files_exist(setup, test_input, expected): +def test_files_exist(setup): """ Checking that the plot and data files are getting created """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - cleanup() - - -@pytest.mark.skip("Image comparisons fail in Github Actions checks.") -def test_images_match(setup): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f"{cwd}/rel_hist_expected.png", - f"{cwd}/rel_hist.png") - assert comparison.mssim == 1 - cleanup() + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/rel_hist.png") diff --git a/test/histogram_2d/custom_histogram_2d.yaml b/test/histogram_2d/custom_histogram_2d.yaml index 292349c20..6bf8c366c 100644 --- a/test/histogram_2d/custom_histogram_2d.yaml +++ b/test/histogram_2d/custom_histogram_2d.yaml @@ -1,5 +1,5 @@ # replace with the location and name of your choosing: -plot_filename: !ENV '${TEST_DIR}/custom_tmp_z2_p500.png' +plot_filename: !ENV '${TEST_OUTPUT}/custom_tmp_z2_p500.png' height: 800 width: 1200 diff --git a/test/histogram_2d/minimal_histogram_2d.yaml b/test/histogram_2d/minimal_histogram_2d.yaml index 291feb3b1..6e9264b3d 100644 --- a/test/histogram_2d/minimal_histogram_2d.yaml +++ b/test/histogram_2d/minimal_histogram_2d.yaml @@ -2,4 +2,4 @@ # configuration file stat_input: !ENV '${TEST_DIR}/grid_diag_temperature.nc' -plot_filename: !ENV '${TEST_DIR}/tmp_z2_p500.png' +plot_filename: !ENV '${TEST_OUTPUT}/tmp_z2_p500.png' diff --git a/test/histogram_2d/test_histogram_2d.py b/test/histogram_2d/test_histogram_2d.py index 1bc96a046..3bc7b9e31 100644 --- a/test/histogram_2d/test_histogram_2d.py +++ b/test/histogram_2d/test_histogram_2d.py @@ -3,36 +3,22 @@ from metplotpy.plots.histogram_2d import histogram_2d as h2d -# from metcalcpy.compare_images import CompareImages - cwd = os.path.dirname(__file__) - -@pytest.fixture -def setup(setup_env): - # Cleanup the plotfile and point1 output file from any previous run - # cleanup() - setup_env(cwd) - custom_config_filename = f"{cwd}/minimal_histogram_2d.yaml" - # print("\n current directory: ", os.getcwd()) - # print("\ncustom config file: ", custom_config_filename, '\n') - - # Invoke the command to generate a histogram_2d plot based on - # the settings in the "defaults" config file. - h2d.main(custom_config_filename) - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # !!!!!!!!! IMPORTANT !!!!!! # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # change the stat_input and plot_filename to explicitly point to this directory before # running the test below because xarray cannot handle relative paths when reading in # filenames -def test_plot_exists(setup, remove_files): - ''' - Checking that only the "defaults" plot file is getting created - - ''' - test_input = "tmp_z2_p500.png" - assert os.path.exists(f"{cwd}/{test_input}") - remove_files(cwd, ['tmp_z2_p500.png']) +@pytest.mark.parametrize( + "yaml_file, expected_output", [ + ("minimal_histogram_2d.yaml", "tmp_z2_p500.png"), + ("custom_histogram_2d.yaml", "custom_tmp_z2_p500.png"), + ] +) +def test_plot_exists(module_setup_env, yaml_file, expected_output, remove_files): + """Checking that only the "defaults" plot file is getting created""" + remove_files(os.environ['TEST_OUTPUT'], [expected_output]) + h2d.main(os.path.join(cwd, yaml_file)) + assert os.path.exists(f"{os.environ['TEST_OUTPUT']}/{expected_output}") diff --git a/test/hovmoeller/conftest.py b/test/hovmoeller/conftest.py deleted file mode 100644 index 264258c21..000000000 --- a/test/hovmoeller/conftest.py +++ /dev/null @@ -1,135 +0,0 @@ -import pytest -import os -from unittest.mock import patch -import shutil -import json -import xarray as xr -from pandas import DatetimeIndex - -# This fixture temporarily sets the working directory -# to the dir containing the test file. This means -# realative file locations can be used for each test -# file. -# NOTE: autouse=True means this applies to ALL tests. -# Code that updates the cwd inside test is now redundant -# and can be deleted. -@pytest.fixture(autouse=True) -def change_test_dir(request, monkeypatch): - monkeypatch.chdir(request.fspath.dirname) - - -@pytest.fixture(autouse=True) -def patch_CompareImages(request): - """This fixture controls the use of CompareImages in the - test suite. By default, all calls to CompareImages will - result in the test skipping. To change this behaviour set - an env var METPLOTPY_COMPAREIMAGES - """ - if bool(os.getenv("METPLOTPY_COMPAREIMAGES")): - yield - else: - class mock_CompareImages: - def __init__(self, img1, img2): - # TODO: rather than skip we could inject an alternative - # comparison that is more relaxed. To do this, extend - # this this class to generate a self.mssim value. - pytest.skip("CompareImages not enabled in pytest. " - "To enable `export METPLOTPY_COMPAREIMAGES=$true`") - try: - with patch.object(request.module, 'CompareImages', mock_CompareImages) as mock_ci: - yield mock_ci - except AttributeError: - # test module doesn't import CompareImages. Do nothing. - yield - - -def ordered(obj): - """Recursive function to sort JSON, even lists of dicts with the same keys""" - if isinstance(obj, dict): - return sorted((k, ordered(v)) for k, v in obj.items()) - if isinstance(obj, list): - return sorted(ordered(x) for x in obj) - else: - return obj - -@pytest.fixture -def assert_json_equal(): - def compare_json(fig, expected_json_file): - """Takes a plotly figure and a json file - """ - # Treat everything as str for comparison purposes. - actual = json.loads(fig.to_json(), parse_float=str, parse_int=str) - with open(expected_json_file) as f: - expected = json.load(f,parse_float=str, parse_int=str) - # Fail with a nice message - if ordered(actual) == ordered(expected): - return True - else: - message = "This test will fail when there have been changes to plot code but the corresponding" \ - "json test file hasn't been updates. To update the test file run `fig.write_json`"\ - " e.g. `scatter.figure.write_json('custom_scatter_expected.json')`" - raise AssertionError(message) - - return compare_json - - -@pytest.fixture -def setup_env(): - def set_environ(test_dir): - print("Setting up environment") - os.environ['METPLOTPY_BASE'] = f"{test_dir}/../../" - os.environ['TEST_DIR'] = test_dir - return set_environ - - -@pytest.fixture() -def remove_files(): - def remove_the_files(test_dir, file_list): - print("Removing the files") - # loop over list of files under test_dir and remove them - for file in file_list: - try: - os.remove(os.path.join(test_dir, file)) - except OSError: - pass - - # also remove intermed_files directory if it exists - print("Removing intermed_files directory if it exists") - try: - shutil.rmtree(f"{test_dir}/intermed_files") - except FileNotFoundError: - pass - - return remove_the_files - - -# data for netCDF file -TEST_NC_DATA = xr.Dataset( - { - "precip": xr.DataArray( - [ - [[0.1, 0.2, 0.3], [0, 1.3, 4], [0, 20, 0]], - [[0, 0, 0], [0, 0, 0], [0, 0, 0]], - ], - coords={ - "lat": [-1, 0, 1], - "lon": [112, 113, 114], - "time": DatetimeIndex(["2024-09-25 00:00:00", "2024-09-25 03:00:33"]), - }, - dims=["time", "lat", "lon"], - attrs={"long_name": "variable long name"}, - ), - }, - attrs={"Conventions": "CF-99.9", "history": "History string"}, -) - -@pytest.fixture() -def nc_test_file(tmp_path_factory): - """Create a netCDF file with a very small amount of data. - File is written to a temp directory and the path to the - file returned as the fixture value. - """ - file_name = tmp_path_factory.mktemp("data") / "test_data.nc" - TEST_NC_DATA.to_netcdf(file_name) - return file_name - diff --git a/test/hovmoeller/custom_hovmoeller.yaml b/test/hovmoeller/custom_hovmoeller.yaml index 559cdb460..4a3917e54 100644 --- a/test/hovmoeller/custom_hovmoeller.yaml +++ b/test/hovmoeller/custom_hovmoeller.yaml @@ -1,4 +1,4 @@ -plot_filename: ./hovmoeller_custom_plot.png +plot_filename: !ENV '${TEST_OUTPUT}/hovmoeller_custom_plot.png' input_data_file: /path/to/WorkingDir/precip.erai.sfc.1p0.2x.2014-2016.nc plot_height: 400 plot_width: 600 diff --git a/test/hovmoeller/minimal_hovmoeller.yaml b/test/hovmoeller/minimal_hovmoeller.yaml index 42283c97c..0c1fb3338 100644 --- a/test/hovmoeller/minimal_hovmoeller.yaml +++ b/test/hovmoeller/minimal_hovmoeller.yaml @@ -1,4 +1,4 @@ # minimal, use all the settings in the default except specify # input data file path and location of the output plot. input_data_file: /path/to/WorkingDir/precip.erai.sfc.1p0.2x.2014-2016.nc -plot_filename: ./hovmoeller_default_plot.png \ No newline at end of file +plot_filename: !ENV '${TEST_OUTPUT}/hovmoeller_default_plot.png' \ No newline at end of file diff --git a/test/hovmoeller/pytest.ini b/test/hovmoeller/pytest.ini deleted file mode 100644 index c339546e5..000000000 --- a/test/hovmoeller/pytest.ini +++ /dev/null @@ -1,20 +0,0 @@ -[pytest] - # Deprecation warnings suppressed. - - # DeprecationWarning in numpy: parsing timezone aware datetimes is deprecated; - # this will raise an error in the future: - # hovmoeller_plotly.py:129: DeprecationWarning: - # - # parsing timezone aware datetimes is deprecated; this will raise an error in the future - - # Second DeprecationWarning in netCDF4: - # netCDF4_.py: 405: DeprecationWarning: - # - # tostring() is deprecated.Use - # tobytes() - # instead. -filterwarnings = - ignore - default:::netCDF4.* - ignore - default:::numpy.* \ No newline at end of file diff --git a/test/hovmoeller/test_hovmoeller.py b/test/hovmoeller/test_hovmoeller.py index f3ce7bdd6..f9e1bf3af 100644 --- a/test/hovmoeller/test_hovmoeller.py +++ b/test/hovmoeller/test_hovmoeller.py @@ -2,10 +2,11 @@ import pytest import metplotpy.plots.hovmoeller.hovmoeller as hov from metplotpy.plots import util -#from metcalcpy.compare_images import CompareImages -def dict_to_yaml(data_dict, - output_yaml = "test_hovmoeller.yaml"): + +cwd = os.path.dirname(__file__) + +def dict_to_yaml(data_dict, output_yaml): """Write dict as yaml config file.""" content = "\n".join(["{k}: {v}".format(k=k,v=v) for k,v in data_dict.items()]) with open(output_yaml, 'w') as f: @@ -13,18 +14,8 @@ def dict_to_yaml(data_dict, return output_yaml -def cleanup(file_to_remove): - try: - path = os.getcwd() - os.remove(os.path.join(path, file_to_remove)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - @pytest.mark.skip() -def test_default_plot_images_match(): +def test_default_plot_images_match(module_setup_env, remove_files): ''' Compare an expected plot with the newly created plot to verify that the plot hasn't @@ -34,33 +25,35 @@ def test_default_plot_images_match(): can sometimes be a different size than the expected (which was generated using the same configuration file and data!) ''' - config_file = os.path.join(os.path.dirname(__file__), "minimal_hovmoeller.yaml") + default_plot = "hovmoeller_default_plot.png" + remove_files(os.environ['TEST_OUTPUT'], [default_plot]) + + config_file = os.path.join(cwd, "minimal_hovmoeller.yaml") hov.main(config_file) - default_plot = "./hovmoeller_default_plot.png" - path = os.getcwd() - plot_file = './hovmoeller_expected_default.png' - actual_file = os.path.join(path, plot_file) - comparison = CompareImages(default_plot, actual_file) - assert comparison.mssim == 1 - # Clean up - cleanup(default_plot) + # default_plot = os.path.join(os.environ['TEST_OUTPUT'], default_plot) + # expected_file = 'hovmoeller_expected_default.png' + # actual_file = os.path.join(cwd, expected_file) + # comparison = CompareImages(default_plot, actual_file) + # assert comparison.mssim == 1 + @pytest.mark.skip("needs large netCDF file to run") -def test_custom_plot_created(): - config_file = os.path.join(os.path.dirname(__file__), "custom_hovmoeller.yaml") +def test_custom_plot_created(module_setup_env, remove_files): + expected_file = "hovmoeller_custom_plot.png" + + remove_files(os.environ['TEST_OUTPUT'], [expected_file]) + + config_file = os.path.join(cwd, "custom_hovmoeller.yaml") hov.main(config_file) - custom_plot = "./hovmoeller_custom_plot.png" - assert os.path.isfile(custom_plot) == True + + assert os.path.isfile(os.path.join(os.environ['TEST_OUTPUT'], expected_file)) # This plot should be different from the default-it has different dimensions # so the comparison should raise a ValueError - default_plot = './hovmoeller_expected_default.png' - with pytest.raises(ValueError): - CompareImages(default_plot, custom_plot) - - # Clean up - cleanup(custom_plot) + # default_plot = os.path.join(cwd, 'hovmoeller_expected_default.png') + # with pytest.raises(ValueError): + # CompareImages(default_plot, expected_file) def make_config(nc_file, out_file): @@ -80,12 +73,19 @@ def make_config(nc_file, out_file): } return config -def test_hovmoeller(nc_test_file,assert_json_equal): - out_file = "hovmoeller_test.png" + +def test_hovmoeller(module_setup_env, remove_files, nc_test_file, assert_json_equal, tmp_path_factory): + output_dir = os.environ['TEST_OUTPUT'] + out_file = os.path.join(output_dir, "hovmoeller_test.png") + + remove_files(output_dir, [os.path.basename(out_file)]) + config = make_config(nc_test_file, out_file) # basic test to see if output writes - min_yaml = dict_to_yaml(config) + output_yaml = tmp_path_factory.mktemp("data") / "test_hovmoeller.yaml" + min_yaml = dict_to_yaml(config, output_yaml=str(output_yaml)) + hov.main(min_yaml) assert os.path.isfile(out_file) @@ -93,22 +93,27 @@ def test_hovmoeller(nc_test_file,assert_json_equal): # test actual functions from plot object plot_obj = hov.Hovmoeller(util.get_params(min_yaml)) + # note: initializing Hovmoeller removes out_file that was previously written + + plot_obj.save_to_file() + assert os.path.isfile(out_file) + # check html write out plot_obj.write_html() - out_html = config['plot_filename'].split('.')[0] + '.html' + base_name, _ = os.path.splitext(config['plot_filename']) + out_html = f"{base_name}.html" assert os.path.isfile(out_html) # finally check json plot values # to regenerate json file run: - plot_obj.figure.write_json('hovmoeller_test.json') - assert_json_equal(plot_obj.figure, 'hovmoeller_test.json') + json_output = os.path.join(output_dir, "hovmoeller_test.json") + plot_obj.figure.write_json(json_output) + assert_json_equal(plot_obj.figure, json_output) - # Clean up - cleanup(out_file) - cleanup(out_html) -def test_get_lat_str(nc_test_file): - min_yaml = dict_to_yaml(make_config(nc_test_file, "test.png")) +def test_get_lat_str(module_setup_env, nc_test_file, tmp_path_factory): + output_yaml = tmp_path_factory.mktemp("data") / "test_hovmoeller.yaml" + min_yaml = dict_to_yaml(make_config(nc_test_file, "test.png"), output_yaml) plot_obj = hov.Hovmoeller(util.get_params(min_yaml)) actual = plot_obj.get_lat_str(-4,-2) diff --git a/test/import/test_import.py b/test/import/test_import.py index 9a6d304ab..7dc821235 100644 --- a/test/import/test_import.py +++ b/test/import/test_import.py @@ -8,7 +8,6 @@ def test_import_hovmoeller(): import metplotpy.plots.hovmoeller.hovmoeller except: assert False - assert True # used in METplus use case: model_applications/medium_range/UserScript_fcstGEFS_Difficulty_Index @@ -18,7 +17,6 @@ def test_import_difficulty_index(): from metplotpy.plots.difficulty_index.plot_difficulty_index import plot_field except: assert False - assert True def test_import_all(): @@ -26,4 +24,3 @@ def test_import_all(): import metplotpy except: assert False - assert True diff --git a/test/line/custom_line.yaml b/test/line/custom_line.yaml index e38a6d850..3ee84e623 100644 --- a/test/line/custom_line.yaml +++ b/test/line/custom_line.yaml @@ -30,6 +30,7 @@ derived_series_1: derived_series_2: [] dump_points_1: 'False' dump_points_2: 'False' +points_path: !ENV '${TEST_OUTPUT}' event_equal: 'True' fcst_var_val_1: RH: @@ -94,7 +95,7 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/line.png' +plot_filename: !ENV '${TEST_OUTPUT}/line.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -102,11 +103,6 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -#points_path: /dir_to_save_points1_file random_seed: null series_line_style: - '-' diff --git a/test/line/custom_line2.yaml b/test/line/custom_line2.yaml index cafc9708f..7f5a0cd99 100644 --- a/test/line/custom_line2.yaml +++ b/test/line/custom_line2.yaml @@ -1,3 +1,8 @@ +plot_filename: !ENV '${TEST_OUTPUT}/line.png' +points_path: !ENV '${TEST_OUTPUT}/custom_line2' + +stat_input: !ENV '${TEST_DIR}/line.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -95,14 +100,12 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/line.png' plot_height: 8.5 plot_res: 72 plot_stat: median plot_type: png16m plot_units: in plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' random_seed: null series_line_style: - '-' @@ -149,7 +152,6 @@ show_signif: - 'False' - 'False' - 'False' -stat_input: !ENV '${TEST_DIR}/line.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/line/custom_line_from_zero.yaml b/test/line/custom_line_from_zero.yaml index 9d320c8c8..3536ca20f 100644 --- a/test/line/custom_line_from_zero.yaml +++ b/test/line/custom_line_from_zero.yaml @@ -1,3 +1,7 @@ +plot_filename: !ENV '${TEST_OUTPUT}/line_from_zero.png' + +stat_input: !ENV '${TEST_DIR}/line.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -95,7 +99,7 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/line_from_zero.png' + plot_height: 8.5 plot_res: 72 plot_stat: median @@ -155,7 +159,6 @@ show_signif: - 'False' - 'False' start_from_zero: 'True' -stat_input: !ENV '${TEST_DIR}/line.data' sync_yaxes: 'False' title: test title title_align: 0.5 @@ -219,8 +222,8 @@ lines: type: vert_line show_legend: - -True - -True - -True - -True - -True \ No newline at end of file +- True +- True +- True +- True +- True \ No newline at end of file diff --git a/test/line/custom_line_groups.yaml b/test/line/custom_line_groups.yaml index 0eafc444f..e04fb9a37 100644 --- a/test/line/custom_line_groups.yaml +++ b/test/line/custom_line_groups.yaml @@ -1,3 +1,10 @@ +plot_filename: !ENV '${TEST_OUTPUT}/line_groups.png' +points_path: !ENV '${TEST_OUTPUT}' +dump_points_1: 'True' +dump_points_2: 'True' + +stat_input: !ENV '${TEST_DIR}/line_groups.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -25,8 +32,6 @@ derived_series_1: - Group_y1_2 TMP ME - DIFF derived_series_2: [] -dump_points_1: 'True' -dump_points_2: 'True' eqbound_high: 0.001 eqbound_low: -0.001 event_equal: 'False' @@ -87,7 +92,6 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/line_groups.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -125,7 +129,6 @@ show_signif: - 'False' - 'False' - 'False' -stat_input: !ENV '${TEST_DIR}/line_groups.data' sync_yaxes: 'False' title: test title title_align: 0.5 @@ -178,6 +181,6 @@ ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 show_legend: - -True - -True - -True \ No newline at end of file +- True +- True +- True \ No newline at end of file diff --git a/test/line/custom_line_groups2.yaml b/test/line/custom_line_groups2.yaml index 0eedd0cf6..6fdcd0529 100644 --- a/test/line/custom_line_groups2.yaml +++ b/test/line/custom_line_groups2.yaml @@ -1,3 +1,10 @@ +plot_filename: !ENV '${TEST_OUTPUT}/line_groups2.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' +dump_points_1: 'True' +dump_points_2: 'True' + +stat_input: !ENV '${TEST_DIR}/line_groups.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -33,8 +40,6 @@ derived_series_1: - Group_y1_2 TMP ME - DIFF derived_series_2: [] -dump_points_1: 'True' -dump_points_2: 'True' eqbound_high: 0.001 eqbound_low: -0.001 event_equal: 'False' @@ -92,14 +97,13 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/intermed_files/line_groups.png' + plot_height: 8.5 plot_res: 72 plot_stat: median plot_type: png16m plot_units: in plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' random_seed: null series_line_style: - '-' @@ -131,7 +135,6 @@ show_signif: - 'False' - 'False' - 'False' -stat_input: !ENV '${TEST_DIR}/line_groups.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/line/env_fcst_var.yaml b/test/line/env_fcst_var.yaml index 419c53d78..5b9454b8d 100644 --- a/test/line/env_fcst_var.yaml +++ b/test/line/env_fcst_var.yaml @@ -1,3 +1,10 @@ +plot_filename: !ENV '${TEST_OUTPUT}/env_fcst_var_stat_line.png' +points_path: !ENV '${TEST_OUTPUT}/env_fcst_var' +dump_points_1: 'True' +dump_points_2: 'True' + +stat_input: !ENV '${TEST_DIR}/line.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -28,8 +35,6 @@ derived_series_1: - GTS RH MAE - DIFF derived_series_2: [] -dump_points_1: 'True' -dump_points_2: 'True' event_equal: 'True' fcst_var_val_1: !ENV ${FCST_VAR_VAL1}: @@ -94,7 +99,6 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/env_fcst_var_stat_line.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -102,11 +106,6 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -points_path: !ENV '${TEST_DIR}/intermed_files/env_fcst_var_stat' random_seed: null series_line_style: - '-' @@ -153,7 +152,6 @@ show_signif: - 'False' - 'False' - 'False' -stat_input: !ENV '${TEST_DIR}/line.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/line/fbias_fixed_vars_vals.yaml b/test/line/fbias_fixed_vars_vals.yaml index 750059427..6c6f90de3 100644 --- a/test/line/fbias_fixed_vars_vals.yaml +++ b/test/line/fbias_fixed_vars_vals.yaml @@ -1,3 +1,7 @@ +plot_filename: !ENV '${TEST_OUTPUT}/fbias_fixed_vars.png' +points_path: !ENV '${TEST_OUTPUT}/fbias_points' +stat_input: !ENV '${TEST_DIR}/fbias_data.txt' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -166,7 +170,6 @@ plot_ci: plot_disp: - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/fbias_fixed_vars.png' plot_height: 8.5 plot_res: 72 plot_stat: mean @@ -175,13 +178,6 @@ plot_units: in plot_width: 11.0 start_from_zero: True - -#Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -points_path: !ENV '${TEST_DIR}/' - random_seed: null series_line_style: - '-' @@ -207,7 +203,6 @@ show_nstats: 'False' show_signif: - 'False' - 'False' -stat_input: !ENV '${TEST_DIR}/fbias_data.txt' sync_yaxes: 'False' title: "Fixed variable fcst_thresh >0.0 for FBIAS" title_align: 0.5 @@ -258,5 +253,5 @@ ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 show_legend: - -True - -True +- True +- True diff --git a/test/line/mv_custom_vert_line.yaml b/test/line/mv_custom_vert_line.yaml index d26335f0d..3ea45e322 100644 --- a/test/line/mv_custom_vert_line.yaml +++ b/test/line/mv_custom_vert_line.yaml @@ -1,3 +1,8 @@ +points_path: !ENV '${TEST_OUTPUT}/mv_custom_vert_line' +plot_filename: !ENV '${TEST_OUTPUT}/vert_line_plot.png' + +stat_input: !ENV '${TEST_DIR}/vert_line_plot_data.txt' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -102,7 +107,6 @@ plot_ci: plot_disp: - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/vert_line_plot.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -110,11 +114,7 @@ plot_type: png16m plot_units: in plot_width: 11.0 -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -points_path: !ENV '${TEST_DIR}/intermed_files' + random_seed: null series_line_style: - '-' @@ -140,7 +140,6 @@ show_nstats: 'True' show_signif: - 'True' - 'True' -stat_input: !ENV '${TEST_DIR}/vert_line_plot_data.txt' sync_yaxes: 'False' title: test title title_align: 0.5 @@ -191,5 +190,5 @@ ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 show_legend: - -True - -True +- True +- True diff --git a/test/line/test_line_groups_plot.py b/test/line/test_line_groups_plot.py deleted file mode 100644 index a0756c036..000000000 --- a/test/line/test_line_groups_plot.py +++ /dev/null @@ -1,99 +0,0 @@ -import pytest -import os -from metplotpy.plots.line import line as l -#from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) - -@pytest.fixture -def setup(): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line_groups.yaml" - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - l.main(custom_config_filename) - - -def cleanup(): - # remove the line.png and .points files - # from any previous runs - try: - plot_file = 'line_groups.png' - points_file_1 = 'line_groups.points1' - points_file_2 = 'line_groups.points2' - html_file = 'line_groups.html' - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(cwd, points_file_1)) - os.remove(os.path.join(cwd, points_file_2)) - os.remove(os.path.join(cwd, html_file)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.parametrize("test_input,expected", - ([f"{cwd}/line_groups.png", True], [f"{cwd}/line_groups.points1", True])) -def test_files_exist(setup, test_input, expected): - ''' - Checking that the plot and data files are getting created - ''' - assert os.path.isfile(test_input) == expected - cleanup() - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - plot_file = 'line_groups.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/line_groups_expected.png', actual_file) - assert comparison.mssim == 1 - cleanup() - -@pytest.mark.parametrize("test_input,expected", - ([f"{cwd}/intermed_files/line_groups.png", True], [f"{cwd}/intermed_files/line_groups.points1", True])) -def test_files_exist( test_input, expected): - ''' - Checking that the plot and data files are getting created - ''' - intermed_dir = f'{cwd}/intermed_files' - try: - os.mkdir(intermed_dir) - except FileExistsError as e: - pass - - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line_groups2.yaml" - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - l.main(custom_config_filename) - assert os.path.isfile(test_input) == expected - - # remove the files that were created, cleanup() isn't applicable for this test. - try: - subdir = os.path.join(cwd, intermed_dir) - plot_file = 'line_groups.png' - points_file_1 = 'line_groups.points1' - points_file_2 = 'line_groups.points2' - html_file = 'line_groups.html' - os.remove(os.path.join(subdir, plot_file)) - os.remove(os.path.join(subdir, points_file_1)) - os.remove(os.path.join(subdir, points_file_2)) - os.remove(os.path.join(subdir, html_file)) - os.rmdir(intermed_dir) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass diff --git a/test/line/test_line_plot.py b/test/line/test_line_plot.py index c7830ec89..648b6dae5 100644 --- a/test/line/test_line_plot.py +++ b/test/line/test_line_plot.py @@ -1,445 +1,190 @@ -import pandas as pd import pytest -import os -from metplotpy.plots.line import line as l - -cwd = os.path.dirname(__file__) - -# from metcalcpy.compare_images import CompareImages - - -@pytest.fixture -def setup(): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line.yaml" - - # Invoke the command to generate a line plot based on - # the custom config file. - l.main(custom_config_filename) - - -def cleanup(): - # remove the line.png and .points files - # from any previous runs - try: - plot_file = 'line.png' - points_file_1 = 'line.points1' - points_file_2 = 'line.points2' - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(cwd, points_file_1)) - os.remove(os.path.join(cwd, points_file_2)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.parametrize("test_input,expected", - ([f"{cwd}/line.png", True], [f"{cwd}/line.points1", False], - [f"{cwd}/line.points2", False])) -def test_files_exist(setup, test_input, expected): - ''' - Checking that the plot file is getting created but the - .points1 and .points2 files are NOT - ''' - assert os.path.isfile(test_input) == expected - cleanup() - - -@pytest.mark.parametrize("test_input,expected", - ([f"{cwd}/line.png", True], [f"{cwd}/intermed_files/line.points1", True], - [f"{cwd}/intermed_files/line.points2", True])) -def test_points_files_exist(test_input, expected): - ''' - Checking that the plot and point data files are getting created - ''' - - # create the intermediate directory to store the .points1 and .points2 files - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError as e: - pass - - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line2.yaml" - l.main(custom_config_filename) - - # Test for expected values - assert os.path.isfile(test_input) == expected - - # cleanup intermediate files and plot - try: - plot_file = 'line.png' - points_file_1 = 'line.points1' - points_file_2 = 'line.points2' - intermed_path = os.path.join(cwd, 'intermed_files') - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(intermed_path, points_file_1)) - os.remove(os.path.join(intermed_path, points_file_2)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -def test_no_nans_in_points_files(): - ''' - Checking that the point data files do not have any NaN's - ''' - - # create the intermediate directory to store the .points1 and .points2 files - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError as e: - pass - - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line2.yaml" - l.main(custom_config_filename) - - # Check for NaN's in the intermediate files,_line.points1 and line.points2 - # Fail if there are any NaN's-this indicates something went wrong with the - # line_series.py module's _create_series_points() method. - nans_found = False - with open(f"{cwd}/intermed_files/line.points1", "r") as f: - data = f.read() - if "NaN" in data: - nans_found = True - - assert nans_found == False - - # Now check line.points2 - with open(f"{cwd}/intermed_files/line.points2", "r") as f: - data = f.read() - if "NaN" in data: - nans_found = True - assert nans_found == False +import pandas as pd +import os - # Verify that the nan.points1 file does indeed trigger a "nans_found" - with open(f"{cwd}/nan.points1", "r") as f: - data = f.read() - if "NaN" in data: - nans_found = True - - # assert - assert nans_found == True - - # cleanup intermediate files and plot - try: - plot_file = 'line.png' - points_file_1 = 'line.points1' - points_file_2 = 'line.points2' - intermed_path = os.path.join(cwd, 'intermed_files') - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(intermed_path, points_file_1)) - os.remove(os.path.join(intermed_path, points_file_2)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.skip() -def test_images_match(setup): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - plot_file = './line.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/line_expected.png', actual_file) - - # !!!WARNING!!! SOMETIMES FILE SIZES DIFFER IN SPITE OF THE PLOTS LOOKING THE SAME - # THIS TEST IS NOT 100% RELIABLE because of differences in machines, OS, etc. - assert comparison.mssim == 1 - cleanup() - - -@pytest.mark.skip() -def test_new_images_match(): - ''' - Compare an expected plot with the start_at_zero option, with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/custom_line_from_zero.yaml" - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - l.main(custom_config_filename) - plot_file = 'line_from_zero.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/line_expected_from_zero.png', actual_file) - - # !!!WARNING!!! SOMETIMES FILE SIZES DIFFER IN SPITE OF THE PLOTS LOOKING THE SAME - # THIS TEST IS NOT 100% RELIABLE because of differences in machines, OS, etc. - assert comparison.mssim == 1 - - # cleanup plot - try: - plot_file = 'line_from_zero.png' - os.remove(os.path.join(cwd, plot_file)) - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -def test_vertical_plot(): - ''' - - Test that the y1 values from the Python version of the vertical plot - match the y1 values from the METviewer Rplot version of the vertical plot. - Avoid relying on image comparison tests. - - ''' - - # create the intermediate directory to store the .points1 and .points2 files - try: - os.mkdir(os.path.join(os.getcwd(), 'intermed_files')) - except FileExistsError as e: - pass - - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIRR'] = cwd - custom_config_filename = f"{cwd}/mv_custom_vert_line.yaml" - l.main(custom_config_filename) - - try: - plot_file = 'vert_line_plot.png' - points_file_1 = 'vert_line_plot.points1' - points_file_2 = 'vert_line_plot.points2' - intermed_path = os.path.join(cwd, 'intermed_files') - - # Retrieve the .points1 files generated by METviewer and METplotpy respectively - mv_df = pd.read_csv(f'{cwd}/intermed_files/vert_plot_y1_from_metviewer.points1', - sep=" ", header=None) - mpp_df = pd.read_csv(f'{cwd}/intermed_files/vert_line_plot.points1', sep=" ", - header=None) - - # ----------------------- - # Compare various values - # ----------------------- - # Verify we are comparing data frames created from the same data - # Same number of rows: - assert mv_df.shape[0] == mpp_df.shape[0] - # Same number of columns: - assert mv_df.shape[1] == mpp_df.shape[1] - - # Values for each column are the same (accounting for precision between R and - # Python and - # different host machines) - for col in range(mv_df.shape[1]): - mv_col: pd.Series = mv_df.loc[:, col] - mpp_col: pd.Series = mpp_df.loc[:, col] - col_diff: pd.Series = mv_col - mpp_col - sum_diff: float = abs(col_diff.sum()) - - # Allow for differences in arithmetic between machines and differences in - # R vs Python arithmetic - # allow difference out to 5th significant figure. - assert sum_diff < 0.00001 - - # cleanup intermediate files and plot - os.remove(os.path.join(path, plot_file)) - os.remove(os.path.join(intermed_path, points_file_1)) - os.remove(os.path.join(intermed_path, points_file_2)) - os.remove(f'{cwd}/intermed_files/vert_plot_y1_from_metviewer.points1') - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -def test_fixed_var_val(): - """ - Verify that the fixed_vars_vals_input setting reproduces the - same data points that METviewer produces. - - """ - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/fbias_fixed_vars_vals.yaml" - - # Invoke the command to generate a line plot based on - # the custom config file. - l.main(custom_config_filename) - - expected_points = f"{cwd}/intermed_files/mv_fixed_var_vals.points1" - - try: - plot_file = 'fbias_fixed_vars_reformatted_input.png' - - intermed_path = os.path.join(cwd, 'intermed_files') - - # Retrieve the .points1 files generated by METviewer and METplotpy respectively - mv_df = pd.read_csv(f'{cwd}/intermed_files/mv_fixed_var_vals.points1', - sep="\t", header=None) - mpp_df = pd.read_csv(f'{cwd}/fbias.points1', sep="\t", header=None) - - # Verify that the values in the generated points1 file are identical - # to those in the METviewer points1 file. - - # First, verify that the points1 files have the same shape - num_mv_rows = mv_df.shape[0] - num_mv_cols = mv_df.shape[1] - num_mpp_rows = mpp_df.shape[0] - num_mpp_cols = mpp_df.shape[1] - - assert num_mv_rows == num_mpp_rows - assert num_mv_cols == num_mpp_cols - - # Verify that all of the rows of both have identical values - for i in range(num_mv_rows): - assert mv_df.iloc[i][0] == mpp_df.iloc[i][0] - - # Clean up the fbias.points1, fbias.points2, and .png files - os.remove(f'{cwd}/fbias.points1') - os.remove(f'{cwd}/fbias.points2') - os.remove(f'{cwd}/fbias_fixed_vars_reformatted_input.png') - os.remove(f'{cwd}/intermed_files/mv_fixed_var_vals.points1') - os.remove(expected_points) - os.rmdir(f'{cwd}/intermed_files') - - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - -def test_envs_fcst_var_stat(): - """ - Verify that the environment vars used for fcst_var_val1/2 and stat1/2 in - a config file creates the same data for plotting as a config file with the - fcst_var_val1 and stat hard-coded in a config file. - - """ - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/env_fcst_var.yaml" - - # Invoke the command to generate a line plot based on - # the custom config file. +from metplotpy.plots.line import line + + +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_line.yaml", [ + "line.png", + ]), + ("custom_line2.yaml", [ + "line.png", + "custom_line2/line.points1", + "custom_line2/line.points2", + ]), + ("custom_line_from_zero.yaml", [ + "line_from_zero.png", + ]), + ("env_fcst_var.yaml", [ + "env_fcst_var_stat_line.png", + "env_fcst_var/line.points1", + "env_fcst_var/line.points2", + ]), + ("mv_custom_vert_line.yaml", [ + "vert_line_plot.png", + "mv_custom_vert_line/vert_line_plot.points1", + "mv_custom_vert_line/vert_line_plot.points2", + ]), + ("fbias_fixed_vars_vals.yaml", [ + "fbias_fixed_vars.png", + "fbias_points/fbias.points1", + ]), + # formerly in test_line_groups_plots.py + ("custom_line_groups.yaml", [ + "line_groups.png", + "line_groups.points1", + "line_groups.points2", + "line_groups.html", + ]), + ("custom_line_groups2.yaml", [ + "line_groups2.png", + "intermed_files/line_groups.points1", + "intermed_files/line_groups.points2", + ]), +]) +def test_line_plot(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" + + remove_files(os.environ['TEST_OUTPUT'], expected_files) + + # used by env_fcst_var.yaml os.environ['FCST_VAR_VAL1'] = "RH" os.environ['FCST_VAR_STAT1'] = 'MAE' os.environ['FCST_VAR_VAL2'] = "TMP" os.environ['FCST_VAR_STAT2'] = 'ME' - l.main(custom_config_filename) - - expected_points1 = f"{cwd}/intermed_files/expected_var_stat_line.points1" - expected_points2 = f"{cwd}/intermed_files/expected_var_stat_line.points2" - expected_df1 = pd.read_csv(f'{expected_points1}', - sep="\t", header=None) - expected_df2 = pd.read_csv( - f'{expected_points2}', sep="\t", header=None - ) - num_expected1_rows= expected_df1.shape[0] - num_expected1_cols = expected_df1.shape[1] - num_expected2_rows = expected_df2.shape[0] - num_expected2_cols = expected_df2.shape[1] + line.main(f"{os.environ['TEST_DIR']}/{input_yaml}") + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") - try: + if input_yaml == "custom_line2.yaml": + check_custom_line2_nans() - # Retrieve the .points1 files generated by METplotpy respectively - mpp_df1 = pd.read_csv(f'{cwd}/intermed_files/env_fcst_var_stat/line.points1', - sep="\t", header=None) - mpp_df2 = pd.read_csv( - f'{cwd}/intermed_files/env_fcst_var_stat/line.points2', sep="\t", header=None - ) + if input_yaml == "mv_custom_vert_line.yaml": + check_vertical_plot() - # Verify that the values in the generated points1/2 files are identical - # to those in the rh_mae_tmp_me_line.points1/2 files. + if input_yaml == "env_fcst_var.yaml": + check_env_fcst_var() - # First, verify that the points1 files have the same shape - num_mpp1_rows = mpp_df1.shape[0] - num_mpp1_cols = mpp_df1.shape[1] - num_mpp2_rows = mpp_df2.shape[0] - num_mpp2_cols = mpp_df2.shape[1] + if input_yaml == "fbias_fixed_vars_vals.yaml": + check_fbias_fixed_vars_vals() - assert num_expected1_rows == num_mpp1_rows - assert num_expected1_cols == num_mpp1_cols - assert num_expected2_rows == num_mpp2_rows - assert num_expected2_cols == num_mpp2_cols - assert mpp_df1.equals(expected_df1) - assert mpp_df2.equals(expected_df2) - - - - # Clean up the fbias.points1, fbias.points2, and .png files - os.remove(f'{cwd}/intermed_files/env_fcst_var_stat/line.points1') - os.remove(f'{cwd}/intermed_files/env_fcst_var_stat/line.points2') - os.rmdir(f'{cwd}/intermed_files/env_fcst_var_stat') - - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass - - -@pytest.mark.skip("Image comparison for development only due to differences in hosts") -def test_fixed_var_val_image_compare(): - """ - Verify that the fixed_vars_vals_input setting reproduces the - expected plot. - - """ - from metcalcpy.compare_images import CompareImages +def check_custom_line2_nans(): + """Checking that no NaNs are found in the pointsN files""" + # Check for NaN's in the intermediate files,_line.points1 and line.points2 + # Fail if there are any NaN's-this indicates something went wrong with the + # line_series.py module's _create_series_points() method. + with open(f"{os.environ['TEST_OUTPUT']}/custom_line2/line.points1", "r") as f: + data = f.read() + assert "NaN" not in data - # Set up the METPLOTPY_BASE so that met_plot.py will correctly find - # the config directory containing all the default config files. - os.environ['METPLOTPY_BASE'] = f"{cwd}/../../" - os.environ['TEST_DIR'] = cwd - custom_config_filename = f"{cwd}/fbias_fixed_vars_vals.yaml" + with open(f"{os.environ['TEST_OUTPUT']}/custom_line2/line.points2", "r") as f: + data = f.read() + assert "NaN" not in data - # Invoke the command to generate a line plot based on - # the custom config file. - l.main(custom_config_filename) + # Verify that the nan.points1 file does indeed trigger a "nans_found" + with open(f"{os.environ['TEST_DIR']}/nan.points1", "r") as f: + data = f.read() + assert "NaN" in data - expected_plot = f"{cwd}/expected_fbias_fixed_vars.png" - try: - plot_file = 'fbias_fixed_vars.png' - created_file = os.path.join(cwd, plot_file) +def check_vertical_plot(): + """Test that the y1 values from the Python version of the vertical plot + match the y1 values from the METviewer Rplot version of the vertical plot. + Avoid relying on image comparison tests.""" + + # Retrieve the .points1 files generated by METviewer and METplotpy respectively + mv_df = pd.read_csv(f"{os.environ['TEST_DIR']}/intermed_files/vert_plot_y1_from_metviewer.points1", + sep=" ", header=None) + mpp_df = pd.read_csv(f"{os.environ['TEST_OUTPUT']}/mv_custom_vert_line/vert_line_plot.points1", sep=" ", + header=None) + + # ----------------------- + # Compare various values + # ----------------------- + # Verify we are comparing data frames created from the same data + # Same number of rows: + assert mv_df.shape[0] == mpp_df.shape[0] + # Same number of columns: + assert mv_df.shape[1] == mpp_df.shape[1] + + # Values for each column are the same (accounting for precision between R and + # Python and + # different host machines) + for col in range(mv_df.shape[1]): + mv_col: pd.Series = mv_df.loc[:, col] + mpp_col: pd.Series = mpp_df.loc[:, col] + col_diff: pd.Series = mv_col - mpp_col + sum_diff: float = abs(col_diff.sum()) + + # Allow for differences in arithmetic between machines and differences in + # R vs Python arithmetic + # allow difference out to 5th significant figure. + assert sum_diff < 0.00001 + + +def check_fbias_fixed_vars_vals(): + """Verify that the fixed_vars_vals_input setting reproduces the same data points that METviewer produces.""" + + # Retrieve the .points1 files generated by METviewer and METplotpy respectively + mv_df = pd.read_csv(f"{os.environ['TEST_DIR']}/intermed_files/mv_fixed_var_vals.points1", + sep="\t", header=None) + mpp_df = pd.read_csv(f"{os.environ['TEST_OUTPUT']}/fbias_points/fbias.points1", sep="\t", header=None) + + # Verify that the values in the generated points1 file are identical + # to those in the METviewer points1 file. + + # First, verify that the points1 files have the same shape + num_mv_rows = mv_df.shape[0] + num_mv_cols = mv_df.shape[1] + num_mpp_rows = mpp_df.shape[0] + num_mpp_cols = mpp_df.shape[1] + + assert num_mv_rows == num_mpp_rows + assert num_mv_cols == num_mpp_cols + + # Verify that all of the rows of both have identical values + for i in range(num_mv_rows): + assert mv_df.iloc[i][0] == mpp_df.iloc[i][0] + + +def check_env_fcst_var(): + """Verify that the environment vars used for fcst_var_val1/2 and stat1/2 in + a config file creates the same data for plotting as a config file with the + fcst_var_val1 and stat hard-coded in a config file.""" + + expected_points1 = f"{os.environ['TEST_DIR']}/intermed_files/expected_var_stat_line.points1" + expected_points2 = f"{os.environ['TEST_DIR']}/intermed_files/expected_var_stat_line.points2" + expected_df1 = pd.read_csv(f'{expected_points1}', sep="\t", header=None) + expected_df2 = pd.read_csv(f'{expected_points2}', sep="\t", header=None) + num_expected1_rows = expected_df1.shape[0] + num_expected1_cols = expected_df1.shape[1] + num_expected2_rows = expected_df2.shape[0] + num_expected2_cols = expected_df2.shape[1] - # first verify that the output plot was created - if os.path.exists(created_file): - assert True - else: - assert False + # Retrieve the .points1 files generated by METplotpy respectively + mpp_df1 = pd.read_csv(f'{os.environ['TEST_OUTPUT']}/env_fcst_var/line.points1', + sep="\t", header=None) + mpp_df2 = pd.read_csv(f'{os.environ['TEST_OUTPUT']}/env_fcst_var/line.points2', sep="\t", header=None) - comparison = CompareImages(expected_plot, created_file) + # Verify that the values in the generated points1/2 files are identical + # to those in the rh_mae_tmp_me_line.points1/2 files. - # !!!WARNING!!! SOMETIMES FILE SIZES DIFFER IN SPITE OF THE PLOTS LOOKING THE - # SAME - # THIS TEST IS NOT 100% RELIABLE because of differences in machines, OS, etc. - assert comparison.mssim == 1 + # First, verify that the points1 files have the same shape + num_mpp1_rows = mpp_df1.shape[0] + num_mpp1_cols = mpp_df1.shape[1] + num_mpp2_rows = mpp_df2.shape[0] + num_mpp2_cols = mpp_df2.shape[1] - # Clean up the fbias.points1, fbias.points2 and the png files - os.remove(f'{cwd}/fbias.points1') - os.remove(f'{cwd}/fbias.points2') - os.remove(created_file) + assert num_expected1_rows == num_mpp1_rows + assert num_expected1_cols == num_mpp1_cols + assert num_expected2_rows == num_mpp2_rows + assert num_expected2_cols == num_mpp2_cols - except OSError as e: - # Typically when files have already been removed or - # don't exist. Ignore. - pass + assert mpp_df1.equals(expected_df1) + assert mpp_df2.equals(expected_df2) diff --git a/test/mpr_plot/mpr_plot_custom.yaml b/test/mpr_plot/mpr_plot_custom.yaml index aad4b4416..9ba67457a 100644 --- a/test/mpr_plot/mpr_plot_custom.yaml +++ b/test/mpr_plot/mpr_plot_custom.yaml @@ -1,5 +1,5 @@ wind_rose: True -plot_filename: !ENV '${TEST_DIR}/mpr_plots.png' +plot_filename: !ENV '${TEST_OUTPUT}/mpr_plots.png' wind_rose_breaks: - 0.0 - 1.0 diff --git a/test/mpr_plot/test_mpr_plot.py b/test/mpr_plot/test_mpr_plot.py index ee724505a..e5972c361 100644 --- a/test/mpr_plot/test_mpr_plot.py +++ b/test/mpr_plot/test_mpr_plot.py @@ -1,41 +1,16 @@ import pytest -import os -from metplotpy.plots.mpr_plot import mpr_plot -#from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['mpr_plots.png'] +import os -@pytest.fixture -def setup(setup_env, remove_files): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/mpr_plot_custom.yaml" +from metplotpy.plots.mpr_plot import mpr_plot - # Invoke the command to generate a Performance Diagram based on - # the custom_performance_diagram.yaml custom config file. - mpr_plot.main(custom_config_filename) +def test_files_exist(module_setup_env, remove_files): + """Checking that the plot and data files are getting created""" + expected_file = "mpr_plots.png" -@pytest.mark.parametrize("test_input, expected", - (["mpr_plots.png", True], ["mpr_plots_expected.png", True])) -def test_files_exist(setup, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) + remove_files(os.environ['TEST_OUTPUT'], expected_file) + mpr_plot.main(f"{os.environ['TEST_DIR']}/mpr_plot_custom.yaml") -@pytest.mark.skip("unreliable-sometimes fails due to differences between machines.") -def test_images_match(setup, remove_files): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/mpr_plots_expected.png', f'{cwd}/mpr_plots.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/performance_diagram/custom_performance_diagram.yaml b/test/performance_diagram/custom_performance_diagram.yaml index 6527cb1ec..e013d446d 100644 --- a/test/performance_diagram/custom_performance_diagram.yaml +++ b/test/performance_diagram/custom_performance_diagram.yaml @@ -1,8 +1,11 @@ --- -# Custom settings specific to performance diagram plot -# Write points file. Set to True for METviewer use, -# False otherwise -dump_points_1: 'False' +plot_filename: !ENV '${TEST_OUTPUT}/performance_diagram_actual.png' + +points_path: !ENV '${TEST_OUTPUT}/intermed_files' +dump_points_1: 'True' + +stat_input: !ENV '${TEST_DIR}/plot_20200317_151252.data' + # Optional, uncomment and set to directory to store the .points1 file # that is used by METviewer (created when dump_points_1 is set to True) @@ -104,14 +107,4 @@ series_line_style: - "--" # dotted line - ":" -stat_input: !ENV '${TEST_DIR}/plot_20200317_151252.data' -plot_filename: !ENV '${TEST_DIR}/performance_diagram_actual.png' event_equal: False - -# To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have -# permissions to the directory you specify. The default, as specified in the default config file is stdout. -#log_filename: ./performance_diagram.log - -# To change the log level, specify a log level: debug, info, warning, error and uncomment the line below. -# Debug and info log level will produce more log output. -#log_level: WARNING diff --git a/test/performance_diagram/custom_performance_diagram_defaultpoints1.yaml b/test/performance_diagram/custom_performance_diagram_defaultpoints1.yaml deleted file mode 100644 index d6e5480f7..000000000 --- a/test/performance_diagram/custom_performance_diagram_defaultpoints1.yaml +++ /dev/null @@ -1,107 +0,0 @@ ---- -# Custom settings specific to performance diagram plot -# Line and marker plots of series data of Success Rate (1-FAR) on x-axis vs. PODY on y-axis. -title: Performance Diagram ("Custom title") -xaxis: Success Ratio - -dump_points_1: 'True' - -# Do not set the points_path so that the points1 path is saved in the same directory as the -# input data. -#points_path: './intermed_files' - -# support two y-axes -yaxis_1: Probability of Detection (PODY) -yaxis_2: '' -legend_ncol: 1 -plot_disp: - - True - - True - - True -series_order: - - 2 - - 1 - - 3 -indy_var: fcst_valid_beg -indy_vals: - # defining the datetimes of interest - - 2016-08-12 06:00:00 - - 2016-08-12 12:00:00 - - 2016-08-12 18:00:00 - - 2016-08-13 00:00:00 - - 2016-08-13 06:00:00 - - 2016-08-13 12:00:00 - - 2016-08-13 18:00:00 - - 2016-08-14 00:00:00 - - 2016-08-14 06:00:00 - - 2016-08-14 12:00:00 - - 2016-08-14 18:00:00 - - 2016-08-15 00:00:00 - - 2016-08-15 12:00:00 - - 2016-08-15 18:00:00 - - 2016-08-16 00:00:00 - - 2016-08-16 06:00:00 - - 2016-08-16 12:00:00 - - 2016-08-16 18:00:00 - - 2016-08-17 00:00:00 - -# support two series values -series_val_1: - model: - - GFS_0p25_G193 - vx_mask: - - NH_CMORPH_G193 - - SH_CMORPH_G193 - - TROP_CMORPH_G193 -series_val_2: {} -fcst_var_val_1: - # Name of the variables of interest, the independent and dependent variables - # will be the same across all fcst_var values - - # fcst_var1 - APCP_06: - # x-axis/independent variable - - FAR - # y-axis/dependent variable - - PODY -fcst_var_val_2: -user_legend: -# - NH -# - SH -# - TROP - - NH - - '' - - TROP - -plot_stat: median -colors: - # red - - "#ff0000" - # limegreen, as name of color - - limegreen - # electric indigo/vivid purple - - "#8000ff" -series_line_width: - - 1 - - 1 - - NA -series_symbols: - # Other supported symbols: small circle = ".", ring/hexagon = "H", rhombus/diamond="d" - # Circle - - "o" - # square - - "s" - # triangle - #- "^" - # ring - - "H" -series_line_style: - # solid line - - "-" - # dashed line - - "--" - # dotted line - - ":" -stat_input: !ENV '${TEST_DIR}/plot_20200317_151252.data' -plot_filename: !ENV '${TEST_DIR}/performance_diagram_defaultpoints1.png' -event_equalize: False diff --git a/test/performance_diagram/custom_performance_diagram_points1.yaml b/test/performance_diagram/custom_performance_diagram_points1.yaml deleted file mode 100644 index aaf207966..000000000 --- a/test/performance_diagram/custom_performance_diagram_points1.yaml +++ /dev/null @@ -1,104 +0,0 @@ ---- -# Custom settings specific to performance diagram plot -# Line and marker plots of series data of Success Rate (1-FAR) on x-axis vs. PODY on y-axis. -title: Performance Diagram ("Custom title") -xaxis: Success Ratio - -dump_points_1: 'True' -points_path: !ENV '${TEST_DIR}/intermed_files' - -# support two y-axes -yaxis_1: Probability of Detection (PODY) -yaxis_2: '' -legend_ncol: 1 -plot_disp: - - True - - True - - True -series_order: - - 2 - - 1 - - 3 -indy_var: fcst_valid_beg -indy_vals: - # defining the datetimes of interest - - 2016-08-12 06:00:00 - - 2016-08-12 12:00:00 - - 2016-08-12 18:00:00 - - 2016-08-13 00:00:00 - - 2016-08-13 06:00:00 - - 2016-08-13 12:00:00 - - 2016-08-13 18:00:00 - - 2016-08-14 00:00:00 - - 2016-08-14 06:00:00 - - 2016-08-14 12:00:00 - - 2016-08-14 18:00:00 - - 2016-08-15 00:00:00 - - 2016-08-15 12:00:00 - - 2016-08-15 18:00:00 - - 2016-08-16 00:00:00 - - 2016-08-16 06:00:00 - - 2016-08-16 12:00:00 - - 2016-08-16 18:00:00 - - 2016-08-17 00:00:00 - -# support two series values -series_val_1: - model: - - GFS_0p25_G193 - vx_mask: - - NH_CMORPH_G193 - - SH_CMORPH_G193 - - TROP_CMORPH_G193 -series_val_2: {} -fcst_var_val_1: - # Name of the variables of interest, the independent and dependent variables - # will be the same across all fcst_var values - - # fcst_var1 - APCP_06: - # x-axis/independent variable - - FAR - # y-axis/dependent variable - - PODY -fcst_var_val_2: -user_legend: -# - NH -# - SH -# - TROP - - NH - - '' - - TROP - -plot_stat: median -colors: - # red - - "#ff0000" - # limegreen, as name of color - - limegreen - # electric indigo/vivid purple - - "#8000ff" -series_line_width: - - 1 - - 1 - - NA -series_symbols: - # Other supported symbols: small circle = ".", ring/hexagon = "H", rhombus/diamond="d" - # Circle - - "o" - # square - - "s" - # triangle - #- "^" - # ring - - "H" -series_line_style: - # solid line - - "-" - # dashed line - - "--" - # dotted line - - ":" -stat_input: !ENV '${TEST_DIR}/plot_20200317_151252.data' -plot_filename: !ENV '${TEST_DIR}/performance_diagram_actual_points1.png' -event_equalize: False diff --git a/test/performance_diagram/test_performance_diagram.py b/test/performance_diagram/test_performance_diagram.py index 511e8a8d6..cc1dbf7f8 100644 --- a/test/performance_diagram/test_performance_diagram.py +++ b/test/performance_diagram/test_performance_diagram.py @@ -1,106 +1,20 @@ import os import pytest -from metplotpy.plots.performance_diagram import performance_diagram as pd -#from metcalcpy.compare_images import CompareImages +from metplotpy.plots.performance_diagram import performance_diagram as performance_diagram -cwd = os.path.dirname(__file__) +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("custom_performance_diagram.yaml", [ + "performance_diagram_actual.png", + "intermed_files/plot_20200317_151252.points1", + ]), +]) +def test_performance_diagram(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" -CLEANUP_FILES = ['performance_diagram_actual.png', 'plot_20200317_151252.points1'] + remove_files(os.environ['TEST_OUTPUT'], expected_files) + performance_diagram.main(f"{os.environ['TEST_DIR']}/{input_yaml}") -@pytest.fixture -def setup(setup_env, remove_files): - setup_env(cwd) - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - custom_config_filename = f"{cwd}/custom_performance_diagram.yaml" - # print("\n current directory: ", os.getcwd()) - # print("\ncustom config file: ", custom_config_filename, '\n') - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - # Retrieve the contents of the custom config file to over-ride - # or augment settings defined by the default config file. - pd.main(custom_config_filename) - - -@pytest.mark.parametrize("test_input,expected_bool",(["performance_diagram_actual.png", True], ["plot_20200317_151252.points1", False])) -def test_plot_exists(setup, test_input, expected_bool, remove_files): - ''' - Checking that only the plot file is getting created and the - .point1 data file is not (dump_points_1 is 'False' in the test config file) - ''' - - assert os.path.isfile(f"{cwd}/{test_input}") == expected_bool - remove_files(cwd, CLEANUP_FILES) - -@pytest.mark.parametrize("test_input,expected_bool",(["./performance_diagram_actual_points1.png", True], ["./intermed_files/plot_20200317_151252.points1", True])) -def test_files_exist(setup_env, test_input, expected_bool, remove_files): - ''' - Checking that only the plot file is getting created and the - .point1 data file is not (dump_points_1 is 'False' in the test config file) - ''' - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_performance_diagram_points1.yaml" - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - # Retrieve the contents of the custom config file to over-ride - # or augment settings defined by the default config file. - pd.main(custom_config_filename) - - assert os.path.isfile(f"{cwd}/{test_input}") == expected_bool - remove_files(cwd, ['performance_diagram_actual_points1.png', 'intermed_files/plot_20200317_151252.points1']) - try: - os.rmdir(os.path.join(cwd, 'intermed_files')) - except OSError: - pass - - -@pytest.mark.parametrize("test_input,expected_bool", (["performance_diagram_defaultpoints1.png", True], ["plot_20200317_151252.points1", True])) -def test_files_exist(setup_env, test_input, expected_bool, remove_files): - ''' - Checking that only the plot file is getting created and the - .point1 data file is not (dump_points_1 is 'False' in the test config file) - ''' - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_performance_diagram_defaultpoints1.yaml" - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - # Retrieve the contents of the custom config file to over-ride - # or augment settings defined by the default config file. - pd.main(custom_config_filename) - - assert os.path.isfile(f"{cwd}/{test_input}") == expected_bool - remove_files(cwd, ['performance_diagram_defaultpoints1.png', 'plot_20200317_151252.points1']) - try: - os.rmdir(os.path.join(cwd, 'intermed_files')) - except OSError: - pass - - -@pytest.mark.skip() -def test_images_match(setup, remove_files): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - custom_config_filename = f"{cwd}/custom_performance_diagram.yaml" - pd.main(custom_config_filename) - - plot_file = 'performance_diagram_actual.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/performance_diagram_expected.png', actual_file) - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/reliability_diagram/custom_reliability_diagram.yaml b/test/reliability_diagram/custom_reliability_diagram.yaml index 30c8e6bbc..e931394f7 100644 --- a/test/reliability_diagram/custom_reliability_diagram.yaml +++ b/test/reliability_diagram/custom_reliability_diagram.yaml @@ -1,3 +1,7 @@ +plot_filename: !ENV '${TEST_OUTPUT}/custom_reliability_diagram.png' + +stat_input: !ENV '${TEST_DIR}/plot_20210311_145053.data' + add_noskill_line: 'True' add_reference_line: 'True' add_skill_line: 'True' @@ -81,7 +85,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/custom_reliability_diagram.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -111,7 +114,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/plot_20210311_145053.data' summary_curves: [] sync_yaxes: 'False' title: test title diff --git a/test/reliability_diagram/custom_reliability_points1.yaml b/test/reliability_diagram/custom_reliability_points1.yaml index adcbb785a..8ea996820 100644 --- a/test/reliability_diagram/custom_reliability_points1.yaml +++ b/test/reliability_diagram/custom_reliability_points1.yaml @@ -1,3 +1,8 @@ +plot_filename: !ENV '${TEST_OUTPUT}/reliability_points1.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' + +stat_input: !ENV '${TEST_DIR}/reliability.data' + add_noskill_line: 'True' add_reference_line: 'True' add_skill_line: 'True' @@ -96,7 +101,6 @@ plot_stat: median plot_type: png16m plot_units: in plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' random_seed: null rely_event_hist: 'True' series_line_style: @@ -180,8 +184,6 @@ ytlab_horiz: 0.5 ytlab_orient: 1 ytlab_perp: 0.5 ytlab_size: 1 -plot_filename: !ENV '${TEST_DIR}/intermed_files/reliability.png' -stat_input: !ENV '${TEST_DIR}/reliability.data' noskill_line_col: 'green' reference_line_col: 'blue' show_legend: diff --git a/test/reliability_diagram/reliability.points1 b/test/reliability_diagram/reliability.points1 deleted file mode 100644 index bf85025dc..000000000 --- a/test/reliability_diagram/reliability.points1 +++ /dev/null @@ -1,12 +0,0 @@ -0.125000 0.005442 0.005189 0.005679 -0.375000 0.095076 0.085846 0.105048 -0.625000 0.155515 0.140058 0.172051 -0.875000 0.254195 0.225073 0.283987 -0.125000 0.005559 0.005308 0.005825 -0.375000 0.121477 0.109670 0.133229 -0.625000 0.180538 0.161182 0.202423 -0.875000 0.306996 0.270081 0.342544 -0.125000 0.005501 0.005249 0.005752 -0.375000 0.108276 0.097758 0.119138 -0.625000 0.168027 0.150620 0.187237 -0.875000 0.280596 0.247577 0.313265 diff --git a/test/reliability_diagram/test_reliability_diagram.py b/test/reliability_diagram/test_reliability_diagram.py index 0ceeb222f..7aa6315ed 100644 --- a/test/reliability_diagram/test_reliability_diagram.py +++ b/test/reliability_diagram/test_reliability_diagram.py @@ -1,65 +1,19 @@ - import pytest import os from metplotpy.plots.reliability_diagram import reliability as r -#from metcalcpy.compare_images import CompareImages cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['reliability.png', 'reliability.points1'] - - -@pytest.fixture -def setup(setup_env, remove_files): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_reliability_use_defaults.yaml" - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - r.main(custom_config_filename) - - -@pytest.mark.parametrize("test_input,expected", - ([CLEANUP_FILES[0], True], [CLEANUP_FILES[1], True])) -def test_files_exist(setup, test_input, expected, remove_files): - ''' - Checking that the plot and data files are getting created - ''' - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("depends on machine on which this is run") -def test_images_match(setup, remove_files): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - comparison = CompareImages(f'{cwd}/{CLEANUP_FILES[0]}', f'{cwd}/{CLEANUP_FILES[1]}') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) +@pytest.mark.parametrize("input_yaml, expected_files", [ + ("custom_reliability_diagram.yaml", ["custom_reliability_diagram.png"]), + ("custom_reliability_points1.yaml", ["reliability_points1.png", "intermed_files/reliability.points1"]), +]) +def test_files_exist(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot and data files are getting created""" -@pytest.mark.parametrize("test_input,expected", - (["intermed_files/reliability.png", True], ["intermed_files/reliability.points1", True])) -def test_files_exist(setup_env, test_input, expected, remove_files): - ''' - Checking that the plot and data files are getting created - ''' - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass + remove_files(os.environ['TEST_OUTPUT'], expected_files) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_reliability_points1.yaml" - r.main(custom_config_filename) + r.main(f"{cwd}/{input_yaml}") - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, ['intermed_files/reliability.png', 'intermed_files/reliability.points1']) - try: - os.rmdir(os.path.join(cwd, 'intermed_files')) - except OSError: - pass + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/revision_box/custom2_revision_box.yaml b/test/revision_box/custom2_revision_box.yaml deleted file mode 100644 index 2334f4f89..000000000 --- a/test/revision_box/custom2_revision_box.yaml +++ /dev/null @@ -1,136 +0,0 @@ -alpha: 0.05 -box_avg: 'False' -box_boxwex: 0.2 -box_notch: 'False' -box_outline: 'True' -box_pts: 'False' -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -circular_block_bootstrap: 'True' -cl_step: 0.05 -colors: -- '#ff0000' -- '#8000ff' -con_series: -- 1 -- 1 -create_html: 'False' -dump_points_1: 'True' -equalize_by_indep: 'True' -event_equal: 'True' -fcst_var_val_1: - TMP: - - ME -fixed_vars_vals_input: - interp_mthd: - interp_mthd_1: - - BILIN - fcst_lev: - fcst_lev_2: - - Z2 - vx_mask: - vx_mask_0: - - CONUS -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -indy_label: -- '2011-07-02 03:00:00' -- '2011-07-02 06:00:00' -- '2011-07-02 09:00:00' -- '2011-07-02 12:00:00' -- '2011-07-02 15:00:00' -- '2011-07-02 18:00:00' -- '2011-07-02 21:00:00' -indy_plot_val: [] -indy_vals: -- '2011-07-02 03:00:00' -- '2011-07-02 06:00:00' -- '2011-07-02 09:00:00' -- '2011-07-02 12:00:00' -- '2011-07-02 15:00:00' -- '2011-07-02 18:00:00' -- '2011-07-02 21:00:00' -indy_var: fcst_valid_beg -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: None -list_stat_1: -- ME -mar: -- 8.0 -- 4.0 -- 5.0 -- 4.0 -method: bca -mgp: -- 1.0 -- 1.0 -- 0.0 - -plot_caption: '' -plot_disp: -- 'True' -- 'True' -plot_filename: !ENV '${TEST_DIR}/intermed_files/revision_box.png' -plot_height: 8.5 -plot_res: 72 -plot_stat: median -plot_type: png16m -plot_units: in -plot_width: 11.0 -random_seed: null -revision_ac: 'True' -revision_run: 'False' -series_order: -- 1 -- 2 -series_val_1: - model: - - AFWAOCv3.5.1_d01 - - NoahMPv3.5.1_d01 -stat_input: !ENV '${TEST_DIR}/revision_box.data' -title: test title -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] -variance_inflation_factor: 'True' -xaxis: test x_label -xaxis_reverse: 'False' -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 -yaxis_1: test y_label -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 - -points_path: !ENV '${TEST_DIR}/intermed_files' -show_legend: -- 'True' -- 'True' \ No newline at end of file diff --git a/test/revision_box/custom_revision_box.yaml b/test/revision_box/custom_revision_box.yaml index fed2f2748..2ae6a252e 100644 --- a/test/revision_box/custom_revision_box.yaml +++ b/test/revision_box/custom_revision_box.yaml @@ -1,3 +1,8 @@ +plot_filename: !ENV '${TEST_OUTPUT}/revision_box.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' + +stat_input: !ENV '${TEST_DIR}/revision_box.data' + alpha: 0.05 box_avg: 'False' box_boxwex: 0.2 @@ -82,7 +87,6 @@ plot_caption: '' plot_disp: - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/revision_box.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -99,7 +103,6 @@ series_val_1: model: - AFWAOCv3.5.1_d01 - NoahMPv3.5.1_d01 -stat_input: !ENV '${TEST_DIR}/revision_box.data' title: test title title_align: 0.5 title_offset: -2 diff --git a/test/revision_box/test_revision_box.py b/test/revision_box/test_revision_box.py index 6932327f9..f6e693eb1 100644 --- a/test/revision_box/test_revision_box.py +++ b/test/revision_box/test_revision_box.py @@ -1,62 +1,18 @@ import pytest import os -from metplotpy.plots.revision_box import revision_box -#from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['revision_box.png', 'revision_box.points1'] - - -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_revision_box.yaml" - - # Invoke the command to generate a Revision Box plot based on - # the custom_revision_box.yaml custom config file. - revision_box.main(custom_config_filename) +from metplotpy.plots.revision_box import revision_box -@pytest.mark.parametrize("test_input, expected", - (["revision_box.png", True], ["revision_box.points1", True])) -def test_files_exist(setup, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup, remove_files): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages(f'{cwd}/revision_box_expected.png', f'{cwd}/revision_box.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) - +def test_custom_revision_box(module_setup_env, remove_files): + """Checking that the plot and data files are getting created""" + expected_files = ( + 'revision_box.png', + 'intermed_files/revision_box.points1' + ) -@pytest.mark.parametrize("test_input, expected", - (["intermed_files/revision_box.png", True], ["intermed_files/revision_box.points1", True])) -def test_files_exist(setup_env, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - setup_env(cwd) - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass + remove_files(os.environ['TEST_OUTPUT'], expected_files) - custom_config_filename = f"{cwd}/custom2_revision_box.yaml" + revision_box.main(f"{os.environ['TEST_DIR']}/custom_revision_box.yaml") - # Invoke the command to generate a Bar plot based on - # the custom_ens_ss.yaml custom config file. - revision_box.main(custom_config_filename) - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/revision_series/custom2_revision_series.yaml b/test/revision_series/custom2_revision_series.yaml deleted file mode 100644 index 9c05a30bc..000000000 --- a/test/revision_series/custom2_revision_series.yaml +++ /dev/null @@ -1,131 +0,0 @@ -alpha: 0.05 -caption_align: 0.0 -caption_col: '#333333' -caption_offset: 3.0 -caption_size: 0.8 -caption_weight: 1 -cex: 1 -circular_block_bootstrap: 'True' -cl_step: 0.05 -colors: -- '#ff0000' -- '#8000ff' -con_series: -- 1 -- 1 -create_html: 'True' -dump_points_1: 'True' -equalize_by_indep: 'False' -event_equal: 'False' -fcst_var_val_1: - TMP: - - ME -fixed_vars_vals_input: {} -grid_col: '#cccccc' -grid_lty: 3 -grid_lwd: 1 -grid_on: 'True' -grid_x: listX -indy_label: -- '2011-07-02 03:00:00' -- '2011-07-02 06:00:00' -- '2011-07-02 09:00:00' -- '2011-07-02 12:00:00' -- '2011-07-02 15:00:00' -- '2011-07-02 18:00:00' -- '2011-07-02 21:00:00' -indy_plot_val: [] -indy_vals: -- '2011-07-02 03:00:00' -- '2011-07-02 06:00:00' -- '2011-07-02 09:00:00' -- '2011-07-02 12:00:00' -- '2011-07-02 15:00:00' -- '2011-07-02 18:00:00' -- '2011-07-02 21:00:00' -indy_var: fcst_valid_beg -legend_box: o -legend_inset: - x: 0.0 - y: -0.25 -legend_ncol: 3 -legend_size: 0.8 -line_type: None -list_stat_1: -- ME -mar: -- 8.0 -- 4.0 -- 5.0 -- 4.0 -method: bca -mgp: -- 1.0 -- 1.0 -- 0.0 -num_iterations: 1 -num_threads: -1 -plot_caption: '' -plot_disp: -- 'True' -- 'True' -plot_filename: !ENV '${TEST_DIR}/intermed_files/revision_series.png' -plot_height: 8.5 -plot_res: 72 -plot_stat: median -plot_type: png16m -plot_units: in -plot_width: 11.0 -random_seed: null -revision_ac: 'True' -revision_run: 'True' - -series_order: -- 1 -- 2 -series_symbols: -- . -- . -series_type: -- p -- b -series_val_1: - model: - - AFWAOCv3.5.1_d01 - - NoahMPv3.5.1_d01 - -start_from_zero: 'False' -stat_input: !ENV '${TEST_DIR}/revision_series.data' -title: Revision series -title_align: 0.5 -title_offset: -2 -title_size: 1.4 -title_weight: 2.0 -user_legend: [] -variance_inflation_factor: 'False' -vert_plot: 'False' -xaxis: fcst_valid_beg -xlab_align: 0.5 -xlab_offset: 2 -xlab_size: 1 -xlab_weight: 1 -xlim: [] -xtlab_decim: 0 -xtlab_horiz: 0.5 -xtlab_orient: 1 -xtlab_perp: -0.75 -xtlab_size: 1 -yaxis_1: ME -ylab_align: 0.5 -ylab_offset: -2 -ylab_size: 1 -ylab_weight: 1 -ylim: [] -ytlab_horiz: 0.5 -ytlab_orient: 1 -ytlab_perp: 0.5 -ytlab_size: 1 -points_path: !ENV '${TEST_DIR}/intermed_files' -show_legend: -- 'True' -- 'True' \ No newline at end of file diff --git a/test/revision_series/custom_revision_series.yaml b/test/revision_series/custom_revision_series.yaml index 30ddf8143..66b38deb5 100644 --- a/test/revision_series/custom_revision_series.yaml +++ b/test/revision_series/custom_revision_series.yaml @@ -1,3 +1,8 @@ +plot_filename: !ENV '${TEST_OUTPUT}/revision_series.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' + +stat_input: !ENV '${TEST_DIR}/revision_series.data' + alpha: 0.05 caption_align: 0.0 caption_col: '#333333' @@ -69,7 +74,6 @@ plot_caption: '' plot_disp: - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/revision_series.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -95,7 +99,6 @@ series_val_1: - NoahMPv3.5.1_d01 start_from_zero: 'False' -stat_input: !ENV '${TEST_DIR}/revision_series.data' title: Revision series title_align: 0.5 title_offset: -2 diff --git a/test/revision_series/test_revision_series.py b/test/revision_series/test_revision_series.py index c381900ad..d8bc43b07 100644 --- a/test/revision_series/test_revision_series.py +++ b/test/revision_series/test_revision_series.py @@ -1,64 +1,17 @@ import pytest import os -from metplotpy.plots.revision_series import revision_series -#from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) -CLEANUP_FILES = ('revision_series.png', 'revision_series.points1') - - -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/custom_revision_series.yaml" - - # Invoke the command to generate a Revision Series plot based on - # the custom_revision_series.yaml custom config file. - revision_series.main(custom_config_filename) - - -@pytest.mark.parametrize("test_input, expected", - (["revision_series.png", True], ["revision_series.points1", True])) -def test_files_exist(setup, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("fails on linux hosts") -def test_images_match(setup, remove_files): - """ - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - """ - comparison = CompareImages('./revision_series_expected.png', './revision_series.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) +from metplotpy.plots.revision_series import revision_series -@pytest.mark.parametrize("test_input, expected", - (["intermed_files/revision_series.png", True], - ["intermed_files/revision_series.points1", True])) -def test_files_exist(setup_env, test_input, expected, remove_files): - """ - Checking that the plot and data files are getting created - """ - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass +@pytest.mark.parametrize("input_yaml, expected_files", [ + ("custom_revision_series.yaml", ["revision_series.png", "intermed_files/revision_series.points1"]), +]) +def test_files_exist(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot and data files are getting created""" - setup_env(cwd) - custom_config_filename = f"{cwd}/custom2_revision_series.yaml" + remove_files(os.environ['TEST_OUTPUT'], expected_files) - # Invoke the command to generate a Bar plot based on - # the custom_ens_ss.yaml custom config file. - revision_series.main(custom_config_filename) - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) + revision_series.main(f"{os.environ['TEST_DIR']}/{input_yaml}") + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/roc_diagram/CTC_ROC.yaml b/test/roc_diagram/CTC_ROC.yaml index f4a728586..15cc27978 100644 --- a/test/roc_diagram/CTC_ROC.yaml +++ b/test/roc_diagram/CTC_ROC.yaml @@ -1,4 +1,6 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC.png' +stat_input: !ENV '${TEST_DIR}/CTC_ROC.data' add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -62,7 +64,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -88,7 +89,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/CTC_ROC_ee.yaml b/test/roc_diagram/CTC_ROC_ee.yaml index 4391d2fdd..face525e3 100644 --- a/test/roc_diagram/CTC_ROC_ee.yaml +++ b/test/roc_diagram/CTC_ROC_ee.yaml @@ -1,4 +1,7 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC_ee.png' +stat_input: !ENV '${TEST_DIR}/CTC_ROC.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -62,7 +65,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC_ee.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -88,7 +90,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/CTC_ROC_summary.yaml b/test/roc_diagram/CTC_ROC_summary.yaml index e24ca49a0..f8c7d36fe 100644 --- a/test/roc_diagram/CTC_ROC_summary.yaml +++ b/test/roc_diagram/CTC_ROC_summary.yaml @@ -1,3 +1,8 @@ +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC_summary.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' + +stat_input: !ENV '${TEST_DIR}/CTC_ROC_summary.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -77,7 +82,6 @@ plot_disp: - 'True' - 'True' - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC_summary.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -123,7 +127,6 @@ show_signif: - 'False' - 'False' start_from_zero: 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC_summary.data' summary_curve: median sync_yaxes: 'False' title: test title @@ -173,6 +176,4 @@ ylim: [] ytlab_horiz: 0.5 ytlab_orient: 1 ytlab_perp: 0.5 -ytlab_size: 1 -points_path: !ENV '${TEST_DIR}/intermed_files' - +ytlab_size: 1 \ No newline at end of file diff --git a/test/roc_diagram/CTC_ROC_thresh.yaml b/test/roc_diagram/CTC_ROC_thresh.yaml index 7bbc26ca4..9a1c5bb65 100644 --- a/test/roc_diagram/CTC_ROC_thresh.yaml +++ b/test/roc_diagram/CTC_ROC_thresh.yaml @@ -1,4 +1,7 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC_thresh.png' +stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -64,7 +67,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC_thresh.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -90,7 +92,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/CTC_ROC_thresh_dump_pts.yaml b/test/roc_diagram/CTC_ROC_thresh_dump_pts.yaml index 3432b2aef..bf8be3f98 100644 --- a/test/roc_diagram/CTC_ROC_thresh_dump_pts.yaml +++ b/test/roc_diagram/CTC_ROC_thresh_dump_pts.yaml @@ -1,4 +1,9 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC_thresh_dump_pts.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files' + +stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -64,14 +69,12 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC_thresh_dump_pts.png' plot_height: 8.5 plot_res: 72 plot_stat: median plot_type: png16m plot_units: in plot_width: 11.0 -points_path: !ENV '${TEST_DIR}/intermed_files' random_seed: null reverse_connection_order: 'True' roc_ctc: true @@ -91,7 +94,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/CTC_ROC_thresh_reverse_pts.yaml b/test/roc_diagram/CTC_ROC_thresh_reverse_pts.yaml index d6d0e4a77..a73d8ae16 100644 --- a/test/roc_diagram/CTC_ROC_thresh_reverse_pts.yaml +++ b/test/roc_diagram/CTC_ROC_thresh_reverse_pts.yaml @@ -1,4 +1,9 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_ROC_thresh_reverse_pts.png' +points_path: !ENV '${TEST_OUTPUT}/intermed_files_reverse_pts' +stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' + + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -64,7 +69,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_ROC_thresh.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -90,7 +94,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/CTC_wind_reformatted.yaml b/test/roc_diagram/CTC_wind_reformatted.yaml index 3874c2d21..f0414eadc 100644 --- a/test/roc_diagram/CTC_wind_reformatted.yaml +++ b/test/roc_diagram/CTC_wind_reformatted.yaml @@ -1,4 +1,7 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/CTC_wind_reformatted.png' +stat_input: !ENV '${TEST_DIR}/ctc_reformatted_wind_P500.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -64,7 +67,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/CTC_wind_reformatted.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -90,7 +92,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/ctc_reformatted_wind_P500.data' sync_yaxes: 'False' title: test title title_align: 0.5 diff --git a/test/roc_diagram/PCT_ROC.yaml b/test/roc_diagram/PCT_ROC.yaml index 8d0b8b64f..ab78006ea 100644 --- a/test/roc_diagram/PCT_ROC.yaml +++ b/test/roc_diagram/PCT_ROC.yaml @@ -1,4 +1,7 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/PCT_ROC.png' +stat_input: !ENV '${TEST_DIR}/PCT_ROC.data' + add_point_thresholds: 'True' alpha: 0.05 box_avg: 'False' @@ -62,7 +65,6 @@ plot_ci: - none plot_disp: - 'True' -plot_filename: !ENV '${TEST_DIR}/PCT_ROC.png' plot_height: 8.5 plot_res: 72 plot_stat: median @@ -88,7 +90,6 @@ series_val_2: {} show_nstats: 'False' show_signif: - 'False' -stat_input: !ENV '${TEST_DIR}/PCT_ROC.data' sync_yaxes: 'False' title: test title PCT ROC data diff --git a/test/roc_diagram/test_roc_diagram.py b/test/roc_diagram/test_roc_diagram.py index a5c22d37a..b44ea918e 100644 --- a/test/roc_diagram/test_roc_diagram.py +++ b/test/roc_diagram/test_roc_diagram.py @@ -2,115 +2,50 @@ import pytest import os + import pandas as pd + from metplotpy.plots.roc_diagram import roc_diagram as roc -# from metcalcpy.compare_images import CompareImages import metcalcpy.util.ctc_statistics as ctc cwd = os.path.dirname(__file__) -# Fixture used for the image comparison -# test. -@pytest.fixture -def setup(setup_env): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - setup_env(cwd) - custom_config_filename = f"{cwd}/CTC_ROC_thresh.yaml" - # print("\n current directory: ", os.getcwd()) - # print("\ncustom config file: ", custom_config_filename, '\n') - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - roc.main(custom_config_filename) - - -@pytest.fixture -def setup_rev_points(setup_env): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - setup_env(cwd) - custom_config_filename = f"{cwd}/CTC_ROC_thresh_reverse_pts.yaml" - print("\n current directory: ", cwd) - print("\ncustom config file: ", custom_config_filename, '\n') - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - roc.main(custom_config_filename) - - -@pytest.fixture -def setup_summary(setup_env): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - setup_env(cwd) - custom_config_filename = f"{cwd}/CTC_ROC_summary.yaml" - - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - roc.main(custom_config_filename) - - -@pytest.fixture -def setup_dump_points(setup_env): - # Cleanup the plotfile and point1 output file from any previous run - cleanup() - setup_env(cwd) - # put any intermediate files in the intermed_files subdirectory of this current - # working directory. *NOTE* This MUST match with what you set up in CTC_ROC_thresh.yaml for the - # points_path configuration setting. - custom_config_filename = f"{cwd}/CTC_ROC_thresh_dump_pts.yaml" - # print("\n current directory: ", os.getcwd()) - # print("\ncustom config file: ", custom_config_filename, '\n') - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Performance Diagram based on - # the test_custom_performance_diagram.yaml custom config file. - roc.main(custom_config_filename) +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("CTC_ROC_thresh.yaml", ["CTC_ROC_thresh.png"]), + ("CTC_ROC_thresh_dump_pts.yaml", ["CTC_ROC_thresh_dump_pts.png", "intermed_files/CTC_ROC_thresh.points1"]), + ("CTC_ROC_summary.yaml", ["CTC_ROC_summary.png", "intermed_files/CTC_ROC_summary.points1"]), + ("CTC_ROC_thresh_reverse_pts.yaml", ["CTC_ROC_thresh_reverse_pts.png", "intermed_files_reverse_pts/CTC_ROC_thresh.points1"]), + ("PCT_ROC.yaml", ["PCT_ROC.png", "PCT_ROC.html"]), + ("CTC_wind_reformatted.yaml", ["CTC_wind_reformatted.png", "CTC_wind_reformatted.html"]), +]) +def test_roc_diagram(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created but the points1 file is NOT""" + remove_files(os.environ['TEST_OUTPUT'], expected_files) -def cleanup(): - # remove the performance_diagram_expected.png and plot_20200317_151252.points1 files - # from any previous runs - # The subdir_path is where the .points1 file will be stored - try: - plot_file = 'CTC_ROC_thresh.png' - html_file = 'CTC_ROC_thresh.html' - os.remove(os.path.join(cwd, html_file)) - os.remove(os.path.join(cwd, plot_file)) - except OSError: - pass + roc.main(f"{cwd}/{input_yaml}") + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") -@pytest.mark.parametrize("test_input,expected_boolean", - (["CTC_ROC_thresh_expected.png", True], ["CTC_ROC_thresh.points1", False])) -def test_files_exist(setup, test_input, expected_boolean): - ''' - Checking that the plot file is getting created but the points1 file is NOT - ''' - assert os.path.isfile(f"{cwd}/{test_input}") == expected_boolean - cleanup() + if input_yaml == "CTC_ROC_thresh_dump_pts.yaml": + check_ctc_thresh_dump_points() + if input_yaml == "CTC_ROC_summary.yaml": + check_expected_ctc_summary() + if input_yaml == "CTC_ROC_thresh_reverse_pts.yaml": + check_expected_ctc_thresh_points_reversed() -def test_expected_ctc_thresh_dump_points(setup_dump_points, remove_files): - ''' +def check_ctc_thresh_dump_points(): + """ For test data, verify that the points in the .points1 file are in the - directory we specified and the values - match what is expected (within round-off tolerance/acceptable precision). - :return: - ''' + directory we specified and the values match what is expected + (within round-off tolerance/acceptable precision). + """ expected_pody = pd.Series([1, 0.8457663, 0.7634846, 0.5093934, 0.1228585, 0]) expected_pofd = pd.Series([1, 0.0688293, 0.049127, 0.0247044, 0.0048342, 0]) - df = pd.read_csv(f"{cwd}/intermed_files/CTC_ROC_thresh.points1", sep='\t', header='infer') + df = pd.read_csv(f"{os.environ['TEST_OUTPUT']}/intermed_files/CTC_ROC_thresh.points1", sep='\t', header='infer') pofd = df.iloc[:, 0] pody = df.iloc[:, 1] @@ -123,22 +58,17 @@ def test_expected_ctc_thresh_dump_points(setup_dump_points, remove_files): for index, expected in enumerate(expected_pofd): assert ctc.round_half_up(expected) - ctc.round_half_up(pofd[index]) == 0.0 - # different cleanup than what is provided by cleanup() - # clean up the intermediate subdirectory and other files - remove_files(cwd, ['CTC_ROC_thresh_dump_pts.png', 'CTC_ROC_thresh_dump_pts.html']) - -def test_expected_ctc_summary(setup_summary, remove_files): - ''' +def check_expected_ctc_summary(): + """ For test data, verify that the points in the .points1 file are in the directory we specified and the values match what is expected (within round-off tolerance/acceptable precision). - :return: - ''' + """ expected_pofd = pd.Series([1, 0.0052708, 0, 1, 0.0084788, 0, 1, 0.0068247, 0]) expected_pody = pd.Series([1, 0.0878715, 0, 1, 0.1166785, 0, 1, 0.1018776, 0]) - df = pd.read_csv(f"{cwd}/intermed_files/CTC_ROC_summary.points1", sep='\t', header='infer') + df = pd.read_csv(f"{os.environ['TEST_OUTPUT']}/intermed_files/CTC_ROC_summary.points1", sep='\t', header='infer') pofd = df.iloc[:, 0] pody = df.iloc[:, 1] @@ -151,12 +81,8 @@ def test_expected_ctc_summary(setup_summary, remove_files): for index, expected in enumerate(expected_pofd): assert ctc.round_half_up(expected) - ctc.round_half_up(pofd[index]) == 0.0 - # different cleanup than what is provided by cleanup() - # clean up the intermediate subdirectory and other files - remove_files(cwd, ['CTC_ROC_summary.png', 'CTC_ROC_summary.html']) - -def test_expected_ctc_thresh_points_reversed(setup_rev_points, remove_files): +def check_expected_ctc_thresh_points_reversed(): ''' For test data, verify that the points in the .points1 file match what is expected (within round-off tolerance/acceptable precision) when @@ -166,7 +92,7 @@ def test_expected_ctc_thresh_points_reversed(setup_rev_points, remove_files): expected_pody = pd.Series([1, 0.8457663, 0.7634846, 0.5093934, 0.1228585, 0]) expected_pofd = pd.Series([1, 0.0688293, 0.0491275, 0.0247044, 0.0048342, 0]) - df = pd.read_csv(f"{cwd}/CTC_ROC_thresh.points1", sep='\t', header='infer') + df = pd.read_csv(f"{os.environ['TEST_OUTPUT']}/intermed_files_reverse_pts/CTC_ROC_thresh.points1", sep='\t', header='infer') pofd = df.iloc[:, 0] pody = df.iloc[:, 1] @@ -179,104 +105,44 @@ def test_expected_ctc_thresh_points_reversed(setup_rev_points, remove_files): for index, expected in enumerate(expected_pofd): assert ctc.round_half_up(expected) - ctc.round_half_up(pofd[index]) == 0.0 - # if we get here, then all elements matched in value and position - - # different cleanup than what is provided by cleanup() - remove_files(cwd, ['CTC_ROC_thresh.png', 'CTC_ROC_thresh.points1', 'CTC_ROC_thresh.html']) - -def test_ee_returns_empty_df(capsys, remove_files): - ''' +def test_ee_returns_empty_df(module_setup_env, capsys, remove_files): + """ use CTC_ROC.data with event equalization set to True. This will result in an empty data frame returned from event equalization. Check for expected output message: "INFO: No resulting data after performing event equalization of axis 1 INFO: No points to plot (most likely as a result of event equalization). " + """ + expected_files = ['CTC_ROC_ee.png', 'CTC_ROC_ee.html'] + remove_files(os.environ['TEST_OUTPUT'], expected_files) - - ''' custom_config_filename = f"{cwd}/CTC_ROC_ee.yaml" + roc.main(custom_config_filename) + + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") + captured = capsys.readouterr() expected = '\nINFO: No resulting data after performing event equalization of axis 1\n' \ 'INFO: No points to plot (most likely as a result of event equalization). \n' - # print('\n\noutput from capsys: ', captured.out) - # print('\nexpected:', expected) - assert captured.out == expected + assert expected in captured.out - # Clean up - remove_files(cwd, ['CTC_ROC_ee.png', 'CTC_ROC_ee.html']) - -@pytest.mark.skip("skip image comparison") -def test_images_match(setup, remove_files): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - - !!!!!WARNING!!!!!: When run within PyCharm IDE, the CTC_ROC_thresh.png plot - can sometimes be a different size than the expected (which was generated - using the same configuration file and data!) - ''' - plot_file = 'CTC_ROC_thresh.png' - actual_file = os.path.join(cwd, plot_file) - comparison = CompareImages(f'{cwd}/CTC_ROC_thresh.png', actual_file) - assert comparison.mssim == 1 - - # cleanup - # different cleanup than what is provided by cleanup() - remove_files(cwd, ['CTC_ROC_thresh.png', 'CTC_ROC_thresh.html']) - - -def test_pct_plot_exists(remove_files): - ''' - Verify that the ROC diagram is generated - ''' - - custom_config_filename = f"{cwd}/PCT_ROC.yaml" - output_plot = f"{cwd}/PCT_ROC.png" - - print("\n Testing for existence of PCT ROC plot...") - roc.main(custom_config_filename) - assert os.path.isfile(output_plot) - remove_files(cwd, ['PCT_ROC.png', 'PCT_ROC.html']) - - -def test_pct_no_warnings(remove_files): +def test_pct_no_warnings(module_setup_env, remove_files): ''' Verify that the ROC diagram is generated without FutureWarnings ''' + remove_files(os.environ['TEST_OUTPUT'], ['PCT_ROC.png', 'PCT_ROC.html']) + custom_config_filename = f"{cwd}/PCT_ROC.yaml" print("\n Testing for FutureWarning..") - try: roc.main(custom_config_filename) except FutureWarning: print("FutureWarning generated") # FutureWarning generated, test fails assert False - - remove_files(cwd, ['PCT_ROC.png', 'PCT_ROC.html']) - - -def test_ctc_reformatted(remove_files): - ''' - Verify that the ROC diagram is generated successfully - from reformatted CTC data. - ''' - - custom_config_filename = f"{cwd}/CTC_wind_reformatted.yaml" - output_plot = f"{cwd}/CTC_wind_reformatted.png" - - print("\n Testing for presence of the CTC_wind_reformatted.png plot...") - - roc.main(custom_config_filename) - assert os.path.isfile(output_plot) - # Checking for plot size isn't reliable - #expected_filesize = int(43239) - #plot_filesize = int(os.path.getsize(output_plot)) - #assert plot_filesize >= expected_filesize - remove_files(cwd, ['CTC_wind_reformatted.png', 'CTC_wind_reformatted.html']) diff --git a/test/roc_diagram/test_roc_diagram.yaml b/test/roc_diagram/test_roc_diagram.yaml index 4ccee027c..243393473 100644 --- a/test/roc_diagram/test_roc_diagram.yaml +++ b/test/roc_diagram/test_roc_diagram.yaml @@ -1,4 +1,8 @@ --- +plot_filename: !ENV '${TEST_OUTPUT}/roc_diagram_actual.png' + +stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' + roc_pct: False roc_ctc: True @@ -91,7 +95,5 @@ caption_align: .1 #0 # axis parallel location adjustment # Make the plot generated in METviewer interactive create_html: 'True' -# input file is relative to the roc_diagram.py module -stat_input: !ENV '${TEST_DIR}/CTC_ROC_thresh.data' -plot_filename: !ENV '${TEST_DIR}/roc_diagram_actual.png' + diff --git a/test/scatter/test_scatter.py b/test/scatter/test_scatter.py index aee0593f4..f4d963f20 100644 --- a/test/scatter/test_scatter.py +++ b/test/scatter/test_scatter.py @@ -1,29 +1,14 @@ import os import math -import shutil import pandas as pd -import yaml -from metplotpy.plots.scatter import scatter as sc + +from metplotpy.plots.scatter import scatter as scatter """ Test for the scatter plot """ -def read_config(config_filename) -> dict: - """ - Args: - @param config_filename: The name of the YAML config file - - Returns: - parms: a dictionary representation of the YAML config file - """ - with open(config_filename, 'r') as stream: - try: - parms = yaml.load(stream, Loader=yaml.FullLoader) - return parms - except yaml.YAMLError as exc: - print(exc) -def test_files_exist(): +def test_scatter(module_setup_env, remove_files): """ Generate a scatter plot from reformatted MPR Usecase data and check that the plot file is created, the dump points file is created @@ -31,19 +16,20 @@ def test_files_exist(): first row of data). Clean up the output directory when finished. """ - os.environ['METPLOTPY_BASE'] = "../../" - test_config_filename = os.path.join(os.getcwd(), "test_scatter_mpr.yaml") - sc.main(test_config_filename) + # note: scatter_log.txt does not appear to be created + expected_files = [ + "scatter_mpr_tmp_obs_lat.png", + "plot_points.txt", + ] + remove_files(os.environ['TEST_OUTPUT'], expected_files) + + scatter.main(f"{os.environ['TEST_DIR']}/test_scatter_mpr.yaml") - # Verify that the plot was generated - plot_file = "scatter_mpr_tmp_obs_lat.png" - path = os.path.join(os.getcwd(), 'output') - fullpath = os.path.join(path, plot_file) - assert os.path.isfile(fullpath) == True + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") - # Verify that the dump point file, plot_points.txt was generated and has expected points - dump_points_file = os.path.join(path, 'plot_points.txt') - assert os.path.isfile(dump_points_file) == True + # Verify that the dump point file, plot_points.txt has expected points + dump_points_file = os.path.join(os.environ['TEST_OUTPUT'], 'plot_points.txt') df = pd.read_csv(dump_points_file, sep='\t', skiprows=0) # expected x, y, and z values for the first row @@ -53,7 +39,3 @@ def test_files_exist(): assert math.isclose( df.iloc[0,0], expected_x ) assert math.isclose(df.iloc[0,1], expected_y) assert math.isclose(df.iloc[0,2], expected_z) - - # clean up files in the output directory and - # the output directory - shutil.rmtree(os.path.join(os.getcwd(), 'output')) diff --git a/test/scatter/test_scatter_mpr.yaml b/test/scatter/test_scatter_mpr.yaml index f436cbcad..18f6ad38f 100644 --- a/test/scatter/test_scatter_mpr.yaml +++ b/test/scatter/test_scatter_mpr.yaml @@ -1,8 +1,14 @@ +plot_filename: !ENV '${TEST_OUTPUT}/scatter_mpr_tmp_obs_lat.png' +points_path: !ENV '${TEST_OUTPUT}' +log_filename: !ENV '${TEST_OUTPUT}/scatter_log.txt' + +stat_input: !ENV '${TEST_DIR}/reformatted_data_for_scatter.data' + + caption_align: 0.4 caption_offset: 2.88 caption_size: 6 dump_points: True -points_path: ./output/ var_val_x_axis: fcst var_val_y_axis: obs fcst_var: TMP @@ -18,7 +24,6 @@ indy_stagger: False legend_box: o legend_ncol: 3 legend_size: 0.8 -log_filename: './output/scatter_log.txt' log_level: INFO # Supported symbols: ., o, ^, d, H, or s (^= triangle, d=diamond, H=hexagon, s=square) marker_symbol: . @@ -26,13 +31,11 @@ marker_symbol: . marker_colormap: 'nipy_spectral' marker_size: 6 plot_caption: 'optional caption' -plot_filename: ./output/scatter_mpr_tmp_obs_lat.png plot_height: 8.5 plot_width: 11.0 show_legend: True show_trendline: True start_from_zero: False -stat_input: ./reformatted_data_for_scatter.data title: "MPR usecase data for TMP, P900-750" title_align: 0.5 title_offset: -2 diff --git a/test/skew_t/test_skew_t.py b/test/skew_t/test_skew_t.py index 42e003ec1..878537067 100644 --- a/test/skew_t/test_skew_t.py +++ b/test/skew_t/test_skew_t.py @@ -1,25 +1,17 @@ -import os import pytest -import shutil + +import os import re from metplotpy.plots.skew_t import skew_t as skew_t -# from metcalcpy.compare_images import CompareImages - -cwd = os.path.dirname(__file__) - -def test_skew_t(setup_env): - setup_env(cwd) - custom_config_filename = os.path.join(cwd, "test_skew_t.yaml") - - # Invoke the command to generate a skew-T Diagram based on - # the test_skew_tm.yaml custom config file. +def test_skew_t(module_setup_env): + custom_config_filename = os.path.join(os.environ['TEST_DIR'], "test_skew_t.yaml") skew_t.main(custom_config_filename) # Verify that files for the ssh052023 data exists for the 0,6, 12,18,24, 30, 42, # 48, 54, and 60 hour data. - output_dir = os.path.join(cwd, 'output') + output_dir = os.environ['TEST_OUTPUT'] # Some of these data files have incomplete data so check for the expected hour # plots. @@ -39,12 +31,6 @@ def test_skew_t(setup_env): _check_files_not_created(files_of_interest) _check_empty_input(files_of_interest) - # Clean up all png files - shutil.rmtree(output_dir) - # If running without the ' -p no:logging' option, then uncomment to ensure that log - # files are removed. - # shutil.rmtree('./logs') - def _check_files_exist(files_of_interest): ''' @@ -80,7 +66,7 @@ def _check_files_exist(files_of_interest): if expected in subset_files_of_interest: num_found += 1 - assert len(subset_files_of_interest) == num_found + assert len(expected_base_filenames) == num_found def _check_files_not_created(files_of_interest): diff --git a/test/skew_t/test_skew_t.yaml b/test/skew_t/test_skew_t.yaml index b0d0759be..202b5a614 100644 --- a/test/skew_t/test_skew_t.yaml +++ b/test/skew_t/test_skew_t.yaml @@ -6,9 +6,9 @@ # Input and output file information input_directory: !ENV '${TEST_DIR}/data/2023/sh052023' input_file_extension: '.dat' -output_directory: !ENV '${TEST_DIR}/output' +output_directory: !ENV '${TEST_OUTPUT}' log_level: "INFO" -log_directory: !ENV '${TEST_DIR}/logs' +log_directory: !ENV '${TEST_OUTPUT}/logs' log_filename: 'tc_diags_skewt.log' # Sounding hours of interest. If all_sounding_hours is set to False, then the diff --git a/test/taylor_diagram/taylor_diagram_custom.yaml b/test/taylor_diagram/taylor_diagram_custom.yaml index 26fce36e0..6f9886f37 100644 --- a/test/taylor_diagram/taylor_diagram_custom.yaml +++ b/test/taylor_diagram/taylor_diagram_custom.yaml @@ -2,7 +2,7 @@ # custom config file to override some of the settings in the # default config file taylor_diagram_defaults.yaml stat_input: !ENV '${TEST_DIR}/plot_dlwr_sample.data' -plot_filename: !ENV '${TEST_DIR}/taylor_diagram_custom.png' +plot_filename: !ENV '${TEST_OUTPUT}/taylor_diagram_custom.png' # change the caption text plot_caption: "Custom caption" diff --git a/test/taylor_diagram/test_neg_and_pos_corr.yaml b/test/taylor_diagram/test_neg_and_pos_corr.yaml index 454f11207..b638a3d70 100644 --- a/test/taylor_diagram/test_neg_and_pos_corr.yaml +++ b/test/taylor_diagram/test_neg_and_pos_corr.yaml @@ -2,7 +2,7 @@ # custom config file to override some of the settings in the # default config file taylor_diagram_defaults.yaml stat_input: !ENV '${TEST_DIR}/plot_dlwr_sample.data' -plot_filename: !ENV '${TEST_DIR}/test_neg_and_pos_corr_plot.png' +plot_filename: !ENV '${TEST_OUTPUT}/test_neg_and_pos_corr_plot.png' taylor_show_gamma: True # Show only positive values of correlation taylor_voc: False diff --git a/test/taylor_diagram/test_pos_corr.yaml b/test/taylor_diagram/test_pos_corr.yaml index 27c995fb3..c51dd5719 100644 --- a/test/taylor_diagram/test_pos_corr.yaml +++ b/test/taylor_diagram/test_pos_corr.yaml @@ -2,7 +2,7 @@ # custom config file to override some of the settings in the # default config file taylor_diagram_defaults.yaml stat_input: !ENV '${TEST_DIR}/plot_dlwr_sample.data' -plot_filename: !ENV '${TEST_DIR}/test_pos_corr_plot.png' +plot_filename: !ENV '${TEST_OUTPUT}/test_pos_corr_plot.png' taylor_show_gamma: True # Show only positive values of correlation taylor_voc: True \ No newline at end of file diff --git a/test/taylor_diagram/test_taylor_diagram.py b/test/taylor_diagram/test_taylor_diagram.py index ab4001ac2..f345d59fd 100644 --- a/test/taylor_diagram/test_taylor_diagram.py +++ b/test/taylor_diagram/test_taylor_diagram.py @@ -1,105 +1,25 @@ -import os -from metplotpy.plots.taylor_diagram import taylor_diagram as td import pytest -#from metcalcpy.compare_images import CompareImages -cwd = os.path.dirname(__file__) +import os + +from metplotpy.plots.taylor_diagram import taylor_diagram as taylor_diagram # Converts MatplotlibDeprecation warnings (which are DeprecationWarning) into errors as # any DeprecationWarnings should be fixed as soon as possible pytestmark = pytest.mark.filterwarnings("error::DeprecationWarning") -def test_pos_corr_file_exists(setup_env): - setup_env(cwd) - - test_config_filename = f"{cwd}/test_pos_corr.yaml" - td.main(test_config_filename) - - # Verify that a plot was generated - plot_file = f"{cwd}/test_pos_corr_plot.png" - expected_file = f"{cwd}/expected_pos_corr_plot.png" - assert os.path.isfile(plot_file) - - # image comparison - #comparison = CompareImages(plot_file,expected_file) - # assert comparison.mssim >= .99 - - # Clean up - os.remove(plot_file) - - -def test_pos_corr_file_exists(setup_env): - setup_env(cwd) - test_config_filename = f"{cwd}/test_pos_corr.yaml" - td.main(test_config_filename) - - # Verify that a plot was generated - plot_file = f"{cwd}/test_pos_corr_plot.png" - assert os.path.isfile(plot_file) - - # Clean up - os.remove(plot_file) - -# Not reliable when the expected image is generated on a Mac and then this -# test is run on non-Mac machine. -# def test_pos_corr_images_match(): -# os.environ['METPLOTPY_BASE'] = "../../metplotpy" -# test_config_filename = "test_pos_corr.yaml" -# td.main(test_config_filename) -# -# # Verify that a plot was generated -# plot_file = "test_pos_corr_plot.png" -# expected_file = "expected_pos_corr_plot.png" -# path = os.getcwd() -# -# # image comparison -# comparison = CompareImages(plot_file, expected_file) -# assert comparison.mssim >= .99 -# -# # Clean up -# os.remove(os.path.join(path, plot_file)) - - -def test_neg_and_pos_corr_file_exists(setup_env): - setup_env(cwd) - test_config_filename = f"{cwd}/test_neg_and_pos_corr.yaml" - td.main(test_config_filename) - - # Verify that a plot was generated - plot_file = f"{cwd}/test_neg_and_pos_corr_plot.png" - assert os.path.isfile(plot_file) - - # Clean up - os.remove(plot_file) - - -# Not reliable when the expected image is generated on a Mac and then this -# test is run on non-Mac machine. -def test_neg_and_pos_corr_images_match(setup_env): - setup_env(cwd) - test_config_filename = f"{cwd}/test_neg_and_pos_corr.yaml" - td.main(test_config_filename) - - # Verify that a plot was generated - plot_file = f"{cwd}/test_neg_and_pos_corr_plot.png" - expected_file = f"{cwd}/expected_neg_and_pos_corr_plot.png" - - # image comparison, with allowance of .99 match instead of 100% match - #comparison = CompareImages(plot_file, expected_file) - #assert comparison.mssim >= .99 - - # Clean up - os.remove(plot_file) +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("test_pos_corr.yaml", ["test_pos_corr_plot.png"]), + ("test_neg_and_pos_corr.yaml", ["test_neg_and_pos_corr_plot.png"]), + ("taylor_diagram_custom.yaml", ["taylor_diagram_custom.png"]), +]) +def test_taylor_diagram(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plot file is getting created""" -def test_custom_plot_exists(setup_env): - setup_env(cwd) - test_config_filename = f"{cwd}/taylor_diagram_custom.yaml" - td.main(test_config_filename) + remove_files(os.environ['TEST_OUTPUT'], expected_files) - # Verify that a plot was generated - plot_file = f"{cwd}/taylor_diagram_custom.png" - assert os.path.isfile(plot_file) + taylor_diagram.main(f"{os.environ['TEST_DIR']}/{input_yaml}") - # Clean up - os.remove(plot_file) + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/tcmpr_plots/test_tcmpr_multi_plots.yaml b/test/tcmpr_plots/tcmpr_multi.yaml similarity index 82% rename from test/tcmpr_plots/test_tcmpr_multi_plots.yaml rename to test/tcmpr_plots/tcmpr_multi.yaml index f94694ec9..0fb6fa0f3 100755 --- a/test/tcmpr_plots/test_tcmpr_multi_plots.yaml +++ b/test/tcmpr_plots/tcmpr_multi.yaml @@ -1,3 +1,11 @@ +plot_dir: !ENV '${TEST_OUTPUT}/multi' +log_filename: !ENV '${TEST_OUTPUT}/multi/tcmpr_log.out' + +tcst_dir: !ENV '${TEST_DIR}/Data/' + +baseline_file: !ENV '${METPLOTPY_BASE}/metplotpy/plots/tcmpr_plots/hfip_baseline.dat' +column_info_file: !ENV '${METPLOTPY_BASE}/metplotpy/plots/tcmpr_plots/plot_tcmpr_hdr.dat' + colors: - 'blue' - 'green' @@ -102,8 +110,7 @@ series_symbols_size: - 7 show_nstats: 'True' -tcst_dir: !ENV '${TEST_DIR}/Data/' -#tcst_dir: '/path/to/tcmpr_sample_data' + tcst_files: [ ] title: '' @@ -133,13 +140,9 @@ event_equal: 'True' skill_ref: - HFSA -plot_dir: !ENV '${TEST_DIR}/output' prefix: '' subtitle: log_level: INFO -log_filename: !ENV '${TEST_DIR}/output/tcmpr_log.out' -baseline_file: './metplotpy/plots/tcmpr_plots/hfip_baseline.dat' -column_info_file: './metplotpy/plots/tcmpr_plots/plot_tcmpr_hdr.dat' hfip_bsln: 'no' diff --git a/test/tcmpr_plots/tcmpr_multi_plots.yaml b/test/tcmpr_plots/tcmpr_multi_plots.yaml deleted file mode 100755 index f444bcc18..000000000 --- a/test/tcmpr_plots/tcmpr_multi_plots.yaml +++ /dev/null @@ -1,148 +0,0 @@ -colors: - - 'blue' - - 'green' - -fixed_vars_vals_input: - BASIN: - - AL - LEVEL: - - SS - - SD - - TS - - TD - - HU - - -indy_vals: - - 0 - - 6 - - 12 - - 18 - - 24 - - 30 - - 36 - - 42 - - 48 - - 54 - - 60 - - 66 - - 72 - - 78 - - 84 - - 90 - - 96 - - 102 - - 108 - - 114 - - 120 - - 126 -indy_label: - - '00' - - '06' - - '12' - - '18' - - '24' - - '30' - - '36' - - '42' - - '48' - - '54' - - '60' - - '66' - - '72' - - '78' - - '84' - - '90' - - '96' - - '102' - - '108' - - '114' - - '120' - - '126' - - -list_stat_1: - - "ABS(AMAX_WIND-BMAX_WIND)" - - "TK_ERR" - - -plot_disp: - - 'True' - - 'True' - - -series_order: - - 1 - - 2 - - -series_val_1: - AMODEL: - - H221 - - M221 - -series_ci: - - 'True' - - 'True' - -series_line_width: - - 1 - - 1 - -series_line_style: - - '-' - - '-' - -series_symbols: - - 'circle-open' - - 'circle-open' - -series_symbols_size: - - 7 - - 7 - -show_nstats: 'True' -tcst_dir: '/path/to/tcmpr_sample_data' -tcst_files: [ ] -title: '' - -mar: - l: 0 #left margin - r: 0 #right margin - b: 90 #bottom margin - t: 100 #top margin - -title_offset: -2.03 -yaxis_1: '' - -plot_type_list: - - 'boxplot' - - 'skill_mn' - - 'skill_md' - - 'relperf' - - 'mean' - - 'median' - - 'rank' - - -rp_diff: -# - '>=1' - - '>=100' -event_equal: 'True' -skill_ref: - - HFSA - -plot_dir: '/path/to/output' -prefix: '' -subtitle: -log_level: INFO -log_filename: '/path/to/log/output/tcmpr_log.out' -baseline_file: 'path/to/metplotpy/plots/tcmpr_plots/hfip_baseline.dat' -column_info_file: 'path/to/metplotpy/plots/tcmpr_plots/plot_tcmpr_hdr.dat' -hfip_bsln: 'no' - - - - - - diff --git a/test/tcmpr_plots/tcmpr_point_tcdiag.yaml b/test/tcmpr_plots/tcmpr_point_tcdiag.yaml index 636e8d636..686e9de3b 100755 --- a/test/tcmpr_plots/tcmpr_point_tcdiag.yaml +++ b/test/tcmpr_plots/tcmpr_point_tcdiag.yaml @@ -1,3 +1,11 @@ +plot_dir: !ENV '${TEST_OUTPUT}/point_tcdiag' +log_filename: !ENV '${TEST_OUTPUT}/point_tcdiag/tcmpr.log' + +baseline_file: !ENV '${METPLOTPY_BASE}/metplotpy/plots/tcmpr_plots/hfip_baseline.dat' +column_info_file: !ENV '${METPLOTPY_BASE}/metplotpy/plots/tcmpr_plots/plot_tcmpr_hdr.dat' + +tcst_dir: !ENV '${TEST_DIR}/Data/TCDiag/' + colors: # - 'green' - 'blue' @@ -72,9 +80,6 @@ series_symbols_size: - 7 - 7 - - -tcst_dir: './Data/TCDiag/' tcst_files: [ ] title: '' title_size: 1. @@ -88,11 +93,8 @@ plot_type_list: event_equal: 'False' - -plot_dir: './output/' prefix: '' - indy_vals: - 0 - 6 @@ -159,4 +161,3 @@ line_type: '-' connect_points: True log_level: INFO -log_filename: './output/tcmpr.log' \ No newline at end of file diff --git a/test/tcmpr_plots/test_tcmpr_plots.py b/test/tcmpr_plots/test_tcmpr_plots.py index 56f7764af..0165b3d24 100644 --- a/test/tcmpr_plots/test_tcmpr_plots.py +++ b/test/tcmpr_plots/test_tcmpr_plots.py @@ -1,85 +1,38 @@ import pytest import os -import metplotpy.plots.tcmpr_plots.tcmpr as t +import metplotpy.plots.tcmpr_plots.tcmpr as tcmpr cwd = os.path.dirname(__file__) - -@pytest.fixture -def setup(setup_env): - setup_env(cwd) - custom_config_filename = f"{cwd}/test_tcmpr_multi_plots.yaml" - - # Invoke the command to generate a line plot based on - # the custom config file - t.main(custom_config_filename) - - -def test_plots_created(setup): - # Check for presence of fourteen plots (seven plot types, one each for the - # ABS(X-Y) and TK_ERR columns. - expected_num_plots = 14 - output_dir = os.path.join(cwd, 'output') - only_files = os.listdir(output_dir) - assert len(only_files) == expected_num_plots - - size_abs_boxplot = 221448 - size_abs_mean = 173448 - size_abs_median = 184775 - size_abs_rank = 255637 - size_abs_relperf = 117889 - size_abs_skill_md = 198979 - size_abs_skill_mn = 185594 - size_tk_boxplot = 192259 - size_tk_mean = 146980 - size_tk_median = 152591 - size_tk_rank = 189702 - size_tk_relperf = 157972 - size_tk_skill_md = 171571 - size_tk_skill_mn = 159396 - expected_sizes = {'ABS(AMAX_WIND-BMAX_WIND)_boxplot.png':size_abs_boxplot, - 'ABS(AMAX_WIND-BMAX_WIND)_mean.png':size_abs_mean, - 'ABS(AMAX_WIND-BMAX_WIND)_median.png':size_abs_median, - 'ABS(AMAX_WIND-BMAX_WIND)_relperf.png':size_abs_relperf, - 'ABS(AMAX_WIND-BMAX_WIND)_skill_md.png':size_abs_skill_md, - 'ABS(AMAX_WIND-BMAX_WIND)_skill_mn.png':size_abs_skill_mn, - 'TK_ERR_boxplot.png':size_tk_boxplot, 'TK_ERR_mean.png':size_tk_mean, - 'TK_ERR_median.png':size_tk_median, - 'TK_ERR_relperf.png':size_tk_relperf, 'TK_ERR_skill_md.png':size_tk_skill_md, - 'TK_ERR_skill_mn.png':size_tk_skill_mn - } - - # Check that filenames are what we expect - expected_names_list = ['ABS(AMAX_WIND-BMAX_WIND)_boxplot.png', 'ABS(AMAX_WIND-BMAX_WIND)_mean.png', - 'ABS(AMAX_WIND-BMAX_WIND)_median.png', - 'ABS(AMAX_WIND-BMAX_WIND)_rank.png', 'ABS(AMAX_WIND-BMAX_WIND)_relperf.png', - 'ABS(AMAX_WIND-BMAX_WIND)_skill_md.png', - 'ABS(AMAX_WIND-BMAX_WIND)_skill_mn.png', - 'TK_ERR_boxplot.png', 'TK_ERR_mean.png', 'TK_ERR_median.png', 'TK_ERR_rank.png', - 'TK_ERR_relperf.png', 'TK_ERR_skill_md.png', 'TK_ERR_skill_mn.png'] - - for cur_file in only_files: - assert cur_file in expected_names_list - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # ONLY RUN THESE TESTS ON A LOCAL MACHINE, they are not reliable when run in Github Actions container - #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # Check that file sizes (in bytes) are consistent (cannot check rank files, the confidence - # intervals are generated using random seed-they will not be identical from one run to another - # for cur_file in only_files: - # match = re.match(r'.+_(mean).png', cur_file) - # if match: - # cur_file_size = int(os.path.getsize(os.path.join(output_dir, cur_file))) - # expected_size = int(expected_sizes[cur_file]) - # assert cur_file_size >= expected_size - # - - # Clean up - try: - for cur_file in only_files: - os.remove(os.path.join(output_dir, cur_file)) - os.rmdir(output_dir) - except FileNotFoundError: - # If files already cleaned up, then ignore error - pass +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("tcmpr_multi.yaml", [ + 'multi/ABS(AMAX_WIND-BMAX_WIND)_boxplot.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_mean.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_median.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_rank.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_relperf.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_skill_md.png', + 'multi/ABS(AMAX_WIND-BMAX_WIND)_skill_mn.png', + 'multi/TK_ERR_boxplot.png', + 'multi/TK_ERR_mean.png', + 'multi/TK_ERR_median.png', + 'multi/TK_ERR_rank.png', # note the rank file will differ each run due to the random seed + 'multi/TK_ERR_relperf.png', + 'multi/TK_ERR_skill_md.png', + 'multi/TK_ERR_skill_mn.png', + ]), + ("tcmpr_point_tcdiag.yaml", [ + "point_tcdiag/AMAX_WIND-BMAX_WIND_pointplot.png", + "point_tcdiag/SHEAR_MAGNITUDE_pointplot.png", + ]), +]) +def test_tcmpr_plots(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the tcmpr plots are getting created""" + + remove_files(os.environ['TEST_OUTPUT'], expected_files) + + tcmpr.main(f"{os.environ['TEST_DIR']}/{input_yaml}") + + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/wind_rose/minimal_wind_rose.yaml b/test/wind_rose/minimal_wind_rose.yaml index 76db46677..d8456d739 100644 --- a/test/wind_rose/minimal_wind_rose.yaml +++ b/test/wind_rose/minimal_wind_rose.yaml @@ -2,10 +2,6 @@ # **NOTE**: update the stat_input and plot_filename settings with the full path to your # input file and output file, respectively. stat_input: !ENV '${TEST_DIR}/point_stat_mpr.txt' -plot_filename: !ENV '${TEST_DIR}/wind_rose_default.png' +plot_filename: !ENV '${TEST_OUTPUT}/wind_rose_minimal.png' -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -#points_path: '/dir_to_save_points1_file' \ No newline at end of file +points_path: !ENV '${TEST_OUTPUT}/minimal' \ No newline at end of file diff --git a/test/wind_rose/test_wind_rose.py b/test/wind_rose/test_wind_rose.py index 04ac62846..e6a7628a2 100644 --- a/test/wind_rose/test_wind_rose.py +++ b/test/wind_rose/test_wind_rose.py @@ -1,102 +1,29 @@ import pytest import os from metplotpy.plots.wind_rose import wind_rose -#from metcalcpy.compare_images import CompareImages cwd = os.path.dirname(__file__) -CLEANUP_FILES = ['wind_rose_custom.png', 'point_stat_mpr.points1'] -@pytest.fixture -def setup(remove_files, setup_env): - # Cleanup the plotfile and point1 output file from any previous run - remove_files(cwd, CLEANUP_FILES) - setup_env(cwd) - custom_config_filename = f"{cwd}/wind_rose_custom.yaml" - - # Invoke the command to generate a Wind rose Diagram based on - # a custom config file. - wind_rose.main(custom_config_filename) - - -def cleanup(): - # remove the .png and .points files - # from any previous runs - try: - plot_file = 'wind_rose_custom.png' - points_file_1 = 'point_stat_mpr.points1' - os.remove(os.path.join(cwd, plot_file)) - os.remove(os.path.join(cwd, points_file_1)) - except OSError: - pass - - -@pytest.mark.parametrize("test_input,expected", - (["wind_rose_expected.png", True], ["wind_rose_expected.points", True])) -def test_files_exist(setup, test_input, expected, remove_files): - ''' - Checking that the plot and data files are getting created - ''' - assert os.path.isfile(f"{cwd}/{test_input}") == expected - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.parametrize("test_input,expected", - (["intermed_files/wind_rose_custom_points.png", True], ["intermed_files/point_stat_mpr.points1", True])) -def test_points1_files_exist(setup_env, test_input, expected, remove_files): - ''' - Checking that the plot file and points1 file are getting created where expected - plot and point file are being saved in the intermed_files subdir - ''' - setup_env(cwd) - custom_config_filename = f"{cwd}/wind_rose_custom_points.yaml" - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Wind Rose Diagram based on - # a custom config file. - wind_rose.main(custom_config_filename) - - assert os.path.isfile(f"{cwd}/{test_input}") == expected - - # remove the plot and points1 files that were created - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.parametrize("test_input,expected", - (["intermed_files/wind_rose_points2.png", True], - ["intermed_files/point_stat_mpr.points1", True])) -def test_points1_files_exist(setup_env, test_input, expected, remove_files): - ''' - Checking that the plot file and points1 file are getting created where expected - plot and point file are being saved in the intermed_files subdir. Verify that when - no stat_file is specified, the point_stat_mpr.txt in the test dir is being used. - ''' - setup_env(cwd) - custom_config_filename = f"{cwd}/wind_rose_custom2_points.yaml" - try: - os.mkdir(os.path.join(cwd, 'intermed_files')) - except FileExistsError: - pass - - # Invoke the command to generate a Wind Rose Diagram based on - # a custom config file. - wind_rose.main(custom_config_filename) - - assert os.path.isfile(f"{cwd}/{test_input}") == expected - - # remove the plot and points1 files and intermed_files that were created - remove_files(cwd, CLEANUP_FILES) - - -@pytest.mark.skip("unreliable sometimes fails due to differences in machines.") -def test_images_match(setup, remove_files): - ''' - Compare an expected plot with the - newly created plot to verify that the plot hasn't - changed in appearance. - ''' - comparison = CompareImages(f'{cwd}/wind_rose_expected.png', f'{cwd}/wind_rose_custom.png') - assert comparison.mssim == 1 - remove_files(cwd, CLEANUP_FILES) +@pytest.mark.parametrize("input_yaml,expected_files", [ + ("wind_rose_custom.yaml", [ + "wind_rose_custom.png", + "custom/point_stat_mpr.points1", + ]), + ("wind_rose_custom_points.yaml", [ + "wind_rose_custom_points.png", + "custom_points/point_stat_mpr.points1", + ]), + ("minimal_wind_rose.yaml", [ + "wind_rose_minimal.png", + "minimal/point_stat_mpr.points1", + ]), +]) +def test_wind_rose(module_setup_env, remove_files, input_yaml, expected_files): + """Checking that the plots are being created""" + + remove_files(os.environ['TEST_OUTPUT'], expected_files) + + wind_rose.main(f"{cwd}/{input_yaml}") + + for expected_file in expected_files: + assert os.path.isfile(f"{os.environ['TEST_OUTPUT']}/{expected_file}") diff --git a/test/wind_rose/wind_rose_custom.yaml b/test/wind_rose/wind_rose_custom.yaml index 605a8792e..c046047ad 100644 --- a/test/wind_rose/wind_rose_custom.yaml +++ b/test/wind_rose/wind_rose_custom.yaml @@ -1,3 +1,10 @@ +plot_filename: !ENV '${TEST_OUTPUT}/wind_rose_custom.png' + +dump_points: True +points_path: !ENV '${TEST_OUTPUT}/custom' + +stat_input: !ENV '${TEST_DIR}/point_stat_mpr.txt' + type: FCST title: Wind Rose wind_rose_breaks: @@ -30,19 +37,6 @@ angularaxis_ticktext: - 'S' - 'W' -# !!!!!!!! IMPORTANT !!!!!! -# Uncomment the stat_input setting and specify the full path to the -# point_stat_mpr.txt file -stat_input: !ENV '${TEST_DIR}/point_stat_mpr.txt' - -plot_filename: !ENV '${TEST_DIR}/wind_rose_custom.png' -dump_points: True - -# Optional, uncomment and set to directory to store the .points1 file -# that is used by METviewer (created when dump_points_1 is set to True) -# if dump_points_1 is True and this is uncommented, the points1 file -# will be saved in the default location (i.e. where the input data file is stored). -# points_path: '/dir_to_save_points1_file' show_in_browser: False # To save your log output to a file, specify a path and filename and uncomment the line below. Make sure you have diff --git a/test/wind_rose/wind_rose_custom2_points.yaml b/test/wind_rose/wind_rose_custom2_points.yaml deleted file mode 100644 index 544405ff0..000000000 --- a/test/wind_rose/wind_rose_custom2_points.yaml +++ /dev/null @@ -1,36 +0,0 @@ -type: FCST -title: Wind Rose -wind_rose_breaks: - - 0.0 - - 1.0 - - 2.0 - - 3.0 - - 4.0 - - 5.0 - - 6.0 -wind_rose_angle: 30 -wind_rose_marker_colors: - - 'rgb(95,78,160)' - - 'rgb(78,176,170)' - - 'rgb(192,228,160)' - - 'rgb(255,255,194)' - - 'rgb(253,193,115)' - - 'rgb(236,94,74)' - - 'rgb(159,11,68)' -create_figure: True -show_legend: True -angularaxis_tickvals: - - 0 - - 90 - - 180 - - 270 -angularaxis_ticktext: - - 'N' - - 'E' - - 'S' - - 'W' -plot_filename: !ENV '${TEST_DIR}/intermed_files/wind_rose_points2.png' -dump_points: True -points_path: !ENV '${TEST_DIR}/intermed_files' -# No stat_input, force creation of 'default' points file name -show_in_browser: False \ No newline at end of file diff --git a/test/wind_rose/wind_rose_custom_points.yaml b/test/wind_rose/wind_rose_custom_points.yaml index 56c1347c3..7f54d6746 100644 --- a/test/wind_rose/wind_rose_custom_points.yaml +++ b/test/wind_rose/wind_rose_custom_points.yaml @@ -1,3 +1,12 @@ +plot_filename: !ENV '${TEST_OUTPUT}/wind_rose_custom_points.png' + +dump_points: True +points_path: !ENV '${TEST_OUTPUT}/custom_points' + +# No stat_input, force creation of 'default' points file name + +show_in_browser: False + type: FCST title: Wind Rose wind_rose_breaks: @@ -29,8 +38,3 @@ angularaxis_ticktext: - 'E' - 'S' - 'W' -plot_filename: !ENV '${TEST_DIR}/intermed_files/wind_rose_custom_points.png' -dump_points: True -points_path: !ENV '${TEST_DIR}/intermed_files' -stat_input: !ENV '${TEST_DIR}/point_stat_mpr.txt' -show_in_browser: False \ No newline at end of file