From fff8059acccc38b832f2a6aac9e749409f240010 Mon Sep 17 00:00:00 2001 From: Le Roux Erwan <erwan.le-roux@irstea.fr> Date: Mon, 6 Apr 2020 21:36:58 +0200 Subject: [PATCH] [contrasting project] add figure 1 --- .../scm_models_data/abstract_study.py | 12 +++- extreme_fit/distribution/gev/gev_params.py | 3 + .../gorman_figures/__init__.py | 0 .../figure1_mean_ratio_return_level_ratio.py | 67 +++++++++++++++++++ .../figure3_daily snowfall fraction.py} | 47 +++++++------ 5 files changed, 103 insertions(+), 26 deletions(-) create mode 100644 projects/contrasting_trends_in_snow_loads/gorman_figures/__init__.py create mode 100644 projects/contrasting_trends_in_snow_loads/gorman_figures/figure1_mean_ratio_return_level_ratio.py rename projects/contrasting_trends_in_snow_loads/{snowfall fraction of total precipitation/daily snowfall fraction.py => gorman_figures/figure3_daily snowfall fraction.py} (69%) diff --git a/extreme_data/meteo_france_data/scm_models_data/abstract_study.py b/extreme_data/meteo_france_data/scm_models_data/abstract_study.py index 54e7da27..adbebbdf 100644 --- a/extreme_data/meteo_france_data/scm_models_data/abstract_study.py +++ b/extreme_data/meteo_france_data/scm_models_data/abstract_study.py @@ -238,12 +238,20 @@ class AbstractStudy(object): ordered_index = [self.year_to_annual_maxima_index[year][i] for year in years] massif_name_to_annual_maxima_ordered_index[massif_name] = ordered_index return massif_name_to_annual_maxima_ordered_index + + @cached_property + def massif_name_to_annual_maxima(self): + massif_name_to_annual_maxima = OrderedDict() + for i, massif_name in enumerate(self.study_massif_names): + maxima = np.array([self.year_to_annual_maxima[year][i] for year in self.ordered_years]) + massif_name_to_annual_maxima[massif_name] = maxima + return massif_name_to_annual_maxima @cached_property def massif_name_to_annual_maxima_ordered_years(self): massif_name_to_annual_maxima_ordered_years = OrderedDict() - for i, massif_name in enumerate(self.study_massif_names): - maxima = np.array([self.year_to_annual_maxima[year][i] for year in self.ordered_years]) + for massif_name in self.study_massif_names: + maxima = self.massif_name_to_annual_maxima[massif_name] annual_maxima_ordered_index = np.argsort(maxima) annual_maxima_ordered_years = [self.ordered_years[idx] for idx in annual_maxima_ordered_index] massif_name_to_annual_maxima_ordered_years[massif_name] = annual_maxima_ordered_years diff --git a/extreme_fit/distribution/gev/gev_params.py b/extreme_fit/distribution/gev/gev_params.py index 79dbe892..ce34b36b 100644 --- a/extreme_fit/distribution/gev/gev_params.py +++ b/extreme_fit/distribution/gev/gev_params.py @@ -37,6 +37,9 @@ class GevParams(AbstractExtremeParams): else: return r.qgev(p, self.location, self.scale, self.shape)[0] + def return_level(self, return_period): + return self.quantile(1 - 1 / return_period) + def density(self, x): if self.has_undefined_parameters: return np.nan diff --git a/projects/contrasting_trends_in_snow_loads/gorman_figures/__init__.py b/projects/contrasting_trends_in_snow_loads/gorman_figures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/projects/contrasting_trends_in_snow_loads/gorman_figures/figure1_mean_ratio_return_level_ratio.py b/projects/contrasting_trends_in_snow_loads/gorman_figures/figure1_mean_ratio_return_level_ratio.py new file mode 100644 index 00000000..fd5608f8 --- /dev/null +++ b/projects/contrasting_trends_in_snow_loads/gorman_figures/figure1_mean_ratio_return_level_ratio.py @@ -0,0 +1,67 @@ +from collections import OrderedDict + +import numpy as np + +from extreme_data.meteo_france_data.scm_models_data.abstract_study import AbstractStudy +from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranSnowfall1Day +from extreme_data.meteo_france_data.scm_models_data.visualization.create_shifted_cmap import get_shifted_map, \ + get_colors, shiftedColorMap +from extreme_fit.estimator.margin_estimator.utils import fitted_stationary_gev +from extreme_fit.model.margin_model.linear_margin_model.abstract_temporal_linear_margin_model import \ + TemporalMarginFitMethod + +import matplotlib.pyplot as plt + +from extreme_trend.visualizers.study_visualizer_for_non_stationary_trends import StudyVisualizerForNonStationaryTrends + + +def mean_ratio(altitude): + pass + + +def massif_name_to_return_level(altitude, year_min, year_max, return_period): + study = SafranSnowfall1Day(altitude=altitude, year_min=year_min, year_max=year_max) + massif_name_to_return_levels = OrderedDict() + for massif_name, maxima in study.massif_name_to_annual_maxima.items(): + gev_param = fitted_stationary_gev(maxima, fit_method=TemporalMarginFitMethod.extremes_fevd_mle) + return_level = gev_param.return_level(return_period=return_period) + massif_name_to_return_levels[massif_name] = return_level + return massif_name_to_return_levels + + +def plot_return_level_ratio(altitude, return_period=30, year_min=1959, year_middle=1989, year_max=2019): + massif_name_to_return_level_past = massif_name_to_return_level(altitude, year_min, year_middle, return_period) + massif_name_to_return_level_recent = massif_name_to_return_level(altitude, year_middle + 1, year_max, + return_period) + massif_name_to_ratio = {m: v / massif_name_to_return_level_past[m] for m, v in + massif_name_to_return_level_recent.items()} + max_ratio = max([e for e in massif_name_to_ratio.values()]) + min_ratio = min([e for e in massif_name_to_ratio.values()]) + midpoint = (max_ratio - 1.0) / (max_ratio - 0) + num = 3 + ticks = np.concatenate([np.linspace(0, midpoint, num), np.linspace(midpoint, 1, num)]) + labels = np.concatenate([np.linspace(min_ratio, 1.0, num), np.linspace(1.0, max_ratio, num)]) + cmap = shiftedColorMap(plt.cm.bwr, midpoint=midpoint, name='shifted') + ax = plt.gca() + print(massif_name_to_ratio) + massif_name_to_color = {m: get_colors([v], cmap, min_ratio, max_ratio)[0] + for m, v in massif_name_to_ratio.items()} + ticks_values_and_labels = ticks, labels + AbstractStudy.visualize_study(ax=ax, + massif_name_to_value=massif_name_to_ratio, + massif_name_to_color=massif_name_to_color, + replace_blue_by_white=True, + axis_off=False, + cmap=cmap, + show_label=False, + add_colorbar=True, + show=False, + vmin=min_ratio, + vmax=max_ratio, + ticks_values_and_labels=ticks_values_and_labels + ) + plt.show() + + +if __name__ == '__main__': + plot_return_level_ratio(altitude=1800) diff --git a/projects/contrasting_trends_in_snow_loads/snowfall fraction of total precipitation/daily snowfall fraction.py b/projects/contrasting_trends_in_snow_loads/gorman_figures/figure3_daily snowfall fraction.py similarity index 69% rename from projects/contrasting_trends_in_snow_loads/snowfall fraction of total precipitation/daily snowfall fraction.py rename to projects/contrasting_trends_in_snow_loads/gorman_figures/figure3_daily snowfall fraction.py index 8403554b..6a1b5cf1 100644 --- a/projects/contrasting_trends_in_snow_loads/snowfall fraction of total precipitation/daily snowfall fraction.py +++ b/projects/contrasting_trends_in_snow_loads/gorman_figures/figure3_daily snowfall fraction.py @@ -8,51 +8,50 @@ from extreme_data.meteo_france_data.scm_models_data.safran.safran import SafranR Altitudes_groups = [[300, 600, 900], [1200, 1500, 1800], [2100, 2400, 2700], [3000, 3300, 3600]] -def compute_smoother_snowfall_fraction(altitudes, year_min, year_max): +def compute_smoother_snowfall_fraction(altitudes, year_min, year_max, lim): all_time_series = np.concatenate([get_time_series(altitude, year_min, year_max) for altitude in altitudes], axis=1) temperature_array, snowfall_array, rainfall_array = all_time_series - paper_setting = False - if paper_setting: - lim = 10 - sigma = 0.5 - else: - lim = 7.5 - sigma = 1 - bins = np.linspace(-lim, lim, num=(4 * 2 * lim) + 1) + nb_bins_for_one_celsius = 4 + bins = np.linspace(-lim, lim, num=int((nb_bins_for_one_celsius * 2 * lim) + 1)) inds = np.digitize(temperature_array, bins) snowfall_fractions = [] for j in range(1, len(bins)): mask = inds == j fraction = np.mean(snowfall_array[mask]) / np.mean(snowfall_array[mask] + rainfall_array[mask]) snowfall_fractions.append(fraction) - new_snowfall_fractions = 100 * gaussian_filter1d(snowfall_fractions, sigma=sigma) x = bins[:-1] + 0.125 - return new_snowfall_fractions, sigma, x + return np.array(snowfall_fractions), x def daily_snowfall_fraction(ax, altitudes, year_min=1959, year_max=2019): - snowfall_fractions, sigma, x = compute_smoother_snowfall_fraction(altitudes, year_min, year_max) + snowfall_fractions, x = compute_smoother_snowfall_fraction(altitudes, year_min, year_max, lim=7) + sigma = 1.0 + snowfall_fractions = 100 * gaussian_filter1d(snowfall_fractions, sigma=sigma) # Plot results label = '{}-{} at {}'.format(year_min, year_max, ' & '.join(['{} m'.format(a) for a in altitudes])) ax.plot(x, snowfall_fractions, label=label, linewidth=4) ax.set_ylabel('Snowfall fraction (%)') - ax.set_xlabel('Daily surface air temperature (Celsius)') - ax.set_title('Snowfall fraction is smoothed with a gaussian filter with standard deviation={}'.format(sigma)) - ax.grid(b=True) - ax.legend() + end_plot(ax, sigma) def snowfall_fraction_difference_between_periods(ax, altitudes, year_min=1959, year_middle=1989, year_max=2019): - snowfall_fractions_past, sigma, x = compute_smoother_snowfall_fraction(altitudes, year_min, year_middle) - snowfall_fractions_recent, sigma, x = compute_smoother_snowfall_fraction(altitudes, year_middle + 1, year_max) - mask = snowfall_fractions_past == 0 + lim = 4 + snowfall_fractions_past, x = compute_smoother_snowfall_fraction(altitudes, year_min, year_middle, lim=lim) + snowfall_fractions_recent, x = compute_smoother_snowfall_fraction(altitudes, year_middle + 1, year_max, lim=lim) + # Ensure that we do not divide by zero + mask = snowfall_fractions_past > 0 x = x[mask] snowfall_ratio = snowfall_fractions_recent[mask] / snowfall_fractions_past[mask] + sigma = 2.0 + snowfall_ratio = gaussian_filter1d(snowfall_ratio, sigma=sigma) label = '{}'.format(' & '.join(['{} m'.format(a) for a in altitudes])) ax.plot(x, snowfall_ratio, label=label, linewidth=4) - ax.set_ylabel('Ratio of Snowfall fraction {}-{} divided by Snowfall fraction {}-{}'.format(year_min, year_middle, - year_middle + 1, - year_max)) + ax.set_ylabel('Ratio of Snowfall fraction {}-{}\n' + 'divided by Snowfall fraction {}-{}'.format(year_middle + 1, year_max, year_min, year_middle)) + end_plot(ax, sigma) + + +def end_plot(ax, sigma): ax.set_xlabel('Daily surface air temperature (Celsius)') ax.set_title('Snowfall fraction is smoothed with a gaussian filter with standard deviation={}'.format(sigma)) ax.grid(b=True) @@ -94,6 +93,6 @@ def daily_snowfall_fraction_wrt_time(): if __name__ == '__main__': - # daily_snowfall_fraction_wrt_altitude(fast=True) + daily_snowfall_fraction_wrt_altitude(fast=False) # daily_snowfall_fraction_wrt_time() - ratio_of_past_and_recent_daily_snowfall_fraction_wrt_altitude() + # ratio_of_past_and_recent_daily_snowfall_fraction_wrt_altitude() -- GitLab