Skip to content

Commit

Permalink
Merge pull request #640 from MetOffice/639_surface_field_histogram_ex…
Browse files Browse the repository at this point in the history
…tension_to_453

Surface field histogram
  • Loading branch information
jfrost-mo authored Aug 5, 2024
2 parents 7337010 + 7485c3d commit 368a297
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 32 deletions.
16 changes: 16 additions & 0 deletions cset-workflow/includes/deterministic_domain_histogram_series.cylc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% if DOMAIN_HISTOGRAM_SERIES_FIELD %}
[runtime]
{% for model_field in MODEL_LEVEL_MODEL_FIELDS %}
[[pre_process_deterministic_domain_histogram_series_{{model_field}}]]
inherit = PARALLEL
[[[environment]]]
CSET_RECIPE_NAME = "generic_histogram_series.yaml"
CSET_ADDOPTS = "--VARNAME='{{model_field}}' --MLEVEL='{{UM_MODEL_LEVELS}}'"

[[collate_deterministic_domain_histogram_series_{{model_field}}]]
inherit = COLLATE
[[[environment]]]
CSET_RECIPE_NAME = "generic_histogram_series.yaml"
CSET_ADDOPTS = "--VARNAME='{{model_field}}' --MLEVEL='{{UM_MODEL_LEVELS}}'"
{% endfor %}
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% if DOMAIN_SURFACE_HISTOGRAM_SERIES_FIELD %}
[runtime]
{% for model_field in SURFACE_MODEL_FIELDS %}
[[pre_process_deterministic_domain_surface_histogram_series_{{model_field}}]]
inherit = PARALLEL
[[[environment]]]
CSET_RECIPE_NAME = "generic_surface_histogram_series.yaml"
CSET_ADDOPTS = "--VARNAME='{{model_field}}'"

[[collate_deterministic_domain_surface_histogram_series_{{model_field}}]]
inherit = COLLATE
[[[environment]]]
CSET_RECIPE_NAME = "generic_surface_histogram_series.yaml"
CSET_ADDOPTS = "--VARNAME='{{model_field}}'"
{% endfor %}
{% endif %}
25 changes: 25 additions & 0 deletions cset-workflow/meta/rose-meta.conf
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,14 @@ type=python_boolean
compulsory=true
sort-key=surface2

[template variables=DOMAIN_SURFACE_HISTOGRAM_SERIES_FIELD]
ns=Diagnostics
description=Create a series of histogram plots for selected surface fields for each cycle time.
help=See includes/deterministic_domain_surface_histogram_series.cylc. This diagnostic requires the user to also enable and enter the SURFACE_MODEL_FIELDS. The series_coordinate in the recipe is set to "time", but can be switched to any other coordinate.
type=python_boolean
compulsory=true
sort-key=surface2

[template variables=LFRIC_PLOT_SPATIAL_SURFACE_MODEL_FIELD]
ns=Diagnostics
description=Create plots for the specified surface fields for structured LFRic data.
Expand Down Expand Up @@ -602,6 +610,23 @@ type=python_list
compulsory=true
sort-key=model1

[template variables=LFRIC_PRESSURE_LEVEL_MODEL_FIELDS]
ns=Diagnostics
description=List of standard names of model fields on pressure levels to plot.
help=Include a list of variable names in python list format, e.g: ["var1","var2"]
type=python_list
compulsory=true
sort-key=pressure3

[template variables=LFRIC_PRESSURE_LEVELS]
ns=Diagnostics
description=List of pressure levels to generate plots for.
help=Include an list of integer pressure levels in hPa in python list format, e.g: [1000,850]
type=python_list
compulsory=true
sort-key=pressure3


