From 3b257b005e863b35c5e4fc6dc4d6fb83b985da14 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Tue, 23 Mar 2021 15:36:23 +0100 Subject: [PATCH] [projection swe] modify interval (and data constraint) for temperature sensitivity. add invidual plots in sensitivity. add changes plot in sensitivity. --- .../adamont_data/cmip5/plot_temperatures.py | 2 +- .../adamont_data/cmip5/temperature_to_year.py | 19 ++-- .../ensemble_fit/abstract_ensemble_fit.py | 2 +- .../visualizer_for_projection_ensemble.py | 6 +- .../visualizer_for_sensitivity.py | 89 ++++++++++++++----- .../discussion/main_sensitivity.py | 15 ++-- .../results/main_projections_ensemble.py | 2 +- 7 files changed, 93 insertions(+), 42 deletions(-) diff --git a/extreme_data/meteo_france_data/adamont_data/cmip5/plot_temperatures.py b/extreme_data/meteo_france_data/adamont_data/cmip5/plot_temperatures.py index e8007d1b..2c68e0c8 100644 --- a/extreme_data/meteo_france_data/adamont_data/cmip5/plot_temperatures.py +++ b/extreme_data/meteo_france_data/adamont_data/cmip5/plot_temperatures.py @@ -88,6 +88,6 @@ def plot_temperature_for_rcp_gcm(ax, gcm, scenario, year_min, year_max, linestyl if __name__ == '__main__': - for anomaly in [True, False][:]: + for anomaly in [True, False][:1]: main_plot_temperature_with_spline_on_top(anomaly=anomaly) # main_plot_temperature_all(anomaly=True, spline=True) diff --git a/extreme_data/meteo_france_data/adamont_data/cmip5/temperature_to_year.py b/extreme_data/meteo_france_data/adamont_data/cmip5/temperature_to_year.py index 6453d9f0..86c4b975 100644 --- a/extreme_data/meteo_france_data/adamont_data/cmip5/temperature_to_year.py +++ b/extreme_data/meteo_france_data/adamont_data/cmip5/temperature_to_year.py @@ -18,8 +18,8 @@ def get_year_min_and_year_max(gcm, scenario, left_limit, right_limit, is_tempera else: year_min, year_max = left_limit, right_limit - # A minimum of 30 years of data is needed to find a trend - if year_max - year_min + 1 >= 30: + # A minimum of 10 years of data is needed for each GCM/RCM + if year_max - year_min + 1 >= 10: return year_min, year_max else: return None, None @@ -70,10 +70,11 @@ def plot_nb_data(is_temperature_interval, is_shift_interval): ax = plt.gca() for gcm in get_gcm_list(adamont_version=2)[:]: for i, scenario in enumerate(rcp_scenarios[2:]): + first_scenario = i == 0 plot_nb_data_one_line(ax, gcm, scenario, left_limit, right_limit, - i == 0, is_temperature_interval) + first_scenario, is_temperature_interval) - ax.legend() + ax.legend(loc='upper left') ticks_labels = get_ticks_labels_for_interval(is_temperature_interval, is_shift_interval) ax.set_xticks(right_limit) ax.set_xticklabels(ticks_labels) @@ -84,15 +85,15 @@ def plot_nb_data(is_temperature_interval, is_shift_interval): Line2D([0], [0], color='k', lw=1, label=scenario_to_str(s), linestyle=get_linestyle_from_scenario(s)) for s in adamont_scenarios_real ] - ax2.legend(handles=legend_elements, loc='upper center') + ax2.legend(handles=legend_elements, loc='lower right') ax2.set_yticks([]) plt.show() def get_interval_limits(is_temperature_interval, is_shift_interval): if is_temperature_interval: - temp_min = np.arange(0, 3, 1) - temp_max = temp_min + 2 + temp_min = np.arange(0, 2, 0.5) + temp_max = temp_min + 1.5 left_limit, right_limit = temp_min, temp_max else: shift = 25 @@ -103,7 +104,7 @@ def get_interval_limits(is_temperature_interval, is_shift_interval): if not is_shift_interval: min_interval_left = min(left_limit) left_limit = [min_interval_left for _ in right_limit] - return left_limit, right_limit + return left_limit[:2], right_limit[:2] def get_ticks_labels_for_interval(is_temperature_interval, is_shift_interval): @@ -117,7 +118,7 @@ def get_ticks_labels_for_interval(is_temperature_interval, is_shift_interval): if __name__ == '__main__': - for shift_interval in [False, True]: + for shift_interval in [False, True][:1]: for temp_interval in [False, True][1:]: print("shift = {}, temp_inteval = {}".format(shift_interval, temp_interval)) plot_nb_data(is_temperature_interval=temp_interval, is_shift_interval=shift_interval) diff --git a/extreme_trend/ensemble_fit/abstract_ensemble_fit.py b/extreme_trend/ensemble_fit/abstract_ensemble_fit.py index 115b0700..b9348041 100644 --- a/extreme_trend/ensemble_fit/abstract_ensemble_fit.py +++ b/extreme_trend/ensemble_fit/abstract_ensemble_fit.py @@ -29,7 +29,7 @@ class AbstractEnsembleFit(object): # Set appropriate setting OneFoldFit.last_year = 2100 - OneFoldFit.nb_years = 95 + OneFoldFit.nb_years = OneFoldFit.last_year - 2005 @property def altitudes(self): diff --git a/extreme_trend/ensemble_fit/visualizer_for_projection_ensemble.py b/extreme_trend/ensemble_fit/visualizer_for_projection_ensemble.py index a75e81b0..70ba3371 100644 --- a/extreme_trend/ensemble_fit/visualizer_for_projection_ensemble.py +++ b/extreme_trend/ensemble_fit/visualizer_for_projection_ensemble.py @@ -31,7 +31,9 @@ class VisualizerForProjectionEnsemble(object): confidence_interval_based_on_delta_method=False, remove_physically_implausible_models=False, gcm_to_year_min_and_year_max=None, + interval_str_prefix='', ): + self.interval_str_prefix = interval_str_prefix self.altitudes_list = altitudes_list self.temporal_covariate_for_fit = temporal_covariate_for_fit self.scenario = scenario @@ -119,14 +121,14 @@ class VisualizerForProjectionEnsemble(object): ] if key in merge_keys: for v in visualizer_list: - v.studies.study.gcm_rcm_couple = (key, "merge") + v.studies.study.gcm_rcm_couple = ("{} {}".format(key, "merge"), self.interval_str_prefix) self.plot_for_visualizer_list(visualizer_list) def plot_together(self): visualizer_list = [together_ensemble_fit.visualizer for together_ensemble_fit in self.ensemble_fits(TogetherEnsembleFit)] for v in visualizer_list: - v.studies.study.gcm_rcm_couple = ("together", "merge") + v.studies.study.gcm_rcm_couple = ("together merge", self.interval_str_prefix) self.plot_for_visualizer_list(visualizer_list) def ensemble_fits(self, ensemble_class): diff --git a/extreme_trend/ensemble_fit/visualizer_for_sensitivity.py b/extreme_trend/ensemble_fit/visualizer_for_sensitivity.py index bd696188..453e8ece 100644 --- a/extreme_trend/ensemble_fit/visualizer_for_sensitivity.py +++ b/extreme_trend/ensemble_fit/visualizer_for_sensitivity.py @@ -2,6 +2,8 @@ from collections import OrderedDict import matplotlib.pyplot as plt from typing import List, Dict +import numpy as np + from extreme_data.meteo_france_data.adamont_data.cmip5.temperature_to_year import get_interval_limits, \ get_year_min_and_year_max, get_ticks_labels_for_interval from extreme_data.meteo_france_data.scm_models_data.utils import Season @@ -40,11 +42,14 @@ class VisualizerForSensivity(object): self.massif_names = massif_names self.left_limits, self.right_limits = get_interval_limits(self.is_temperature_interval, self.is_shift_interval) + self.left_limit_to_right_limit = OrderedDict(zip(self.left_limits, self.right_limits)) self.right_limit_to_visualizer = {} # type: Dict[float, VisualizerForProjectionEnsemble] for left_limit, right_limit in zip(self.left_limits, self.right_limits): - print("Interval is", left_limit, right_limit) + interval_str_prefix = "{}-{}".format(left_limit, right_limit) + interval_str_prefix = interval_str_prefix.replace('.', ',') + print("Interval is", interval_str_prefix) # Build gcm_to_year_min_and_year_max gcm_to_year_min_and_year_max = {} gcm_list = list(set([g for g, r in gcm_rcm_couples])) @@ -64,29 +69,61 @@ class VisualizerForSensivity(object): massif_names=massif_names, temporal_covariate_for_fit=temporal_covariate_for_fit, remove_physically_implausible_models=remove_physically_implausible_models, - gcm_to_year_min_and_year_max=gcm_to_year_min_and_year_max + gcm_to_year_min_and_year_max=gcm_to_year_min_and_year_max, + interval_str_prefix=interval_str_prefix, ) self.right_limit_to_visualizer[right_limit] = visualizer def plot(self): - # todo: before reactivating the subplot, i should ensure that we can modify the prefix - # todo: so that we can have all the subplot for the merge visualizer - # , and not just the plots for the last t_min - # for visualizer in self.temp_min_to_visualizer.values(): - # visualizer.plot() + for visualizer in self.right_limit_to_visualizer.values(): + visualizer.plot() merge_visualizer_str_list = [] if IndependentEnsembleFit in self.ensemble_fit_classes: merge_visualizer_str_list.extend([AbstractEnsembleFit.Median_merge, AbstractEnsembleFit.Mean_merge]) if TogetherEnsembleFit in self.ensemble_fit_classes: merge_visualizer_str_list.append(AbstractEnsembleFit.Together_merge) for merge_visualizer_str in merge_visualizer_str_list: - self.sensitivity_plot(merge_visualizer_str) + self.sensitivity_plot_percentages(merge_visualizer_str) + for relative in [True, False]: + self.sensitivity_plot_changes(merge_visualizer_str, relative) - def sensitivity_plot(self, merge_visualizer_str): + def sensitivity_plot_changes(self, merge_visualizer_str, relative): ax = plt.gca() for altitudes in self.altitudes_list: altitude_class = get_altitude_class_from_altitudes(altitudes) - self.interval_plot(ax, altitude_class, merge_visualizer_str) + self.interval_plot_changes(ax, altitude_class, merge_visualizer_str, relative) + + ticks_labels = get_ticks_labels_for_interval(self.is_temperature_interval, self.is_shift_interval) + name = 'relative changes' if relative else "changes" + ax.set_ylabel(name) + ax.set_xlabel('Interval used to compute the trends ') + ax.set_xticks(self.right_limits) + ax.set_xticklabels(ticks_labels) + lim_left, lim_right = ax.get_xlim() + ax.hlines(0, xmin=lim_left, xmax=lim_right, linestyles='dashed') + ax.legend(prop={'size': 7}, loc='upper center', ncol=2) + # ax.set_ylim((0, 122)) + # ax.set_yticks([i * 10 for i in range(11)]) + self.save_plot(merge_visualizer_str, name) + + def interval_plot_changes(self, ax, altitude_class, merge_visualizer_str, relative): + linestyle = get_linestyle_for_altitude_class(altitude_class) + + mean_changes = [] + for v in self.right_limit_to_visualizer.values(): + merge_visualizer = self.get_merge_visualizer(altitude_class, v, merge_visualizer_str) + changes, non_stationary_changes = merge_visualizer.all_changes(self.massif_names, relative=relative, + with_significance=False) + mean_changes.append(np.mean(changes)) + + label = altitude_class().formula + ax.plot(self.right_limits, mean_changes, linestyle=linestyle, label=label, color='darkgreen') + + def sensitivity_plot_percentages(self, merge_visualizer_str): + ax = plt.gca() + for altitudes in self.altitudes_list: + altitude_class = get_altitude_class_from_altitudes(altitudes) + self.interval_plot_percentages(ax, altitude_class, merge_visualizer_str) ticks_labels = get_ticks_labels_for_interval(self.is_temperature_interval, self.is_shift_interval) ax.set_ylabel('Percentages of massifs (\%)') @@ -96,16 +133,9 @@ class VisualizerForSensivity(object): ax.legend(prop={'size': 7}, loc='upper center', ncol=2) ax.set_ylim((0, 122)) ax.set_yticks([i * 10 for i in range(11)]) - merge_visualizer = self.first_merge_visualizer(merge_visualizer_str) - temp_cov = self.temporal_covariate_for_fit is AnomalyTemperatureWithSplineTemporalCovariate - merge_visualizer.plot_name = 'Sensitivity plot with ' \ - 'shift={} temp_interval={}, temp_cov={}'.format(self.is_shift_interval, - self.is_temperature_interval, - temp_cov) - merge_visualizer.show_or_save_to_file(no_title=True) - plt.close() + self.save_plot(merge_visualizer_str, "percentages") - def interval_plot(self, ax, altitude_class, merge_visualizer_str): + def interval_plot_percentages(self, ax, altitude_class, merge_visualizer_str): linestyle = get_linestyle_for_altitude_class(altitude_class) increasing_key = 'increasing' decreasing_key = 'decreasing' @@ -130,16 +160,19 @@ class VisualizerForSensivity(object): color = label_to_color[label] ax.plot(self.right_limits, l, label=label_improved, color=color, linestyle=linestyle) + # Merge visualizer + def get_merge_visualizer(self, altitude_class, visualizer_projection: VisualizerForProjectionEnsemble, merge_visualizer_str): if merge_visualizer_str in [AbstractEnsembleFit.Median_merge, AbstractEnsembleFit.Mean_merge]: independent_ensemble_fit = \ - visualizer_projection.altitude_class_to_ensemble_class_to_ensemble_fit[altitude_class][ - IndependentEnsembleFit] + visualizer_projection.altitude_class_to_ensemble_class_to_ensemble_fit[altitude_class][ + IndependentEnsembleFit] merge_visualizer = independent_ensemble_fit.merge_function_name_to_visualizer[merge_visualizer_str] else: together_ensemble_fit = \ - visualizer_projection.altitude_class_to_ensemble_class_to_ensemble_fit[altitude_class][TogetherEnsembleFit] + visualizer_projection.altitude_class_to_ensemble_class_to_ensemble_fit[altitude_class][ + TogetherEnsembleFit] merge_visualizer = together_ensemble_fit.visualizer merge_visualizer.studies.study.gcm_rcm_couple = (merge_visualizer_str, "merge") return merge_visualizer @@ -148,3 +181,15 @@ class VisualizerForSensivity(object): altitude_class = get_altitude_class_from_altitudes(self.altitudes_list[0]) visualizer_projection = list(self.right_limit_to_visualizer.values())[0] return self.get_merge_visualizer(altitude_class, visualizer_projection, merge_visualizer_str) + + # Utils + + def save_plot(self, merge_visualizer_str, name): + merge_visualizer = self.first_merge_visualizer(merge_visualizer_str) + temp_cov = self.temporal_covariate_for_fit is AnomalyTemperatureWithSplineTemporalCovariate + merge_visualizer.plot_name = 'Sensitivity plot for {} with ' \ + 'shift={} temp_interval={}, temp_cov={}'.format(name, self.is_shift_interval, + self.is_temperature_interval, + temp_cov) + merge_visualizer.show_or_save_to_file(no_title=True) + plt.close() diff --git a/projects/projected_extreme_snowfall/discussion/main_sensitivity.py b/projects/projected_extreme_snowfall/discussion/main_sensitivity.py index a2e5e60c..70c7de45 100644 --- a/projects/projected_extreme_snowfall/discussion/main_sensitivity.py +++ b/projects/projected_extreme_snowfall/discussion/main_sensitivity.py @@ -44,21 +44,24 @@ def main(): set_seed_for_test() AbstractExtractEurocodeReturnLevel.ALPHA_CONFIDENCE_INTERVAL_UNCERTAINTY = 0.2 - fast = False - scenarios = rcp_scenarios[-1:] if fast is False else [AdamontScenario.rcp85] + fast = None + scenarios = [AdamontScenario.rcp85] + scenarios = rcp_scenarios[1:] for scenario in scenarios: gcm_rcm_couples = get_gcm_rcm_couples(scenario) if fast is None: + scenarios = scenarios[:1] massif_names = None gcm_rcm_couples = gcm_rcm_couples[4:6] AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 - altitudes_list = altitudes_for_groups[3:] + altitudes_list = altitudes_for_groups[1:3] elif fast: + scenarios = scenarios[:1] massif_names = ['Vanoise', 'Haute-Maurienne'] gcm_rcm_couples = gcm_rcm_couples[4:6] AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 - altitudes_list = altitudes_for_groups[:1] + altitudes_list = altitudes_for_groups[1:3] else: massif_names = None altitudes_list = altitudes_for_groups[:] @@ -72,11 +75,11 @@ def main(): model_classes = ALTITUDINAL_GEV_MODELS_BASED_ON_POINTWISE_ANALYSIS assert scenario in rcp_scenarios remove_physically_implausible_models = True - temp_cov = False + temp_cov = True temporal_covariate_for_fit = AnomalyTemperatureWithSplineTemporalCovariate if temp_cov else TimeTemporalCovariate print('Covariate is {}'.format(temporal_covariate_for_fit)) - for is_temperature_interval in [True, False][1:]: + for is_temperature_interval in [True, False][:1]: for is_shift_interval in [True, False][1:]: visualizer = VisualizerForSensivity( altitudes_list, gcm_rcm_couples, study_class, Season.annual, scenario, diff --git a/projects/projected_extreme_snowfall/results/main_projections_ensemble.py b/projects/projected_extreme_snowfall/results/main_projections_ensemble.py index 01b20911..edc30d24 100644 --- a/projects/projected_extreme_snowfall/results/main_projections_ensemble.py +++ b/projects/projected_extreme_snowfall/results/main_projections_ensemble.py @@ -45,7 +45,7 @@ def main(): set_seed_for_test() AbstractExtractEurocodeReturnLevel.ALPHA_CONFIDENCE_INTERVAL_UNCERTAINTY = 0.2 - fast = False + fast = True scenarios = rcp_scenarios[::-1] if fast is False else [AdamontScenario.rcp85] for scenario in scenarios: -- GitLab