From b88a67cbaa011eefbd5c460fad20798603efd419 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 2 Dec 2019 12:02:25 +0100 Subject: [PATCH] [PAPER 1] add histogram plot --- .../eurocode_data/main_eurocode_drawing.py | 2 +- .../main_result_trends_and_return_levels.py | 14 +++-- ...sualizer.py => plot_uncertainty_curves.py} | 15 +++-- .../plot_uncertainty_histogram.py | 56 +++++++++++++++++++ ...dy_visualizer_for_non_stationary_trends.py | 41 ++++++++++---- .../confidence_interval_method.py | 5 ++ 6 files changed, 113 insertions(+), 20 deletions(-) rename experiment/paper_past_snow_loads/result_trends_and_return_levels/{eurocode_visualizer.py => plot_uncertainty_curves.py} (93%) create mode 100644 experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_histogram.py diff --git a/experiment/eurocode_data/main_eurocode_drawing.py b/experiment/eurocode_data/main_eurocode_drawing.py index 4b19537e..ca616dcd 100644 --- a/experiment/eurocode_data/main_eurocode_drawing.py +++ b/experiment/eurocode_data/main_eurocode_drawing.py @@ -7,7 +7,7 @@ from experiment.meteo_france_data.scm_models_data.visualization.study_visualizat StudyVisualizer from extreme_fit.model.result_from_model_fit.result_from_extremes.eurocode_return_level_uncertainties import \ ConfidenceIntervalMethodFromExtremes -from experiment.paper_past_snow_loads.result_trends_and_return_levels.eurocode_visualizer import \ +from experiment.paper_past_snow_loads.result_trends_and_return_levels.plot_uncertainty_curves import \ plot_uncertainty_massifs, get_model_name from experiment.eurocode_data.massif_name_to_departement import MASSIF_NAMES_ALPS from experiment.eurocode_data.utils import EUROCODE_ALTITUDES 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 93bd053f..3c6df869 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 @@ -5,9 +5,11 @@ from experiment.meteo_france_data.scm_models_data.visualization.study_visualizat ALL_ALTITUDES_WITHOUT_NAN from experiment.paper_past_snow_loads.paper_utils import paper_study_classes, paper_altitudes, \ load_altitude_to_visualizer -from experiment.paper_past_snow_loads.result_trends_and_return_levels.eurocode_visualizer import \ +from experiment.paper_past_snow_loads.result_trends_and_return_levels.plot_uncertainty_curves import \ plot_uncertainty_massifs from experiment.meteo_france_data.scm_models_data.crocus.crocus import CrocusSnowLoadTotal +from experiment.paper_past_snow_loads.result_trends_and_return_levels.plot_uncertainty_histogram import \ + plot_uncertainty_histogram from experiment.paper_past_snow_loads.study_visualizer_for_non_stationary_trends import \ StudyVisualizerForNonStationaryTrends from extreme_fit.model.result_from_model_fit.result_from_extremes.confidence_interval_method import \ @@ -47,8 +49,8 @@ def intermediate_result(altitudes, massif_names=None, visualizer.plot_trends(max_abs_tdrl) # Plot graph plot_uncertainty_massifs(altitude_to_visualizer) - return altitude_to_visualizer - + # Plot histogram + plot_uncertainty_histogram(altitude_to_visualizer) def major_result(): @@ -62,8 +64,12 @@ def major_result(): if __name__ == '__main__': # major_result() + intermediate_result(altitudes=[900, 1200], massif_names=['Chartreuse', 'Vanoise', 'Mercantour'], + uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.my_bayes, + ConfidenceIntervalMethodFromExtremes.ci_mle]) + # intermediate_result(altitudes=[900, 1200], massif_names=None) # intermediate_result(ALL_ALTITUDES_WITHOUT_NAN) - intermediate_result(paper_altitudes) + # intermediate_result(paper_altitudes) # minor_result(altitude=600) # intermediate_result(altitudes=[1500, 1800], massif_names=['Chartreuse'], # uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle, diff --git a/experiment/paper_past_snow_loads/result_trends_and_return_levels/eurocode_visualizer.py b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py similarity index 93% rename from experiment/paper_past_snow_loads/result_trends_and_return_levels/eurocode_visualizer.py rename to experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py index 5d6bbedf..bd9723a1 100644 --- a/experiment/paper_past_snow_loads/result_trends_and_return_levels/eurocode_visualizer.py +++ b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_curves.py @@ -1,4 +1,5 @@ from typing import Dict +import matplotlib.pyplot as plt import numpy as np @@ -9,6 +10,7 @@ from extreme_fit.model.result_from_model_fit.result_from_extremes.abstract_extra AbstractExtractEurocodeReturnLevel from experiment.eurocode_data.massif_name_to_departement import massif_name_to_eurocode_region from experiment.meteo_france_data.scm_models_data.visualization.utils import create_adjusted_axes +from extreme_fit.model.result_from_model_fit.result_from_extremes.confidence_interval_method import ci_method_to_color from root_utils import get_display_name_from_object_type @@ -16,7 +18,7 @@ def plot_uncertainty_massifs(altitude_to_visualizer: Dict[int, StudyVisualizerFo """ Plot several uncertainty plots :return: """ - altitude_to_visualizer = {a:v for a,v in altitude_to_visualizer.items() if a in EUROCODE_ALTITUDES} + altitude_to_visualizer = {a: v for a, v in altitude_to_visualizer.items() if a in EUROCODE_ALTITUDES} visualizer = list(altitude_to_visualizer.values())[-1] # Subdivide massif names in group of 3 m = 1 @@ -49,6 +51,7 @@ def plot_subgroup_uncertainty_massifs(altitude_to_visualizer: Dict[int, StudyVis model_names_str = 'NonStationarity=' + '_'.join([str(e) for e in visualizer.non_stationary_contexts]) visualizer.plot_name = model_names_str + '_' + massif_names_str visualizer.show_or_save_to_file(no_title=True) + plt.close() def plot_single_uncertainty_massif(altitude_to_visualizer: Dict[int, StudyVisualizerForNonStationaryTrends], @@ -78,19 +81,19 @@ def plot_single_uncertainty_massif_and_non_stationary_context(ax, massif_name, n """ Generic function that might be used by many other more global functions""" altitudes = list(altitude_to_visualizer.keys()) visualizer = list(altitude_to_visualizer.values())[0] - colors = ['tab:green', 'tab:brown'][::-1] alpha = 0.2 # Display the EUROCODE return level eurocode_region = massif_name_to_eurocode_region[massif_name]() # Display the return level from model class - for j, (color, uncertainty_method) in enumerate(zip(colors, visualizer.uncertainty_methods)): + for j, uncertainty_method in enumerate(visualizer.uncertainty_methods): if j == 0: # Plot eurocode norm eurocode_region.plot_eurocode_snow_load_on_ground_characteristic_value_variable_action(ax, altitudes=altitudes) # Plot uncertainties + color = ci_method_to_color[uncertainty_method] valid_altitudes = plot_valid_return_level_uncertainties(alpha, altitude_to_visualizer, altitudes, ax, color, massif_name, non_stationary_context, uncertainty_method) @@ -118,7 +121,8 @@ def plot_single_uncertainty_massif_and_non_stationary_context(ax, massif_name, n def plot_tdrl_bars(altitude_to_visualizer, ax, massif_name, valid_altitudes): - visualizers = [v for a, v in altitude_to_visualizer.items() if a in valid_altitudes and massif_name in v.uncertainty_massif_names] + visualizers = [v for a, v in altitude_to_visualizer.items() if + a in valid_altitudes and massif_name in v.uncertainty_massif_names] if len(visualizers) > 0: tdrl_values = [v.massif_name_to_tdrl_value[massif_name] for v in visualizers] # Plot bars @@ -155,5 +159,6 @@ def plot_valid_return_level_uncertainties(alpha, altitude_to_visualizer, altitud upper_bound = [r.confidence_interval[1] for r in ordered_return_level_uncertainties] confidence_interval_str = ' {}'.format(AbstractExtractEurocodeReturnLevel.percentage_confidence_interval) confidence_interval_str += '\% confidence interval' - ax.fill_between(valid_altitudes, lower_bound, upper_bound, color=color, alpha=alpha, label=label_name + confidence_interval_str) + ax.fill_between(valid_altitudes, lower_bound, upper_bound, color=color, alpha=alpha, + label=label_name + confidence_interval_str) return valid_altitudes diff --git a/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_histogram.py b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_histogram.py new file mode 100644 index 00000000..dbbfc221 --- /dev/null +++ b/experiment/paper_past_snow_loads/result_trends_and_return_levels/plot_uncertainty_histogram.py @@ -0,0 +1,56 @@ +from typing import Dict +import matplotlib.pyplot as plt +import numpy as np + +from experiment.eurocode_data.utils import EUROCODE_RETURN_LEVEL_STR +from experiment.paper_past_snow_loads.study_visualizer_for_non_stationary_trends import \ + StudyVisualizerForNonStationaryTrends +from extreme_fit.model.result_from_model_fit.result_from_extremes.confidence_interval_method import ci_method_to_color + + +def plot_uncertainty_histogram(altitude_to_visualizer: Dict[int, StudyVisualizerForNonStationaryTrends]): + """ Plot one graph for each non-stationary context + :return: + """ + visualizer = list(altitude_to_visualizer.values())[0] + for non_stationary_context in visualizer.non_stationary_contexts: + plot_histogram(altitude_to_visualizer, non_stationary_context) + + +def plot_histogram(altitude_to_visualizer, non_stationary_context): + """ + Plot a single graph for potentially several confidence interval method + :param altitude_to_visualizer: + :param non_stationary_context: + :return: + """ + visualizers = list(altitude_to_visualizer.values()) + visualizer = visualizers[0] + ax = plt.gca() + altitudes = np.array(list(altitude_to_visualizer.keys())) + bincenters = altitudes + for j, ci_method in enumerate(visualizer.uncertainty_methods): + if len(visualizer.uncertainty_methods) == 2: + offset = -50 if j == 0 else 50 + bincenters = altitudes + offset + + width = 100 + plot_histogram_ci_method(visualizers, non_stationary_context, ci_method, ax, bincenters, width=width) + ax.set_xticks(altitudes) + ax.set_ylabel('Massifs exceeding French standards (\%)') + ax.set_xlabel('Altitude (m)') + ax.set_ylim([0, 100]) + ax.set_yticks([10 * i for i in range(11)]) + # visualizer.plot_name = 'Percentage ' + # visualizer.show = True + # visualizer.show_or_save_to_file(no_title=True) + plt.show() + + +def plot_histogram_ci_method(visualizers, non_stationary_context, ci_method, ax, bincenters, width): + three_percentages_of_excess = [v.three_percentages_of_excess(ci_method, non_stationary_context) for v in + visualizers] + y = [d[1] for d in three_percentages_of_excess] + yerr = np.array([[d[1] - d[0], d[2] - d[1]] for d in three_percentages_of_excess]).transpose() + print(y, three_percentages_of_excess) + ax.bar(bincenters, y, width=width, color=ci_method_to_color[ci_method], yerr=yerr) 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 39bc7ca2..dbc85bf4 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 @@ -6,6 +6,7 @@ from typing import Dict, Tuple import numpy as np from cached_property import cached_property +from experiment.eurocode_data.massif_name_to_departement import massif_name_to_eurocode_region from experiment.eurocode_data.utils import EUROCODE_QUANTILE, EUROCODE_RETURN_LEVEL_STR from experiment.meteo_france_data.plot.create_shifted_cmap import get_shifted_map, get_colors from experiment.meteo_france_data.scm_models_data.abstract_study import AbstractStudy @@ -117,15 +118,15 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): 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, - replace_blue_by_white=False, - axis_off=False, show_label=False, - add_colorbar=True, - massif_name_to_marker_style=self.massif_name_to_marker_style, - massif_name_to_color=self.massif_name_to_tdrl_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)) + replace_blue_by_white=False, + axis_off=False, show_label=False, + add_colorbar=True, + massif_name_to_marker_style=self.massif_name_to_marker_style, + massif_name_to_color=self.massif_name_to_tdrl_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)) ax.get_xaxis().set_visible(True) ax.set_xticks([]) ax.set_xlabel('Altitude = {}m'.format(self.study.altitude), fontsize=12) @@ -187,7 +188,7 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): return len(self.non_stationary_contexts) def all_massif_name_to_eurocode_uncertainty_for_minimized_aic_model_class(self, ci_method, non_stationary_context) \ - -> Dict[str, Tuple[int, EurocodeConfidenceIntervalFromExtremes]]: + -> Dict[str, EurocodeConfidenceIntervalFromExtremes]: # Compute for the uncertainty massif names arguments = [ [self.massif_name_to_non_null_years_and_maxima[m], @@ -212,6 +213,7 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): @cached_property def triplet_to_eurocode_uncertainty(self): + # -> Dict[(str, bool, str), EurocodeConfidenceIntervalFromExtremes] d = {} for ci_method in self.uncertainty_methods: for non_stationary_uncertainty in self.non_stationary_contexts: @@ -234,3 +236,22 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer): else: res = [compute_gelman_convergence_value(*argument) for argument in arguments] return dict(zip(self.uncertainty_massif_names, res)) + + # Some values for the histogram + + @cached_property + def massif_name_to_eurocode_values(self): + """Eurocode values for the altitude""" + return {m: r().lois_de_variation_de_la_valeur_caracteristique(altitude=self.study.altitude) + for m, r in massif_name_to_eurocode_region.items() if m in self.uncertainty_massif_names} + + def three_percentages_of_excess(self, ci_method, non_stationary_context): + eurocode_and_uncertainties = [(self.massif_name_to_eurocode_values[massif_name], + self.triplet_to_eurocode_uncertainty[ + (ci_method, non_stationary_context, massif_name)]) + for massif_name in self.uncertainty_massif_names] + a = np.array([(uncertainty.confidence_interval[0] > eurocode, + uncertainty.mean_estimate > eurocode, + uncertainty.confidence_interval[1] > eurocode) + for eurocode, uncertainty in eurocode_and_uncertainties]) + return 100 * np.mean(a, axis=0) diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py index 958dae9f..e28d30fb 100644 --- a/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py +++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/confidence_interval_method.py @@ -16,3 +16,8 @@ ci_method_to_method_name = { ConfidenceIntervalMethodFromExtremes.ci_boot: 'boot', ConfidenceIntervalMethodFromExtremes.ci_proflik: 'proflik', } + +ci_method_to_color = { + ConfidenceIntervalMethodFromExtremes.ci_mle: 'tab:brown', + ConfidenceIntervalMethodFromExtremes.my_bayes: 'tab:green' +} \ No newline at end of file -- GitLab