From d41a72d9af268288780bd6bfd4f705129978989f Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Wed, 19 Mar 2025 17:31:03 +0000 Subject: [PATCH 01/13] introduce callback function to convert precipitation units to mm hr-1. Colourbar scale changed accordingly for surface_microphysical_rainfall_rate. Still requires change to colourbar --- src/CSET/operators/_colorbar_definition.json | 2 +- src/CSET/operators/read.py | 31 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/CSET/operators/_colorbar_definition.json b/src/CSET/operators/_colorbar_definition.json index 2cb58eb59..372caa636 100644 --- a/src/CSET/operators/_colorbar_definition.json +++ b/src/CSET/operators/_colorbar_definition.json @@ -392,7 +392,7 @@ }, "surface_microphysical_rainfall_rate": { "cmap": "cividis", - "max": 0.001, + "max": 256.0, "min": 0 }, "surface_microphysical_rainfall_rate_difference": { diff --git a/src/CSET/operators/read.py b/src/CSET/operators/read.py index 896a53929..c4ab0a7a4 100644 --- a/src/CSET/operators/read.py +++ b/src/CSET/operators/read.py @@ -240,6 +240,7 @@ def callback(cube: iris.cube.Cube, field, filename: str): _fix_lfric_longnames(cube) _fix_um_lightning(cube) _lfric_time_callback(cube) + _convert_precipitation_units(cube) return callback @@ -665,3 +666,33 @@ def _check_input_files(input_paths: list[str], filename_pattern: str) -> list[Pa if len(files) == 0: raise FileNotFoundError(f"No files found for {input_paths}") return files + + +def _convert_precipitation_units(cube: iris.cube.Cube): + """To convert the unit of precipitation from kg m-2 s-1 to mm hr-1. + + Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. + """ + try: + # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": + if cube.long_name == "surface_microphysical_rainfall_rate": + if cube.units == "kg m-2 s-1": + logging.info( + "Converting precipitation units from kg m-2 s-1 to mm hr-1" + ) + # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water + cube.data = cube.data * 3600.0 + + # update the units + cube.units = "mm hr-1" + else: + logging.warning( + "Precipitation units are not in 'kg m-2 s-1', skipping conversion" + ) + except iris.exceptions.CoordinateNotFoundError: + logging.warning( + "Precipitation cube does not contain the required coordinate, skipping conversion" + ) + except KeyError: + logging.warning("STASH attribute not found in cube, cannot convert units") + return cube From 16ea41545380e6c8ba56b09dd948b47ca961832b Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Thu, 20 Mar 2025 14:55:41 +0000 Subject: [PATCH 02/13] moved callback function for converting precipitation units from read operator into plot operator --- src/CSET/operators/plot.py | 36 ++++++++++++++++++++++++++++++++++++ src/CSET/operators/read.py | 31 ------------------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 848eef666..0b5f1b9c4 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -975,6 +975,9 @@ def spatial_contour_plot( TypeError If the cube isn't a single cube. """ + # Convert precipitation units if necessary + _convert_precipitation_units_callback(cube) + _spatial_plot("contourf", cube, filename, sequence_coordinate, stamp_coordinate) return cube @@ -1024,6 +1027,9 @@ def spatial_pcolormesh_plot( TypeError If the cube isn't a single cube. """ + # Convert precipitation units if necessary + _convert_precipitation_units_callback(cube) + _spatial_plot("pcolormesh", cube, filename, sequence_coordinate, stamp_coordinate) return cube @@ -1479,3 +1485,33 @@ def plot_histogram_series( _make_plot_html_page(complete_plot_index) return cubes + + +def _convert_precipitation_units_callback(cube: iris.cube.Cube): + """To convert the unit of precipitation from kg m-2 s-1 to mm hr-1. + + Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. + """ + try: + # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": + if cube.long_name == "surface_microphysical_rainfall_rate": + if cube.units == "kg m-2 s-1": + logging.info( + "Converting precipitation units from kg m-2 s-1 to mm hr-1" + ) + # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water + cube.data = cube.data * 3600.0 + + # update the units + cube.units = "mm hr-1" + else: + logging.warning( + "Precipitation units are not in 'kg m-2 s-1', skipping conversion" + ) + except iris.exceptions.CoordinateNotFoundError: + logging.warning( + "Precipitation cube does not contain the required coordinate, skipping conversion" + ) + except KeyError: + logging.warning("STASH attribute not found in cube, cannot convert units") + return cube diff --git a/src/CSET/operators/read.py b/src/CSET/operators/read.py index c4ab0a7a4..896a53929 100644 --- a/src/CSET/operators/read.py +++ b/src/CSET/operators/read.py @@ -240,7 +240,6 @@ def callback(cube: iris.cube.Cube, field, filename: str): _fix_lfric_longnames(cube) _fix_um_lightning(cube) _lfric_time_callback(cube) - _convert_precipitation_units(cube) return callback @@ -666,33 +665,3 @@ def _check_input_files(input_paths: list[str], filename_pattern: str) -> list[Pa if len(files) == 0: raise FileNotFoundError(f"No files found for {input_paths}") return files - - -def _convert_precipitation_units(cube: iris.cube.Cube): - """To convert the unit of precipitation from kg m-2 s-1 to mm hr-1. - - Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. - """ - try: - # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": - if cube.long_name == "surface_microphysical_rainfall_rate": - if cube.units == "kg m-2 s-1": - logging.info( - "Converting precipitation units from kg m-2 s-1 to mm hr-1" - ) - # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water - cube.data = cube.data * 3600.0 - - # update the units - cube.units = "mm hr-1" - else: - logging.warning( - "Precipitation units are not in 'kg m-2 s-1', skipping conversion" - ) - except iris.exceptions.CoordinateNotFoundError: - logging.warning( - "Precipitation cube does not contain the required coordinate, skipping conversion" - ) - except KeyError: - logging.warning("STASH attribute not found in cube, cannot convert units") - return cube From 82b44c99a40d77acd09d070eee5ccc3b107826ed Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Thu, 20 Mar 2025 17:30:57 +0000 Subject: [PATCH 03/13] remove vmin and vmax from call if norm is already supplied. Not sure this is correct. --- src/CSET/operators/_colorbar_definition.json | 14 ++++++++++++-- src/CSET/operators/plot.py | 13 +++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/CSET/operators/_colorbar_definition.json b/src/CSET/operators/_colorbar_definition.json index 372caa636..c06f7ac39 100644 --- a/src/CSET/operators/_colorbar_definition.json +++ b/src/CSET/operators/_colorbar_definition.json @@ -392,8 +392,18 @@ }, "surface_microphysical_rainfall_rate": { "cmap": "cividis", - "max": 256.0, - "min": 0 + "levels": [ + 0.125, + 0.25, + 0.5, + 1, + 2, + 4, + 8, + 16, + 32, + 64 + ] }, "surface_microphysical_rainfall_rate_difference": { "cmap": "bwr", diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 0b5f1b9c4..b25709c76 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -245,6 +245,7 @@ def _colorbar_map_levels(cube: iris.cube.Cube): # smooth range. norm = mpl.colors.BoundaryNorm(levels, ncolors=cmap.N) logging.debug("Using levels for %s colorbar.", varname) + logging.info("Using levels: %s", levels) except KeyError: # Get the range for this variable. vmin, vmax = var_colorbar["min"], var_colorbar["max"] @@ -299,13 +300,13 @@ def _plot_and_save_spatial_plot( # Filled contour plot of the field. plot = iplt.contourf(cube, cmap=cmap, levels=levels, norm=norm) elif method == "pcolormesh": - try: - vmin = min(levels) - vmax = max(levels) - except TypeError: - vmin, vmax = None, None + # try: + # vmin = min(levels) + # vmax = max(levels) + # except TypeError: + # vmin, vmax = None, None # pcolormesh plot of the field. - plot = iplt.pcolormesh(cube, cmap=cmap, norm=norm, vmin=vmin, vmax=vmax) + plot = iplt.pcolormesh(cube, cmap=cmap, norm=norm) else: raise ValueError(f"Unknown plotting method: {method}") From 88033c245229d032fed973e85b1e1d743d2dfd95 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Tue, 25 Mar 2025 11:43:09 +0000 Subject: [PATCH 04/13] moving ppn unit conversion into _plot_spatial --- src/CSET/operators/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index b25709c76..7e5570fc6 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -889,6 +889,9 @@ def _spatial_plot( # Ensure we've got a single cube. cube = _check_single_cube(cube) + # Convert precipitation units if necessary + _convert_precipitation_units_callback(cube) + # Make postage stamp plots if stamp_coordinate exists and has more than a # single point. plotting_func = _plot_and_save_spatial_plot @@ -976,9 +979,6 @@ def spatial_contour_plot( TypeError If the cube isn't a single cube. """ - # Convert precipitation units if necessary - _convert_precipitation_units_callback(cube) - _spatial_plot("contourf", cube, filename, sequence_coordinate, stamp_coordinate) return cube From 491ea35778bd80c29576987f9beb7a422205b1c1 Mon Sep 17 00:00:00 2001 From: Sylvia Bohnenstengel <62748926+Sylviabohnenstengel@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:54:45 +0000 Subject: [PATCH 05/13] Update src/CSET/operators/plot.py Co-authored-by: James Frost --- src/CSET/operators/plot.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 7e5570fc6..6ab60dcfb 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -1509,10 +1509,4 @@ def _convert_precipitation_units_callback(cube: iris.cube.Cube): logging.warning( "Precipitation units are not in 'kg m-2 s-1', skipping conversion" ) - except iris.exceptions.CoordinateNotFoundError: - logging.warning( - "Precipitation cube does not contain the required coordinate, skipping conversion" - ) - except KeyError: - logging.warning("STASH attribute not found in cube, cannot convert units") return cube From b5c15fa67a8b7533e0a5687f26804f3ae99e8d71 Mon Sep 17 00:00:00 2001 From: Sylvia Bohnenstengel <62748926+Sylviabohnenstengel@users.noreply.github.com> Date: Tue, 25 Mar 2025 11:55:22 +0000 Subject: [PATCH 06/13] Update src/CSET/operators/plot.py Co-authored-by: James Frost --- src/CSET/operators/plot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 6ab60dcfb..b9cfe15e6 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -1493,7 +1493,6 @@ def _convert_precipitation_units_callback(cube: iris.cube.Cube): Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. """ - try: # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": if cube.long_name == "surface_microphysical_rainfall_rate": if cube.units == "kg m-2 s-1": From b882497b4eb4c9f0bcadcbb712d094c685f95598 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Tue, 25 Mar 2025 12:10:39 +0000 Subject: [PATCH 07/13] fix indentation issue --- src/CSET/operators/plot.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index b9cfe15e6..989e5c4a6 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -1493,19 +1493,17 @@ def _convert_precipitation_units_callback(cube: iris.cube.Cube): Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. """ - # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": - if cube.long_name == "surface_microphysical_rainfall_rate": - if cube.units == "kg m-2 s-1": - logging.info( - "Converting precipitation units from kg m-2 s-1 to mm hr-1" - ) - # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water - cube.data = cube.data * 3600.0 - - # update the units - cube.units = "mm hr-1" - else: - logging.warning( - "Precipitation units are not in 'kg m-2 s-1', skipping conversion" - ) + # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": + if cube.long_name == "surface_microphysical_rainfall_rate": + if cube.units == "kg m-2 s-1": + logging.info("Converting precipitation units from kg m-2 s-1 to mm hr-1") + # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water + cube.data = cube.data * 3600.0 + + # update the units + cube.units = "mm hr-1" + else: + logging.warning( + "Precipitation units are not in 'kg m-2 s-1', skipping conversion" + ) return cube From 3f8132dd76d9b0986df086310e1e13dcf49b7157 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Tue, 25 Mar 2025 12:31:53 +0000 Subject: [PATCH 08/13] move function into private section --- src/CSET/operators/plot.py | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 989e5c4a6..e63aee68a 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -933,6 +933,27 @@ def _spatial_plot( _make_plot_html_page(complete_plot_index) +def _convert_precipitation_units_callback(cube: iris.cube.Cube): + """To convert the unit of precipitation from kg m-2 s-1 to mm hr-1. + + Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. + """ + # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": + if cube.long_name == "surface_microphysical_rainfall_rate": + if cube.units == "kg m-2 s-1": + logging.info("Converting precipitation units from kg m-2 s-1 to mm hr-1") + # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water + cube.data = cube.data * 3600.0 + + # update the units + cube.units = "mm hr-1" + else: + logging.warning( + "Precipitation units are not in 'kg m-2 s-1', skipping conversion" + ) + return cube + + #################### # Public functions # #################### @@ -1486,24 +1507,3 @@ def plot_histogram_series( _make_plot_html_page(complete_plot_index) return cubes - - -def _convert_precipitation_units_callback(cube: iris.cube.Cube): - """To convert the unit of precipitation from kg m-2 s-1 to mm hr-1. - - Some precipitation diagnostics are output with unit kg m-2 s-1 and are converted to mm hr-1. - """ - # if cube.attributes["STASH"] == "m01s04i203" or cube.long_name == "surface_microphysical_rainfall_rate": - if cube.long_name == "surface_microphysical_rainfall_rate": - if cube.units == "kg m-2 s-1": - logging.info("Converting precipitation units from kg m-2 s-1 to mm hr-1") - # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water - cube.data = cube.data * 3600.0 - - # update the units - cube.units = "mm hr-1" - else: - logging.warning( - "Precipitation units are not in 'kg m-2 s-1', skipping conversion" - ) - return cube From 003ce0988fd429a47058d6295a49e24ac3bef559 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Wed, 26 Mar 2025 16:51:43 +0000 Subject: [PATCH 09/13] new internal function for colorbar for microphysical precipitation --- src/CSET/operators/plot.py | 48 +++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index e63aee68a..4b79a4d11 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -246,6 +246,11 @@ def _colorbar_map_levels(cube: iris.cube.Cube): norm = mpl.colors.BoundaryNorm(levels, ncolors=cmap.N) logging.debug("Using levels for %s colorbar.", varname) logging.info("Using levels: %s", levels) + # Overwrite cmap, levels and norm for specific variables that require custom colorbar_map as these + # can not be defined in the json file. + cmap, levels, norm = _custom_colourmap_precipitation( + cube, cmap, levels, norm + ) except KeyError: # Get the range for this variable. vmin, vmax = var_colorbar["min"], var_colorbar["max"] @@ -954,6 +959,46 @@ def _convert_precipitation_units_callback(cube: iris.cube.Cube): return cube +def _custom_colourmap_precipitation(cube: iris.cube.Cube, cmap, levels, norm): + """Return a custom colourmap for the current recipe.""" + import matplotlib.colors as mcolors + + if ( + cube.long_name == "surface_microphysical_rainfall_rate" + or cube.standard_name == "surface_microphysical_rainfall_rate" + or cube.var_name == "surface_microphysical_rainfall_rate" + ): + # Define the levels and colors + levels = [0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128] + colors = [ + (0, 0, 0.6), + "b", + "c", + "g", + "y", + (1, 0.5, 0), + "r", + "m", + (0.6, 0.6, 0.6), + "k", + ] + + # Create a custom colormap + cmap = mcolors.ListedColormap(colors) + + # Normalize the levels + norm = mcolors.BoundaryNorm(levels, cmap.N) + logging.info( + "change colormap for surface_microphysical_rainfall_rate colorbar." + ) + else: + # do nothing and keep existing colorbar attributes + cmap = cmap + levels = levels + norm = norm + return cmap, levels, norm + + #################### # Public functions # #################### @@ -1049,9 +1094,6 @@ def spatial_pcolormesh_plot( TypeError If the cube isn't a single cube. """ - # Convert precipitation units if necessary - _convert_precipitation_units_callback(cube) - _spatial_plot("pcolormesh", cube, filename, sequence_coordinate, stamp_coordinate) return cube From b0ee03daaaea1cc27936bade578e1fc27eacc125 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Thu, 27 Mar 2025 15:05:42 +0000 Subject: [PATCH 10/13] remove vmin/vmax when norm is calculated for pcolormesh. this enables plotting of fields with level information such as precipitation instead of vmin/vmax information. --- src/CSET/operators/_colorbar_definition.json | 14 ++----------- src/CSET/operators/plot.py | 22 ++++++++++++-------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/CSET/operators/_colorbar_definition.json b/src/CSET/operators/_colorbar_definition.json index c06f7ac39..b899b7a60 100644 --- a/src/CSET/operators/_colorbar_definition.json +++ b/src/CSET/operators/_colorbar_definition.json @@ -392,18 +392,8 @@ }, "surface_microphysical_rainfall_rate": { "cmap": "cividis", - "levels": [ - 0.125, - 0.25, - 0.5, - 1, - 2, - 4, - 8, - 16, - 32, - 64 - ] + "max": 256.0, + "min": 0.0 }, "surface_microphysical_rainfall_rate_difference": { "cmap": "bwr", diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 4b79a4d11..6af7ff92f 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -258,6 +258,9 @@ def _colorbar_map_levels(cube: iris.cube.Cube): # Calculate levels from range. levels = np.linspace(vmin, vmax, 51) norm = None + cmap, levels, norm = _custom_colourmap_precipitation( + cube, cmap, levels, norm + ) return cmap, levels, norm except KeyError: logging.debug("Cube name %s has no colorbar definition.", varname) @@ -305,13 +308,16 @@ def _plot_and_save_spatial_plot( # Filled contour plot of the field. plot = iplt.contourf(cube, cmap=cmap, levels=levels, norm=norm) elif method == "pcolormesh": - # try: - # vmin = min(levels) - # vmax = max(levels) - # except TypeError: - # vmin, vmax = None, None - # pcolormesh plot of the field. - plot = iplt.pcolormesh(cube, cmap=cmap, norm=norm) + try: + vmin = min(levels) + vmax = max(levels) + except TypeError: + vmin, vmax = None, None + # pcolormesh plot of the field and ensure not to use norm and not vmin/vmax if levels are defined. + if norm is not None: + vmin = None + vmax = None + plot = iplt.pcolormesh(cube, cmap=cmap, norm=norm, vmin=vmin, vmax=vmax) else: raise ValueError(f"Unknown plotting method: {method}") @@ -982,10 +988,8 @@ def _custom_colourmap_precipitation(cube: iris.cube.Cube, cmap, levels, norm): (0.6, 0.6, 0.6), "k", ] - # Create a custom colormap cmap = mcolors.ListedColormap(colors) - # Normalize the levels norm = mcolors.BoundaryNorm(levels, cmap.N) logging.info( From 4463e55bb82dc414706ee7d76341417c69234d7f Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Thu, 27 Mar 2025 15:20:46 +0000 Subject: [PATCH 11/13] change colourbar_map for precipitation and align with ukep_plot. --- src/CSET/operators/plot.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 6af7ff92f..5b7507549 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -975,8 +975,9 @@ def _custom_colourmap_precipitation(cube: iris.cube.Cube, cmap, levels, norm): or cube.var_name == "surface_microphysical_rainfall_rate" ): # Define the levels and colors - levels = [0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128] + levels = [0, 0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 32, 64, 128, 256] colors = [ + "w", (0, 0, 0.6), "b", "c", @@ -984,9 +985,11 @@ def _custom_colourmap_precipitation(cube: iris.cube.Cube, cmap, levels, norm): "y", (1, 0.5, 0), "r", + "pink", "m", - (0.6, 0.6, 0.6), - "k", + "purple", + "maroon", + "gray", ] # Create a custom colormap cmap = mcolors.ListedColormap(colors) From 2d8c92321412cb1a6f94ef1cd7d5efdab06cdfa0 Mon Sep 17 00:00:00 2001 From: Sylviabohnenstengel Date: Thu, 27 Mar 2025 17:28:36 +0000 Subject: [PATCH 12/13] enable a tick for each level if less than 20 levels and include levels into colourbar.json file. --- src/CSET/operators/_colorbar_definition.json | 17 +++++++++++++++-- src/CSET/operators/plot.py | 6 +++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/CSET/operators/_colorbar_definition.json b/src/CSET/operators/_colorbar_definition.json index b899b7a60..7f670e1ec 100644 --- a/src/CSET/operators/_colorbar_definition.json +++ b/src/CSET/operators/_colorbar_definition.json @@ -392,8 +392,21 @@ }, "surface_microphysical_rainfall_rate": { "cmap": "cividis", - "max": 256.0, - "min": 0.0 + "levels": [ + 0, + 0.125, + 0.25, + 0.5, + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256 + ] }, "surface_microphysical_rainfall_rate_difference": { "cmap": "bwr", diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index 5b7507549..a63d26097 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -313,7 +313,7 @@ def _plot_and_save_spatial_plot( vmax = max(levels) except TypeError: vmin, vmax = None, None - # pcolormesh plot of the field and ensure not to use norm and not vmin/vmax if levels are defined. + # pcolormesh plot of the field and ensure to use norm and not vmin/vmax if levels are defined. if norm is not None: vmin = None vmax = None @@ -384,6 +384,10 @@ def _plot_and_save_spatial_plot( # Add colour bar. cbar = fig.colorbar(plot) cbar.set_label(label=f"{cube.name()} ({cube.units})", size=20) + # add ticks and tick_labels for every levels if less than 20 levels exist + if levels is not None and len(levels) < 20: + cbar.set_ticks(levels) + cbar.set_ticklabels([f"{level:.1f}" for level in levels]) # Save plot. fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) From 7d8dd9ab623ab6a1a5f1ef3502f26cc374562f17 Mon Sep 17 00:00:00 2001 From: Sylvia Bohnenstengel <62748926+Sylviabohnenstengel@users.noreply.github.com> Date: Mon, 31 Mar 2025 09:30:13 +0100 Subject: [PATCH 13/13] Update src/CSET/operators/plot.py Co-authored-by: James Frost --- src/CSET/operators/plot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index b611d361b..97049ae3d 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -959,11 +959,11 @@ def _convert_precipitation_units_callback(cube: iris.cube.Cube): if cube.long_name == "surface_microphysical_rainfall_rate": if cube.units == "kg m-2 s-1": logging.info("Converting precipitation units from kg m-2 s-1 to mm hr-1") - # manually convert from kg m-2 s-1 to mm hr-1 assuming 1kg water = 1l water = 1dm^3 water - cube.data = cube.data * 3600.0 - - # update the units - cube.units = "mm hr-1" + # Convert from kg m-2 s-1 to mm s-1 assuming 1kg water = 1l water = 1dm^3 water. + # This is a 1:1 conversion, so we just change the units. + cube.units = "mm s-1" + # Convert the units to per hour. + cube.convert_units("mm hr-1") else: logging.warning( "Precipitation units are not in 'kg m-2 s-1', skipping conversion"