diff --git a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/abstract_hypercube_visualizer.py b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/abstract_hypercube_visualizer.py new file mode 100644 index 0000000000000000000000000000000000000000..13524c335b8ce8a3001013423d340461b625dedc --- /dev/null +++ b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/abstract_hypercube_visualizer.py @@ -0,0 +1,95 @@ +import os +import os.path as op +from typing import Dict, Tuple + +import matplotlib.pyplot as plt +import pandas as pd + +from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer +from utils import cached_property, VERSION_TIME, get_display_name_from_object_type + + +class AbstractHypercubeVisualizer(object): + """ + A study visualizer contain some massifs and years. This forms the base DataFrame of the hypercube + Additional index will come from the tuple. + Tuple could contain altitudes, type of snow quantity + """ + + def __init__(self, tuple_to_study_visualizer: Dict[Tuple, StudyVisualizer], + trend_test_class, + fast=False, + save_to_file=False): + self.nb_data_for_fast_mode = 7 if fast else None + self.save_to_file = save_to_file + self.trend_test_class = trend_test_class + self.tuple_to_study_visualizer = tuple_to_study_visualizer # type: Dict[Tuple, StudyVisualizer] + + # Main attributes defining the hypercube + + @property + def trend_test_name(self): + return get_display_name_from_object_type(self.trend_test_class) + + @cached_property + def starting_years(self): + starting_years = self.study_visualizer.starting_years + if self.nb_data_for_fast_mode is not None: + starting_years = starting_years[:self.nb_data_for_fast_mode] + return starting_years + + def tuple_values(self, idx): + return sorted(set([t[idx] if isinstance(t, tuple) else t for t in self.tuple_to_study_visualizer.keys()])) + + @cached_property + def df_hypercube_trend_type(self) -> pd.DataFrame: + df_spatio_temporal_trend_types = [ + study_visualizer.df_trend_spatio_temporal(self.trend_test_class, self.starting_years, + self.nb_data_for_fast_mode) + for study_visualizer in self.tuple_to_study_visualizer.values()] + return pd.concat(df_spatio_temporal_trend_types, keys=list(self.tuple_to_study_visualizer.keys()), axis=0) + + @cached_property + def df_hypercube_trend_strength(self) -> pd.DataFrame: + df_spatio_temporal_trend_types = [ + study_visualizer.df_trend_spatio_temporal(self.trend_test_class, self.starting_years, + self.nb_data_for_fast_mode) + for study_visualizer in self.tuple_to_study_visualizer.values()] + return pd.concat(df_spatio_temporal_trend_types, keys=list(self.tuple_to_study_visualizer.keys()), axis=0) + + # Some properties + + @property + def study_title(self): + return self.study.title + + def show_or_save_to_file(self, specific_title=''): + if self.save_to_file: + main_title, *_ = '_'.join(self.study_title.split()).split('/') + filename = "{}/{}/".format(VERSION_TIME, main_title) + filename += specific_title + filepath = op.join(self.study.result_full_path, filename + '.png') + dirname = op.dirname(filepath) + if not op.exists(dirname): + os.makedirs(dirname, exist_ok=True) + plt.savefig(filepath) + else: + plt.show() + + @property + def study_visualizer(self) -> StudyVisualizer: + return list(self.tuple_to_study_visualizer.values())[0] + + @property + def study(self): + return self.study_visualizer.study + + @property + def starting_year_to_weights(self): + # Load uniform weights by default + uniform_weight = 1 / len(self.starting_years) + return {year: uniform_weight for year in self.starting_years} + + + + diff --git a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/hypercube_visualizer.py b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/altitude_hypercube_visualizer.py similarity index 58% rename from experiment/meteo_france_SCM_study/visualization/hypercube_visualization/hypercube_visualizer.py rename to experiment/meteo_france_SCM_study/visualization/hypercube_visualization/altitude_hypercube_visualizer.py index c710200db79413babbaab7df2d85792bdcaf2dff..5c692a918bcfce40038e01e816c93a8408d87bb5 100644 --- a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/hypercube_visualizer.py +++ b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/altitude_hypercube_visualizer.py @@ -1,97 +1,14 @@ -import os -import os.path as op -from typing import Dict, Tuple - import matplotlib.pyplot as plt import pandas as pd +from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.abstract_hypercube_visualizer import \ + AbstractHypercubeVisualizer from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer from experiment.trend_analysis.univariate_trend_test.abstract_trend_test import AbstractTrendTest -from utils import cached_property, VERSION_TIME, get_display_name_from_object_type - - -class HypercubeVisualizer(object): - """ - A study visualizer contain some massifs and years. This forms the base DataFrame of the hypercube - Additional index will come from the tuple. - Tuple could contain altitudes, type of snow quantity - """ - - def __init__(self, tuple_to_study_visualizer: Dict[Tuple, StudyVisualizer], - trend_test_class, - fast=False, - save_to_file=False): - self.nb_data_for_fast_mode = 7 if fast else None - self.save_to_file = save_to_file - self.trend_test_class = trend_test_class - self.tuple_to_study_visualizer = tuple_to_study_visualizer # type: Dict[Tuple, StudyVisualizer] - - # Main attributes defining the hypercube - - @property - def trend_test_name(self): - return get_display_name_from_object_type(self.trend_test_class) - - @cached_property - def starting_years(self): - starting_years = self.study_visualizer.starting_years - if self.nb_data_for_fast_mode is not None: - starting_years = starting_years[:self.nb_data_for_fast_mode] - return starting_years - - @cached_property - def tuple_to_df_trend_type(self): - df_spatio_temporal_trend_types = [ - study_visualizer.df_trend_spatio_temporal(self.trend_test_class, self.starting_years, - self.nb_data_for_fast_mode) - for study_visualizer in self.tuple_to_study_visualizer.values()] - return dict(zip(self.tuple_to_study_visualizer.keys(), df_spatio_temporal_trend_types)) - - def tuple_values(self, idx): - return sorted(set([t[idx] if isinstance(t, tuple) else t for t in self.tuple_to_study_visualizer.keys()])) - - @cached_property - def df_hypercube(self) -> pd.DataFrame: - keys = list(self.tuple_to_df_trend_type.keys()) - values = list(self.tuple_to_df_trend_type.values()) - df = pd.concat(values, keys=keys, axis=0) - return df +from utils import get_display_name_from_object_type - # Some properties - @property - def study_title(self): - return self.study.title - - def show_or_save_to_file(self, specific_title=''): - if self.save_to_file: - main_title, *_ = '_'.join(self.study_title.split()).split('/') - filename = "{}/{}/".format(VERSION_TIME, main_title) - filename += specific_title - filepath = op.join(self.study.result_full_path, filename + '.png') - dirname = op.dirname(filepath) - if not op.exists(dirname): - os.makedirs(dirname, exist_ok=True) - plt.savefig(filepath) - else: - plt.show() - - @property - def study_visualizer(self) -> StudyVisualizer: - return list(self.tuple_to_study_visualizer.values())[0] - - @property - def study(self): - return self.study_visualizer.study - - @property - def starting_year_to_weights(self): - # Load uniform weights by default - uniform_weight = 1 / len(self.starting_years) - return {year: uniform_weight for year in self.starting_years} - - -class AltitudeHypercubeVisualizer(HypercubeVisualizer): +class AltitudeHypercubeVisualizer(AbstractHypercubeVisualizer): @property def altitudes(self): @@ -109,7 +26,7 @@ class AltitudeHypercubeVisualizer(HypercubeVisualizer): # Map each trend type to its serie with percentages trend_type_to_s_percentages = {} for trend_type in self.trend_types: - df_bool = (self.df_hypercube == trend_type) + df_bool = (self.df_hypercube_trend_type == trend_type) # Reduce the entire dataframe to a serie s_percentages = reduction_function(df_bool) assert isinstance(s_percentages, pd.Series) @@ -125,10 +42,8 @@ class AltitudeHypercubeVisualizer(HypercubeVisualizer): def subtitle_to_reduction_function(self, reduction_function, level=None, add_detailed_plot=False): def reduction_function_with_level(df_bool): - if level is None: - return reduction_function(df_bool) - else: - return reduction_function(df_bool, level) + return reduction_function(df_bool) if level is None else reduction_function(df_bool, level) + return {'global': reduction_function_with_level} def visualize_trend_test_evolution(self, reduction_function, xlabel, xlabel_values, ax=None, marker='o', @@ -214,10 +129,10 @@ class AltitudeHypercubeVisualizer(HypercubeVisualizer): # Take the mean with respect to the years df_bool = df_bool.mean(axis=1) # Take the mean with respect the massifs - print(df_bool.head()) return df_bool.mean(level=level) - for subtitle, reduction_function in self.subtitle_to_reduction_function(altitude_reduction, level=self.altitude_index_level, + for subtitle, reduction_function in self.subtitle_to_reduction_function(altitude_reduction, + level=self.altitude_index_level, add_detailed_plot=add_detailed_plots).items(): self.visualize_trend_test_evolution(reduction_function=reduction_function, xlabel='altitude', xlabel_values=self.altitudes, ax=ax, marker=marker, @@ -230,51 +145,7 @@ class AltitudeHypercubeVisualizer(HypercubeVisualizer): # Take the mean with respect the altitude return df_bool.mean(level=level) - for subtitle, reduction_function in self.subtitle_to_reduction_function(massif_reduction,level=self.massif_index_level, + for subtitle, reduction_function in self.subtitle_to_reduction_function(massif_reduction, + level=self.massif_index_level, add_detailed_plot=add_detailed_plots).items(): self.visualize_trend_test_repartition(reduction_function, axes, subtitle=subtitle) - - -class QuantityAltitudeHypercubeVisualizer(AltitudeHypercubeVisualizer): - - @property - def study_title(self): - return 'Quantity Altitude Study' - - def subtitle_to_reduction_function(self, reduction_function, level=None, add_detailed_plot=False): - subtitle_to_reduction_function = super().subtitle_to_reduction_function(reduction_function, level, add_detailed_plot) - - def get_function_from_tuple(tuple_for_axis_0): - def f(df_bool: pd.DataFrame): - # Loc with a tuple with respect the axis 0 - df_bool = df_bool.loc[tuple_for_axis_0, :].copy() - # Apply the reduction function - if level is None: - return reduction_function(df_bool) - else: - return reduction_function(df_bool, level-1) - - return f - - # Add the detailed plot, taken by loc with respect to the first index - if add_detailed_plot: - tuples_axis_0 = self.tuple_values(idx=0) - for tuple_axis_0 in tuples_axis_0: - subtitle_to_reduction_function[tuple_axis_0] = get_function_from_tuple(tuple_axis_0) - return subtitle_to_reduction_function - - @property - def quantities(self): - return self.tuple_values(idx=0) - - @property - def altitudes(self): - return self.tuple_values(idx=1) - - @property - def altitude_index_level(self): - return 1 - - @property - def massif_index_level(self): - return 2 diff --git a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/main_hypercube_visualization.py b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/main_hypercube_visualization.py index 987de94118d5dc42a6659f7cd671d9d9ae1d3d7a..28e8e3bcd9b5c17e2ce64850e6cdea144932d991 100644 --- a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/main_hypercube_visualization.py +++ b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/main_hypercube_visualization.py @@ -2,8 +2,10 @@ import time from itertools import product from collections import OrderedDict -from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.hypercube_visualizer import \ - AltitudeHypercubeVisualizer, QuantityAltitudeHypercubeVisualizer +from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.altitude_hypercube_visualizer import \ + AltitudeHypercubeVisualizer +from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.quantity_altitude_visualizer import \ + QuantityAltitudeHypercubeVisualizer from experiment.meteo_france_SCM_study.visualization.study_visualization.main_study_visualizer import ALL_ALTITUDES, \ SCM_STUDIES, study_iterator, study_iterator_global from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer @@ -90,9 +92,9 @@ def fast_trends_with_quantity_altitude_hypercube(): def main_run(): - # fast_trends_with_altitude_hypercube() + fast_trends_with_altitude_hypercube() # fast_trends_with_quantity_altitude_hypercube() - full_trends_with_quantity_altitude_hypercube() + # full_trends_with_quantity_altitude_hypercube() if __name__ == '__main__': diff --git a/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/quantity_altitude_visualizer.py b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/quantity_altitude_visualizer.py new file mode 100644 index 0000000000000000000000000000000000000000..92d20988786352aefc381ea614068d7e638468ce --- /dev/null +++ b/experiment/meteo_france_SCM_study/visualization/hypercube_visualization/quantity_altitude_visualizer.py @@ -0,0 +1,46 @@ +import pandas as pd + +from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.altitude_hypercube_visualizer import \ + AltitudeHypercubeVisualizer + + +class QuantityAltitudeHypercubeVisualizer(AltitudeHypercubeVisualizer): + + @property + def study_title(self): + return 'Quantity Altitude Study' + + def subtitle_to_reduction_function(self, reduction_function, level=None, add_detailed_plot=False): + subtitle_to_reduction_function = super().subtitle_to_reduction_function(reduction_function, + level, add_detailed_plot) + + def get_function_from_tuple(tuple_for_axis_0): + def f(df_bool: pd.DataFrame): + # Loc with a tuple with respect the axis 0 + df_bool = df_bool.loc[tuple_for_axis_0, :].copy() + # Apply the reduction function + return reduction_function(df_bool) if level is None else reduction_function(df_bool, level-1) + return f + + # Add the detailed plot, taken by loc with respect to the first index + if add_detailed_plot: + tuples_axis_0 = self.tuple_values(idx=0) + for tuple_axis_0 in tuples_axis_0: + subtitle_to_reduction_function[tuple_axis_0] = get_function_from_tuple(tuple_axis_0) + return subtitle_to_reduction_function + + @property + def quantities(self): + return self.tuple_values(idx=0) + + @property + def altitudes(self): + return self.tuple_values(idx=1) + + @property + def altitude_index_level(self): + return 1 + + @property + def massif_index_level(self): + return 2 diff --git a/experiment/meteo_france_SCM_study/visualization/studies_visualization/main_studies_visualizer.py b/experiment/meteo_france_SCM_study/visualization/studies_visualization/main_studies_visualizer.py index fc0f64a30d5d47444c0de4659f017c2c34217241..23c2c0fa56c95bd4594266c58cae4124d380145e 100644 --- a/experiment/meteo_france_SCM_study/visualization/studies_visualization/main_studies_visualizer.py +++ b/experiment/meteo_france_SCM_study/visualization/studies_visualization/main_studies_visualizer.py @@ -1,7 +1,4 @@ import time - -from experiment.meteo_france_SCM_study.visualization.hypercube_visualization.hypercube_visualizer import \ - AltitudeHypercubeVisualizer from experiment.trend_analysis.abstract_score import MannKendall, WeigthedScore, MeanScore, MedianScore from experiment.trend_analysis.univariate_trend_test.abstract_gev_trend_test import GevLocationTrendTest, \ GevScaleTrendTest, GevShapeTrendTest @@ -11,7 +8,7 @@ from experiment.meteo_france_SCM_study.visualization.studies_visualization.studi 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, SCM_STUDIES, study_iterator + study_iterator_global, SCM_STUDIES from experiment.meteo_france_SCM_study.visualization.study_visualization.study_visualizer import StudyVisualizer from collections import OrderedDict