From 4faa115a861d5500f4ce9c827cefcb0d403fc0e3 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Tue, 10 Dec 2019 14:57:56 +0100 Subject: [PATCH] [PAPER 1] create relative change plot --- .../plot/create_shifted_cmap.py | 2 +- .../main_result_trends_and_return_levels.py | 27 ++++--- .../plot_uncertainty_curves.py | 4 +- ...dy_visualizer_for_non_stationary_trends.py | 77 +++++++++++++------ .../abstract_gev_trend_test.py | 26 +++++-- 5 files changed, 97 insertions(+), 39 deletions(-) diff --git a/experiment/meteo_france_data/plot/create_shifted_cmap.py b/experiment/meteo_france_data/plot/create_shifted_cmap.py index 73c4a88e..dd49798c 100644 --- a/experiment/meteo_france_data/plot/create_shifted_cmap.py +++ b/experiment/meteo_france_data/plot/create_shifted_cmap.py @@ -32,7 +32,7 @@ def create_colorbase_axis(ax, label, cmap, norm, ticks_values_and_labels=None): if ticks_values_and_labels is not None: cb.ax.set_yticklabels([str(t) for t in ticks_values_and_labels[1]]) if isinstance(label, str): - cb.set_label(label) + cb.set_label(label, fontsize=15) return norm diff --git a/experiment/paper_past_snow_loads/result_trends_and_return_levels/main_result_trends_and_return_levels.py b/experiment/paper_past_snow_loads/result_trends_and_return_levels/main_result_trends_and_return_levels.py index 796edeae..65332ae3 100644 --- a/experiment/paper_past_snow_loads/result_trends_and_return_levels/main_result_trends_and_return_levels.py +++ b/experiment/paper_past_snow_loads/result_trends_and_return_levels/main_result_trends_and_return_levels.py @@ -17,14 +17,14 @@ from root_utils import NB_CORES mpl.rcParams['text.usetex'] = True mpl.rcParams['text.latex.preamble'] = [r'\usepackage{amsmath}'] - +import matplotlib.pyplot as plt def minor_result(altitude): """Plot trends for a single altitude to be fast""" visualizer = StudyVisualizerForNonStationaryTrends(CrocusSnowLoadTotal(altitude=altitude), multiprocessing=True, ) visualizer.plot_trends() - # plt.show() + plt.show() def compute_minimized_aic(visualizer): _ = visualizer.massif_name_to_minimized_aic_non_stationary_trend_test @@ -50,7 +50,7 @@ def intermediate_result(altitudes, massif_names=None, # Load variable object efficiently for v in altitude_to_visualizer.values(): _ = v.study.year_to_variable_object - # Plot trends + # Compute minimized value efficiently visualizers = list(altitude_to_visualizer.values()) if multiprocessing: with Pool(NB_CORES) as p: @@ -59,9 +59,13 @@ def intermediate_result(altitudes, massif_names=None, for visualizer in visualizers: _ = compute_minimized_aic(visualizer) # Compute common max value for the colorbar - max_abs_tdrl = max([visualizer.max_abs_tdrl for visualizer in visualizers]) - for visualizer in altitude_to_visualizer.values(): - visualizer.plot_trends(max_abs_tdrl) + altitudes_for_plot_trend = [900, 1800, 2700] + visualizers_for_altitudes = [visualizer + for altitude, visualizer in altitude_to_visualizer.items() + if altitude in altitudes_for_plot_trend] + max_abs_tdrl = max([visualizer.max_abs_change for visualizer in visualizers_for_altitudes]) + for visualizer in visualizers_for_altitudes: + visualizer.plot_trends(max_abs_tdrl, add_colorbar=visualizer.study.altitude==2700) # Plot graph plot_uncertainty_massifs(altitude_to_visualizer) @@ -73,7 +77,7 @@ def major_result(): uncertainty_methods = [ConfidenceIntervalMethodFromExtremes.my_bayes, ConfidenceIntervalMethodFromExtremes.ci_mle][:] massif_names = None - for study_class in paper_study_classes[1:2]: + for study_class in paper_study_classes[:1]: if study_class == CrocusSnowLoadEurocode: non_stationary_uncertainty = [False] else: @@ -82,16 +86,21 @@ def major_result(): if __name__ == '__main__': - major_result() + # major_result() # intermediate_result(altitudes=paper_altitudes, massif_names=['Maurienne'], # uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.my_bayes, # ConfidenceIntervalMethodFromExtremes.ci_mle][1:], # non_stationary_uncertainty=[False, True][1:], # multiprocessing=True) + intermediate_result(altitudes=paper_altitudes, massif_names=['Maurienne'], + uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.my_bayes, + ConfidenceIntervalMethodFromExtremes.ci_mle][:], + non_stationary_uncertainty=[False, True][:], + multiprocessing=True) # intermediate_result(altitudes=[900, 1200], massif_names=None) # intermediate_result(ALL_ALTITUDES_WITHOUT_NAN) # intermediate_result(paper_altitudes) - # minor_result(altitude=600) + # minor_result(altitude=900) # intermediate_result(altitudes=[1500, 1800], massif_names=['Chartreuse'], # uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle, # ConfidenceIntervalMethodFromExtremes.ci_bayes], diff --git a/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py index 5ad18222..d1da622f 100644 --- a/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py +++ b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py @@ -138,7 +138,9 @@ def plot_tdrl_bars(altitude_to_visualizer, ax, massif_name, valid_altitudes, leg if len(visualizers) > 0: tdrl_values = [v.massif_name_to_tdrl_value[massif_name] for v in visualizers] # Plot bars - colors = [v.massif_name_to_tdrl_color[massif_name] for v in visualizers] + # colors = [v.massif_name_to_color[massif_name] for v in visualizers] + # From snow on, we set a black color for the bars + colors = ['white' for v in visualizers] ax.bar(valid_altitudes, tdrl_values, width=150, color=colors, label=visualizers[0].label_tdrl_bar, edgecolor='black', hatch='//') # Plot markers diff --git a/experiment/paper_past_snow_loads/study_visualizer_for_non_stationary_trends.py b/experiment/paper_past_snow_loads/study_visualizer_for_non_stationary_trends.py index da62927e..4fa5978d 100644 --- a/experiment/paper_past_snow_loads/study_visualizer_for_non_stationary_trends.py +++ b/experiment/paper_past_snow_loads/study_visualizer_for_non_stationary_trends.py @@ -38,12 +38,14 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): uncertainty_methods=None, non_stationary_contexts=None, uncertainty_massif_names=None, - effective_temporal_covariate=2017): + effective_temporal_covariate=2017, + relative_change_trend_plot=True): super().__init__(study, show, save_to_file, only_one_graph, only_first_row, vertical_kde_plot, year_for_kde_plot, plot_block_maxima_quantiles, temporal_non_stationarity, transformation_class, verbose, multiprocessing, complete_non_stationary_trend_analysis, normalization_under_one_observations, score_class) # Add some attributes + self.relative_change_trend_plot = relative_change_trend_plot self.effective_temporal_covariate = effective_temporal_covariate self.non_stationary_contexts = non_stationary_contexts self.uncertainty_methods = uncertainty_methods @@ -60,7 +62,7 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): self.non_stationary_trend_test = [GevLocationTrendTest, GevScaleTrendTest, GevLocationAndScaleTrendTest] self.non_stationary_trend_test_to_marker = dict(zip(self.non_stationary_trend_test, ["s", "^", "D"])) - self.global_max_abs_tdrl = None + self.global_max_abs_change = None # Utils @@ -105,53 +107,64 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): massif_name_to_trend_test_that_minimized_aic[massif_name] = trend_test_that_minimized_aic return massif_name_to_trend_test_that_minimized_aic - # Part 1 - Trends @property - def max_abs_tdrl(self): - return max(abs(min(self.massif_name_to_tdrl_value.values())), max(self.massif_name_to_tdrl_value.values())) + def max_abs_change(self): + return max(abs(min(self.massif_name_to_change_value.values())), max(self.massif_name_to_change_value.values())) @cached_property - def _max_abs_tdrl(self): - return self.global_max_abs_tdrl if self.global_max_abs_tdrl is not None else self.max_abs_tdrl + def _max_abs_change(self): + return self.global_max_abs_change if self.global_max_abs_change is not None else self.max_abs_change - def plot_trends(self, max_abs_tdrl=None): + def plot_trends(self, max_abs_tdrl=None, add_colorbar=True): if max_abs_tdrl is not None: - self.global_max_abs_tdrl = max_abs_tdrl - ax = self.study.visualize_study(massif_name_to_value=self.massif_name_to_tdrl_value, + self.global_max_abs_change = max_abs_tdrl + ax = self.study.visualize_study(massif_name_to_value=self.massif_name_to_change_value, replace_blue_by_white=False, axis_off=False, show_label=False, - add_colorbar=True, + add_colorbar=add_colorbar, massif_name_to_marker_style=self.massif_name_to_marker_style, - massif_name_to_color=self.massif_name_to_tdrl_color, + massif_name_to_color=self.massif_name_to_color, cmap=self.cmap, show=False, ticks_values_and_labels=self.ticks_values_and_labels, - label=self.label_tdrl_bar + ' for {}'.format(EUROCODE_RETURN_LEVEL_STR)) + label=self.label) ax.get_xaxis().set_visible(True) ax.set_xticks([]) - ax.set_xlabel('Altitude = {}m'.format(self.study.altitude), fontsize=12) + ax.set_xlabel('Altitude = {}m'.format(self.study.altitude), fontsize=15) self.plot_name = 'tdlr_trends' self.show_or_save_to_file(add_classic_title=False, tight_layout=True, no_title=True, - dpi=dpi_paper1_figure) + dpi=500) plt.close() + @property + def label(self): + if self.relative_change_trend_plot: + label_tdlr_bar = 'Relative change between {} and {}'.format(self.initial_year, self.final_year) + else: + label_tdlr_bar = self.label_tdrl_bar + label = label_tdlr_bar + '\nfor {}'.format(EUROCODE_RETURN_LEVEL_STR) + if self.relative_change_trend_plot: + # change units + label = label.split('(')[0] + '(\%)' + return label + @property def label_tdrl_bar(self): return 'Change in {} years'.format(AbstractGevTrendTest.nb_years_for_quantile_evolution) @property def ticks_values_and_labels(self): - graduation = 0.2 + graduation = 10 if self.relative_change_trend_plot else 0.2 positive_ticks = [] tick = graduation - while tick < self._max_abs_tdrl: + while tick < self._max_abs_change: positive_ticks.append(round(tick, 1)) tick += graduation all_ticks_labels = [-t for t in positive_ticks] + [0] + positive_ticks - ticks_values = [((t / self._max_abs_tdrl) + 1) / 2 for t in all_ticks_labels] + ticks_values = [((t / self._max_abs_change) + 1) / 2 for t in all_ticks_labels] return ticks_values, all_ticks_labels @cached_property @@ -159,14 +172,34 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): return {m: t.time_derivative_of_return_level for m, t in self.massif_name_to_minimized_aic_non_stationary_trend_test.items()} + @cached_property + def massif_name_to_relative_change_value(self): + return {m: t.relative_change_in_return_level(initial_year=self.initial_year, final_year=self.final_year) + for m, t in self.massif_name_to_minimized_aic_non_stationary_trend_test.items()} + + @property + def initial_year(self): + return self.final_year - 50 + + @property + def final_year(self): + return 2010 + + @cached_property + def massif_name_to_change_value(self): + if self.relative_change_trend_plot: + return self.massif_name_to_relative_change_value + else: + return self.massif_name_to_tdrl_value + @cached_property def cmap(self): - return get_shifted_map(-self._max_abs_tdrl, self._max_abs_tdrl) + return get_shifted_map(-self._max_abs_change, self._max_abs_change) @cached_property - def massif_name_to_tdrl_color(self): - return {m: get_colors([v], self.cmap, -self._max_abs_tdrl, self._max_abs_tdrl)[0] - for m, v in self.massif_name_to_tdrl_value.items()} + def massif_name_to_color(self): + return {m: get_colors([v], self.cmap, -self._max_abs_change, self._max_abs_change)[0] + for m, v in self.massif_name_to_change_value.items()} @cached_property def massif_name_to_marker_style(self): diff --git a/experiment/trend_analysis/univariate_test/abstract_gev_trend_test.py b/experiment/trend_analysis/univariate_test/abstract_gev_trend_test.py index 59184411..71ff1725 100644 --- a/experiment/trend_analysis/univariate_test/abstract_gev_trend_test.py +++ b/experiment/trend_analysis/univariate_test/abstract_gev_trend_test.py @@ -143,17 +143,31 @@ class AbstractGevTrendTest(AbstractUnivariateTest): return self.constrained_estimator.margin_function_from_fit.get_gev_params(coordinate=np.array([1958]), is_transformed=False) + def time_derivative_times_years(self, nb_years): + # Compute the slope strength + slope = self._slope_strength() + # Delta T must in the same unit as were the parameter of slope mu1 and sigma1 + slope *= nb_years * self.coordinates.transformed_distance_between_two_successive_years[0] + return slope + @property def time_derivative_of_return_level(self): if self.crashed: return 0.0 else: - # Compute the slope strength - slope = self._slope_strength() - # Delta T must in the same unit as were the parameter of slope mu1 and sigma1 - slope *= self.nb_years_for_quantile_evolution * \ - self.coordinates.transformed_distance_between_two_successive_years[0] - return slope + return self.time_derivative_times_years(self.nb_years_for_quantile_evolution) + + def relative_change_in_return_level(self, initial_year, final_year): + return_level_values = [] + for year in [initial_year, final_year]: + gev_params = self.unconstrained_estimator.margin_function_from_fit.get_gev_params(coordinate=np.array([year]), + is_transformed=False) + return_level_values.append(gev_params.quantile(self.quantile_level)) + change_until_final_year = self.time_derivative_times_years(nb_years=final_year - initial_year) + change_in_between = (return_level_values[1] - return_level_values[0]) + np.testing.assert_almost_equal(change_until_final_year, change_in_between, decimal=5) + initial_return_level = return_level_values[0] + return 100 * change_until_final_year / initial_return_level def _slope_strength(self): raise NotImplementedError -- GitLab