Commit a7fa4dda authored by Le Roux Erwan's avatar Le Roux Erwan
Browse files

[SCM][SCORE TREND] add altitude visualization for the studies

parent 3bf99043
No related merge requests found
Showing with 113 additions and 14 deletions
+113 -14
from experiment.meteo_france_SCM_study.abstract_score import MannKendall, WeigthedScore, MeanScore, MedianScore
from experiment.meteo_france_SCM_study.abstract_study import AbstractStudy from experiment.meteo_france_SCM_study.abstract_study import AbstractStudy
from experiment.meteo_france_SCM_study.crocus.crocus import CrocusDepth, CrocusSwe, ExtendedCrocusDepth, \ from experiment.meteo_france_SCM_study.crocus.crocus import CrocusDepth, CrocusSwe, ExtendedCrocusDepth, \
ExtendedCrocusSwe ExtendedCrocusSwe
from experiment.meteo_france_SCM_study.safran.safran import SafranSnowfall, ExtendedSafranSnowfall, \ from experiment.meteo_france_SCM_study.safran.safran import SafranSnowfall, ExtendedSafranSnowfall, \
ExtendedSafranTotalPrecip ExtendedSafranTotalPrecip
from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies import Studies from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies import Studies
from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies_visualizer import StudiesVisualizer from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies_visualizer import StudiesVisualizer, \
AltitudeVisualizer
from experiment.meteo_france_SCM_study.visualization.study_visualization.main_study_visualizer import ALL_ALTITUDES, \
study_iterator_global
from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer
from collections import OrderedDict from collections import OrderedDict
SCM_STUDIES = [SafranSnowfall, CrocusSwe, CrocusDepth]
SCM_EXTENDED_STUDIES = [ExtendedSafranTotalPrecip, ExtendedSafranSnowfall, ExtendedCrocusSwe, ExtendedCrocusDepth]
SCM_STUDY_TO_EXTENDED_STUDY = OrderedDict(zip(SCM_STUDIES, SCM_EXTENDED_STUDIES))
def normal_visualization(): def normal_visualization():
for study_type in SCM_EXTENDED_STUDIES[:1]: for study_type in [ExtendedSafranTotalPrecip]:
extended_studies = Studies(study_type) extended_studies = Studies(study_type)
studies_visualizer = StudiesVisualizer(extended_studies) studies_visualizer = StudiesVisualizer(extended_studies)
studies_visualizer.mean_as_a_function_of_altitude(region_only=True) studies_visualizer.mean_as_a_function_of_altitude(region_only=True)
def altitude_trends():
save_to_file = False
only_first_one = False
# altitudes that have 20 massifs at least
altitudes = ALL_ALTITUDES[3:-6]
# altitudes = ALL_ALTITUDES[:2]
visualizers = [StudyVisualizer(study, save_to_file=save_to_file, temporal_non_stationarity=True, verbose=True,
score_class=MedianScore)
for study in study_iterator_global(study_classes=[SafranSnowfall], only_first_one=only_first_one,
altitudes=altitudes)]
altitude_to_visualizer = OrderedDict(zip(altitudes, visualizers))
visualizer = AltitudeVisualizer(altitude_to_visualizer)
visualizer.negative_trend_percentages_evolution()
if __name__ == '__main__': if __name__ == '__main__':
normal_visualization() altitude_trends()
from collections import OrderedDict, Counter
from typing import Dict
import numpy as np import numpy as np
import pandas as pd import pandas as pd
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from experiment.meteo_france_SCM_study.abstract_extended_study import AbstractExtendedStudy from experiment.meteo_france_SCM_study.abstract_extended_study import AbstractExtendedStudy
from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies import \ from experiment.meteo_france_SCM_study.visualization.studies_visualization.studies import \
Studies Studies
from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer
from experiment.meteo_france_SCM_study.visualization.utils import plot_df from experiment.meteo_france_SCM_study.visualization.utils import plot_df
from utils import cached_property, get_display_name_from_object_type
class StudiesVisualizer(object): class StudiesVisualizer(object):
...@@ -29,11 +35,86 @@ class StudiesVisualizer(object): ...@@ -29,11 +35,86 @@ class StudiesVisualizer(object):
for study in self.studies.altitude_to_study.values(): for study in self.studies.altitude_to_study.values():
mean_serie = study.df_annual_total.loc[:, massif_names].mean(axis=0) mean_serie = study.df_annual_total.loc[:, massif_names].mean(axis=0)
mean_series.append(mean_serie) mean_series.append(mean_serie)
df_mean = pd.concat(mean_series, axis=1) # type: pd.DataFrame df_mean = pd.concat(mean_series, axis=1) # type: pd.DataFrame
df_mean.columns = self.studies.altitude_list df_mean.columns = self.studies.altitude_list
plot_df(df_mean) plot_df(df_mean)
class AltitudeVisualizer(object):
def __init__(self, altitude_to_study_visualizer: Dict[int, StudyVisualizer]):
assert isinstance(altitude_to_study_visualizer, OrderedDict)
self.altitude_to_study_visualizer = altitude_to_study_visualizer
@property
def altitudes(self):
return list(self.altitude_to_study_visualizer.keys())
@cached_property
def all_percentages(self):
return [v.percentages_of_negative_trends()[0] for v in self.altitude_to_study_visualizer.values()]
@property
def any_study_visualizer(self) -> StudyVisualizer:
return list(self.altitude_to_study_visualizer.values())[0]
def get_item_fct(self, year):
idx = self.any_study_visualizer.starting_years.index(year)
f = lambda s: s[idx]
return f
@cached_property
def starting_year(self):
return self.any_study_visualizer.starting_years[0]
def get_top_potential_years(self, reverse=False):
top_n = 5
top_top = 3
# keep the top_n for each altitude
all_years = [[year for year, _ in sorted(enumerate(p), key=lambda s:s[1], reverse=reverse)[-top_n:]] for p in self.all_percentages]
from itertools import chain
all_years = list(chain(*all_years))
years = [y for y, _ in sorted(Counter(all_years).items(), key=lambda s:s[1])[-top_top:]]
years = [y + self.starting_year for y in years]
return years
def negative_trend_percentages_evolution(self):
curve_name__metric_and_color = [
('max', np.max, 'r'),
('mean', np.mean, 'b'),
('median', np.median, 'c'),
('min', np.min, 'g'),
]
# Add some years
# spotted_years = [1963, 1976]
# years_to_display = spotted_years
str_markers = ['o'] + [m for m in Line2D.markers if isinstance(m, str)][3:]
# for year, marker in zip(years_to_display, str_markers):
# new = (str(year), self.get_item_fct(year), 'y', marker + ':')
# curve_name__metric_and_color.append(new)
for year, marker in zip(self.get_top_potential_years(), str_markers):
new = (str(year), self.get_item_fct(year), 'm', marker + ':')
curve_name__metric_and_color.append(new)
for year, marker in zip(self.get_top_potential_years(reverse=True), str_markers):
new = (str(year), self.get_item_fct(year), 'y', marker + ':')
curve_name__metric_and_color.append(new)
fig, ax = plt.subplots(1, 1, figsize=self.any_study_visualizer.figsize)
for curve_name, metric, color, *marker in curve_name__metric_and_color[:]:
marker, curve_name = (marker[0], curve_name + ' starting year') if marker \
else ('-', curve_name + ' over the starting years')
values = [metric(p) for p in self.all_percentages]
ax.plot(self.altitudes, values, color + marker, label=curve_name)
ax.legend()
ax.set_xticks(self.altitudes)
ax.set_yticks(list(range(0,101, 10)))
ax.grid()
ax.axhline(y=50, color='k')
ax.set_ylabel('% of negative trends')
ax.set_xlabel('altitude')
scoer_class_name = get_display_name_from_object_type(self.any_study_visualizer.score_class)
title = 'Distribution of negative trend for the {}'.format(scoer_class_name)
ax.set_title(title)
plt.show()
...@@ -402,7 +402,7 @@ class StudyVisualizer(object): ...@@ -402,7 +402,7 @@ class StudyVisualizer(object):
def visualize_score_wrt_starting_year(self, ax, massif_name): def visualize_score_wrt_starting_year(self, ax, massif_name):
if massif_name is None: if massif_name is None:
percentage, title = self.percentage_of_negative_trends() percentage, title = self.percentages_of_negative_trends()
scores = percentage scores = percentage
ax.set_ylabel('% of negative trends') ax.set_ylabel('% of negative trends')
# Add two lines of interest # Add two lines of interest
...@@ -420,24 +420,27 @@ class StudyVisualizer(object): ...@@ -420,24 +420,27 @@ class StudyVisualizer(object):
ax.set_title(title) ax.set_title(title)
ax.xaxis.set_ticks(self.starting_years[2::20]) ax.xaxis.set_ticks(self.starting_years[2::20])
def percentage_of_negative_trends(self): def percentages_of_negative_trends(self):
print('start computing percentages negative trends')
# scores = np.median([np.array(v) < 0 for v in self.massif_name_to_scores.values()], axis=0) # scores = np.median([np.array(v) < 0 for v in self.massif_name_to_scores.values()], axis=0)
# Take the mean with respect to the massifs
# We obtain an array whose length equal the length of starting years
scores = np.mean([np.array(v) < 0 for v in self.massif_name_to_scores.values()], axis=0) scores = np.mean([np.array(v) < 0 for v in self.massif_name_to_scores.values()], axis=0)
percentage = 100 * scores percentages = 100 * scores
# First argmin, first argmax # First argmin, first argmax
argmin, argmax = np.argmin(scores), np.argmax(scores) argmin, argmax = np.argmin(scores), np.argmax(scores)
# Last argmin, last argmax # Last argmin, last argmax
# argmin, argmax = len(scores) - 1 - np.argmin(scores[::-1]), len(scores) - 1 - np.argmax(scores[::-1]) # argmin, argmax = len(scores) - 1 - np.argmin(scores[::-1]), len(scores) - 1 - np.argmax(scores[::-1])
top_starting_year_for_positive_trend = self.starting_years[argmin] top_starting_year_for_positive_trend = self.starting_years[argmin]
top_starting_year_for_negative_trend = self.starting_years[argmax] top_starting_year_for_negative_trend = self.starting_years[argmax]
top_percentage_positive_trend = round(100 - percentage[argmin], 0) top_percentage_positive_trend = round(100 - percentages[argmin], 0)
top_percentage_negative_trend = round(percentage[argmax], 0) top_percentage_negative_trend = round(percentages[argmax], 0)
title = "Global trend; > 0: {}% in {}; < 0: {}% in {}".format(top_percentage_positive_trend, title = "Global trend; > 0: {}% in {}; < 0: {}% in {}".format(top_percentage_positive_trend,
top_starting_year_for_positive_trend, top_starting_year_for_positive_trend,
top_percentage_negative_trend, top_percentage_negative_trend,
top_starting_year_for_negative_trend) top_starting_year_for_negative_trend)
return percentage, title return percentages, title
def visualize_all_mean_and_max_graphs(self): def visualize_all_mean_and_max_graphs(self):
specified_massif_ids = [self.study.study_massif_names.index(massif_name) specified_massif_ids = [self.study.study_massif_names.index(massif_name)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment