From c6d9303f14d0843b1b480c2d89d90956353bdce4 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 2 Dec 2019 14:43:48 +0100 Subject: [PATCH] [PAPER 1] improve all uncertainty plots --- experiment/eurocode_data/eurocode_region.py | 4 ++- .../scm_models_data/abstract_study.py | 22 +++++++++------- .../main_study_visualizer.py | 2 +- .../main_result_trends_and_return_levels.py | 14 ++++++----- .../plot_uncertainty_curves.py | 25 ++++++++++++++----- .../plot_uncertainty_histogram.py | 21 ++++++++++------ .../confidence_interval_method.py | 15 +++++++++-- 7 files changed, 70 insertions(+), 33 deletions(-) diff --git a/experiment/eurocode_data/eurocode_region.py b/experiment/eurocode_data/eurocode_region.py index 5fc80319..fb4ca7d9 100644 --- a/experiment/eurocode_data/eurocode_region.py +++ b/experiment/eurocode_data/eurocode_region.py @@ -44,7 +44,9 @@ class AbstractEurocodeRegion(object): def lois_de_variation_1000_and_2000(self): return 3.5, -2.45 - def plot_eurocode_snow_load_on_ground_characteristic_value_variable_action(self, ax, altitudes, label='Eurocode standards', linestyle=None): + def plot_eurocode_snow_load_on_ground_characteristic_value_variable_action(self, ax, altitudes, + label='French standards', + linestyle=None): ax.plot(altitudes, [self.valeur_caracteristique(altitude) for altitude in altitudes], label=label, color=self.eurocode_color, linewidth=5, linestyle=linestyle) diff --git a/experiment/meteo_france_data/scm_models_data/abstract_study.py b/experiment/meteo_france_data/scm_models_data/abstract_study.py index 173cfa44..23f39bc5 100644 --- a/experiment/meteo_france_data/scm_models_data/abstract_study.py +++ b/experiment/meteo_france_data/scm_models_data/abstract_study.py @@ -401,22 +401,26 @@ class AbstractStudy(object): # Add legend for the marker if massif_name_to_marker_style is not None: - labels = ['\mathcal{M}_{\mu_1}', '\mathcal{M}_{\sigma_1}', '\mathcal{M}_{\mu_1, \sigma_1}'] - markers = ["s", "^", "D"] - legend_elements = [ - Line2D([0], [0], marker=marker, color='w', label='${}$'.format(label), - markerfacecolor='w', markeredgecolor='k', markersize=8) - for label, marker in zip(labels, markers) - ] + legend_elements = cls.get_legend_for_model_symbol(markersize=8) ax.legend(handles=legend_elements, bbox_to_anchor=(0.01, 0.03), loc='lower left') - ax.annotate("Filled symbol = significant trend ", xy=(0.05, 0.015), xycoords='axes fraction', - fontsize=7) + ax.annotate("Filled symbol = significant trend ", xy=(0.05, 0.015), xycoords='axes fraction', fontsize=7) if show: plt.show() return ax + @classmethod + def get_legend_for_model_symbol(cls, markersize): + labels = ['\mathcal{M}_{\mu_1}', '\mathcal{M}_{\sigma_1}', '\mathcal{M}_{\mu_1, \sigma_1}'] + markers = ["s", "^", "D"] + legend_elements = [ + Line2D([0], [0], marker=marker, color='w', label='${}$'.format(label), + markerfacecolor='w', markeredgecolor='k', markersize=markersize) + for label, marker in zip(labels, markers) + ] + return legend_elements + """ CLASS ATTRIBUTES COMMON TO ALL OBJECTS (written as object attributes/methods for simplicity) diff --git a/experiment/meteo_france_data/scm_models_data/visualization/study_visualization/main_study_visualizer.py b/experiment/meteo_france_data/scm_models_data/visualization/study_visualization/main_study_visualizer.py index 67ac17dd..0e32a1e6 100644 --- a/experiment/meteo_france_data/scm_models_data/visualization/study_visualization/main_study_visualizer.py +++ b/experiment/meteo_france_data/scm_models_data/visualization/study_visualization/main_study_visualizer.py @@ -34,7 +34,7 @@ SCM_STUDY_CLASS_TO_ABBREVIATION = { SafranSnowfall: 'SF3', CrocusSweTotal: 'SWE', CrocusSwe3Days: 'SWE3', - CrocusSnowLoadEurocode: 'GSL_Eurocode', + CrocusSnowLoadEurocode: 'GSL from annual maximum of HS and {}'.format(eurocode_snow_density), CrocusDepth: 'SD', CrocusSnowLoadTotal: 'max GSL', CrocusSnowLoad3Days: 'GSL3', 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 3c6df869..d472fa8e 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 @@ -7,7 +7,7 @@ from experiment.paper_past_snow_loads.paper_utils import paper_study_classes, pa load_altitude_to_visualizer 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.meteo_france_data.scm_models_data.crocus.crocus import CrocusSnowLoadTotal, CrocusSnowLoadEurocode 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 \ @@ -58,15 +58,17 @@ def major_result(): ConfidenceIntervalMethodFromExtremes.ci_mle][:] massif_names = None non_stationary_uncertainty = [False, True][:] - for study_class in paper_study_classes[2:]: + for study_class in paper_study_classes[:2]: intermediate_result(paper_altitudes, massif_names, non_stationary_uncertainty, uncertainty_methods, study_class) if __name__ == '__main__': - # major_result() - intermediate_result(altitudes=[900, 1200], massif_names=['Chartreuse', 'Vanoise', 'Mercantour'], - uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.my_bayes, - ConfidenceIntervalMethodFromExtremes.ci_mle]) + major_result() + # intermediate_result(altitudes=paper_altitudes, massif_names=['Chartreuse', 'Vanoise', 'Mercantour'], + # uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.my_bayes, + # ConfidenceIntervalMethodFromExtremes.ci_mle][1:], + # non_stationary_uncertainty=[False, True][1:], + # study_class=CrocusSnowLoadEurocode) # intermediate_result(altitudes=[900, 1200], massif_names=None) # intermediate_result(ALL_ALTITUDES_WITHOUT_NAN) # intermediate_result(paper_altitudes) 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 bd9723a1..1192911f 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 @@ -4,6 +4,9 @@ import matplotlib.pyplot as plt import numpy as np from experiment.eurocode_data.utils import EUROCODE_RETURN_LEVEL_STR, EUROCODE_ALTITUDES +from experiment.meteo_france_data.scm_models_data.abstract_study import AbstractStudy +from experiment.meteo_france_data.scm_models_data.visualization.study_visualization.main_study_visualizer import \ + SCM_STUDY_CLASS_TO_ABBREVIATION 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.abstract_extract_eurocode_return_level import \ @@ -102,20 +105,20 @@ def plot_single_uncertainty_massif_and_non_stationary_context(ax, massif_name, n plot_tdrl_bars(altitude_to_visualizer, ax, massif_name, valid_altitudes) ax.legend(loc=2) - ax.set_ylim([-1, 16]) + # ax.set_ylim([-1, 16]) massif_name_str = massif_name.replace('_', ' ') eurocode_region_str = get_display_name_from_object_type(type(eurocode_region)) is_non_stationary_model = non_stationary_context if isinstance(non_stationary_context, bool) else 'Non' in non_stationary_context if is_non_stationary_model: - non_stationary_context = 'non-stationary' + non_stationary_context = 'selected non-stationary models' else: - non_stationary_context = 'stationary' - title = '{} ({} Eurocodes area) with a {} model'.format(massif_name_str, eurocode_region_str, - non_stationary_context) + non_stationary_context = 'the stationary model' + title = '{} massif with {}'.format(massif_name_str, non_stationary_context) ax.set_title(title) ax.set_xticks(altitudes) - ax.set_ylabel(EUROCODE_RETURN_LEVEL_STR) + ylabel = EUROCODE_RETURN_LEVEL_STR.replace('GSL', SCM_STUDY_CLASS_TO_ABBREVIATION[type(visualizer.study)]) + ax.set_ylabel(ylabel) ax.set_xlabel('Altitude (m)') ax.grid() @@ -131,10 +134,20 @@ def plot_tdrl_bars(altitude_to_visualizer, ax, massif_name, valid_altitudes): edgecolor='black', hatch='//') # Plot markers markers_kwargs = [v.massif_name_to_marker_style[massif_name] for v in visualizers] + for k in markers_kwargs: + k['markersize'] = 7 for altitude, marker_kwargs, value in zip(valid_altitudes, markers_kwargs, tdrl_values): # ax.plot([altitude], [value / 2], **marker_kwargs) # Better to plot all the markers on the same line ax.plot([altitude], 0, **marker_kwargs) + # Add a legend plot + legend_elements = AbstractStudy.get_legend_for_model_symbol(markersize=9) + ax2 = ax.twinx() + # ax2.legend(handles=legend_elements, bbox_to_anchor=(0.93, 0.7), loc='upper right') + # ax2.annotate("Filled symbol = significant trend ", xy=(0.85, 0.5), xycoords='axes fraction', fontsize=7) + ax2.legend(handles=legend_elements, loc='upper right') + ax2.annotate("Filled symbol = significant trend ", xy=(0.75, 0.97), xycoords='axes fraction', fontsize=10) + ax2.set_yticks([]) def plot_valid_return_level_uncertainties(alpha, altitude_to_visualizer, altitudes, ax, color, massif_name, 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 index dbbfc221..468b538f 100644 --- 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 @@ -2,16 +2,18 @@ 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.eurocode_data.utils import EUROCODE_RETURN_LEVEL_STR, EUROCODE_ALTITUDES 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 +from extreme_fit.model.result_from_model_fit.result_from_extremes.confidence_interval_method import ci_method_to_color, \ + ci_method_to_label def plot_uncertainty_histogram(altitude_to_visualizer: Dict[int, StudyVisualizerForNonStationaryTrends]): """ Plot one graph for each non-stationary context :return: """ + altitude_to_visualizer = {a: v for a, v in altitude_to_visualizer.items() if a in EUROCODE_ALTITUDES} visualizer = list(altitude_to_visualizer.values())[0] for non_stationary_context in visualizer.non_stationary_contexts: plot_histogram(altitude_to_visualizer, non_stationary_context) @@ -33,24 +35,27 @@ def plot_histogram(altitude_to_visualizer, non_stationary_context): 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.legend() 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.plot_name = 'Percentages of exceedance with non_stationary={}'.format(non_stationary_context) # visualizer.show = True - # visualizer.show_or_save_to_file(no_title=True) - plt.show() + visualizer.show_or_save_to_file(no_title=True) 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] + epsilon = 0.5 + three_percentages_of_excess = [(a, b, c) if a == b else (max(epsilon, a), b, c) for (a, b, c) in three_percentages_of_excess] + three_percentages_of_excess = [(a, b, c) if b == c else (a, b, min(100 - epsilon, c)) for (a, b, c) in three_percentages_of_excess] 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) + label = ci_method_to_label[ci_method] + color = ci_method_to_color[ci_method] + ax.bar(bincenters, y, width=width, color=color, yerr=yerr, label=label, ecolor='black', capsize=5) 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 e28d30fb..d46c9b5b 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 @@ -17,7 +17,18 @@ ci_method_to_method_name = { ConfidenceIntervalMethodFromExtremes.ci_proflik: 'proflik', } +# ci_method_to_color = { +# ConfidenceIntervalMethodFromExtremes.ci_mle: 'tab:brown', +# ConfidenceIntervalMethodFromExtremes.my_bayes: 'tab:green' +# } + ci_method_to_color = { - ConfidenceIntervalMethodFromExtremes.ci_mle: 'tab:brown', - ConfidenceIntervalMethodFromExtremes.my_bayes: 'tab:green' + ConfidenceIntervalMethodFromExtremes.ci_mle: 'yellowgreen', + ConfidenceIntervalMethodFromExtremes.my_bayes: 'darkgreen' +} + +common_part_and_uncertainty = 'Return level and its uncertainty with the' +ci_method_to_label = { + ConfidenceIntervalMethodFromExtremes.ci_mle: 'Bayesian procedure', + ConfidenceIntervalMethodFromExtremes.my_bayes: 'Delta method ' } \ No newline at end of file -- GitLab