Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 39 additions & 29 deletions src/CSET/cset_workflow/meta/diagnostics/rose-meta.conf
Comment thread
ukmo-huw-lewis marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -1978,76 +1978,86 @@ title=Multi-variable plots
ns=Diagnostics/Multi-variable
title=SPATIAL_MULTI_VARIABLE
description=Create spatially mapped plots for the specified surface fields.
help=This generates spatial maps of 3 variables over-plotted.
A colour-filled map of VARNAME_BASE cube is plotted for the chosen domain.
A masked colour-filled layer of VARNAME_OVERLAY cube is overlaid on top.
A contour of VARNAME_CONTOUR is then overlaid on top of both.
A list of variables can be provided to generate multiple different combinations of multi-variable outputs.
help=This generates spatial maps with masked color-filled overlay and/or contours over-plotted.
A colour-filled map of MULTI_BASE_FIELDS is plotted for the chosen domain.
A masked colour-filled layer of MULTI_OVERLAY_FIELDS is overlaid on top.
A contour of MULTI_CONTOUR_FIELDS is then overlaid on top of both.
If either MULTI_OVERLAY_FIELDS or MULTI_CONTOUR_FIELDS variable is not set, 2-layer outputs
are generated.
type=python_boolean
compulsory=true
sort-key=multi1
trigger=template variables=MULTI_BASE_FIELD: True;
template variables=MULTI_OVERLAY_FIELD: True;
template variables=MULTI_OVERLAY_MASK_CONDITION: True;
template variables=MULTI_OVERLAY_MASK_VALUE: True;
template variables=MULTI_CONTOUR_FIELD: True;
trigger=template variables=MULTI_BASE_FIELDS: True;
template variables=MULTI_OVERLAY_FIELDS: True;
template variables=MULTI_OVERLAY_MASK_CONDITIONS: True;
template variables=MULTI_OVERLAY_MASK_VALUES: True;
template variables=MULTI_CONTOUR_FIELDS: True;
template variables=SPATIAL_MULTI_FIELD_METHOD: True;

[template variables=MULTI_BASE_FIELD]
[template variables=MULTI_BASE_FIELDS]
ns=Diagnostics/Multi-variable
title=Base variable
description=Surface (2D) diagnostic variable to form base layer in output.
title=Base variables
description=Surface (2D) diagnostic variable(s) to form base layer in output.
A different multi-variable plot is generated for each entry.
help=Quoted variable names for base surface (2D) variable. The names should follow CF naming
conventions, and will be translated appropriately. Where applicable, a STASH code in
the format "m??s??i???" may be used instead.
compulsory=true
type=quoted
type=python_list
sort-key=multi2

[template variables=MULTI_OVERLAY_FIELD]
[template variables=MULTI_OVERLAY_FIELDS]
ns=Diagnostics/Multi-variable
title=Overlay variable (masked)
description=Masked diagnostic variable to form overlay layer in output.
title=Overlay variables (masked)
description=Masked diagnostic variable name(s) to form overlay layer in output.
Provide an overlay variable entry for each base variable requested.
If blank or None set, no overlay variables are plotted.
help=Quoted variable names for masked variable. The names should follow CF naming
conventions, and will be translated appropriately. Where applicable, a STASH code in
the format "m??s??i???" may be be used instead.
compulsory=true
type=quoted
type=python_list
sort-key=multi3

[template variables=MULTI_OVERLAY_MASK_CONDITION]
[template variables=MULTI_OVERLAY_MASK_CONDITIONS]
ns=Diagnostics/Multi-variable
title=Overlay variable mask condition
title=Overlay variable mask conditions
description=Set logical condition to control overlay masking. See help for details.
Comment thread
ukmo-huw-lewis marked this conversation as resolved.
Potential values: "ge", "gt", "eq", "lt", "le"
Provide an overlay condition entry for each overlay variable requested.
help=For example, if set to "ge", only the overlay variable values
greater than or equal to overlay variable mask value will be
over-plotted.
values="ge", "gt", "eq", "lt", "le"
compulsory=true
type=python_list
sort-key=multi4

