From 54c2c62a501b63b354da59d92e1137c828cfc078 Mon Sep 17 00:00:00 2001
From: Le Roux Erwan <erwan.le-roux@irstea.fr>
Date: Wed, 15 May 2019 18:29:49 +0200
Subject: [PATCH] [SCM][SCORE TREND] add score graph depending on starting year

---
 .../main_study_visualizer.py                  |  22 +++-
 .../study_visualization/study_visualizer.py   | 113 +++++++++++++++---
 2 files changed, 115 insertions(+), 20 deletions(-)

diff --git a/experiment/meteo_france_SCM_study/visualization/study_visualization/main_study_visualizer.py b/experiment/meteo_france_SCM_study/visualization/study_visualization/main_study_visualizer.py
index ace9884b..27012848 100644
--- a/experiment/meteo_france_SCM_study/visualization/study_visualization/main_study_visualizer.py
+++ b/experiment/meteo_france_SCM_study/visualization/study_visualization/main_study_visualizer.py
@@ -104,9 +104,8 @@ def normal_visualization(temporal_non_stationarity=False):
         for study in study_iterator(study_class, only_first_one=only_first_one, altitudes=[300]):
             study_visualizer = StudyVisualizer(study, save_to_file=save_to_file,
                                                temporal_non_stationarity=temporal_non_stationarity)
-            study_visualizer.window_size_for_smoothing = 1
-            study_visualizer.number_of_top_values = 10
-            study_visualizer.visualize_all_mean_and_max_graphs()
+            print(study_visualizer.massif_name_to_scores)
+            # study_visualizer.visualize_all_mean_and_max_graphs()
 
             # study_visualizer.visualize_independent_margin_fits(threshold=[None, 20, 40, 60][0])
             # study_visualizer.visualize_annual_mean_values()
@@ -117,6 +116,18 @@ def all_normal_vizu():
         study_visualizer = StudyVisualizer(study, save_to_file=True, temporal_non_stationarity=True)
         study_visualizer.visualize_all_mean_and_max_graphs()
 
+def scores_vizu():
+    for study in study_iterator_global(study_classes=ALL_STUDIES, only_first_one=True, altitudes=[1800]):
+        study_visualizer = StudyVisualizer(study, save_to_file=False, temporal_non_stationarity=True)
+        # study_visualizer.visualize_all_score_wrt_starting_year()
+        study_visualizer.visualize_all_score_wrt_starting_year()
+
+
+def all_scores_vizu():
+    for study in study_iterator_global(study_classes=[SafranSnowfall], only_first_one=False, altitudes=ALL_ALTITUDES):
+        study_visualizer = StudyVisualizer(study, save_to_file=True, temporal_non_stationarity=True)
+        study_visualizer.visualize_all_score_wrt_starting_year()
+
 def complete_analysis(only_first_one=False):
     """An overview of everything that is possible with study OR extended study"""
     for study_class, extended_study_class in list(SCM_STUDY_TO_EXTENDED_STUDY.items())[:]:
@@ -157,14 +168,15 @@ def trend_analysis():
 def main_run():
     # normal_visualization(temporal_non_stationarity=True)
     # trend_analysis()
-    all_normal_vizu()
+    # all_normal_vizu()
 
     # annual_mean_vizu_compare_durand_study(safran=True, take_mean_value=True, altitude=2100)
 
     # max_stable_process_vizu_compare_gaume_study(altitude=1800, nb_days=1)
     # extended_visualization()
     # complete_analysis()
-
+    # scores_vizu()
+    all_scores_vizu()
 
 if __name__ == '__main__':
     start = time.time()
