diff --git a/esmvaltool/diag_scripts/seaice/seaice_sensitivity.py b/esmvaltool/diag_scripts/seaice/seaice_sensitivity.py index 9f1c0c41d3..6b3b1053e6 100644 --- a/esmvaltool/diag_scripts/seaice/seaice_sensitivity.py +++ b/esmvaltool/diag_scripts/seaice/seaice_sensitivity.py @@ -6,6 +6,7 @@ import iris import matplotlib.pyplot as plt import pandas as pd +import yaml from matplotlib.colors import Normalize from scipy import stats @@ -37,13 +38,24 @@ def get_provenance_record(cfg, caption): return record -def list_datasets(data): - """Actually returns a set of datatsets, to avoid duplication.""" - logger.debug("listing datasets") - datasets = set() +def create_categorised_dataset_dict(data): + """Create a dictionary of datasets categorised into models and observations.""" + logger.debug("Creating categorised dataset dictionary from %s", data) + # Initialise blank dictionary + dict = { + 'models': {}, + 'observations': {}, + } + + # Iterate over the data for element in data: - datasets.add(element["dataset"]) - return datasets + if 'observation' in element: + if element['observation']: + dict['observations'][element['dataset']] = {} + else: + dict['models'][element['dataset']] = {} + + return dict def extract_cube(data, variable_group): @@ -142,28 +154,6 @@ def write_obs_from_cfg(cfg): obs_dict["notz_style"]["std_dev"] = notz_values["standard deviation"] obs_dict["notz_style"]["plausible"] = notz_values["plausible range"] - # Add a blank dictionary for the Roach-style plot - obs_dict["roach_style"] = {} - - # Add each observation point to the dictionary - roach_values = cfg["observations"]["annual trends (Roach-style plot)"] - for point in roach_values.keys(): - obs_dict["roach_style"][point] = {} - - # Add the individual values for the observation point - obs_dict["roach_style"][point]["annual_tas_trend"] = roach_values[ - point - ]["GMST trend"] - obs_dict["roach_style"][point]["annual_siconc_trend"] = roach_values[ - point - ]["SIA trend"] - obs_dict["roach_style"][point]["r_value"] = roach_values[point][ - "Pearson CC of SIA over GMST" - ] - obs_dict["roach_style"][point]["p_value"] = roach_values[point][ - "significance of SIA over GMST" - ] - return obs_dict @@ -208,7 +198,7 @@ def write_dictionary_to_csv(cfg, model_dict, filename): csv_filepath = f"{cfg['work_dir']}/{filename}.csv" # Write the data to a csv file (via a Pandas DataFrame) - pd.DataFrame.from_dict(model_dict, orient="index").to_csv(csv_filepath) + pd.DataFrame.from_dict(model_dict, orient="index").to_csv(csv_filepath, index_label="Dataset") logger.info("Wrote data to %s", csv_filepath) # Create a provenance record for the csv file @@ -349,54 +339,36 @@ def roach_style_plot_from_dict(data_dictionary, titles_dictionary, cfg): if inner_dict["label"] == "to_label": plt.annotate(dataset, xy=(x, y), xytext=(x + 0.01, y - 0.005)) - # Read from observations dictionary - obs_years = titles_dictionary["obs"]["obs_period"] - obs_dict = titles_dictionary["obs"]["roach_style"] - - # Add the observations - for point in obs_dict.keys(): - # Get the values for the point - x = obs_dict[point]["annual_tas_trend"] - y = obs_dict[point]["annual_siconc_trend"] - r_corr = obs_dict[point]["r_value"] - p_val = obs_dict[point]["p_value"] - - # Provide a default colour for the point if Pearson coefficient is missing - if r_corr is None: - r_corr = 0 - - # Provide a pattern for the point if the p-value is present and sufficiently large - if p_val is not None and p_val >= 0.05: - h = 5 * "/" # This is a hatch pattern - else: - h = None - - # Plot the point only if both x and y values are provided - if x is not None and y is not None: - plt.scatter( - x, - y, - marker="s", - s=150, - c=[r_corr], - hatch=h, - cmap=cmap, - norm=norm, - zorder=0, - edgecolors="black", - ) + # # Provide a default colour for the point if Pearson coefficient is missing + # if r_corr is None: + # r_corr = 0 + # + # # Provide a pattern for the point if the p-value is present and sufficiently large + # if p_val is not None and p_val >= 0.05: + # h = 5 * "/" # This is a hatch pattern + # else: + # h = None + # + # # Plot the point only if both x and y values are provided + # if x is not None and y is not None: + # plt.scatter( + # x, + # y, + # marker="s", + # s=150, + # c=[r_corr], + # hatch=h, + # cmap=cmap, + # norm=norm, + # zorder=0, + # edgecolors="black", + # ) # Add a colour bar plt.colorbar(label="Pearson correlation coefficient") - # Create caption based on whether observational temp trend is present - if obs_dict["first point"]["annual_tas_trend"] is not None: - caption = ( - "Decadal trends of sea ice area and global mean temperature." - f"Observations from {obs_years} are plotted as squares." - ) - else: - caption = "Decadal trends of sea ice area and global mean temperature." + # Create caption + caption = "Decadal trends of sea ice area and global mean temperature." # Save the figure (also closes it) save_figure( @@ -419,22 +391,18 @@ def main(cfg): titles_and_obs_dict = create_titles_dict(input_data, cfg) logger.debug("Titles and observations dictionary: %s", titles_and_obs_dict) - # Initialize blank data dictionary to send to plotting codes later - data_dict = {} - # Get list of datasets from cfg logger.info("Listing datasets in the data") - datasets = list_datasets(input_data) + dataset_dict = create_categorised_dataset_dict(input_data) + data_dict = dataset_dict['models'] + # Iterate over each dataset - for dataset in datasets: + for dataset in data_dict.keys(): # Select only data from that dataset logger.debug("Selecting data from %s", dataset) selection = select_metadata(input_data, dataset=dataset) - # Add the dataset to the dictionary with a blank inner dictionary - data_dict[dataset] = {} - # Add an entry to determine labelling in plots if "label_dataset" in selection[0]: data_dict[dataset]["label"] = "to_label" diff --git a/esmvaltool/recipes/recipe_seaice_sensitivity.yml b/esmvaltool/recipes/recipe_seaice_sensitivity.yml index b64191b41c..1a232805b0 100644 --- a/esmvaltool/recipes/recipe_seaice_sensitivity.yml +++ b/esmvaltool/recipes/recipe_seaice_sensitivity.yml @@ -21,24 +21,33 @@ documentation: maintainer: - parsons_naomi -defaults: &defaults {ensemble: r1i1p1f1, exp: historical, grid: gn, project: CMIP6} -datasets: - - {<<: *defaults, dataset: HadGEM3-GC31-LL, institute: MOHC, ensemble: r1i1p1f3, label_dataset: True} - - {<<: *defaults, dataset: UKESM1-0-LL, institute: MOHC, ensemble: r1i1p1f2, label_dataset: True} - - {<<: *defaults, dataset: ACCESS-CM2, institute: CSIRO-ARCCSS} - - {<<: *defaults, dataset: ACCESS-ESM1-5, institute: CSIRO} - - {<<: *defaults, dataset: BCC-CSM2-MR, institute: BCC} - - {<<: *defaults, dataset: CAMS-CSM1-0, institute: CAMS} - - {<<: *defaults, dataset: CanESM5, institute: CCCma} - - {<<: *defaults, dataset: CESM2, institute: NCAR} - - {<<: *defaults, dataset: CESM2-WACCM, institute: NCAR} - - {<<: *defaults, dataset: CESM2-WACCM-FV2, institute: NCAR} - - {<<: *defaults, dataset: FIO-ESM-2-0, institute: FIO-QLNM} - - {<<: *defaults, dataset: MIROC6, institute: MIROC} - - {<<: *defaults, dataset: MPI-ESM-1-2-HAM, institute: HAMMOZ-Consortium} - - {<<: *defaults, dataset: MPI-ESM1-2-HR, institute: MPI-M} - - {<<: *defaults, dataset: MPI-ESM1-2-LR, institute: MPI-M} - - {<<: *defaults, dataset: MRI-ESM2-0, institute: MRI} +model_defaults: &model_defaults { ensemble: r1i1p1f1, exp: historical, grid: gn, project: CMIP6} +model_datasets: &model_datasets + - {<<: *model_defaults, dataset: HadGEM3-GC31-LL, institute: MOHC, ensemble: r1i1p1f3, label_dataset: True} + - {<<: *model_defaults, dataset: UKESM1-0-LL, institute: MOHC, ensemble: r1i1p1f2, label_dataset: True} + - {<<: *model_defaults, dataset: ACCESS-CM2, institute: CSIRO-ARCCSS} + - {<<: *model_defaults, dataset: ACCESS-ESM1-5, institute: CSIRO} + - {<<: *model_defaults, dataset: BCC-CSM2-MR, institute: BCC} + - {<<: *model_defaults, dataset: CAMS-CSM1-0, institute: CAMS} + - {<<: *model_defaults, dataset: CanESM5, institute: CCCma} + - {<<: *model_defaults, dataset: CESM2, institute: NCAR} + - {<<: *model_defaults, dataset: CESM2-WACCM, institute: NCAR} + - {<<: *model_defaults, dataset: CESM2-WACCM-FV2, institute: NCAR} + - {<<: *model_defaults, dataset: FIO-ESM-2-0, institute: FIO-QLNM} + - {<<: *model_defaults, dataset: MIROC6, institute: MIROC} + - {<<: *model_defaults, dataset: MPI-ESM-1-2-HAM, institute: HAMMOZ-Consortium} + - {<<: *model_defaults, dataset: MPI-ESM1-2-HR, institute: MPI-M} + - {<<: *model_defaults, dataset: MPI-ESM1-2-LR, institute: MPI-M} + - {<<: *model_defaults, dataset: MRI-ESM2-0, institute: MRI} + +obs_defaults: &obs_defaults { project: OBS, observation: True, tier: 2} +tasa_obs: &tasa_obs + - { <<: *obs_defaults, dataset: GISTEMP, type: ground, version: v4 } + - { <<: *obs_defaults, dataset: HadCRUT5, type: ground, version: 5.0.1.0-analysis } + - { <<: *obs_defaults, dataset: NOAAGlobalTemp, type: ground, version: v5.0.0, mip: Amon } + +arctic_si_obs: &arctic_si_obs + - { <<: *obs_defaults, dataset: OSI-450-nh, type: reanaly, version: v3, mip: OImon, supplementary_variables: [{short_name: areacello, mip: fx}]} preprocessors: extract_test_period: @@ -112,9 +121,24 @@ diagnostics: siconc: preprocessor: pp_arctic_sept_sea_ice mip: SImon + additional_datasets: + *model_datasets tas: preprocessor: pp_avg_ann_global_temp mip: Amon + additional_datasets: + *model_datasets + si_obs: + short_name: siconc + preprocessor: pp_arctic_sept_sea_ice + additional_datasets: + *arctic_si_obs + tasa_obs: + short_name: tasa + preprocessor: pp_avg_ann_global_temp + mip: Amon + additional_datasets: + *tasa_obs scripts: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py @@ -124,22 +148,6 @@ diagnostics: mean: -4.01 standard deviation: 0.32 plausible range: 1.28 - annual trends (Roach-style plot): - first point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: - second point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: - third point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: antarctic: @@ -148,9 +156,24 @@ diagnostics: siconc: preprocessor: pp_antarctic_avg_ann_sea_ice mip: SImon + additional_datasets: + *model_datasets tas: preprocessor: pp_avg_ann_global_temp mip: Amon + additional_datasets: + *model_datasets +# si_obs: +# short_name: siconc +# preprocessor: pp_antarctic_avg_ann_sea_ice +# additional_datasets: +# *antarctic_si_obs + tasa_obs: + short_name: tasa + preprocessor: pp_avg_ann_global_temp + mip: Amon + additional_datasets: + *tasa_obs scripts: sea_ice_sensitivity_script: script: seaice/seaice_sensitivity.py @@ -160,19 +183,3 @@ diagnostics: mean: standard deviation: plausible range: - annual trends (Roach-style plot): - first point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: - second point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: - third point: - GMST trend: - SIA trend: - Pearson CC of SIA over GMST: - significance of SIA over GMST: