diff --git a/extreme_data/meteo_france_data/scm_models_data/visualization/create_shifted_cmap.py b/extreme_data/meteo_france_data/scm_models_data/visualization/create_shifted_cmap.py index e3ad6d16e256c9b5bcf01ed81b96fece868d4f8f..662212c08cc1a0cf52a8506ebeefb02d05c274fd 100644 --- a/extreme_data/meteo_france_data/scm_models_data/visualization/create_shifted_cmap.py +++ b/extreme_data/meteo_france_data/scm_models_data/visualization/create_shifted_cmap.py @@ -4,6 +4,7 @@ import matplotlib.cm as cm import matplotlib.colorbar as cbar import matplotlib.pyplot as plt import numpy as np +from matplotlib.colors import LinearSegmentedColormap from mpl_toolkits.axes_grid1 import make_axes_locatable from extreme_fit.distribution.abstract_params import AbstractParams @@ -24,6 +25,13 @@ def get_shifted_map(vmin, vmax, cmap=plt.cm.bwr): return shifted_cmap +def get_half_colormap(cmap): + colors = cmap(np.linspace(0.5, 1, cmap.N // 2)) + # Create a new colormap from those colors + cmap2 = LinearSegmentedColormap.from_list('Upper Half', colors) + return cmap2 + + def create_colorbase_axis(ax, label, cmap, norm, ticks_values_and_labels=None, fontsize=15): divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.0) @@ -78,6 +86,15 @@ def ticks_values_and_labels_for_percentages(graduation, max_abs_change): ticks_values = [((t / max_abs_change) + 1) / 2 for t in all_ticks_labels] return ticks_values, all_ticks_labels +def ticks_values_and_labels_for_positive_value(graduation, max_abs_change): + positive_ticks = [] + tick = 0 + while tick < max_abs_change: + positive_ticks.append(round(tick, 1)) + tick += graduation + ticks_values = [(t / max_abs_change) for t in positive_ticks] + return ticks_values, positive_ticks + def ticks_and_labels_centered_on_one(max_ratio, min_ratio): """When we compute some ratio of two values. diff --git a/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py b/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py index 70e8fa68e568b46714a3cac2d774a8376b2256e6..1779e184db7a02ec61781c01e8b4783da0566616 100644 --- a/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py +++ b/extreme_data/meteo_france_data/scm_models_data/visualization/plot_utils.py @@ -3,7 +3,8 @@ import matplotlib.colors as mcolors from extreme_data.meteo_france_data.scm_models_data.abstract_study import AbstractStudy from extreme_data.meteo_france_data.scm_models_data.visualization.create_shifted_cmap import \ - ticks_values_and_labels_for_percentages, get_shifted_map, get_colors + ticks_values_and_labels_for_percentages, get_shifted_map, get_colors, ticks_values_and_labels_for_positive_value, \ + get_half_colormap def plot_against_altitude(altitudes, ax, massif_id, massif_name, values): @@ -21,12 +22,20 @@ def plot_against_altitude(altitudes, ax, massif_id, massif_name, values): ax.plot(altitudes, values, color=color, linewidth=2, label=massif_name_str, linestyle=linestyle) -def load_plot(cmap, graduation, label, massif_name_to_value, altitude, fit_method, add_x_label=True): +def load_plot(cmap, graduation, label, massif_name_to_value, altitude, fit_method, add_x_label=True, + negative_and_positive_values=True): max_abs_change = max([abs(e) for e in massif_name_to_value.values()]) - ticks, labels = ticks_values_and_labels_for_percentages(graduation=graduation, max_abs_change=max_abs_change) - min_ratio = -max_abs_change - max_ratio = max_abs_change - cmap = get_shifted_map(min_ratio, max_ratio, cmap) + if negative_and_positive_values: + ticks, labels = ticks_values_and_labels_for_percentages(graduation=graduation, max_abs_change=max_abs_change) + min_ratio = -max_abs_change + max_ratio = max_abs_change + cmap = get_shifted_map(min_ratio, max_ratio, cmap) + else: + ticks, labels = ticks_values_and_labels_for_positive_value(graduation=graduation, max_abs_change=max_abs_change) + cmap = get_half_colormap(cmap) + min_ratio = 0 + max_ratio = max_abs_change + massif_name_to_color = {m: get_colors([v], cmap, min_ratio, max_ratio)[0] for m, v in massif_name_to_value.items()} ticks_values_and_labels = ticks, labels diff --git a/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py b/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py index 34174e08676015ea7f00839da2d87e32fba4b7b8..3288a89df130052b9f362c8eb2ffdcdea80d9bef 100644 --- a/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py +++ b/extreme_data/meteo_france_data/scm_models_data/visualization/study_visualizer.py @@ -708,19 +708,21 @@ class StudyVisualizer(VisualizationParameters): # PLot functions that should be common - def plot_map(self, cmap, fit_method, graduation, label, massif_name_to_value, plot_name, add_x_label=True): + def plot_map(self, cmap, fit_method, graduation, label, massif_name_to_value, plot_name, add_x_label=True, + negative_and_positive_values=True): load_plot(cmap, graduation, label, massif_name_to_value, self.study.altitude, fitmethod_to_str(fit_method), - add_x_label=add_x_label) + add_x_label=add_x_label, negative_and_positive_values=negative_and_positive_values) self.plot_name = plot_name # self.show_or_save_to_file(add_classic_title=False, tight_layout=True, no_title=True, dpi=500) self.show_or_save_to_file(add_classic_title=False, no_title=True, dpi=500) plt.close() - def plot_abstract(self, massif_name_to_value, label, plot_name, fit_method='', graduation=10.0, cmap=plt.cm.bwr, add_x_label=True): + def plot_abstract(self, massif_name_to_value, label, plot_name, fit_method='', graduation=10.0, cmap=plt.cm.bwr, + add_x_label=True, negative_and_positive_values=True): # Regroup the plot by altitudes plot_name1 = '{}/{}'.format(self.study.altitude, plot_name) # Regroup the plot by type of plot also plot_name2 = '{}/{}'.format(plot_name.split()[0], plot_name) for plot_name in [plot_name1, plot_name2]: - self.plot_map(cmap, fit_method, graduation, label, massif_name_to_value, plot_name, add_x_label) + self.plot_map(cmap, fit_method, graduation, label, massif_name_to_value, plot_name, add_x_label, negative_and_positive_values) diff --git a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/main_snowfall_article.py b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/main_snowfall_article.py index 3a6a9feccf6cc6f2999aa0f1eea41b4b2924c21e..8c4090873a7868389ac45ed921aef81a5f42c020 100644 --- a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/main_snowfall_article.py +++ b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/main_snowfall_article.py @@ -72,8 +72,8 @@ def intermediate_result(altitudes, massif_names=None, _ = compute_minimized_aic(visualizer) # Plots - # validation_plot(altitude_to_visualizer) - # plot_snowfall_mean(altitude_to_visualizer) + validation_plot(altitude_to_visualizer) + plot_snowfall_mean(altitude_to_visualizer) plot_snowfall_time_derivative_mean(altitude_to_visualizer) @@ -84,7 +84,7 @@ def major_result(): study_classes = [SafranSnowfall1Day] model_subsets_for_uncertainty = None altitudes = paper_altitudes - altitudes = [900, 1200, 1500, 1800, 2100, 2400, 2700, 3000] + altitudes = [300, 600, 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600, 3900] # altitudes = [900, 1200] for study_class in study_classes: diff --git a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/snowfall_plot.py b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/snowfall_plot.py index a51a470135b80e19ccc934a41dd72f384908c3ce..2565d6c1d413f7be167cb68437879e43e1be8c32 100644 --- a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/snowfall_plot.py +++ b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/snowfall_plot.py @@ -22,43 +22,47 @@ def fit_linear_regression(x, y): def plot_snowfall_time_derivative_mean(altitude_to_visualizer: Dict[int, StudyVisualizerForMeanValues]): visualizer = list(altitude_to_visualizer.values())[0] + study = visualizer.study # Plot the curve for the evolution of the mean massif_name_to_a, massif_name_to_b, massif_name_to_r2_score = plot_mean(altitude_to_visualizer, derivative=True) # Augmentation every km massif_name_to_augmentation_every_km = {m: a * 1000 for m, a in massif_name_to_a.items()} visualizer.plot_abstract_fast(massif_name_to_augmentation_every_km, - label='Augmentation of time derivative of mean annual maxima for every km of elevation ()', + label='Augmentation of time derivative of mean annual maxima of {}\n for every km of elevation ({})'.format(SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)], study.variable_unit), add_x_label=False) # Value at 2000 m massif_name_to_mean_at_2000 = {m: a * 2000 + massif_name_to_b[m] for m, a in massif_name_to_a.items()} - visualizer.plot_abstract_fast(massif_name_to_mean_at_2000, label='Time derivative of mean annual maxima of at 2000 m ()', + visualizer.plot_abstract_fast(massif_name_to_mean_at_2000, label='Time derivative of mean annual maxima \nof {} at 2000 m ({})'.format(SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)], study.variable_unit), add_x_label=False) # Altitude for the change of dynamic massif_name_to_altitude_change_dynamic = {m: - massif_name_to_b[m] / a for m, a in massif_name_to_a.items()} # Keep only those that are in a reasonable range massif_name_to_altitude_change_dynamic = {m: d for m, d in massif_name_to_altitude_change_dynamic.items() if 0 < d < 3000} - visualizer.plot_abstract_fast(massif_name_to_altitude_change_dynamic, label='Altitude for the change of dynamic ()', + visualizer.plot_abstract_fast(massif_name_to_altitude_change_dynamic, label='Altitude for the change of dynamic (m)', add_x_label=False, graduation=500) # R2 score - visualizer.plot_abstract_fast(massif_name_to_r2_score, label='r2', graduation=0.1, add_x_label=False) + visualizer.plot_abstract_fast(massif_name_to_r2_score, label='r2 time derivative of the mean', graduation=0.1, add_x_label=False, + negative_and_positive_values=False) def plot_snowfall_mean(altitude_to_visualizer: Dict[int, StudyVisualizerForMeanValues]): visualizer = list(altitude_to_visualizer.values())[0] + study = visualizer.study # Plot the curve for the evolution of the mean massif_name_to_a, massif_name_to_b, massif_name_to_r2_score = plot_mean(altitude_to_visualizer, derivative=False) # Augmentation every km massif_name_to_augmentation_every_km = {m: a * 1000 for m, a in massif_name_to_a.items()} visualizer.plot_abstract_fast(massif_name_to_augmentation_every_km, - label='Augmentation of mean annual maxima for every km of elevation ()', - add_x_label=False) + label='Augmentation of mean annual maxima of {} \nfor every km of elevation ({})'.format(SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)], study.variable_unit), + add_x_label=False, negative_and_positive_values=False) # Value at 2000 m massif_name_to_mean_at_2000 = {m: a * 2000 + massif_name_to_b[m] for m, a in massif_name_to_a.items()} - visualizer.plot_abstract_fast(massif_name_to_mean_at_2000, label='Mean annual maxima of at 2000 m ()', - add_x_label=False) + visualizer.plot_abstract_fast(massif_name_to_mean_at_2000, label='Mean annual maxima of {} at 2000 m ()'.format(SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)], study.variable_unit), + add_x_label=False, negative_and_positive_values=False) # R2 score - visualizer.plot_abstract_fast(massif_name_to_r2_score, label='r2', graduation=0.1, add_x_label=False) + visualizer.plot_abstract_fast(massif_name_to_r2_score, label='r2 mean', graduation=0.1, + add_x_label=False, negative_and_positive_values=False) def plot_mean(altitude_to_visualizer: Dict[int, StudyVisualizerForMeanValues], derivative=False): diff --git a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/study_visualizer_for_mean_values.py b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/study_visualizer_for_mean_values.py index 70e5d768e149f0762c0c2fe1458291cccae86048..9fd53430349a839b029fc0afa3529d6e34c88350 100644 --- a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/study_visualizer_for_mean_values.py +++ b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/study_visualizer_for_mean_values.py @@ -35,7 +35,7 @@ class StudyVisualizerForMeanValues(StudyVisualizerForNonStationaryTrends): return massif_name_to_empirical_value @cached_property - def massif_name_to_parametric_mean(self): + def massif_name_to_model_mean(self): massif_name_to_parameter_value = {} for massif_name, trend_test in self.massif_name_to_trend_test_that_minimized_aic.items(): parameter_value = trend_test.unconstrained_average_mean_value @@ -47,11 +47,12 @@ class StudyVisualizerForMeanValues(StudyVisualizerForNonStationaryTrends): massif_name_to_relative_difference = {} for massif_name in self.massif_name_to_trend_test_that_minimized_aic.keys(): e = self.massif_name_to_empirical_mean[massif_name] - p = self.massif_name_to_parametric_mean[massif_name] + p = self.massif_name_to_model_mean[massif_name] relative_diference = 100 * (p-e) / e massif_name_to_relative_difference[massif_name] = relative_diference return massif_name_to_relative_difference - def plot_abstract_fast(self, massif_name_to_value, label, graduation=10.0, cmap=plt.cm.coolwarm, add_x_label=True): - super().plot_abstract(massif_name_to_value, label, label, self.fit_method, graduation, cmap, add_x_label) + def plot_abstract_fast(self, massif_name_to_value, label, graduation=10.0, cmap=plt.cm.coolwarm, add_x_label=True, + negative_and_positive_values=True): + super().plot_abstract(massif_name_to_value, label, label, self.fit_method, graduation, cmap, add_x_label, negative_and_positive_values) diff --git a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/validation_plot.py b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/validation_plot.py index 5fa8ee8bb790eb7846073a95ed0af46c72e40458..2da8bda5d8de1dce3d4e161fcfa38e1a738dedfe 100644 --- a/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/validation_plot.py +++ b/projects/contrasting_trends_in_snow_loads/snowfall_versus_time_and_altitude/validation_plot.py @@ -2,6 +2,8 @@ from typing import Dict import matplotlib.pyplot as plt +from extreme_data.meteo_france_data.scm_models_data.visualization.main_study_visualizer import \ + SCM_STUDY_CLASS_TO_ABBREVIATION from projects.contrasting_trends_in_snow_loads.snowfall_versus_time_and_altitude.study_visualizer_for_mean_values import \ StudyVisualizerForMeanValues from projects.ogorman.gorman_figures.figure1.study_visualizer_for_double_stationary_fit import \ @@ -28,7 +30,7 @@ def plot_shoe_relative_differences_distribution(altitude_to_relative_differences width = 150 ax.boxplot([altitude_to_relative_differences[a] for a in altitudes], positions=altitudes, widths=width) ax.set_xlim([min(altitudes) - width, max(altitudes) + width]) - ylabel = 'Relative difference between empirical mean and parametric mean (\%)' + ylabel = 'Relative difference of the model mean w.r.t. the empirical mean (\%)' ax.set_ylabel(ylabel) ax.set_xlabel('Altitude (m)') ax.legend() @@ -36,12 +38,13 @@ def plot_shoe_relative_differences_distribution(altitude_to_relative_differences def plot_relative_difference_map(visualizer: StudyVisualizerForMeanValues): - label = ' mean annual maxima of {} ({})'.format('', '') + study = visualizer.study + label = ' mean annual maxima of {} ({})'.format(SCM_STUDY_CLASS_TO_ABBREVIATION[type(study)], study.variable_unit) visualizer.plot_abstract_fast(massif_name_to_value=visualizer.massif_name_to_empirical_mean, - label='Empirical' + label) - - visualizer.plot_abstract_fast(massif_name_to_value=visualizer.massif_name_to_parametric_mean, - label='Model' + label) + label='Empirical' + label, negative_and_positive_values=False) + visualizer.plot_abstract_fast(massif_name_to_value=visualizer.massif_name_to_model_mean, + label='Model' + label, negative_and_positive_values=False) visualizer.plot_abstract_fast(massif_name_to_value=visualizer.massif_name_to_relative_difference_for_mean, - label='Relative difference of' + label, graduation=1) + label='Relative difference of the model mean w.r.t. the empirical mean \n' + 'for the ' + label, graduation=1) return list(visualizer.massif_name_to_relative_difference_for_mean.values())