[template variables=MULTI_OVERLAY_MASK_VALUE]
[template variables=MULTI_OVERLAY_MASK_VALUES]
ns=Diagnostics/Multi-variable
title=Overlay variable mask value
title=Overlay variable mask values
description=Set variable threshold value to control overlay masking. See help for details.
help=Overlay output controlled by mask condition and mask value. For example, to overplot all non-zero rainfall, set OVERLAY_FIELD="surface_microphysical_rainfall_rate"; OVERLAY_CONDITION="ge"; OVERLAY_MASK_VALUE="0.05"
help=Overlay output controlled by mask condition and mask value. For example, to overplot all non-zero rainfall, set OVERLAY_FIELDS=["surface_microphysical_rainfall_rate"]; OVERLAY_CONDITIONS=["ge"]; OVERLAY_MASK_VALUES=["0.05"]
compulsory=true
type=real
type=python_list
sort-key=multi5

[template variables=MULTI_CONTOUR_FIELD]
[template variables=MULTI_CONTOUR_FIELDS]
ns=Diagnostics/Multi-variable
title=Contour variable
description=Diagnostic variable to form contour layer in multi-variable output.
title=Contour variables
description=Diagnostic variable(s) to form contour layer in multi-variable output.
Provide a contour variable entry for each base variable requested.
If blank or None set, no overlay variables are plotted.
help=Quoted variable names for contour variable. The names should follow CF naming
conventions, and will be translated appropriately. Where applicable, a STASH code in
the format "m??s??i???" may be be used instead.
compulsory=true
type=quoted
type=python_list
sort-key=multi6

[template variables=SPATIAL_MULTI_FIELD_METHOD]
ns=Diagnostics/Multi-variable
description=Select analysis method(s) for output mapped plots. Add all options required.
description=Select analysis method(s) for all output mapped plots. Add all options required.
Leave blank or set to "SEQ" (sequence) for plots each diagnostic output time.
For time-collapsed outputs over each analysis period, set to "MEAN", "MAX", "MIN", "STD_DEV" etc.
help=Quoted analysis methods. Settings should be based on available iris.analysis methods for collapsing cube dimensions.
Expand Down
10 changes: 5 additions & 5 deletions src/CSET/cset_workflow/rose-suite.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ MODERATE_RAIN_PRESENCE_SPATIAL_DIFFERENCE=False
MODERATE_RAIN_PRESENCE_SPATIAL_PLOT=False
!!MODULES_LIST=
!!MODULES_PURGE=True
!!MULTI_BASE_FIELD=""
!!MULTI_CONTOUR_FIELD=""
!!MULTI_OVERLAY_FIELD=""
!!MULTI_OVERLAY_MASK_CONDITION="ge"
!!MULTI_OVERLAY_MASK_VALUE=0.0
!!MULTI_BASE_FIELDS=[]
!!MULTI_CONTOUR_FIELDS=[]
!!MULTI_OVERLAY_FIELDS=[]
!!MULTI_OVERLAY_MASK_CONDITIONS=[]
!!MULTI_OVERLAY_MASK_VALUES=[]
!!PLEVEL_TRANSECT_AGGREGATION=False,False,False,False
!!PLEVEL_TRANSECT_AGGREGATION_DIFFERENCE=False,False,False,False
!!PLEVEL_TRANSECT_DIFFERENCE=False
Expand Down
61 changes: 41 additions & 20 deletions src/CSET/loaders/spatial_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,28 +564,49 @@ def load(conf: Config):
aggregation=False,
)

