Code source de pyspc.plotting.regime

#!/usr/bin/python3
# -*- coding: utf-8 -*-
########################################################################
#
# This file is part of python module <pyspc>.
# Copyright (C) 2013-2021  R. Marty
#   (renaud.marty@developpement-durable.gouv.fr)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see COPYING.txt).
# If not, see <http://www.gnu.org/licenses/>.
#
########################################################################
"""
Images - Peak Flow comparison
"""
import matplotlib.pyplot as mplt


[docs] def plot_regime(data=None, fig_filename=None, boxplot=False, fill=False): """ Tracer l'analyse des pointes de crue amont et aval Parameters ---------- data : dict Dictionnaire des régimes hydrologiques fig_filename : str Nom du fichier image boxplot : bool Tracer les quantiles sous forme de boxplot (True) ou d'enveloppes quantiliques (False). Par défaut: False. fill : bool Remplir les boxplots/enveloppes quantiliques. Par défaut: False Returns ------- fig_filename : str Nom du fichier image See Also -------- pyspc.core.serie.Serie.regime pyspc.core.series.Series.regime """ # ========================================================================= # --- INFORMATION REGIME # ========================================================================= loc = list({c[0] for c in data.columns})[0] var = list({c[1] for c in data.columns})[0] ics = find_confidence_intervals(data.columns) # ========================================================================= # --- TRACER FIGURE INITIALE # ========================================================================= fig = mplt.figure(dpi=300, figsize=(11.69, 8.27)) ax = fig.add_axes((0.05, 0.08, 0.90, 0.85)) # ========================================================================= # --- VERSION boxplot # ========================================================================= if boxplot: bxpstats = _data2bxpstats(data, loc, var) props = ax.bxp(bxpstats, showmeans=True, meanline=True, patch_artist=True) if fill: for patch in props['boxes']: patch.set_facecolor('lightskyblue') patch.set_edgecolor('tab:blue') patch.set_alpha(0.8) else: for patch in props['boxes']: patch.set_facecolor('white') patch.set_edgecolor('tab:blue') for patch in props['medians']: patch.set_color('black') for patch in props['means']: patch.set_color('blue') for patch in props['whiskers']: patch.set_color('tab:grey') for patch in props['caps']: patch.set_color('tab:grey') # ========================================================================= # --- VERSION classique # ========================================================================= else: if fill: for ic in ics: ax.fill_between( data.index, data[(loc, var, ic[1])], data[(loc, var, ic[2])], color='tab:cyan', alpha=1 - ic[0]/100., label=f'ic{ic[0]}') else: for ic in ics: ax.plot(data.index, data[(loc, var, ic[1])], color='tab:cyan', linestyle='-', linewidth=2, marker='', label=ic[1]) ax.plot(data.index, data[(loc, var, ic[2])], color='tab:cyan', linestyle='-', linewidth=2, marker='', label=ic[2]) ax.scatter(data.index, data[(loc, var, 'min')], s=10, color='white', edgecolor='black', marker='o', label='min') ax.scatter(data.index, data[(loc, var, 'max')], s=10, color='white', edgecolor='black', marker='o', label='max') ax.plot(data.index, data[(loc, var, 'q50')], color='tab:blue', linestyle='-', linewidth=2, marker='', label='med') ax.plot(data.index, data[(loc, var, 'mean')], color='tab:orange', linestyle='-', linewidth=2, marker='', label='moy') fig.legend(bbox_to_anchor=(0.5, 0.02), loc=10, ncol=8, fontsize=12) # ========================================================================= # --- TRACER FIGURE FINALE # ========================================================================= fig.suptitle(f"Régme hydrologique - {loc} - {var}", fontsize=12, fontweight='bold') if fig_filename is None: return fig mplt.savefig(fig_filename, dpi=300) mplt.close(fig) return fig_filename
[docs] def _data2bxpstats(data, loc, var): """ Construire la liste des boxplots à partir du régime Parameters ---------- data : dict Dictionnaire des régimes hydrologiques loc : str Lieu var : str Grandeur Returns ------- bxpstats : list Dictionnaires contenant les informations de chaque boxplot - med: Median (scalar). - q1, q3: First & third quartiles (scalars). - whislo, whishi: Lower & upper whisker positions (scalars). - mean: Mean (scalar). Needed if showmeans=True. - fliers: Data beyond the whiskers (array-like). Needed if showfliers=True. - label: Name of the dataset (str). If available, this will be used a tick label for the boxplot See Also -------- https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.bxp.html """ bxpstats = [] for row in data.iterrows(): bx = { 'label': row[0], 'med': row[1][(loc, var, 'q50')], # Median (50th percentile) 'mean': row[1][(loc, var, 'mean')], # Mean 'fliers': [row[1][(loc, var, 'min')], row[1][(loc, var, 'max')]] # Outliers } # 'whislo': 162.6, # Bottom whisker position # 'q1' : 170.2, # First quartile (25th percentile) # 'q3' : 180.4, # Third quartile (75th percentile) # 'whishi': 187.8, # Top whisker position for k1, k2 in zip(['whislo', 'q1', 'q3', 'whishi'], ['q10', 'q25', 'q75', 'q90']): try: bx[k1] = row[1][(loc, var, k2)] except KeyError as ke: raise ValueError( f"La fréquence '{k2}' est nécessaire pour tracer le " "régime sous forme de boxplot") from ke bxpstats.append(bx) return bxpstats
[docs] def find_confidence_intervals(cols): """Définir les bornes d'un intervalle de confiance.""" ics = [] skip = ['amin', 'amax', 'q50', 'mean', 'min', 'max'] for c in cols: if c[-1] in skip: continue fc = int(float(c[-1].replace('q', ''))) for c2 in cols: if c2[-1] in skip: continue fc2 = int(float(c2[-1].replace('q', ''))) if fc + fc2 != 100: continue ics.append((max(fc, fc2) - min(fc, fc2), min(c[-1], c2[-1]), max(c[-1], c2[-1]))) ics = sorted(list(set(ics)), reverse=True) return ics