From 10d1ead1b042d9ac992b8b071622edc38f1b1240 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 22 Feb 2021 11:57:30 +0100 Subject: [PATCH] [projections] fix max abs issue for the plots. add temperature as temporal covariate for the visualizer (and for the plot manage the covariate before and the covariate after) --- .../altitudes_fit/altitudes_studies.py | 13 ++++-- ...es_visualizer_for_non_stationary_models.py | 16 ++++++- .../one_fold_analysis/one_fold_fit.py | 43 ++++++++++++++----- .../ensemble_fit/independent_ensemble_fit.py | 4 -- ...ation_temporal_for_projections_ensemble.py | 8 ++-- .../visualizer_for_projection_ensemble.py | 8 ++++ 6 files changed, 67 insertions(+), 25 deletions(-) diff --git a/projects/altitude_spatial_model/altitudes_fit/altitudes_studies.py b/projects/altitude_spatial_model/altitudes_fit/altitudes_studies.py index e5162707..d0942825 100644 --- a/projects/altitude_spatial_model/altitudes_fit/altitudes_studies.py +++ b/projects/altitude_spatial_model/altitudes_fit/altitudes_studies.py @@ -154,16 +154,21 @@ class AltitudesStudies(object): ax.set_xlim((x[0], x[-1])) # Plot for the paper 2 - if massif_name == "Vanoise": + if massif_name == "Vanoise" and (not issubclass(self.study_class, AbstractAdamontStudy)): # ax.yaxis.set_ticks([25 * (j) for j in range(6)]) ax.yaxis.set_ticks([25 * (j) for j in range(7)]) + labelsize = 20 + fontsize = 15 + else: + fontsize = 10 + labelsize = 10 - ax.tick_params(axis='both', which='major', labelsize=20) + ax.tick_params(axis='both', which='major', labelsize=labelsize) handles, labels = ax.get_legend_handles_labels() - ax.legend(handles[::-1], labels[::-1], prop={'size': 20}) + ax.legend(handles[::-1], labels[::-1], prop={'size': labelsize}) plot_name = 'Annual maxima of {} in {}'.format(STUDY_CLASS_TO_ABBREVIATION[self.study_class], massif_name.replace('_', ' ')) - ax.set_ylabel('{} ({})'.format(plot_name, self.study.variable_unit), fontsize=15) + ax.set_ylabel('{} ({})'.format(plot_name, self.study.variable_unit), fontsize=fontsize) # ax.set_xlabel('years', fontsize=15) plot_name = 'time series/' + plot_name self.show_or_save_to_file(plot_name=plot_name, show=show, no_title=True, tight_layout=True) diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py index f389f218..dbdd61e5 100644 --- a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py +++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/altitudes_studies_visualizer_for_non_stationary_models.py @@ -30,6 +30,8 @@ from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.one_fold_fi OneFoldFit from root_utils import NB_CORES from spatio_temporal_dataset.coordinates.abstract_coordinates import AbstractCoordinates +from spatio_temporal_dataset.coordinates.temporal_coordinates.abstract_temporal_covariate_for_fit import \ + AnomalyTemperatureTemporalCovariate from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset @@ -120,6 +122,10 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): return {massif_name: old_fold_fit for massif_name, old_fold_fit in self._massif_name_to_one_fold_fit.items() if old_fold_fit.has_at_least_one_valid_model} + @property + def first_one_fold_fit(self): + return list(self.massif_name_to_one_fold_fit.values())[0] + def plot_moments(self): for method_name in self.moment_names[:2]: for order in self.orders: @@ -177,13 +183,19 @@ class AltitudesStudiesVisualizerForNonStationaryModels(StudyVisualizer): massif_name_to_value = self.method_name_and_order_to_d(method_name, order) # Plot settings moment = ' '.join(method_name.split('_')) - str_for_last_year = ' in {}'.format(OneFoldFit.last_year) + d_temperature = {'C': '{C}'} + str_for_last_year = ' at +${}^o\mathrm{C}$' \ + if self.temporal_covariate_for_fit is AnomalyTemperatureTemporalCovariate else ' in {}' + str_for_last_year = str_for_last_year.format(self.first_one_fold_fit.covariate_after, **d_temperature) moment = moment.replace('moment', '{}{}'.format(OneFoldFit.get_moment_str(order=order), str_for_last_year)) plot_name = '{}{} '.format(OneFoldFit.folder_for_plots, moment) if 'change' in method_name: plot_name = plot_name.replace(str_for_last_year, '') - plot_name += ' between {} and {}'.format(OneFoldFit.last_year - OneFoldFit.nb_years, OneFoldFit.last_year) + add_str = ' between +${}^o\mathrm{C}$ and +${}^o\mathrm{C}$' if self.temporal_covariate_for_fit is AnomalyTemperatureTemporalCovariate \ + else ' between {} and {}' + plot_name += add_str.format(self.first_one_fold_fit.covariate_before, self.first_one_fold_fit.covariate_after, **d_temperature) + if 'relative' not in method_name: # Put the relative score as text on the plot for the change. massif_name_to_text = {m: ('+' if v > 0 else '') + str(int(v)) + '\%' for m, v in diff --git a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py index 5e45ad28..72045b2b 100644 --- a/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py +++ b/projects/altitude_spatial_model/altitudes_fit/one_fold_analysis/one_fold_fit.py @@ -34,6 +34,8 @@ from extreme_fit.model.result_from_model_fit.result_from_extremes.eurocode_retur from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.altitude_group import AbstractAltitudeGroup, \ DefaultAltitudeGroup, altitudes_for_groups from root_utils import classproperty, NB_CORES, batch +from spatio_temporal_dataset.coordinates.temporal_coordinates.abstract_temporal_covariate_for_fit import \ + AnomalyTemperatureTemporalCovariate, TimeTemporalCovariate from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset from spatio_temporal_dataset.slicer.split import Split from spatio_temporal_dataset.spatio_temporal_observations.annual_maxima_observations import AnnualMaxima @@ -46,6 +48,7 @@ class OneFoldFit(object): quantile_level = 1 - (1 / return_period) nb_years = 60 last_year = 2019 + last_anomaly = 2 def __init__(self, massif_name: str, dataset: AbstractDataset, models_classes, fit_method=MarginFitMethod.extremes_fevd_mle, @@ -96,8 +99,8 @@ class OneFoldFit(object): elif order is None: return '{}-year return levels'.format(cls.return_period) - def get_moment(self, altitude, year, order=1): - gev_params = self.get_gev_params(altitude, year) + def get_moment(self, altitude, temporal_covariate, order=1): + gev_params = self.get_gev_params(altitude, temporal_covariate) if order == 1: return gev_params.mean elif order == 2: @@ -113,7 +116,7 @@ class OneFoldFit(object): return gev_params def moment(self, altitudes, order=1): - return [self.get_moment(altitude, self.last_year, order) for altitude in altitudes] + return [self.get_moment(altitude, self.covariate_after, order) for altitude in altitudes] @property def change_in_return_level_for_reference_altitude(self) -> float: @@ -123,20 +126,38 @@ class OneFoldFit(object): def relative_change_in_return_level_for_reference_altitude(self) -> float: return self.relative_changes_of_moment(altitudes=[self.altitude_plot], order=None)[0] - def changes_of_moment(self, altitudes, nb_years=nb_years, order=1): + def changes_of_moment(self, altitudes, order=1): changes = [] for altitude in altitudes: - mean_after = self.get_moment(altitude, self.last_year, order) - mean_before = self.get_moment(altitude, self.last_year - nb_years, order) + mean_after = self.get_moment(altitude, self.covariate_after, order) + mean_before = self.get_moment(altitude, self.covariate_before, order) change = mean_after - mean_before changes.append(change) return changes - def relative_changes_of_moment(self, altitudes, nb_years=nb_years, order=1): + @property + def covariate_before(self): + return self._covariate_before_and_after[0] + + @property + def covariate_after(self): + return self._covariate_before_and_after[1] + + @property + def _covariate_before_and_after(self): + if self.temporal_covariate_for_fit in [None, TimeTemporalCovariate]: + return self.last_year - self.nb_years, self.last_year + elif self.temporal_covariate_for_fit is AnomalyTemperatureTemporalCovariate: + # In 2020, we are roughly at 1 degree. Thus it natural to see the augmentation from 1 to 2 degree. + return 1, self.last_anomaly + else: + raise NotImplementedError + + def relative_changes_of_moment(self, altitudes, order=1): relative_changes = [] for altitude in altitudes: - mean_after = self.get_moment(altitude, self.last_year, order) - mean_before = self.get_moment(altitude, self.last_year - nb_years, order) + mean_after = self.get_moment(altitude, self.covariate_after, order) + mean_before = self.get_moment(altitude, self.covariate_before, order) relative_change = 100 * (mean_after - mean_before) / mean_before relative_changes.append(relative_change) return relative_changes @@ -321,8 +342,8 @@ class OneFoldFit(object): def sign_of_change(self, function_from_fit): return_levels = [] - for year in [self.last_year - self.nb_years, self.last_year]: - coordinate = np.array([self.altitude_plot, year]) + for temporal_covariate in self._covariate_before_and_after: + coordinate = np.array([self.altitude_plot, temporal_covariate]) return_level = function_from_fit.get_params( coordinate=coordinate, is_transformed=False).return_level(return_period=self.return_period) diff --git a/projects/projected_snowfall/elevation_temporal_model_for_projections/ensemble_fit/independent_ensemble_fit.py b/projects/projected_snowfall/elevation_temporal_model_for_projections/ensemble_fit/independent_ensemble_fit.py index 0cd6db0f..d7285684 100644 --- a/projects/projected_snowfall/elevation_temporal_model_for_projections/ensemble_fit/independent_ensemble_fit.py +++ b/projects/projected_snowfall/elevation_temporal_model_for_projections/ensemble_fit/independent_ensemble_fit.py @@ -33,7 +33,3 @@ class IndependentEnsembleFit(AbstractEnsembleFit): self.remove_physically_implausible_models) self.gcm_rcm_couple_to_visualizer[gcm_rcm_couple] = visualizer - # Assign max - visualizer_list = list(self.gcm_rcm_couple_to_visualizer.values()) - compute_and_assign_max_abs(visualizer_list) - diff --git a/projects/projected_snowfall/elevation_temporal_model_for_projections/main_elevation_temporal_for_projections_ensemble.py b/projects/projected_snowfall/elevation_temporal_model_for_projections/main_elevation_temporal_for_projections_ensemble.py index a14affb8..37a5cdc3 100644 --- a/projects/projected_snowfall/elevation_temporal_model_for_projections/main_elevation_temporal_for_projections_ensemble.py +++ b/projects/projected_snowfall/elevation_temporal_model_for_projections/main_elevation_temporal_for_projections_ensemble.py @@ -20,7 +20,7 @@ from extreme_data.meteo_france_data.adamont_data.adamont_scenario import Adamont from projects.projected_snowfall.elevation_temporal_model_for_projections.ensemble_fit.independent_ensemble_fit import \ IndependentEnsembleFit from spatio_temporal_dataset.coordinates.temporal_coordinates.abstract_temporal_covariate_for_fit import \ - AnomalyTemperatureTemporalCovariate + AnomalyTemperatureTemporalCovariate, TimeTemporalCovariate matplotlib.use('Agg') @@ -40,16 +40,16 @@ def main(): scenario = AdamontScenario.rcp85 gcm_rcm_couples = get_gcm_rcm_couples(scenario) ensemble_fit_class = [IndependentEnsembleFit] - temporal_covariate_for_fit = [None, AnomalyTemperatureTemporalCovariate][0] + temporal_covariate_for_fit = [TimeTemporalCovariate, AnomalyTemperatureTemporalCovariate][1] set_seed_for_test() AbstractExtractEurocodeReturnLevel.ALPHA_CONFIDENCE_INTERVAL_UNCERTAINTY = 0.2 fast = False if fast is None: massif_names = None - gcm_rcm_couples = gcm_rcm_couples[:5] + gcm_rcm_couples = gcm_rcm_couples[:1] AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 - altitudes_list = altitudes_for_groups[:1] + altitudes_list = altitudes_for_groups[1:2] elif fast: AbstractExtractEurocodeReturnLevel.NB_BOOTSTRAP = 10 massif_names = None diff --git a/projects/projected_snowfall/elevation_temporal_model_for_projections/visualizer_for_projection_ensemble.py b/projects/projected_snowfall/elevation_temporal_model_for_projections/visualizer_for_projection_ensemble.py index adbb4485..5c69fa54 100644 --- a/projects/projected_snowfall/elevation_temporal_model_for_projections/visualizer_for_projection_ensemble.py +++ b/projects/projected_snowfall/elevation_temporal_model_for_projections/visualizer_for_projection_ensemble.py @@ -29,6 +29,7 @@ from projects.altitude_spatial_model.altitudes_fit.one_fold_analysis.one_fold_fi OneFoldFit from projects.altitude_spatial_model.altitudes_fit.plots.plot_histogram_altitude_studies import \ plot_histogram_all_trends_against_altitudes, plot_shoe_plot_changes_against_altitude +from projects.altitude_spatial_model.altitudes_fit.utils_altitude_studies_visualizer import compute_and_assign_max_abs from projects.projected_snowfall.elevation_temporal_model_for_projections.ensemble_fit.independent_ensemble_fit import \ IndependentEnsembleFit from spatio_temporal_dataset.coordinates.abstract_coordinates import AbstractCoordinates @@ -77,6 +78,13 @@ class MetaVisualizerForProjectionEnsemble(object): def plot(self): if IndependentEnsembleFit in self.ensemble_fit_classes: + # Set max abs + visualizer_list = [] + for ensemble_fit in self.ensemble_fits(IndependentEnsembleFit): + visualizer_list.extend(list(ensemble_fit.gcm_rcm_couple_to_visualizer.values())) + # Potentially I could add more visualizer here... + compute_and_assign_max_abs(visualizer_list) + # Plot self.plot_independent() def plot_independent(self): -- GitLab