# Multi-variable spatial plotting
if conf.SPATIAL_MULTI_VARIABLE:
for model, method in itertools.product(models, conf.SPATIAL_MULTI_FIELD_METHOD):
# Multi-variable spatial plotting.
yield RawRecipe(
recipe="multi_surface_spatial_plot_sequence.yaml",
variables={
"VARNAME_BASE": conf.MULTI_BASE_FIELD,
"VARNAME_OVER": conf.MULTI_OVERLAY_FIELD,
"OVERLAY_MASK_CONDITION": conf.MULTI_OVERLAY_MASK_CONDITION,
"OVERLAY_MASK_VALUE": conf.MULTI_OVERLAY_MASK_VALUE,
"VARNAME_CONTOUR": conf.MULTI_CONTOUR_FIELD,
"MODEL_NAME": model["name"],
"METHOD": method,
"SUBAREA_TYPE": conf.SUBAREA_TYPE if conf.SELECT_SUBAREA else None,
"SUBAREA_EXTENT": conf.SUBAREA_EXTENT
if conf.SELECT_SUBAREA
else None,
"SUBAREA_NAME": conf.SUBAREA_NAME if conf.SELECT_SUBAREA else "",
},
model_ids=model["id"],
aggregation=False,
)
# Loop over all potential variable combinations, using zip to ensure inputs for all plots requested.
for base, overlay, mask_condition, mask_value, contour in zip(
conf.MULTI_BASE_FIELDS,
conf.MULTI_OVERLAY_FIELDS,
conf.MULTI_OVERLAY_MASK_CONDITIONS,
conf.MULTI_OVERLAY_MASK_VALUES,
conf.MULTI_CONTOUR_FIELDS,
strict=True,
):
# Set recipe by selected input variable combinations
multi_recipe = "multi_surface_spatial_plot_sequence.yaml"
if not contour or contour.lower() == "none":
multi_recipe = "multi_overlay_spatial_plot_sequence.yaml"
if not overlay or overlay.lower() == "none":
multi_recipe = "multi_contour_spatial_plot_sequence.yaml"

# Multi-variable spatial plotting - set same inputs for all recipes.
yield RawRecipe(
recipe=multi_recipe,
variables={
"VARNAME_BASE": base,
"VARNAME_OVER": overlay,
"OVERLAY_MASK_CONDITION": mask_condition,
"OVERLAY_MASK_VALUE": mask_value,
"VARNAME_CONTOUR": contour,
"MODEL_NAME": model["name"],
"METHOD": method,
"SUBAREA_TYPE": conf.SUBAREA_TYPE
if conf.SELECT_SUBAREA
else None,
"SUBAREA_EXTENT": conf.SUBAREA_EXTENT
if conf.SELECT_SUBAREA
else None,
"SUBAREA_NAME": conf.SUBAREA_NAME
if conf.SELECT_SUBAREA
else "",
},
model_ids=model["id"],
aggregation=False,
)