[template variables=PLOT_SPATIAL_PRESSURE_LEVEL_MODEL_FIELD]
ns=Diagnostics
description=Create plots for the specified pressure level fields.
Expand Down
60 changes: 33 additions & 27 deletions src/CSET/operators/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ def _plot_and_save_vertical_line_series(
# Set y-axis limits and ticks.
ax.set_ylim(1100, 100)

# test if series_coordinate is model level data. The um data uses model_level_number
# and lfric uses full_levels as coordinate.
# Test if series_coordinate is model level data. The UM data uses
# model_level_number and lfric uses full_levels as coordinate.
elif series_coordinate in ("model_level_number", "full_levels", "half_levels"):
# Define y-ticks and labels for vertical axis.
y_ticks = cube.coord(series_coordinate).points
Expand All @@ -431,6 +431,9 @@ def _plot_and_save_vertical_line_series(
xlabel=f"{cube.name()} / {cube.units}",
title=title,
)
ax.ticklabel_format(axis="x")
ax.tick_params(axis="y")
ax.autoscale()

# Save plot.
fig.savefig(filename, bbox_inches="tight", dpi=150)
Expand Down Expand Up @@ -725,6 +728,7 @@ def spatial_contour_plot(
except iris.exceptions.CoordinateNotFoundError:
pass

# Must have a sequence coordinate.
try:
cube.coord(sequence_coordinate)
except iris.exceptions.CoordinateNotFoundError as err:
Expand Down Expand Up @@ -876,23 +880,24 @@ def plot_vertical_line_series(
except iris.exceptions.CoordinateNotFoundError as err:
raise ValueError(f"Cube must have a {series_coordinate} coordinate.") from err

# If several individual vertical lines are plotted with time as sequence_coordinate
# for the time slider option.
try:
cube.coord(sequence_coordinate)
if cube.ndim > 1:
cube.coord(sequence_coordinate)
except iris.exceptions.CoordinateNotFoundError as err:
raise ValueError(f"Cube must have a {sequence_coordinate} coordinate.") from err
raise ValueError(
f"Cube must have a {sequence_coordinate} coordinate or be 1D."
) from err

# Ensure we have a name for the plot file.
recipe_title = get_recipe_metadata().get("title", "Untitled")
if filename is None:
filename = slugify(recipe_title)

# set the lower and upper limit for the x-axis to ensure all plots
# have same range. This needs to read the whole cube over the range of
# the sequence and if applicable postage stamp coordinate.
# This only works if the plotting is done in the collate section of a
# recipe and not in the parallel section of a recipe.
# Set the lower and upper limit for the x-axis to ensure all plots have same
# range. This needs to read the whole cube over the range of the sequence
# and if applicable postage stamp coordinate. This only works if the
# plotting is done in the collate section of a recipe and not in the
# parallel section of a recipe.
vmin = np.floor(cube.data.min())
vmax = np.ceil(cube.data.max())

Expand Down Expand Up @@ -1032,10 +1037,10 @@ def plot_histogram_series(
A histogram plot can be plotted, but if the sequence_coordinate (i.e. time)
is present then a sequence of plots will be produced using the time slider
functionality to scroll through histograms against time.
If a stamp_coordinate is present then postage stamp plots will be produced.
If stamp_coordinate and single_plot is True,
all postage stamp plots will be plotted in a single plot instead of separate postage stamp plots.
functionality to scroll through histograms against time. If a
stamp_coordinate is present then postage stamp plots will be produced. If
stamp_coordinate and single_plot is True, all postage stamp plots will be
plotted in a single plot instead of separate postage stamp plots.
Parameters
----------
Expand All @@ -1047,18 +1052,19 @@ def plot_histogram_series(
to the recipe name.
sequence_coordinate: str, optional
Coordinate about which to make a plot sequence. Defaults to ``"time"``.
This coordinate must exist in the cube and will be used for the time slider.
This coordinate must exist in the cube and will be used for the time
slider.
stamp_coordinate: str, optional
Coordinate about which to plot postage stamp plots. Defaults to
``"realization"``.
single_plot: bool, optional
If True, all postage stamp plots will be plotted in a single plot.
If False, each postage stamp plot will be plotted separately.
Is only valid if stamp_coordinate exists and has more than a single point.
If True, all postage stamp plots will be plotted in a single plot. If
False, each postage stamp plot will be plotted separately. Is only valid
if stamp_coordinate exists and has more than a single point.
histtype: str, optional
The type of histogram to plot. Options are "step" for a line
histogram or "barstacked", "stepfilled". "Step" is the default option,
but can be changed in the rose-suite.conf configuration.
The type of histogram to plot. Options are "step" for a line histogram
or "barstacked", "stepfilled". "Step" is the default option, but can be
changed in the rose-suite.conf configuration.
Returns
-------
Expand Down Expand Up @@ -1105,11 +1111,11 @@ def plot_histogram_series(
except iris.exceptions.CoordinateNotFoundError as err:
raise ValueError(f"Cube must have a {sequence_coordinate} coordinate.") from err

# Set the lower and upper limit for the colorbar to ensure all plots
# have same range. This needs to read the whole cube over the range of
# the sequence and if applicable postage stamp coordinate.
# This only works if the plotting is done in the collate section of a
# recipe and not in the parallel section of a recipe.
# Set the lower and upper limit for the colorbar to ensure all plots have
# same range. This needs to read the whole cube over the range of the
# sequence and if applicable postage stamp coordinate. This only works if
# the plotting is done in the collate section of a recipe and not in the
# parallel section of a recipe.
vmin = np.floor((cube.data.min()))
vmax = np.ceil((cube.data.max()))

Expand Down
9 changes: 7 additions & 2 deletions src/CSET/recipes/generic_histogram_series.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
category: Quick Look
title: $VARNAME $MLEVEL Level Histogram Plot
description: |
Extracts and plots the probability density of $MLEVEL level $VARNAME from a file at model level $MLEVEL. It uses [`plt.hist`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hist.html) to plot the probability density so that the area under the histogram integrates to 1. `stacked` is set to True so the sum of the histograms is normalized to 1. In case of ensemble data choose from postage stamp plot or single plot via the single_plot option in the recipe directly.
Extracts and plots the probability density of $MLEVEL level $VARNAME from a
file at model level $MLEVEL. It uses
[`plt.hist`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hist.html)
to plot the probability density so that the area under the histogram
integrates to 1. `stacked` is set to True so the sum of the histograms is
normalized to 1. In case of ensemble data choose from postage stamp plot or
single plot via the single_plot option in the recipe directly.
parallel:
- operator: read.read_cube
Expand Down Expand Up @@ -34,4 +40,3 @@ collate:
# stamp_coordinate and single_plot optional and only required for ensemble data
stamp_coordinate: "realization"
single_plot: False
histtype: $HISTTYPE
37 changes: 37 additions & 0 deletions src/CSET/recipes/generic_surface_histogram_series.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
category: Quick Look
title: $VARNAME Surface Level Histogram Plot
description: |
Extracts and plots the probability density of surface `$VARNAME`. It uses
[`plt.hist`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hist.html)
to plot the probability density so that the area under the histogram
integrates to 1. stacked is set to True so the sum of the histograms is
normalized to 1.
parallel:
- operator: read.read_cube
constraint:
operator: constraints.combine_constraints
variable_constraint:
operator: constraints.generate_var_constraint
varname: $VARNAME
validity_time_constraint:
operator: constraints.generate_time_constraint
time_start: $VALIDITY_TIME
pressure_level_constraint:
operator: constraints.generate_level_constraint
coordinate: pressure
levels: []

- operator: write.write_cube_to_nc
filename: intermediate/histogram


collate:
- operator: read.read_cube
filename_pattern: intermediate/*.nc

- operator: write.write_cube_to_nc
overwrite: True

- operator: plot.plot_histogram_series
sequence_coordinate: time
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
category: Quick Look
title: Domain mean $VARNAME vertical profile as series
description: Plots a time series of the vertical profile of domain mean $VARNAME using the model_level_number coordinate.
description: Plots a time series of the vertical profile of domain mean $VARNAME using the full_levels coordinate.

# Pre-processing steps.
parallel:
Expand All @@ -27,8 +27,8 @@ parallel:
filename: intermediate/model_level_domain_mean

# Collation steps.
# Reads in intermediate cube and plots it.
collate:
# Reads in intermediate cube and plots it.
- operator: read.read_cube
filename_pattern: intermediate/*.nc

Expand All @@ -37,6 +37,6 @@ collate:
series_coordinate: full_levels
sequence_coordinate: time

# Make a single NetCDF with all the data inside it.
# Make a single NetCDF with all the data inside it.
- operator: write.write_cube_to_nc
overwrite: True

0 comments on commit 368a297

Please sign in to comment.