diff --git a/experiment/meteo_france_SCM_study/visualization/study_visualization/study_visualizer.py b/experiment/meteo_france_SCM_study/visualization/study_visualization/study_visualizer.py
index af6b1a6e..affa1088 100644
--- a/experiment/meteo_france_SCM_study/visualization/study_visualization/study_visualizer.py
+++ b/experiment/meteo_france_SCM_study/visualization/study_visualization/study_visualizer.py
@@ -166,7 +166,7 @@ class StudyVisualizer(object):
 
     # PLOT FOR SEVERAL MASSIFS
 
-    def visualize_massif_graphs(self, visualize_function, use_ordered_massif_names=False):
+    def visualize_massif_graphs(self, visualize_function, specified_massif_ids=None):
         if self.only_one_graph:
             fig, ax = plt.subplots(1, 1, figsize=self.figsize)
             visualize_function(ax, 0)
@@ -180,12 +180,9 @@ class StudyVisualizer(object):
                     ax = axes[massif_id]
                     visualize_function(ax, massif_id)
             else:
-                if use_ordered_massif_names:
-                    massif_ids = [self.study.study_massif_names.index(massif_name) for massif_name in
-                                  self.ordered_massif_names]
-                else:
-                    massif_ids = list(range(len(self.study.study_massif_names)))
-                for j, massif_id in enumerate(massif_ids):
+                if specified_massif_ids is None:
+                    specified_massif_ids = list(range(len(self.study.study_massif_names)))
+                for j, massif_id in enumerate(specified_massif_ids):
                     row_id, column_id = j // nb_columns, j % nb_columns
                     ax = axes[row_id, column_id]
                     visualize_function(ax, massif_id)
@@ -328,15 +325,16 @@ class StudyVisualizer(object):
         return all_massif_data
 
     @cached_property
-    def massif_name_to_score(self):
+    def massif_name_to_score(self, starting_year=1958):
         # Ordered massif by scores
         massif_name_to_score = {}
         for massif_id, massif_name in enumerate(self.study.study_massif_names):
             years, smooth_maxima = self.smooth_maxima_x_y(massif_id)
-            start_year = years[0]
+            idx_starting_year = years.index(starting_year)
+            smooth_maxima = smooth_maxima[idx_starting_year:]
             sorted_indices = [i for i, e in sorted(enumerate(smooth_maxima), key=lambda s: s[1])]
-            mean_max_year = np.mean(sorted_indices[-self.number_of_top_values:]) + start_year
-            mean_min_years = np.mean(sorted_indices[:self.number_of_top_values]) + start_year
+            mean_max_year = np.mean(sorted_indices[-self.number_of_top_values:]) + starting_year
+            mean_min_years = np.mean(sorted_indices[:self.number_of_top_values]) + starting_year
             score = mean_max_year - mean_min_years
             massif_name_to_score[massif_name] = (score, mean_max_year, mean_min_years)
         return massif_name_to_score
@@ -345,11 +343,96 @@ class StudyVisualizer(object):
     def ordered_massif_names(self):
         return sorted(self.study.study_massif_names[:], key=lambda s: self.massif_name_to_score[s][0])
 
