From de3f2832e21f91751f23e7384b8510993278f600 Mon Sep 17 00:00:00 2001 From: James Frost Date: Tue, 20 Aug 2024 10:56:39 +0100 Subject: [PATCH] Set plotting resolution from workflow config --- .../run_cset_recipe/bin/run-cset-recipe.py | 2 ++ src/CSET/__init__.py | 10 ++++++- src/CSET/operators/__init__.py | 29 ++++++++++++++++--- src/CSET/operators/plot.py | 24 ++++++++++----- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/cset-workflow/app/run_cset_recipe/bin/run-cset-recipe.py b/cset-workflow/app/run_cset_recipe/bin/run-cset-recipe.py index 525727788..4091fb3f5 100755 --- a/cset-workflow/app/run_cset_recipe/bin/run-cset-recipe.py +++ b/cset-workflow/app/run_cset_recipe/bin/run-cset-recipe.py @@ -159,6 +159,7 @@ def parallel(): f"--input-dir={data_directory()}", f"--output-dir={output_directory()}", f"--style-file={os.getenv('COLORBAR_FILE', '')}", + f"--plot-resolution={os.getenv('PLOT_RESOLUTION', '')}", "--parallel-only", ), check=True, @@ -188,6 +189,7 @@ def collate(): f"--recipe={recipe_file()}", f"--output-dir={output_directory()}", f"--style-file={os.getenv('COLORBAR_FILE', '')}", + f"--plot-resolution={os.getenv('PLOT_RESOLUTION', '')}", "--collate-only", ), check=True, diff --git a/src/CSET/__init__.py b/src/CSET/__init__.py index 90e256ae2..92c75fc19 100644 --- a/src/CSET/__init__.py +++ b/src/CSET/__init__.py @@ -76,6 +76,9 @@ def main(): parser_bake.add_argument( "-s", "--style-file", type=Path, help="colour bar definition to use" ) + parser_bake.add_argument( + "--plot-resolution", type=int, help="plotting resolution in dpi" + ) parser_bake.set_defaults(func=_bake_command) parser_graph = subparsers.add_parser("graph", help="visualise a recipe file") @@ -207,10 +210,15 @@ def _bake_command(args, unparsed_args): args.output_dir, recipe_variables, args.style_file, + args.plot_resolution, ) if not args.parallel_only: execute_recipe_collate( - args.recipe, args.output_dir, recipe_variables, args.style_file + args.recipe, + args.output_dir, + recipe_variables, + args.style_file, + args.plot_resolution, ) diff --git a/src/CSET/operators/__init__.py b/src/CSET/operators/__init__.py index cd473f176..da8c0347a 100644 --- a/src/CSET/operators/__init__.py +++ b/src/CSET/operators/__init__.py @@ -142,7 +142,14 @@ def _step_parser(step: dict, step_input: any) -> str: return operator(**kwargs) -def _run_steps(recipe, steps, step_input, output_directory: Path, style_file: Path): +def _run_steps( + recipe, + steps, + step_input, + output_directory: Path, + style_file: Path, + plot_resolution: int, +) -> None: """Execute the steps in a recipe.""" original_working_directory = Path.cwd() os.chdir(output_directory) @@ -159,6 +166,8 @@ def _run_steps(recipe, steps, step_input, output_directory: Path, style_file: Pa # Create metadata file used by some steps. if style_file: recipe["style_file_path"] = str(style_file) + if plot_resolution: + recipe["plot_resolution"] = plot_resolution _write_metadata(recipe) # Execute the recipe. for step in steps: @@ -174,6 +183,7 @@ def execute_recipe_parallel( output_directory: Path, recipe_variables: dict = None, style_file: Path = None, + plot_resolution: int = None, ) -> None: """Parse and executes the parallel steps from a recipe file. @@ -188,8 +198,12 @@ def execute_recipe_parallel( input. output_directory: Path Pathlike indicating desired location of output. - recipe_variables: dict + recipe_variables: dict, optional Dictionary of variables for the recipe. + style_file: Path, optional + Path to a style file. + plot_resolution: int, optional + Resolution of plots in dpi. Raises ------ @@ -213,7 +227,7 @@ def execute_recipe_parallel( logging.error("Output directory is a file. %s", output_directory) raise err steps = recipe["parallel"] - _run_steps(recipe, steps, step_input, output_directory, style_file) + _run_steps(recipe, steps, step_input, output_directory, style_file, plot_resolution) def execute_recipe_collate( @@ -221,6 +235,7 @@ def execute_recipe_collate( output_directory: Path, recipe_variables: dict = None, style_file: Path = None, + plot_resolution: int = None, ) -> None: """Parse and execute the collation steps from a recipe file. @@ -234,6 +249,10 @@ def execute_recipe_collate( Pathlike indicating desired location of output. Must already exist. recipe_variables: dict Dictionary of variables for the recipe. + style_file: Path, optional + Path to a style file. + plot_resolution: int, optional + Resolution of plots in dpi. Raises ------ @@ -249,4 +268,6 @@ def execute_recipe_collate( recipe = parse_recipe(recipe_yaml, recipe_variables) # If collate doesn't exist treat it as having no steps. steps = recipe.get("collate", []) - _run_steps(recipe, steps, output_directory, output_directory, style_file) + _run_steps( + recipe, steps, output_directory, output_directory, style_file, plot_resolution + ) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index d061fcf9d..6d4cdf4e7 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -35,6 +35,14 @@ from CSET._common import get_recipe_metadata, render_file, slugify from CSET.operators._utils import get_cube_yxcoordname, is_transect +##################### +# Runtime constants # +##################### + +# Resolution of rasterised plots in pixels per inch. +PLOT_RESOLUTION = get_recipe_metadata().get("plot_resolution", 100) + + ############################ # Private helper functions # ############################ @@ -248,7 +256,7 @@ def _plot_and_save_contour_plot( cbar.set_label(label=f"{cube.name()} ({cube.units})", size=20) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved contour plot to %s", filename) plt.close(fig) @@ -311,7 +319,7 @@ def _plot_and_save_postage_stamp_contour_plot( # Overall figure title. fig.suptitle(title) - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved contour postage stamp plot to %s", filename) plt.close(fig) @@ -347,7 +355,7 @@ def _plot_and_save_line_series( ax.autoscale() # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved line plot to %s", filename) plt.close(fig) @@ -436,7 +444,7 @@ def _plot_and_save_vertical_line_series( ax.autoscale() # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved line plot to %s", filename) plt.close(fig) @@ -492,7 +500,7 @@ def _plot_and_save_scatter_plot( ax.autoscale() # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved scatter plot to %s", filename) plt.close(fig) @@ -551,7 +559,7 @@ def _plot_and_save_histogram_series( ) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved line plot to %s", filename) plt.close(fig) @@ -620,7 +628,7 @@ def _plot_and_save_postage_stamp_histogram_series( # Overall figure title. fig.suptitle(title) - fig.savefig(filename, bbox_inches="tight", dpi=100) + fig.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) logging.info("Saved histogram postage stamp plot to %s", filename) plt.close(fig) @@ -658,7 +666,7 @@ def _plot_and_save_postage_stamps_in_single_plot_histogram_series( ax.legend() # Save the figure to a file - plt.savefig(filename, bbox_inches="tight", dpi=100) + plt.savefig(filename, bbox_inches="tight", dpi=PLOT_RESOLUTION) # Close the figure plt.close(fig)