From 883067a19011f43b9af8ac1f5fbcf0f49c0bbb8a Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Mon, 25 Nov 2019 16:02:39 +0100
Subject: [PATCH] [PAPER 1] add ticks to the colorbar for the trend. add
 histogram & marker to the uncertainty plot

---
 .../plot/create_shifted_cmap.py               |  7 ++-
 .../scm_models_data/abstract_study.py         |  3 +-
 .../eurocode_visualizer.py                    | 20 ++++++-
 .../main_result_trends_and_return_levels.py   | 17 +++---
 ...dy_visualizer_for_non_stationary_trends.py | 58 +++++++++++++++----
 .../abstract_result_from_extremes.py          |  6 +-
 .../result_from_mle_extremes.py               |  5 +-
 7 files changed, 86 insertions(+), 30 deletions(-)

diff --git a/experiment/meteo_france_data/plot/create_shifted_cmap.py b/experiment/meteo_france_data/plot/create_shifted_cmap.py
index 8edc0375..73c4a88e 100644
--- a/experiment/meteo_france_data/plot/create_shifted_cmap.py
+++ b/experiment/meteo_france_data/plot/create_shifted_cmap.py
@@ -24,10 +24,13 @@ def get_shifted_map(vmin, vmax):
     return shifted_cmap
 
 
-def create_colorbase_axis(ax, label, cmap, norm):
+def create_colorbase_axis(ax, label, cmap, norm, ticks_values_and_labels=None):
     divider = make_axes_locatable(ax)
     cax = divider.append_axes('right', size='5%', pad=0.0)
-    cb = cbar.ColorbarBase(cax, cmap=cmap, norm=norm)
+    ticks = ticks_values_and_labels[0] if ticks_values_and_labels is not None else None
+    cb = cbar.ColorbarBase(cax, cmap=cmap, norm=norm, ticks=ticks)
+    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)
     return norm
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 e194878b..bb1429a9 100644
--- a/experiment/meteo_france_data/scm_models_data/abstract_study.py
+++ b/experiment/meteo_france_data/scm_models_data/abstract_study.py
@@ -306,6 +306,7 @@ class AbstractStudy(object):
                         massif_name_to_hatch_boolean_list=None,
                         norm=None,
                         massif_name_to_marker_style=None,
+                        ticks_values_and_labels=None,
                         ):
         if ax is None:
             ax = plt.gca()
@@ -391,7 +392,7 @@ class AbstractStudy(object):
         # create the colorbar only at the end
         if add_colorbar:
             if len(set(values)) > 1:
-                create_colorbase_axis(ax, label, cmap, norm)
+                create_colorbase_axis(ax, label, cmap, norm, ticks_values_and_labels=ticks_values_and_labels)
         if axis_off:
             plt.axis('off')
 
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/eurocode_visualizer.py
index fcf66c6f..1c917c6e 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/eurocode_visualizer.py
@@ -38,9 +38,10 @@ def plot_uncertainty_massifs(altitude_to_visualizer: Dict[int, StudyVisualizerFo
     """
     visualizer = list(altitude_to_visualizer.values())[0]
     # Subdivide massif names in group of 3
-    m = 3
+    m = 1
     uncertainty_massif_names = visualizer.uncertainty_massif_names
     n = (len(uncertainty_massif_names) // m) + 1
+    print('total nb of massif', n)
     for i in list(range(n))[:]:
         massif_names = uncertainty_massif_names[m * i: m * (i + 1)]
         print(massif_names)
@@ -97,7 +98,7 @@ 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:olive']
+    colors = ['tab:green', 'tab:brown'][::-1]
     alpha = 0.2
     # Display the EUROCODE return level
     eurocode_region = massif_name_to_eurocode_region[massif_name]()
@@ -106,14 +107,27 @@ def plot_single_uncertainty_massif_and_non_stationary_context(ax, massif_name, n
     for j, (color, uncertainty_method) in enumerate(zip(colors, visualizer.uncertainty_methods)):
         # Plot eurocode standards only for the first loop
         if j == 0:
+            # Plot eurocode norm
             eurocode_region.plot_eurocode_snow_load_on_ground_characteristic_value_variable_action(ax,
                                                                                                    altitudes=altitudes)
+            # Plot bars of TDRL only in the non stationary case
+            if non_stationary_context:
+                tdrl_values = [v.massif_name_to_tdrl_value[massif_name] for v in altitude_to_visualizer.values()]
+                # Plot bars
+                colors = [v.massif_name_to_tdrl_color[massif_name] for v in altitude_to_visualizer.values()]
+                ax.bar(altitudes, tdrl_values, width=150, color=colors)
+                # Plot markers
+                markers_kwargs = [v.massif_name_to_marker_style(markersize=4)[massif_name]
+                                  for v, tdrl_value in zip(altitude_to_visualizer.values(), tdrl_values)]
+                for altitude, marker_kwargs, value in zip(altitudes, markers_kwargs, tdrl_values):
+                    ax.plot([altitude], [value / 2], **marker_kwargs)
+
         # Plot uncertainties
         plot_valid_return_level_uncertainties(alpha, altitude_to_visualizer, altitudes, ax, color, massif_name,
                                               non_stationary_context, uncertainty_method)
 
     ax.legend(loc=2)
-    ax.set_ylim([0.0, 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,
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 6c867dfb..70ad497e 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
@@ -4,6 +4,7 @@ import os.path as op
 import matplotlib as mpl
 import matplotlib.pyplot as plt
 
+from experiment.meteo_france_data.plot.create_shifted_cmap import get_shifted_map
 from experiment.meteo_france_data.scm_models_data.visualization.study_visualization.study_visualizer import \
     StudyVisualizer
 from experiment.paper_past_snow_loads.result_trends_and_return_levels.eurocode_visualizer import \
@@ -23,6 +24,7 @@ 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()
 
 
 def intermediate_result(altitudes, massif_names=None,
@@ -67,16 +69,17 @@ def major_result():
 
 if __name__ == '__main__':
     # minor_result(altitude=1800)
-    intermediate_result(altitudes=[1500, 1800], massif_names=['Chartreuse'],
-                        uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle],
-                        non_stationary_uncertainty=[False])
+    # intermediate_result(altitudes=[1500, 1800], massif_names=['Chartreuse'],
+    #                     uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle,
+    #                                          ConfidenceIntervalMethodFromExtremes.ci_bayes],
+    #                     non_stationary_uncertainty=[True])
     # intermediate_result(altitudes=[1500, 1800], massif_names=None,
     #                     uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle],
     #                     non_stationary_uncertainty=[False])
     # intermediate_result(altitudes=[300, 600, 900, 1200, 1500, 1800], massif_names=None,
     #                     uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle],
     #                     non_stationary_uncertainty=[False])
-    # intermediate_result(altitudes=[300, 600, 900, 1200, 1500, 1800], massif_names=['Vercors', 'Oisans', 'Devoluy'],
-    #                     uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle,
-    #                                          ConfidenceIntervalMethodFromExtremes.ci_bayes],
-    #                     non_stationary_uncertainty=[False, True])
+    intermediate_result(altitudes=[300, 600, 900, 1200, 1500, 1800], massif_names=None,
+                        uncertainty_methods=[ConfidenceIntervalMethodFromExtremes.ci_mle,
+                                             ConfidenceIntervalMethodFromExtremes.ci_bayes],
+                        non_stationary_uncertainty=[False, True])
diff --git a/experiment/paper_past_snow_loads/result_trends_and_return_levels/study_visualizer_for_non_stationary_trends.py b/experiment/paper_past_snow_loads/result_trends_and_return_levels/study_visualizer_for_non_stationary_trends.py
index 85272623..0bcacfd0 100644
--- a/experiment/paper_past_snow_loads/result_trends_and_return_levels/study_visualizer_for_non_stationary_trends.py
+++ b/experiment/paper_past_snow_loads/result_trends_and_return_levels/study_visualizer_for_non_stationary_trends.py
@@ -7,6 +7,7 @@ import numpy as np
 from cached_property import cached_property
 
 from experiment.eurocode_data.utils import EUROCODE_QUANTILE
+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
 from experiment.meteo_france_data.scm_models_data.visualization.study_visualization.study_visualizer import \
     StudyVisualizer
@@ -55,6 +56,8 @@ 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
+
     # Utils
 
     @cached_property
@@ -91,8 +94,9 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer):
         massif_name_to_trend_test_that_minimized_aic = {}
         for massif_name, (x, y) in self.massif_name_to_non_null_years_and_maxima.items():
             quantile_level = self.massif_name_to_eurocode_quantile_level_in_practice[massif_name]
-            non_stationary_trend_test = [t(years=x, maxima=y, starting_year=starting_year, quantile_level=quantile_level)
-                                         for t in self.non_stationary_trend_test]
+            non_stationary_trend_test = [
+                t(years=x, maxima=y, starting_year=starting_year, quantile_level=quantile_level)
+                for t in self.non_stationary_trend_test]
             trend_test_that_minimized_aic = sorted(non_stationary_trend_test, key=lambda t: t.aic)[0]
             massif_name_to_trend_test_that_minimized_aic[massif_name] = trend_test_that_minimized_aic
         return massif_name_to_trend_test_that_minimized_aic
@@ -103,32 +107,62 @@ class StudyVisualizerForNonStationaryTrends(StudyVisualizer):
     def max_abs_tdrl(self):
         return max(abs(min(self.massif_name_to_tdrl_value.values())), max(self.massif_name_to_tdrl_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 plot_trends(self, max_abs_tdrl=None):
-        if max_abs_tdrl is None:
-            max_abs_tdrl = self.max_abs_tdrl
-        assert max_abs_tdrl > 0
+        if max_abs_tdrl is not None:
+            self.global_max_abs_tdrl = max_abs_tdrl
         self.study.visualize_study(massif_name_to_value=self.massif_name_to_tdrl_value,
-                                   vmin=-max_abs_tdrl, vmax=max_abs_tdrl,
-                                   replace_blue_by_white=False, axis_off=True, show_label=False,
+                                   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,
-                                   show=self.show)
+                                   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=self.show,
+                                   ticks_values_and_labels=self.ticks_values_and_labels,
+                                   label=self.label_trend_bar)
         self.plot_name = 'tdlr_trends'
         self.show_or_save_to_file(add_classic_title=False, tight_layout=False, no_title=True)
         plt.close()
 
+    @property
+    def label_trend_bar(self):
+        return 'Change in {} years for Eurocode quantile of SL (kN $m^-2$)'.format(AbstractGevTrendTest.nb_years_for_quantile_evolution)
+
+    @property
+    def ticks_values_and_labels(self):
+        graduation = 0.2
+        positive_ticks = []
+        tick = graduation
+        while tick < self._max_abs_tdrl:
+            positive_ticks.append(round(tick, 1))
+            tick += graduation
+        all_ticks_labels = [-t for t in positive_ticks] + [0] + positive_ticks
+        ticks_values = [(t / 2 * self._max_abs_tdrl) + 0.5 for t in all_ticks_labels]
+        return ticks_values, all_ticks_labels
+
     @cached_property
     def massif_name_to_tdrl_value(self):
         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 cmap(self):
+        return get_shifted_map(-self._max_abs_tdrl, self._max_abs_tdrl)
 
-    @property
-    def massif_name_to_marker_style(self):
+    @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_marker_style(self, markersize=5):
         d = {}
         for m, t in self.massif_name_to_minimized_aic_non_stationary_trend_test.items():
             d[m] = {'marker': self.non_stationary_trend_test_to_marker[type(t)],
                     'color': 'k',
-                    'markersize': 5,
+                    'markersize': markersize,
                     'fillstyle': 'full' if t.is_significant else 'none'}
         return d
 
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
index 240d6535..10c67292 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/abstract_result_from_extremes.py
@@ -1,5 +1,6 @@
 import numpy as np
 import pandas as pd
+import rpy2
 from rpy2 import robjects
 
 from extreme_fit.distribution.gev.gev_params import GevParams
@@ -48,7 +49,10 @@ class AbstractResultFromExtremes(AbstractResultFromModelFit):
             qcov = r("make.qcov")(self.result_from_fit,
                                   **kwargs)
             common_kwargs['qcov'] = qcov
-        mean_estimate, confidence_interval = self._confidence_interval_method(common_kwargs, ci_method, return_period)
+        try:
+            mean_estimate, confidence_interval = self._confidence_interval_method(common_kwargs, ci_method, return_period)
+        except rpy2.rinterface.RRuntimeError:
+            mean_estimate, confidence_interval = np.nan, (np.nan, np.nan)
         return mean_estimate, confidence_interval
 
     def _confidence_interval_method(self, common_kwargs, ci_method, return_period):
diff --git a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
index 243eb2e9..56a167bf 100644
--- a/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
+++ b/extreme_fit/model/result_from_model_fit/result_from_extremes/result_from_mle_extremes.py
@@ -24,10 +24,7 @@ class ResultFromMleExtremes(AbstractResultFromExtremes):
                 'method': method_name,
             # xrange = NULL, nint = 20
         }
-        try:
-            res = r.ci(self.result_from_fit, **mle_ci_parameters, **common_kwargs)
-        except rpy2.rinterface.RRuntimeError:
-            return np.nan, (np.nan, np.nan)
+        res = r.ci(self.result_from_fit, **mle_ci_parameters, **common_kwargs)
         if self.is_non_stationary:
             a = np.array(res)[0]
             lower, mean_estimate, upper, _ = a
-- 
GitLab