+    @property
+    def starting_years(self):
+        start_year, stop_year = self.study.start_year_and_stop_year
+        return list(range(start_year, stop_year - 2 * self.number_of_top_values))
+
+    @cached_property
+    def massif_name_to_scores(self):
+        """
+        This score respect the following property.
+        Between two successive score, then if the starting year was neither a top10 maxima nor a top10 minima,
+        then the score will not change
+
+        The following case for instance gives a constant score wrt to the starting year
+        because all the maxima and all the minima are at the end
+            smooth_maxima = [0 for _ in years]
+            smooth_maxima[-20:-10] = [i for i in range(10)]
+            smooth_maxima[-10:] = [-i for i in range(10)]
+        :return:
+        """
+        # Ordered massif by scores
+        massif_name_to_scores = {}
+        for massif_id, massif_name in enumerate(self.study.study_massif_names):
+            years, smooth_maxima = self.smooth_maxima_x_y(massif_id)
+            sorted_years = [i + self.study.start_year_and_stop_year[0]
+                            for i, e in sorted(enumerate(smooth_maxima), key=lambda s: s[1])]
+            scores = []
+            for j, starting_year in enumerate(self.starting_years):
+                mean_max_year = np.mean(sorted_years[-self.number_of_top_values:])
+                mean_min_years = np.mean(sorted_years[:self.number_of_top_values])
+                score = mean_max_year - mean_min_years
+                scores.append(score)
+                sorted_years.remove(starting_year)
+            massif_name_to_scores[massif_name] = scores
+        return massif_name_to_scores
+
+    def visualize_all_score_wrt_starting_year(self):
+        # Build
+        specified_massif_names = sorted(self.study.study_massif_names,
+                                        key=lambda s: np.mean(self.massif_name_to_scores[s]))
+        specified_massif_names = sorted(self.study.study_massif_names, key=lambda s: self.massif_name_to_scores[s][0])
+        # Add one graph at the end
+        specified_massif_names += [None]
+        self.visualize_massif_graphs(self.visualize_score_wrt_starting_year,
+                                     specified_massif_ids=specified_massif_names)
+        plot_name = ''
+        plot_name += '{} top values for each score, abscisse represents starting year for a trend'.format(
+            self.number_of_top_values)
+        self.plot_name = plot_name
+        self.show_or_save_to_file()
+
+    def visualize_score_wrt_starting_year(self, ax, massif_name):
+        if massif_name is None:
+            percentage, title = self.percentage_of_negative_trends()
+            scores = percentage
+            ax.set_ylabel('% of negative trends')
+        else:
+            ax.set_ylabel('max score - min score ')
+            scores = self.massif_name_to_scores[massif_name]
+            title = massif_name
+        ax.plot(self.starting_years, scores)
+        ax.set_title(title)
+        ax.xaxis.set_ticks(self.starting_years[2::20])
+
+    def percentage_of_negative_trends(self):
+        mean = np.mean([np.array(v) < 0 for v in self.massif_name_to_scores.values()], axis=0)
+        percentage = 100 * mean
+        argmin, argmax = np.argmin(mean), np.argmax(mean)
+        top_starting_year_for_positive_trend = self.starting_years[argmin]
+        top_starting_year_for_negative_trend = self.starting_years[argmax]
+        top_percentage_positive_trend = round(100 - percentage[argmin], 0)
+        top_percentage_negative_trend = round(percentage[argmax], 0)
+        title = "Global trend; > 0: {}% in {}; < 0: {}% in {}".format(top_percentage_negative_trend,
+                                                                  top_starting_year_for_positive_trend,
+                                                                  top_percentage_positive_trend,
+                                                                  top_starting_year_for_negative_trend)
+
+        return percentage, title
+
     def visualize_all_mean_and_max_graphs(self):
-        self.visualize_massif_graphs(self.visualize_mean_and_max_graph, use_ordered_massif_names=True)
-        self.plot_name = ' smoothing values temporally with sliding window of size {}' \
-                         'and {} top values taking into account'.format(
-            self.window_size_for_smoothing, self.number_of_top_values)
+        specified_massif_ids = [self.study.study_massif_names.index(massif_name)
+                                for massif_name in
+                                sorted(self.study.study_massif_names, key=lambda s: self.massif_name_to_score[s])]
+        self.visualize_massif_graphs(self.visualize_mean_and_max_graph,
+                                     specified_massif_ids=specified_massif_ids)
+        plot_name = ''
+        if self.window_size_for_smoothing > 1:
+            plot_name += ' smoothing values temporally with sliding window of size {}'.format(
+                self.window_size_for_smoothing)
+        plot_name += '{} top values taken into account for the metric'.format(self.number_of_top_values)
+        self.plot_name = plot_name
         self.show_or_save_to_file()
 
     def visualize_mean_and_max_graph(self, ax, massif_id):
-- 
GitLab