diff --git a/docs/source/conf.py b/docs/source/conf.py index 2af96ce82..f2b184903 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -4,6 +4,8 @@ https://www.sphinx-doc.org/en/master/usage/configuration.html """ +from sphinx_gallery.sorting import ExplicitOrder + # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information @@ -20,6 +22,7 @@ "sphinx.ext.napoleon", "sphinx.ext.doctest", "sphinx.ext.extlinks", + "sphinx_gallery.gen_gallery", ] # -- Options for HTML output ------------------------------------------------- @@ -61,3 +64,28 @@ # Met Office internal webserver. r"https://wwwspice/.+", ] + +# -- Sphinx gallery config ---------------------------------------------------- + +sphinx_gallery_conf = { + "plot_gallery": True, + "examples_dirs": "reference/cset_gallery/examples", # input scripts + "gallery_dirs": "reference/cset_gallery/generated", # output pages + "filename_pattern": r"\.py$", + "image_scrapers": ("matplotlib",), + "thumbnail_size": (800, 600), + "capture_repr": (), # disable capture of printed / returned output + "nested_sections": False, + "subsection_order": ExplicitOrder( + [ + "reference/cset_gallery/examples/spatial", + "reference/cset_gallery/examples/line", + "reference/cset_gallery/examples/custom", + ] + ), +} + +suppress_warnings = [ + "toc.not_included", + "toc.excluded", +] diff --git a/docs/source/index.rst b/docs/source/index.rst index 53c35565c..1b270586a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -26,6 +26,9 @@ Useful links `Source Code`_ | `Issue Tracker`_ | Releases_ | `Discussion Forum`_ + +For examples of CSET outputs, see :doc:`reference/cset_gallery/index`. + For information on how to use CSET, see :doc:`getting-started/index`. For information on getting involved as a developer, see diff --git a/docs/source/reference/cli.rst b/docs/source/reference/cli.rst index 5341f9b30..16bb7fb64 100644 --- a/docs/source/reference/cli.rst +++ b/docs/source/reference/cli.rst @@ -1,5 +1,5 @@ -CLI Usage -========= +Command Line Usage (CLI) +======================== .. _cset-bake-command: diff --git a/docs/source/reference/cset_gallery/examples/README.rst b/docs/source/reference/cset_gallery/examples/README.rst new file mode 100644 index 000000000..a8e5234a2 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/README.rst @@ -0,0 +1 @@ +.. orphan diff --git a/docs/source/reference/cset_gallery/examples/custom/README.rst b/docs/source/reference/cset_gallery/examples/custom/README.rst new file mode 100644 index 000000000..2d77c89de --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/custom/README.rst @@ -0,0 +1,2 @@ +Customising CSET outputs +======================== diff --git a/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_cutout.py b/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_cutout.py new file mode 100644 index 000000000..0e6f3bc6e --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_cutout.py @@ -0,0 +1,69 @@ +""" +Trim edge gridcells +=================== + +Generate spatial map of a 2D field over selected sub-region of data with domain edges trimmed. + +Spatial maps are generated using either CSET operators :py:mod:`CSET.operators.plot.spatial_pcolormesh_plot` or :py:mod:`CSET.operators.plot.spatial_contour_plot`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_spatial_plot_sequence.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- See :doc:`/reference/cset_gallery/generated/spatial/plot_surface_spatial` for general settings. +- Set ``SUBAREA_TYPE`` and ``SUBAREA_EXTENT`` to select trim widths, and use ``SUBAREA_NAME`` to control labelling. +- Example to generate spatial maps for selected sub-area of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_spatial_plot_sequence + cset bake -i "input_data_path" -o "my_output_path" + -r generic_surface_spatial_plot_sequence + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" + --METHOD="" + --SUBAREA_TYPE='gridcells' --SUBAREA_EXTENT=[3, 2, 3, 1] --SUBAREA_NAME='' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set ``SELECT_SUBAREA`` to ``True``, set ``SUBAREA_TYPE`` to ``gridcells`` and set ``SUBAREA_EXTENT``. +- Set other required configuration options on ``Diagnostics / Surface (2D) fields`` panel. + +:: + + SELECT_SUBAREA = True + SPATIAL_SURFACE_FIELD = True + SUBAREA_TYPE = 'gridcells' + SUBAREA_EXTENT = [3, 2, 3, 1] + SUBAREA_NAME = '' + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_path = "../../../../../../tests/test_data/air_temp.nc" + +# Read selected variable(s) of interest. +# Use read_cube parameters to control edge trim selection. +cube = cset_read.read_cubes( + file_path, + ["temperature_at_screen_level"], + subarea_type="gridcells", + subarea_extent=[3, 2, 3, 1], +)[0] + +# Plot single example frame using spatial_contour_plot +cset_plot.spatial_contour_plot(cube[-1]) diff --git a/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_global_cutout.py b/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_global_cutout.py new file mode 100644 index 000000000..6d6bd15db --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/custom/plot_surface_spatial_global_cutout.py @@ -0,0 +1,69 @@ +""" +Select lat-lon subarea +====================== + +Generate spatial map of a 2D field over selected sub-region of data. + +Spatial maps are generated using either CSET operators :py:mod:`CSET.operators.plot.spatial_pcolormesh_plot` or :py:mod:`CSET.operators.plot.spatial_contour_plot`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_spatial_plot_sequence.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- See :doc:`/reference/cset_gallery/generated/spatial/plot_surface_spatial_global` for general settings. +- Set ``SUBAREA_TYPE`` and ``SUBAREA_EXTENT`` to select sub-region, and use ``SUBAREA_NAME`` to control labelling. +- Example to generate spatial maps for selected sub-area of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_spatial_plot_sequence + cset bake -i "input_data_path" -o "my_output_path" + -r generic_surface_spatial_plot_sequence + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" + --METHOD="" + --SUBAREA_TYPE='realworld' --SUBAREA_EXTENT=[-40.0, 40.0, -20.0, 55.0] --SUBAREA_NAME='Africa' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set ``SELECT_SUBAREA`` to ``True``, choose ``SUBAREA_TYPE`` and set ``SUBAREA_EXTENT`` and ``SUBAREA_NAME``. +- Set other required configuration options on ``Diagnostics / Surface (2D) fields`` panel. + +:: + + SELECT_SUBAREA = True + SPATIAL_SURFACE_FIELD = True + SUBAREA_TYPE = 'realworld' + SUBAREA_EXTENT = [-40.0, 40.0, -20.0, 55.0] + SUBAREA_NAME = 'Africa' + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_path = "../../../../../../tests/test_data/air_temperature_global.nc" + +# Read selected variable(s) of interest. +# Use read_cube parameters to control subarea selection. +cube = cset_read.read_cube( + file_path, + ["temperature_at_screen_level"], + subarea_type="realworld", + subarea_extent=[-40.0, 40.0, -20.0, 55.0], +) + +# Plot single example frame using spatial_pcolormesh_plot +cset_plot.spatial_pcolormesh_plot(cube) diff --git a/docs/source/reference/cset_gallery/examples/line/README.rst b/docs/source/reference/cset_gallery/examples/line/README.rst new file mode 100644 index 000000000..4df0d86f6 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/line/README.rst @@ -0,0 +1,4 @@ +.. orphan + +Line plots +========== diff --git a/docs/source/reference/cset_gallery/examples/line/plot_line_histogram.py b/docs/source/reference/cset_gallery/examples/line/plot_line_histogram.py new file mode 100644 index 000000000..7f69061a0 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/line/plot_line_histogram.py @@ -0,0 +1,65 @@ +""" +Histogram plot +============== + +Generate histogram of region-averaged field. + +Line are generated using either CSET operators :py:mod:`CSET.operators.plot.plot_histogram_series`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_histogram_series.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Use ``SEQUENCE="realization"`` to generate one histogram for all times. +- Use ``SEQUENCE="time"`` for a histogram at each output time. +- Example to generate full domain histogram of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_histogram_series + cset bake -i "input_data_path" ["input_data_path2" "input_data_path3" "..."] -o "my_output_path" + -r generic_surface_histogram_series.yaml + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" "my_model_label2" "my_model_label3" "..." + --SEQUENCE="realization" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel. +- Set ``HISTOGRAM_SURFACE_FIELD_SEQUENCE=False`` to generate one histogram for all times. +- Set ``HISTOGRAM_SURFACE_FIELD_SEQUENCE=True`` for a histogram at each output time. + +:: + + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + HISTOGRAM_SURFACE_FIELD = True + HISTOGRAM_SURFACE_FIELD_SEQUENCE = False + + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_paths = "../../../../../../tests/test_data/air_temperature_global.nc" + +# Read selected variable(s) of interest +cubes = cset_read.read_cubes(file_paths, ["temperature_at_screen_level"]) + +# Plot domain histogram +cset_plot.plot_histogram_series(cubes, sequence_coordinate="realization") diff --git a/docs/source/reference/cset_gallery/examples/line/plot_line_power_spectra.py b/docs/source/reference/cset_gallery/examples/line/plot_line_power_spectra.py new file mode 100644 index 000000000..5dd21c493 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/line/plot_line_power_spectra.py @@ -0,0 +1,69 @@ +""" +Power spectra plot +================== + +Generate power spectra of region-averaged field. + +Line are generated using either CSET operators :py:mod:`CSET.operators.plot.plot_line_series`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_power_spectrum_series.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Use ``SINGLE_PLOT=True`` to generate one plot for all times. +- Use ``SINGLE_PLOT=False`` for a plot at each output time. +- Example to generate full-domain power spectra of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_domain_mean_time_series + cset bake -i "input_data_path" ["input_data_path2" "input_data_path3" "..."] -o "my_output_path" + -r generic_surface_domain_mean_time_series + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" "my_model_label2" "my_model_label3" "..." + --SINGLE_PLOT="True" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel. +- Set ``SPECTRUM_SURFACE_FIELD_SEQUENCE=False`` to generate spectrum for all times. +- Set ``SPECTRUM_SURFACE_FIELD_SEQUENCE=True`` for spectrum at each output time. + +:: + + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + SPECTRUM_SURFACE_FIELD = True + SPECTRUM_SURFACE_FIELD_SEQUENCE = False + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.power_spectrum as cset_spectra +import CSET.operators.read as cset_read + +# Set path to input data +file_paths = "../../../../../../tests/test_data/air_temperature_global.nc" + +# Read selected variable(s) of interest +cubes = cset_read.read_cubes(file_paths, ["temperature_at_screen_level"]) + +# Compute domain power spectrum +spectra = cset_spectra.calculate_power_spectrum(cubes) + +# Plot power spectrum as line plot +cset_plot.plot_line_series( + spectra, series_coordinate="physical_wavenumber", single_plot=True +) diff --git a/docs/source/reference/cset_gallery/examples/line/plot_line_timeseries.py b/docs/source/reference/cset_gallery/examples/line/plot_line_timeseries.py new file mode 100644 index 000000000..40f695d6b --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/line/plot_line_timeseries.py @@ -0,0 +1,68 @@ +""" +Time series plot +================ + +Generate time series of region-averaged field. + +Line are generated using either CSET operators :py:mod:`CSET.operators.plot.plot_line_series`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_domain_mean_time_series.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Example to generate full-domain spatial maps of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_domain_mean_time_series + cset -v bake -i "input_data_path" ["input_data_path2" "input_data_path3" "..."] -o "my_output_path" + -r generic_surface_domain_mean_time_series.yaml + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" "my_model_label2" "my_model_label3" "..." + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel: + +:: + + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + TIMESERIES_SURFACE_FIELD = True + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.collapse as cset_collapse +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_paths = [ + "../../../../../../tests/test_data/long_forecast_air_temp_fcst_1.nc", + "../../../../../../tests/test_data/long_forecast_air_temp_fcst_a.nc", +] + +# Read selected variable(s) of interest +cubes = cset_read.read_cubes( + file_paths, ["temperature_at_screen_level"], model_names=["model_1", "model_a"] +) + +# Collapse input data over selected dimensions +collapsed_cubes = cset_collapse.collapse( + cubes, ["grid_latitude", "grid_longitude"], "MEAN" +) + +# Plot domain mean time series +cset_plot.plot_line_series(collapsed_cubes) diff --git a/docs/source/reference/cset_gallery/examples/line/plot_line_vertical.py b/docs/source/reference/cset_gallery/examples/line/plot_line_vertical.py new file mode 100644 index 000000000..07bdf9020 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/line/plot_line_vertical.py @@ -0,0 +1,63 @@ +""" +Vertical profile plot +===================== + +Generate vertical profile of region-averaged field. + +Line are generated using either CSET operators :py:mod:`CSET.operators.plot.plot_vertical_line_series`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_level_domain_mean_vertical_profile_series.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Example to generate domain mean vertical profiles of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_level_domain_mean_vertical_profile_series + cset -v bake -i "input_data_path" ["input_data_path2" "input_data_path3" "..."] -o "my_output_path" + -r generic_level_domain_mean_vertical_profile_series + --VARNAME="air_temperature" + --MODEL_NAME="my_model_label" "my_model_label2" "my_model_label3" "..." + --LEVELTYPE="pressure" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel: + +:: + + PRESSURE_LEVEL_FIELDS = ['air_temperature', , ...] + PRESSURE_LEVELS = ['1000','850', , ...] + PROFILE_PLEVEL = True + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.collapse as cset_collapse +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_paths = "../../../../../../tests/test_data/transect_out_umpl.nc" + +# Read selected variable(s) of interest +cubes = cset_read.read_cubes(file_paths, ["air_temperature"]) + +# Collapse input data over selected dimensions +collapsed_cubes = cset_collapse.collapse(cubes, ["longitude", "time"], "MEAN") + +# Plot domain mean time series +cset_plot.plot_vertical_line_series(collapsed_cubes, series_coordinate="pressure") diff --git a/docs/source/reference/cset_gallery/examples/spatial/README.rst b/docs/source/reference/cset_gallery/examples/spatial/README.rst new file mode 100644 index 000000000..702349758 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/spatial/README.rst @@ -0,0 +1,4 @@ +.. orphan + +Spatial plots +============= diff --git a/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial.py b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial.py new file mode 100644 index 000000000..4967b9465 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial.py @@ -0,0 +1,58 @@ +""" +Regional spatial plot +===================== + +Generate spatial map of a 2D field (regional data example). + +Spatial maps are generated using either CSET operators :py:mod:`CSET.operators.plot.spatial_pcolormesh_plot` or :py:mod:`CSET.operators.plot.spatial_contour_plot`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_spatial_plot_sequence.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Example to generate full-domain spatial maps of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_spatial_plot_sequence + cset bake -i "input_data_path" -o "my_output_path" + -r generic_surface_spatial_plot_sequence + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" + --METHOD="" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel: + +:: + + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + SPATIAL_SURFACE_FIELD = True + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_path = "../../../../../../tests/test_data/air_temp.nc" + +# Read selected variable(s) of interest +cube = cset_read.read_cubes(file_path, ["temperature_at_screen_level"])[0] + +# Plot single example frame (final time output only, using spatial_contour_plot) +cset_plot.spatial_contour_plot(cube[-1]) diff --git a/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_difference.py b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_difference.py new file mode 100644 index 000000000..f1a756b9b --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_difference.py @@ -0,0 +1,75 @@ +""" +Spatial difference plot +======================= + +Generate spatial map of a 2D field difference (regional data example). + +Differences are calculated using the CSET operator :py:mod:`CSET.operators.misc.difference`. +Spatial maps are generated using either CSET operators :py:mod:`CSET.operators.plot.spatial_pcolormesh_plot` or :py:mod:`CSET.operators.plot.spatial_contour_plot`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_spatial_difference.yaml`` + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Example to generate full-domain spatial maps of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_spatial_difference + cset bake -i "input_data_path_1" "input_data_path_2" -o "my_output_path" + -r generic_surface_spatial_difference + --VARNAME="air_temperature" + --BASE_MODEL="Model 1" + --OTHER_MODEL="Model 2" + --MODEL_NAME="my_model_label" + --METHOD="" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel: + +:: + + SURFACE_FIELDS = ['air_temperature', , ...] + SPATIAL_DIFFERENCE_SURFACE_FIELD = True + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.constraints as cset_constrain +import CSET.operators.misc as cset_misc +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_path = [ + "/home/users/mike.bush/repos/CSET/tests/test_data/air_temp.nc", + "/home/users/mike.bush/repos/CSET//tests/test_data/air_temp_a.nc", +] + +# Generating constraints that Iris can understand that can be used later in the code +constraint_nomethods = cset_constrain.generate_cell_methods_constraint([]) +constraint_var = cset_constrain.generate_var_constraint("air_temperature") +both_constraints = cset_constrain.combine_constraints( + constraint=constraint_nomethods, additional_constraint_1=constraint_var +) + +# Read selected variable(s) of interest +cubes = cset_read.read_cubes(file_path, constraint=both_constraints) + +# +diff = cset_misc.difference(cubes) + +# Plot single example frame (final time output only, using spatial_contour_plot) +cset_plot.spatial_contour_plot(diff[-1]) diff --git a/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_global.py b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_global.py new file mode 100644 index 000000000..ffedff952 --- /dev/null +++ b/docs/source/reference/cset_gallery/examples/spatial/plot_surface_spatial_global.py @@ -0,0 +1,58 @@ +""" +Global spatial plot +=================== + +Generate spatial map of a 2D field (global data example). + +Spatial maps are generated using either CSET operators :py:mod:`CSET.operators.plot.spatial_pcolormesh_plot` or :py:mod:`CSET.operators.plot.spatial_contour_plot`. + +General functionality is provided using :doc:`CSET recipe ` ``generic_surface_spatial_plot_sequence.yaml``. + + +A) Using *cset bake* on the command line +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Access recipe file using ``cset cookbook``. +- Set required recipe inputs on command-line (or as environment variables for greater flexibility). +- Example to generate full-domain spatial maps of ``VARNAME`` for all output times: + +.. code-block:: + + cset cookbook generic_surface_spatial_plot_sequence + cset bake -i "input_data_path" -o "my_output_path" + -r generic_surface_spatial_plot_sequence + --VARNAME="temperature_at_screen_level" + --MODEL_NAME="my_model_label" + --METHOD="" + --SUBAREA_TYPE='None' --SUBAREA_EXTENT='None' --SUBAREA_NAME='None' + [-s STYLE_FILE] [--plot-resolution PLOT_RESOLUTION] [--skip-write] + + +B) Configuring the *cset_workflow* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Update workflow configuration settings via ``rose edit`` GUI or in ``rose-suite.conf`` file. +- Complete ``General setup options`` and ``Cycling and Model options`` details - see :doc:`/usage/workflow-configure`. +- Set required configuration options on ``Diagnostics / Surface (2D) fields`` panel: + +:: + + SURFACE_FIELDS = ['temperature_at_screen_level', , ...] + SPATIAL_SURFACE_FIELD = True + + +C) Example python code +^^^^^^^^^^^^^^^^^^^^^^ +""" + +import CSET.operators.plot as cset_plot +import CSET.operators.read as cset_read + +# Set path to input data +file_path = "../../../../../../tests/test_data/air_temperature_global.nc" + +# Read selected variable(s) of interest +cube = cset_read.read_cube(file_path, ["temperature_at_screen_level"]) + +# Plot single example frame using spatial_pcolormesh_plot +cset_plot.spatial_pcolormesh_plot(cube) diff --git a/docs/source/reference/cset_gallery/index.rst b/docs/source/reference/cset_gallery/index.rst new file mode 100644 index 000000000..898800ffb --- /dev/null +++ b/docs/source/reference/cset_gallery/index.rst @@ -0,0 +1,16 @@ +:orphan: + + +CSET Gallery +============ + +This gallery demonstrates example CSET functionality. + +The gallery is divided into sections as described below. All entries show the code used to produce the example plot. Additionally there are links to download the code directly as source or as part of a jupyter notebook, these links are at the bottom of the page. + +Examples use test_data provided with CSET release. + +.. toctree:: + :maxdepth: 1 + + generated/index diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst index 642b8314c..e63eae3f5 100644 --- a/docs/source/reference/index.rst +++ b/docs/source/reference/index.rst @@ -8,6 +8,7 @@ components. :maxdepth: 1 glossary + cset_gallery/index cli recipe-format operators diff --git a/pyproject.toml b/pyproject.toml index 4e169090c..4a967eb74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,7 @@ src = ["src", "test"] [tool.ruff.lint] extend-select = ["B", "D", "I"] +per-file-ignores = {"docs/source/reference/cset_gallery/examples/**/*.py" = ["D"]} [tool.ruff.lint.pydocstyle] convention = "numpy" diff --git a/src/CSET/operators/plot.py b/src/CSET/operators/plot.py index a8a72a51e..31ca8b647 100644 --- a/src/CSET/operators/plot.py +++ b/src/CSET/operators/plot.py @@ -21,6 +21,7 @@ import logging import math import os +import sys from typing import Literal import cartopy.crs as ccrs @@ -74,6 +75,11 @@ ############################ +def in_sphinx_gallery(): + """Test if running plot code in sphinx-gallery context.""" + return "sphinx_gallery" in sys.modules + + def _append_to_plot_index(plot_index: list) -> list: """Add plots into the plot index, returning the complete plot index.""" with open("meta.json", "r+t", encoding="UTF-8") as fp: @@ -773,9 +779,10 @@ def _plot_and_save_spatial_plot( logging.debug("Set colorbar ticks and labels.") # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved spatial plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved spatial plot to %s", filename) + plt.close(fig) def _plot_and_save_postage_stamp_spatial_plot( @@ -898,10 +905,10 @@ def _plot_and_save_postage_stamp_spatial_plot( # Overall figure title. fig.suptitle(title, fontsize=16) - - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved contour postage stamp plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved contour postage stamp plot to %s", filename) + plt.close(fig) def _plot_and_save_line_series( @@ -1015,9 +1022,10 @@ def _plot_and_save_line_series( ax.legend(handles=handles, loc="best", ncol=1, frameon=True, fontsize=16) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved line plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved line plot to %s", filename) + plt.close(fig) def _plot_and_save_line_power_spectrum_series( @@ -1140,9 +1148,10 @@ def _plot_and_save_line_power_spectrum_series( ax.legend(handles=handles, loc="best", ncol=1, frameon=True, fontsize=16) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved line plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved line plot to %s", filename) + plt.close(fig) def _plot_and_save_vertical_line_series( @@ -1282,9 +1291,10 @@ def _plot_and_save_vertical_line_series( ax.legend(handles=handles, loc="best", ncol=1, frameon=True, fontsize=16) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved line plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved line plot to %s", filename) + plt.close(fig) def _plot_and_save_scatter_plot( @@ -1356,9 +1366,10 @@ def _plot_and_save_scatter_plot( ax.autoscale() # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved scatter plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved scatter plot to %s", filename) + plt.close(fig) def _plot_and_save_vector_plot( @@ -1469,9 +1480,10 @@ def _plot_and_save_vector_plot( iplt.quiver(cube_u[::step, ::step], cube_v[::step, ::step], pivot="middle") # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved vector plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved vector plot to %s", filename) + plt.close(fig) def _plot_and_save_histogram_series( @@ -1591,9 +1603,10 @@ def _plot_and_save_histogram_series( ax.legend(loc="best", ncol=1, frameon=True, fontsize=16) # Save plot. - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved histogram plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved histogram plot to %s", filename) + plt.close(fig) def _plot_and_save_postage_stamp_histogram_series( @@ -1650,10 +1663,10 @@ def _plot_and_save_postage_stamp_histogram_series( # Overall figure title. fig.suptitle(title, fontsize=16) - - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved histogram postage stamp plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved histogram postage stamp plot to %s", filename) + plt.close(fig) def _plot_and_save_postage_stamps_in_single_plot_histogram_series( @@ -1926,7 +1939,7 @@ def spatial_multi_pcolormesh_plot( overlay_cube: iris.cube.Cube | None = None, contour_cube: iris.cube.Cube | None = None, point_cube: iris.cube.Cube | None = None, - filename: str = None, + filename: str | None = None, sequence_coordinate: str = "time", stamp_coordinate: str = "realization", **kwargs, @@ -2945,7 +2958,7 @@ def _plot_and_save_postage_stamp_power_spectrum_series( stamp_coordinate: str, filename: str, title: str, - series_coordinate: str = None, + series_coordinate: str | None = None, **kwargs, ): """Plot and save postage (ensemble members) stamps for a power spectrum series. @@ -3065,9 +3078,10 @@ def _plot_and_save_postage_stamp_power_spectrum_series( ax = plt.gca() ax.set_title(f"Member #{member.coord(stamp_coordinate).points[0]}") - fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - logging.info("Saved histogram postage stamp plot to %s", filename) - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved power spectrum histogram plot to %s", filename) + plt.close(fig) def _plot_and_save_postage_stamps_in_single_plot_power_spectrum_series( @@ -3196,7 +3210,7 @@ def _plot_and_save_postage_stamps_in_single_plot_power_spectrum_series( ax.set_title(title, fontsize=16) # Save the figure to a file - plt.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) - - # Close the figure - plt.close(fig) + if not in_sphinx_gallery(): + fig.savefig(filename, bbox_inches="tight", dpi=_get_plot_resolution()) + logging.info("Saved power spectrum plot to %s", filename) + plt.close(fig) diff --git a/tests/conftest.py b/tests/conftest.py index 88c704a8e..1832855b0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -325,7 +325,7 @@ def long_forecast_multi_day(long_forecast_multi_day_read_only): def long_forecast_many_cubes_read_only(): """Get long_forecast_may_cubes to run tests on. It is NOT safe to modify.""" return read.read_cubes( - "tests/test_data/long_forecast_air_temp_fcst_*.nc", "air_temperature" + "tests/test_data/long_forecast_air_temp_fcst_[123].nc", "air_temperature" ) diff --git a/tests/test_data/air_temp_a.nc b/tests/test_data/air_temp_a.nc new file mode 100644 index 000000000..3b22c4739 Binary files /dev/null and b/tests/test_data/air_temp_a.nc differ diff --git a/tests/test_data/long_forecast_air_temp_fcst_a.nc b/tests/test_data/long_forecast_air_temp_fcst_a.nc new file mode 100644 index 000000000..2ff9846d4 Binary files /dev/null and b/tests/test_data/long_forecast_air_temp_fcst_a.nc differ