# Moist Absolutely Unstable Layer presence
if conf.MAUL_PRESENCE:
Expand Down
11 changes: 6 additions & 5 deletions src/CSET/operators/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1890,8 +1890,8 @@ def spatial_pcolormesh_plot(

def spatial_multi_pcolormesh_plot(
cube: iris.cube.Cube,
overlay_cube: iris.cube.Cube,
contour_cube: iris.cube.Cube,
overlay_cube: iris.cube.Cube | None = None,
contour_cube: iris.cube.Cube | None = None,
filename: str = None,
sequence_coordinate: str = "time",
stamp_coordinate: str = "realization",
Expand Down Expand Up @@ -1919,14 +1919,15 @@ def spatial_multi_pcolormesh_plot(
Iris cube of the data to plot. It should have two spatial dimensions,
such as lat and lon, and may also have a another two dimension to be
plotted sequentially and/or as postage stamp plots.
overlay_cube: Cube
overlay_cube: Cube, optional
Iris cube of the data to plot as an overlay on top of basis cube. It should have two spatial dimensions,
such as lat and lon, and may also have a another two dimension to be
plotted sequentially and/or as postage stamp plots. This is likely to be a masked cube in order not to hide the underlying basis cube.
contour_cube: Cube
If not provided, output plot generated without overlay cube.
contour_cube: Cube, optional
Iris cube of the data to plot as a contour overlay on top of basis cube and overlay_cube. It should have two spatial dimensions,
such as lat and lon, and may also have a another two dimension to be
plotted sequentially and/or as postage stamp plots.
plotted sequentially and/or as postage stamp plots. If not provided, output plot generated without contours.
filename: str, optional
Name of the plot to write, used as a prefix for plot sequences. Defaults
to the recipe name.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
category: Multivar Spatial Plot
title: "$MODEL_NAME $VARNAME_BASE $METHOD $SUBAREA_NAME\n(contour: $VARNAME_CONTOUR)"
description: Extracts and overplots the $METHOD of $VARNAME_BASE and $VARNAME_CONTOUR from all times in $MODEL_NAME.

steps:

- operator: read.read_cubes
file_paths: $INPUT_PATHS
subarea_type: $SUBAREA_TYPE
subarea_extent: $SUBAREA_EXTENT
constraint: ['$VARNAME_BASE', '$VARNAME_CONTOUR']

- operator: filters.filter_multiple_cubes
constraint:
operator: constraints.generate_cell_methods_constraint
cell_methods: []
varname: ['$VARNAME_BASE', '$VARNAME_CONTOUR']

- operator: collapse.collapse
coordinate: [time]
method: $METHOD

- operator: plot.spatial_multi_pcolormesh_plot
cube:
operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME_BASE
contour_cube:
operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME_CONTOUR
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
category: Multivar Spatial Plot
title: "$MODEL_NAME $VARNAME_BASE $METHOD $SUBAREA_NAME\n(overlay: $VARNAME_OVER $OVERLAY_MASK_CONDITION $OVERLAY_MASK_VALUE)"
description: Extracts and overplots the $METHOD of $VARNAME_BASE and $VARNAME_OVER from all times in $MODEL_NAME.

steps:

- operator: read.read_cubes
file_paths: $INPUT_PATHS
subarea_type: $SUBAREA_TYPE
subarea_extent: $SUBAREA_EXTENT
constraint: ['$VARNAME_BASE', '$VARNAME_OVER']

- operator: filters.filter_multiple_cubes
constraint:
operator: constraints.generate_cell_methods_constraint
cell_methods: []
varname: ['$VARNAME_BASE', '$VARNAME_OVER']

- operator: collapse.collapse
coordinate: [time]
method: $METHOD

- operator: plot.spatial_multi_pcolormesh_plot
cube:
operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME_BASE

overlay_cube:
operator: filters.apply_mask
original_field:
operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME_OVER
mask:
operator: filters.generate_mask
mask_field:
operator: filters.filter_cubes
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME_OVER
condition: $OVERLAY_MASK_CONDITION
value: $OVERLAY_MASK_VALUE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
category: Multivar Spatial Plot
title: "$MODEL_NAME multi-variable $VARNAME_BASE $METHOD $SUBAREA_NAME"
title: "$MODEL_NAME $VARNAME_BASE $METHOD $SUBAREA_NAME\n(overlay: $VARNAME_OVER $OVERLAY_MASK_CONDITION $OVERLAY_MASK_VALUE)\n(contour: $VARNAME_CONTOUR)"
description: Extracts and overplots the $METHOD of $VARNAME_BASE, $VARNAME_OVER and $VARNAME_CONTOUR from all times in $MODEL_NAME.

steps:
Expand Down
25 changes: 25 additions & 0 deletions tests/operators/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,31 @@ def test_spatial_multi_variable_plot(cube, tmp_working_dir):
assert Path("untitled_20220921050000.png").is_file()


def test_spatial_multi_variable_plot_nolayers(cube, tmp_working_dir):
"""Plot spatial plot with single input cube only."""
# Call spatial_multi_pcolormesh_plot with only cube as input.
plot.spatial_multi_pcolormesh_plot(cube[0], sequence_coordinate="time")
assert Path("untitled_20220921030000.png").is_file()


def test_spatial_multi_variable_plot_overlay_only(cube, tmp_working_dir):
"""Plot spatial plot with based and overlay cube only."""
# Call spatial_multi_pcolormesh_plot with only cube and overlay_cube.
plot.spatial_multi_pcolormesh_plot(
cube[0], overlay_cube=cube[0], sequence_coordinate="time"
)
assert Path("untitled_20220921030000.png").is_file()


def test_spatial_multi_variable_plot_contour_only(cube, tmp_working_dir):
"""Plot spatial plot with based and contour cube only."""
# Call spatial_multi_pcolormesh_plot with only cube and contour_cube.
plot.spatial_multi_pcolormesh_plot(
cube[0], contour_cube=cube[0], sequence_coordinate="time"
)
assert Path("untitled_20220921030000.png").is_file()


@pytest.mark.slow
def test_vector_plot_with_filename(vector_cubes, tmp_working_dir):
"""Plot a vector plot of u10 and v10 components."""
Expand Down