From 41384fbdc44723a94e693fe2c586f8e553ec80d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 09:43:28 -0400 Subject: [PATCH 01/31] HelpOutput.plot_area_monthly_avg: add year_from and year_to arg and return fig --- pyhelp/output.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 55a5bd4..a5eda2b 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -195,7 +195,9 @@ def _create_figure(self, fsize=None, margins=None): return fig, ax - def plot_area_monthly_avg(self, figname=None): + def plot_area_monthly_avg(self, figname: str = None, + year_from: int = -np.inf, + year_to: int = np.inf) -> Figure: """ Plot the monthly average values of the water budget in mm/month for the whole study area. @@ -241,6 +243,8 @@ def plot_area_monthly_avg(self, figname=None): if figname is not None: fig.savefig(figname) + return fig + def plot_area_yearly_avg(self, figname=None): """ Plot the average yearly values of the water budget in mm/year From c88b85a5c370797d7d469ec80c3833b127731c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 09:44:03 -0400 Subject: [PATCH 02/31] HelpOutput.plot_area_monthly_avg:: complete docstring --- pyhelp/output.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index a5eda2b..87acd04 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -13,6 +13,7 @@ import os.path as osp # ---- Third party imports +from matplotlib.figure import Figure import matplotlib.pyplot as plt import pandas as pd import numpy as np @@ -201,10 +202,27 @@ def plot_area_monthly_avg(self, figname: str = None, """ Plot the monthly average values of the water budget in mm/month for the whole study area. - """ fig, ax = self._create_figure( fsize=(9, 6.5), margins=(1.5, 1, 0.25, 0.7)) + Parameters + ---------- + figname : str, optional + The abolute path of the file where to save the figure to disk. + Note that the format of the file is inferred from the extension of + "figname". + year_from : int, optional + Year from which the average monthly values are calculated. + The default is -np.inf. + year_to : int, optional + Year to which the average monthly values are calculated. + The default is np.inf. + + Returns + ------- + Figure + The matplotlib figure instance created by this method. + """ avg_monthly = self.calc_area_monthly_avg() months = range(1, 13) l1, = ax.plot(months, np.mean(avg_monthly['precip'], axis=0), From e75b37e2118e00e9f8817c52f74682cbdae80241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 09:44:22 -0400 Subject: [PATCH 03/31] HelpOutput.plot_area_monthly_avg: change ylabel --- pyhelp/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 87acd04..a390368 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -238,7 +238,7 @@ def plot_area_monthly_avg(self, figname: str = None, l6, = ax.plot(months, np.mean(avg_monthly['subrun2'], axis=0), marker='o', mec='white', clip_on=False, lw=2) - ax.set_ylabel('Composantes du bilan hydrologique\n(mm/mois)', + ax.set_ylabel('Moyennes mensuelles (mm/mois)', fontsize=16, labelpad=10) ax.set_xlabel('Mois', fontsize=16, labelpad=10) ax.axis(ymin=-5) From 421377b6a9f62a90fd12b1a608df653e9981e8e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 09:44:38 -0400 Subject: [PATCH 04/31] HelpOutput.plot_area_monthly_avg: improve code --- pyhelp/output.py | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index a390368..4b230b6 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -224,19 +224,21 @@ def plot_area_monthly_avg(self, figname: str = None, The matplotlib figure instance created by this method. """ avg_monthly = self.calc_area_monthly_avg() - months = range(1, 13) - l1, = ax.plot(months, np.mean(avg_monthly['precip'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) - l2, = ax.plot(months, np.mean(avg_monthly['rechg'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) - l3, = ax.plot(months, np.mean(avg_monthly['runoff'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) - l4, = ax.plot(months, np.mean(avg_monthly['evapo'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) - l5, = ax.plot(months, np.mean(avg_monthly['subrun1'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) - l6, = ax.plot(months, np.mean(avg_monthly['subrun2'], axis=0), - marker='o', mec='white', clip_on=False, lw=2) + + fig, ax = self._create_figure(fsize=(9, 6.5)) + + months = list(range(1, 13)) + varnames = ['precip', 'rechg', 'runoff', 'evapo', 'subrun1', 'subrun2'] + labels = ["Précipitations totales", + "Recharge au roc", + "Ruissellement de surface", + "Évapotranspiration", + "Ruissellement hypodermique superficiel", + "Ruissellement hypodermique profond"] + for varname, label in zip(varnames, labels): + ax.plot(months, np.mean(avg_monthly[varname], axis=0), + marker='o', mec='white', clip_on=False, lw=2, + label=label) ax.set_ylabel('Moyennes mensuelles (mm/mois)', fontsize=16, labelpad=10) @@ -244,19 +246,17 @@ def plot_area_monthly_avg(self, figname: str = None, ax.axis(ymin=-5) ax.grid(axis='both', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) ax.set_xticks(months) + + # http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3619 ax.set_xticklabels(['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc']) ax.tick_params(axis='both', direction='out', labelsize=12) - lines = [l1, l2, l3, l4, l5, l6] - labels = ["Précipitations totales", "Recharge au roc", - "Ruissellement de surface", "Évapotranspiration", - "Ruissellement hypodermique superficiel", - "Ruissellement hypodermique profond"] - legend = ax.legend(lines, labels, numpoints=1, fontsize=12, - borderaxespad=0, loc='lower left', borderpad=0.5, - bbox_to_anchor=(0, 1), ncol=2) - legend.draw_frame(False) + ax.legend( + numpoints=1, fontsize=12, frameon=False, borderaxespad=0, + loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1), ncol=2) + + fig.tight_layout() if figname is not None: fig.savefig(figname) From c96ff74e929f44dc4d9dcbb2958c5a936319866e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 09:45:22 -0400 Subject: [PATCH 05/31] HelpOutput._create_figure: fix bug if margins is None --- pyhelp/output.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 4b230b6..12d4ec4 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -180,9 +180,9 @@ def _create_figure(self, fsize=None, margins=None): # Setup figure size. if fsize is not None: fwidth, fheight = fsize + fig.set_size_inches(*fsize) else: fwidth, fheight = fig.get_size_inches() - fig.set_size_inches(*fsize) # Setup axe margins. if margins is not None: @@ -190,9 +190,9 @@ def _create_figure(self, fsize=None, margins=None): top_margin = margins[1]/fheight right_margin = margins[2]/fwidth bot_margin = margins[3]/fheight - ax.set_position([left_margin, bot_margin, - 1 - left_margin - right_margin, - 1 - top_margin - bot_margin]) + ax.set_position([left_margin, bot_margin, + 1 - left_margin - right_margin, + 1 - top_margin - bot_margin]) return fig, ax @@ -202,8 +202,6 @@ def plot_area_monthly_avg(self, figname: str = None, """ Plot the monthly average values of the water budget in mm/month for the whole study area. - fig, ax = self._create_figure( - fsize=(9, 6.5), margins=(1.5, 1, 0.25, 0.7)) Parameters ---------- From d05fa9acebb66003c2b2bd0daa3d314c364aaaf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 10:11:58 -0400 Subject: [PATCH 06/31] HelpOutput.calc_area_monthly_avg: return pandas dataframe instead of 2D numpy matrices Pandas dataframes are much easier to manipulate than numpy 2D arrays. --- pyhelp/output.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 12d4ec4..5291ae0 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -109,21 +109,33 @@ def save_to_csv(self, path_to_csv: str, # ---- Calcul def calc_area_monthly_avg(self): """ - Calcul the monthly values of the water budget in mm/month for the + Calcul the water budget average monthly values in mm/month for the whole study area. - Return a dictionary that contains a 2D numpy array for each - component of the water budget with average values calculated over - the study area for each month of every year for which data is - available. + Returns + ------- + dict + A dictionary that contains a pandas dataframe for each + component of the water budget with monthly average values + calculated over the whole study area for each month (columns) and + every year (index) for which data is available. """ Np = len(self.data['cid']) - len(self.data['idx_nan']) - keys = ['precip', 'runoff', 'evapo', 'perco', - 'subrun1', 'subrun2', 'rechg'] - if self.data is None: - return {key: np.zeros((1, 12)) for key in keys} - else: - return {key: np.nansum(self.data[key], axis=0)/Np for key in keys} + + monthly_avg = {} + for varname in VARNAMES: + if self.data is None: + df = pd.DataFrame( + columns=list(range(1, 13))) + else: + df = pd.DataFrame( + data=np.nansum(self.data[varname], axis=0) / Np, + index=self.data['years'], + columns=list(range(1, 13))) + df.columns.name = 'month' + df.index.name = 'year' + monthly_avg[varname] = df + return monthly_avg def calc_area_yearly_avg(self): """ From dc7ecb3b96032e1ae38aab55ce7e94cb9c149c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 10:24:18 -0400 Subject: [PATCH 07/31] HelpOutput.calc_area_yearly_avg: update docstring and now return a dict of pandas dataframe --- pyhelp/output.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 5291ae0..8df48a4 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -139,16 +139,20 @@ def calc_area_monthly_avg(self): def calc_area_yearly_avg(self): """ - Calcul the average yearly values of the water budget in mm/year - for the whole study area. + Calcul the water budget average yearly values in mm/year for the + whole study area. - Return a dictionary that contains a numpy array for each - component of the water budget with average values calculated over - the study area for every year for which data is available. + Returns + ------- + dict + A dictionary that contains pandas dataframe for each + component of the water budget with with yearly average values + calculated over the whole study area for each year (index) for + which data is available. """ monthly_avg = self.calc_area_monthly_avg() - keys = list(monthly_avg.keys()) - return {key: np.sum(monthly_avg[key], axis=1) for key in keys} + return {varname: monthly_avg[varname].sum(axis=1) for + varname in VARNAMES} def calc_cells_yearly_avg(self, year_from: int = -np.inf, year_to: int = np.inf) -> dict: From 3825b0863704b29ddbd8e8e1ad2cf88311a696cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 10:45:06 -0400 Subject: [PATCH 08/31] Define global VARNAMES and LABELS --- pyhelp/output.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 8df48a4..70a5399 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -20,8 +20,14 @@ import h5py from scipy.stats import linregress -VARNAMES = ['precip', 'runoff', 'evapo', 'perco', - 'subrun1', 'subrun2', 'rechg'] + +VARNAMES = ['precip', 'rechg', 'runoff', 'evapo', 'subrun1', 'subrun2'] +LABELS = ["Précipitations totales", + "Recharge au roc", + "Ruissellement de surface", + "Évapotranspiration", + "Ruissellement hypodermique superficiel", + "Ruissellement hypodermique profond"] class HelpOutput(object): @@ -242,14 +248,7 @@ def plot_area_monthly_avg(self, figname: str = None, fig, ax = self._create_figure(fsize=(9, 6.5)) months = list(range(1, 13)) - varnames = ['precip', 'rechg', 'runoff', 'evapo', 'subrun1', 'subrun2'] - labels = ["Précipitations totales", - "Recharge au roc", - "Ruissellement de surface", - "Évapotranspiration", - "Ruissellement hypodermique superficiel", - "Ruissellement hypodermique profond"] - for varname, label in zip(varnames, labels): + for varname, label in zip(VARNAMES, LABELS): ax.plot(months, np.mean(avg_monthly[varname], axis=0), marker='o', mec='white', clip_on=False, lw=2, label=label) From 4df72e461c3fd2541441672148f3172b2080893f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 10:51:52 -0400 Subject: [PATCH 09/31] HelpOutput.plot_area_yearly_avg: improve code --- pyhelp/output.py | 54 ++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 70a5399..025d921 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -281,56 +281,32 @@ def plot_area_yearly_avg(self, figname=None): Plot the average yearly values of the water budget in mm/year for the whole study area. """ - fig, ax = self._create_figure( - fsize=(8, 6.5), margins=(1.5, 0.5, 0.25, 0.25)) + fig, ax = self._create_figure(fsize=(8, 6.5)) area_yearly_avg = self.calc_area_yearly_avg() - avg_yearly_precip = np.mean(area_yearly_avg['precip']) - avg_yearly_rechg = np.mean(area_yearly_avg['rechg']) - avg_yearly_runoff = np.mean(area_yearly_avg['runoff']) - avg_yearly_evapo = np.mean(area_yearly_avg['evapo']) - avg_yearly_subrun1 = np.mean(area_yearly_avg['subrun1']) - avg_yearly_subrun2 = np.mean(area_yearly_avg['subrun2']) - - l1 = ax.bar(1, avg_yearly_precip, 0.85, align='center') - l2 = ax.bar(2, avg_yearly_rechg, 0.85, align='center') - l3 = ax.bar(3, avg_yearly_runoff, 0.85, align='center') - l4 = ax.bar(4, avg_yearly_evapo, 0.85, align='center') - l5 = ax.bar(5, avg_yearly_subrun1, 0.85, align='center') - l6 = ax.bar(6, avg_yearly_subrun2, 0.85, align='center') + x = 0 + for varname, label in zip(VARNAMES, LABELS): + x += 1 + var_avg_yearly = area_yearly_avg[varname].mean() + ax.bar(x, var_avg_yearly, 0.85, align='center', + label=label) + ax.text(x, var_avg_yearly + 10, "%d\nmm/an" % var_avg_yearly, + ha='center', va='bottom') ax.axis(ymin=0, ymax=1200, xmin=0, xmax=7) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) ax.set_axisbelow(True) - ax.text(1, avg_yearly_precip + 10, "%d\nmm/an" % avg_yearly_precip, - ha='center', va='bottom') - ax.text(2, avg_yearly_rechg + 10, "%d\nmm/an" % avg_yearly_rechg, - ha='center', va='bottom') - ax.text(3, avg_yearly_runoff + 10, "%d\nmm/an" % avg_yearly_runoff, - ha='center', va='bottom') - ax.text(4, avg_yearly_evapo + 10, "%d\nmm/an" % avg_yearly_evapo, - ha='center', va='bottom') - ax.text(5, avg_yearly_subrun1 + 10, "%d\nmm/an" % avg_yearly_subrun1, - ha='center', va='bottom') - ax.text(6, avg_yearly_subrun2 + 10, "%d\nmm/an" % avg_yearly_subrun2, - ha='center', va='bottom') - ax.tick_params(axis='y', direction='out', labelsize=12) ax.tick_params(axis='x', direction='out', length=0) - ax.set_ylabel('Composantes du bilan hydrologique\n(mm/an)', - fontsize=16, labelpad=10) + ax.set_ylabel('Moyennes annuelles (mm/an)', fontsize=16, labelpad=10) ax.set_xticklabels([]) - lines = [l1, l2, l3, l4, l5, l6] - labels = ["Précipitations totales", "Recharge au roc", - "Ruissellement de surface", "Évapotranspiration", - "Ruissellement hypodermique superficiel", - "Ruissellement hypodermique profond"] - legend = ax.legend(lines, labels, numpoints=1, fontsize=12, - borderaxespad=0, loc='upper right', borderpad=0.5, - bbox_to_anchor=(1, 1), ncol=1) - legend.draw_frame(False) + ax.legend( + numpoints=1, fontsize=12, borderaxespad=0, loc='upper right', + borderpad=0.5, bbox_to_anchor=(1, 1), ncol=1, frameon=False) + + fig.tight_layout() if figname is not None: fig.savefig(figname) From 70a4b41166fa49b1d12e9236995644c9aa4c5d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:22:08 -0400 Subject: [PATCH 10/31] HelpOutput.plot_area_yearly_avg: improve text placement --- pyhelp/output.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 025d921..b459b81 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -14,6 +14,7 @@ # ---- Third party imports from matplotlib.figure import Figure +from matplotlib import transforms import matplotlib.pyplot as plt import pandas as pd import numpy as np @@ -283,15 +284,23 @@ def plot_area_yearly_avg(self, figname=None): """ fig, ax = self._create_figure(fsize=(8, 6.5)) + text_offset = transforms.ScaledTranslation( + 0, 3/72, fig.dpi_scale_trans) + area_yearly_avg = self.calc_area_yearly_avg() x = 0 + text_handles = [] for varname, label in zip(VARNAMES, LABELS): x += 1 var_avg_yearly = area_yearly_avg[varname].mean() ax.bar(x, var_avg_yearly, 0.85, align='center', label=label) - ax.text(x, var_avg_yearly + 10, "%d\nmm/an" % var_avg_yearly, - ha='center', va='bottom') + text_handles.append( + ax.text(x, var_avg_yearly, "%d\nmm/an" % var_avg_yearly, + ha='center', va='bottom', + transform=ax.transData + text_offset)) + fig.canvas.draw() + ax.axis(ymin=0, ymax=1200, xmin=0, xmax=7) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) From f8fc1eb5e2b828ff448f40a459c8af1cb5d8bfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:23:19 -0400 Subject: [PATCH 11/31] HelpOutput: plot_area_yearly_avg: improve ymax --- pyhelp/output.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index b459b81..c8ae6c5 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -301,8 +301,17 @@ def plot_area_yearly_avg(self, figname=None): transform=ax.transData + text_offset)) fig.canvas.draw() + # Setup axis limits. + ymax = 0 + for handle in text_handles: + bbox = handle.get_window_extent(fig.canvas.get_renderer()) + bbox = bbox.transformed(ax.transData.inverted()) + ymax = max(ymax, bbox.y1) + ymax = np.ceil(ymax * 1.025) + print(ymax) + + ax.axis(ymin=0, ymax=ymax, xmin=0.25, xmax=6.75) - ax.axis(ymin=0, ymax=1200, xmin=0, xmax=7) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) ax.set_axisbelow(True) From 57739cbd21b648d9e7bc4cb623d8da4f6ab473a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:24:15 -0400 Subject: [PATCH 12/31] HelpOutput.plot_area_yearly_avg: put legend outside and reduce height --- pyhelp/output.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index c8ae6c5..c9fd336 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -282,7 +282,7 @@ def plot_area_yearly_avg(self, figname=None): Plot the average yearly values of the water budget in mm/year for the whole study area. """ - fig, ax = self._create_figure(fsize=(8, 6.5)) + fig, ax = self._create_figure(fsize=(8.5, 5)) text_offset = transforms.ScaledTranslation( 0, 3/72, fig.dpi_scale_trans) @@ -321,19 +321,15 @@ def plot_area_yearly_avg(self, figname=None): ax.set_xticklabels([]) ax.legend( - numpoints=1, fontsize=12, borderaxespad=0, loc='upper right', - borderpad=0.5, bbox_to_anchor=(1, 1), ncol=1, frameon=False) + numpoints=1, fontsize=12, frameon=False, borderaxespad=0, + loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1, 1, 1), + ncol=2) fig.tight_layout() if figname is not None: fig.savefig(figname) - # Add a graph title. - # offset = transforms.ScaledTranslation(0/72, 12/72, fig.dpi_scale_trans) - # ax.text(0.5, 1, figname_sufix, fontsize=16, ha='center', va='bottom', - # transform=ax.transAxes+offset) - def plot_area_yearly_series(self, figname=None): """ Plot the yearly values of the water budget in mm/year for the whole From e838ee683c16be940d16a88512b624b733045481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:32:39 -0400 Subject: [PATCH 13/31] HelpOutput.plot_area_yearly_avg: improve height to 9 from 8.5 --- pyhelp/output.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index c9fd336..70c2ea7 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -282,7 +282,7 @@ def plot_area_yearly_avg(self, figname=None): Plot the average yearly values of the water budget in mm/year for the whole study area. """ - fig, ax = self._create_figure(fsize=(8.5, 5)) + fig, ax = self._create_figure(fsize=(9, 5)) text_offset = transforms.ScaledTranslation( 0, 3/72, fig.dpi_scale_trans) @@ -308,8 +308,6 @@ def plot_area_yearly_avg(self, figname=None): bbox = bbox.transformed(ax.transData.inverted()) ymax = max(ymax, bbox.y1) ymax = np.ceil(ymax * 1.025) - print(ymax) - ax.axis(ymin=0, ymax=ymax, xmin=0.25, xmax=6.75) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) From 43d9300ffe9d5516d77098182f0f6a7f9f324bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:35:25 -0400 Subject: [PATCH 14/31] HelpOutput.plot_area_monthly_avg: remove markers We already have the grid, the markers are not necessary --- pyhelp/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 70c2ea7..f4ecd6e 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -251,7 +251,7 @@ def plot_area_monthly_avg(self, figname: str = None, months = list(range(1, 13)) for varname, label in zip(VARNAMES, LABELS): ax.plot(months, np.mean(avg_monthly[varname], axis=0), - marker='o', mec='white', clip_on=False, lw=2, + marker=None, mec='white', clip_on=False, lw=2, label=label) ax.set_ylabel('Moyennes mensuelles (mm/mois)', From ecd354f9d8a5e47be0bc645f282755148cf2af79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:36:29 -0400 Subject: [PATCH 15/31] HelpOutput.plot_area_monthly_avg: add back marker but remove vertical grid --- pyhelp/output.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index f4ecd6e..01b97a3 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -251,14 +251,14 @@ def plot_area_monthly_avg(self, figname: str = None, months = list(range(1, 13)) for varname, label in zip(VARNAMES, LABELS): ax.plot(months, np.mean(avg_monthly[varname], axis=0), - marker=None, mec='white', clip_on=False, lw=2, + marker='o', mec='white', clip_on=False, lw=2, label=label) ax.set_ylabel('Moyennes mensuelles (mm/mois)', fontsize=16, labelpad=10) ax.set_xlabel('Mois', fontsize=16, labelpad=10) ax.axis(ymin=-5) - ax.grid(axis='both', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) + ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) ax.set_xticks(months) # http://bdl.oqlf.gouv.qc.ca/bdl/gabarit_bdl.asp?id=3619 From b244fd47a6cc84dbb7f0253296b44b11076731cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:55:24 -0400 Subject: [PATCH 16/31] HelpOutput.plot_area_monthly_avg: apply year mask --- pyhelp/output.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 01b97a3..76d548e 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -250,7 +250,11 @@ def plot_area_monthly_avg(self, figname: str = None, months = list(range(1, 13)) for varname, label in zip(VARNAMES, LABELS): - ax.plot(months, np.mean(avg_monthly[varname], axis=0), + vardataf = avg_monthly[varname] + yearmask = ( + (vardataf.index >= year_from) & + (vardataf.index <= year_to)) + ax.plot(months, vardataf.loc[yearmask, :].mean(axis=0), marker='o', mec='white', clip_on=False, lw=2, label=label) From c4cd5c365cff6d91abe1793eeff980e79389ac85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 11:56:14 -0400 Subject: [PATCH 17/31] HelpOutput.plot_area_yearly_avg: implement yearly mask --- pyhelp/output.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 76d548e..a4b619e 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -281,10 +281,30 @@ def plot_area_monthly_avg(self, figname: str = None, return fig - def plot_area_yearly_avg(self, figname=None): + def plot_area_yearly_avg(self, figname: str = None, + year_from: int = -np.inf, + year_to: int = np.inf) -> Figure: """ - Plot the average yearly values of the water budget in mm/year + Plot the yearly average values of the water budget in mm/year for the whole study area. + + Parameters + ---------- + figname : str, optional + The abolute path of the file where to save the figure to disk. + Note that the format of the file is inferred from the extension of + "figname". + year_from : int, optional + Year from which the average yearly values are calculated. + The default is -np.inf. + year_to : int, optional + Year to which the average yearly values are calculated. + The default is np.inf. + + Returns + ------- + Figure + The matplotlib figure instance created by this method. """ fig, ax = self._create_figure(fsize=(9, 5)) @@ -296,7 +316,13 @@ def plot_area_yearly_avg(self, figname=None): text_handles = [] for varname, label in zip(VARNAMES, LABELS): x += 1 - var_avg_yearly = area_yearly_avg[varname].mean() + + vardataf = area_yearly_avg[varname] + yearmask = ( + (vardataf.index >= year_from) & + (vardataf.index <= year_to)) + var_avg_yearly = vardataf.loc[yearmask].mean() + ax.bar(x, var_avg_yearly, 0.85, align='center', label=label) text_handles.append( @@ -332,6 +358,8 @@ def plot_area_yearly_avg(self, figname=None): if figname is not None: fig.savefig(figname) + return fig + def plot_area_yearly_series(self, figname=None): """ Plot the yearly values of the water budget in mm/year for the whole From 842c1d29e2c6e7e9900b2cbf296ec5f7ce6555f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 12:06:37 -0400 Subject: [PATCH 18/31] Improve docstrings --- pyhelp/output.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index a4b619e..0d88c4e 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -93,11 +93,11 @@ def save_to_csv(self, path_to_csv: str, Parameters ---------- year_from : int, optional - Year from which the average annual values are calculated. - The default is -np.inf. + Minimum year of the period over which the average annual values + are calculated. The default is -np.inf. year_to : int, optional - Year to which the average annual values are calculated. - The default is np.inf. + Maximum year of the period over which the average annual values + are calculated. The default is np.inf. """ print("Saving data to {}...".format(osp.basename(path_to_csv))) df = pd.DataFrame(index=self.data['cid']) @@ -169,11 +169,11 @@ def calc_cells_yearly_avg(self, year_from: int = -np.inf, Parameters ---------- year_from : int, optional - Year from which the average annual values are calculated. - The default is -np.inf. + Minimum year of the period over which the average annual values + are calculated. The default is -np.inf. year_to : int, optional - Year to which the average annual values are calculated. - The default is np.inf. + Maximum year of the period over which the average annual values + are calculated. The default is np.inf. Returns ------- @@ -233,11 +233,11 @@ def plot_area_monthly_avg(self, figname: str = None, Note that the format of the file is inferred from the extension of "figname". year_from : int, optional - Year from which the average monthly values are calculated. - The default is -np.inf. + Minimum year of the period over which the average monthly values + are calculated. The default is -np.inf. year_to : int, optional - Year to which the average monthly values are calculated. - The default is np.inf. + Maximum year of the period over which the average monthly values + are calculated. The default is np.inf. Returns ------- @@ -295,11 +295,11 @@ def plot_area_yearly_avg(self, figname: str = None, Note that the format of the file is inferred from the extension of "figname". year_from : int, optional - Year from which the average yearly values are calculated. - The default is -np.inf. + Minimum year of the period over which the average annual values + are calculated. The default is -np.inf. year_to : int, optional - Year to which the average yearly values are calculated. - The default is np.inf. + Maximum year of the period over which the average annual values + are calculated. The default is np.inf. Returns ------- From c15f685a4dbcc28f1ee184d974a84a20ceac2f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 13:40:32 -0400 Subject: [PATCH 19/31] Uniformize colors --- pyhelp/output.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 0d88c4e..39d47bc 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -29,6 +29,7 @@ "Évapotranspiration", "Ruissellement hypodermique superficiel", "Ruissellement hypodermique profond"] +COLORS = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'] class HelpOutput(object): @@ -249,14 +250,14 @@ def plot_area_monthly_avg(self, figname: str = None, fig, ax = self._create_figure(fsize=(9, 6.5)) months = list(range(1, 13)) - for varname, label in zip(VARNAMES, LABELS): + for varname, label, color in zip(VARNAMES, LABELS, COLORS): vardataf = avg_monthly[varname] yearmask = ( (vardataf.index >= year_from) & (vardataf.index <= year_to)) ax.plot(months, vardataf.loc[yearmask, :].mean(axis=0), marker='o', mec='white', clip_on=False, lw=2, - label=label) + label=label, color=color) ax.set_ylabel('Moyennes mensuelles (mm/mois)', fontsize=16, labelpad=10) @@ -314,7 +315,7 @@ def plot_area_yearly_avg(self, figname: str = None, area_yearly_avg = self.calc_area_yearly_avg() x = 0 text_handles = [] - for varname, label in zip(VARNAMES, LABELS): + for varname, label, color in zip(VARNAMES, LABELS, COLORS): x += 1 vardataf = area_yearly_avg[varname] @@ -324,7 +325,7 @@ def plot_area_yearly_avg(self, figname: str = None, var_avg_yearly = vardataf.loc[yearmask].mean() ax.bar(x, var_avg_yearly, 0.85, align='center', - label=label) + label=label, color=color) text_handles.append( ax.text(x, var_avg_yearly, "%d\nmm/an" % var_avg_yearly, ha='center', va='bottom', From ad979f610256ea9b39953d4bf890fd1be62366b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 13:41:44 -0400 Subject: [PATCH 20/31] HelpOutput: refactor plot_area_yearly_series --- pyhelp/output.py | 107 ++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 62 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 39d47bc..8f21004 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -361,86 +361,69 @@ def plot_area_yearly_avg(self, figname: str = None, return fig - def plot_area_yearly_series(self, figname=None): + def plot_area_yearly_series(self, figname: str = None, + year_from: int = -np.inf, + year_to: int = np.inf) -> Figure: """ - Plot the yearly values of the water budget in mm/year for the whole - study area. + Plot the yearly values of the water budget in mm/year calculated + over the whole study area. + + Parameters + ---------- + figname : str, optional + The abolute path of the file where to save the figure to disk. + Note that the format of the file is inferred from the extension of + "figname". + year_from : int, optional + Minimum year of the period over which the annual values + are plotted. The default is -np.inf. + year_to : int, optional + Maximum year of the period over which the annual values + are calculated. The default is np.inf. + + Returns + ------- + Figure + The matplotlib figure instance created by this method. """ fig, ax = self._create_figure( fsize=(9, 6.5), margins=(1.5, 1, 0.25, 0.7)) years = self.data['years'] yearly_avg = self.calc_area_yearly_avg() + mask_years = (years >= year_from) & (years <= year_to) + + for varname, label, color in zip(VARNAMES, LABELS, COLORS): + masked_data = yearly_avg[varname].loc[mask_years] + masked_years = masked_data.index.values.astype('int') - # Precipitation - precip = yearly_avg['precip'] - l1, = ax.plot(years, precip, marker='o', mec='white', - clip_on=False, lw=2, color='#1f77b4') - slope, intercept, r_val, p_val, std_err = linregress(years, precip) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#1f77b4') - - # Recharge - rechg = yearly_avg['rechg'] - l2, = ax.plot(years, rechg, marker='o', mec='white', clip_on=False, - lw=2, color='#ff7f0e') - slope, intercept, r_val, p_val, std_err = linregress(years, rechg) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#ff7f0e') - - # Runoff - runoff = yearly_avg['runoff'] - l3, = ax.plot(years, runoff, marker='o', mec='white', clip_on=False, - lw=2, color='#2ca02c') - slope, intercept, r_val, p_val, std_err = linregress(years, runoff) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#2ca02c') - - # Evapotranspiration - evapo = yearly_avg['evapo'] - l4, = ax.plot(years, evapo, marker='o', mec='white', clip_on=False, - lw=2, color='#d62728') - slope, intercept, r_val, p_val, std_err = linregress(years, evapo) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#d62728') - - # Superficial subsurface runoff - subrun1 = yearly_avg['subrun1'] - l5, = ax.plot(years, subrun1, marker='o', mec='white', - clip_on=False, lw=2, color='#9467bd') - slope, intercept, r_val, p_val, std_err = linregress(years, subrun1) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#9467bd') - - # Superficial subsurface runoff - subrun2 = yearly_avg['subrun2'] - l6, = ax.plot(years, subrun2, marker='o', mec='white', - clip_on=False, lw=2, color='#8c564b') - slope, intercept, r_val, p_val, std_err = linregress(years, subrun2) - ax.plot(years, years * slope + intercept, marker=None, mec='white', - clip_on=False, lw=1, dashes=[5, 3], color='#8c564b') + ax.plot(masked_years, masked_data, marker='o', mec='white', + clip_on=False, lw=2, color=color, label=label) + + slope, intercept, r_val, p_val, std_err = linregress( + masked_years, masked_data.values) + + ax.plot(masked_years, masked_years * slope + intercept, + marker=None, mec='white', clip_on=False, lw=1, + dashes=[5, 3], color=color) ax.tick_params(axis='both', direction='out', labelsize=12) - ax.set_ylabel('Composantes du bilan hydrologique\n(mm/an)', + ax.set_ylabel('Composantes annuelles\ndu bilan hydrologique (mm/an)', fontsize=16, labelpad=10) ax.set_xlabel('Années', fontsize=16, labelpad=10) - ax.axis(ymin=0, ymax=1600) + ax.axis(ymin=0) + ax.xaxis.get_major_locator().set_params(integer=True) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) - lines = [l1, l2, l3, l4, l5, l6] - labels = ["Précipitations totales", "Recharge au roc", - "Ruissellement de surface", "Évapotranspiration", - "Ruissellement hypodermique superficiel", - "Ruissellement hypodermique profond"] - - legend = ax.legend(lines, labels, numpoints=1, fontsize=12, - borderaxespad=0, loc='lower left', borderpad=0.5, - bbox_to_anchor=(0, 1), ncol=2) - legend.draw_frame(False) + ax.legend(numpoints=1, fontsize=12, frameon=False, + borderaxespad=0, loc='lower left', borderpad=0.5, + bbox_to_anchor=(0, 1), ncol=2) if figname is not None: fig.savefig(figname) + return fig + if __name__ == "__main__": output_fpath = "C:/Users/User/pyhelp/example/help_example.out" From 0d9b41c27fc59755185e4de66ab1ad8acc3a875d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 14:11:51 -0400 Subject: [PATCH 21/31] Use dicts for COLORS and LABELS --- pyhelp/output.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 8f21004..f5b3ce9 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -23,13 +23,18 @@ VARNAMES = ['precip', 'rechg', 'runoff', 'evapo', 'subrun1', 'subrun2'] -LABELS = ["Précipitations totales", - "Recharge au roc", - "Ruissellement de surface", - "Évapotranspiration", - "Ruissellement hypodermique superficiel", - "Ruissellement hypodermique profond"] -COLORS = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'] +LABELS = {'precip': "Précipitations totales", + 'rechg': "Recharge au roc", + 'runoff': "Ruissellement de surface", + 'evapo': "Évapotranspiration", + 'subrun1': "Ruissellement hypodermique superficiel", + 'subrun2': "Ruissellement hypodermique profond"} +COLORS = {'precip': '#1f77b4', + 'rechg': '#ff7f0e', + 'runoff': '#2ca02c', + 'evapo': '#d62728', + 'subrun1': '#9467bd', + 'subrun2': '#8c564b'} class HelpOutput(object): @@ -250,14 +255,14 @@ def plot_area_monthly_avg(self, figname: str = None, fig, ax = self._create_figure(fsize=(9, 6.5)) months = list(range(1, 13)) - for varname, label, color in zip(VARNAMES, LABELS, COLORS): + for varname in VARNAMES: vardataf = avg_monthly[varname] yearmask = ( (vardataf.index >= year_from) & (vardataf.index <= year_to)) ax.plot(months, vardataf.loc[yearmask, :].mean(axis=0), marker='o', mec='white', clip_on=False, lw=2, - label=label, color=color) + label=LABELS[varname], color=COLORS[varname]) ax.set_ylabel('Moyennes mensuelles (mm/mois)', fontsize=16, labelpad=10) @@ -315,7 +320,7 @@ def plot_area_yearly_avg(self, figname: str = None, area_yearly_avg = self.calc_area_yearly_avg() x = 0 text_handles = [] - for varname, label, color in zip(VARNAMES, LABELS, COLORS): + for varname in VARNAMES: x += 1 vardataf = area_yearly_avg[varname] @@ -325,7 +330,7 @@ def plot_area_yearly_avg(self, figname: str = None, var_avg_yearly = vardataf.loc[yearmask].mean() ax.bar(x, var_avg_yearly, 0.85, align='center', - label=label, color=color) + label=LABELS[varname], color=COLORS[varname]) text_handles.append( ax.text(x, var_avg_yearly, "%d\nmm/an" % var_avg_yearly, ha='center', va='bottom', @@ -393,19 +398,20 @@ def plot_area_yearly_series(self, figname: str = None, yearly_avg = self.calc_area_yearly_avg() mask_years = (years >= year_from) & (years <= year_to) - for varname, label, color in zip(VARNAMES, LABELS, COLORS): + for varname in VARNAMES: masked_data = yearly_avg[varname].loc[mask_years] masked_years = masked_data.index.values.astype('int') ax.plot(masked_years, masked_data, marker='o', mec='white', - clip_on=False, lw=2, color=color, label=label) + clip_on=False, lw=2, color=COLORS[varname], + label=LABELS[varname]) slope, intercept, r_val, p_val, std_err = linregress( masked_years, masked_data.values) ax.plot(masked_years, masked_years * slope + intercept, marker=None, mec='white', clip_on=False, lw=1, - dashes=[5, 3], color=color) + dashes=[5, 3], color=COLORS[varname]) ax.tick_params(axis='both', direction='out', labelsize=12) ax.set_ylabel('Composantes annuelles\ndu bilan hydrologique (mm/an)', From 8bdd1c8a13b6242875180d60555488ebc0156b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 14:16:00 -0400 Subject: [PATCH 22/31] Add 'perco' to the list of VARNAMES --- pyhelp/output.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index f5b3ce9..b16ed03 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -22,7 +22,8 @@ from scipy.stats import linregress -VARNAMES = ['precip', 'rechg', 'runoff', 'evapo', 'subrun1', 'subrun2'] +VARNAMES = ['precip', 'rechg', 'runoff', 'evapo', + 'subrun1', 'subrun2', 'perco'] LABELS = {'precip': "Précipitations totales", 'rechg': "Recharge au roc", 'runoff': "Ruissellement de surface", @@ -255,7 +256,7 @@ def plot_area_monthly_avg(self, figname: str = None, fig, ax = self._create_figure(fsize=(9, 6.5)) months = list(range(1, 13)) - for varname in VARNAMES: + for varname in VARNAMES[:-1]: vardataf = avg_monthly[varname] yearmask = ( (vardataf.index >= year_from) & @@ -320,7 +321,7 @@ def plot_area_yearly_avg(self, figname: str = None, area_yearly_avg = self.calc_area_yearly_avg() x = 0 text_handles = [] - for varname in VARNAMES: + for varname in VARNAMES[:-1]: x += 1 vardataf = area_yearly_avg[varname] @@ -398,7 +399,7 @@ def plot_area_yearly_series(self, figname: str = None, yearly_avg = self.calc_area_yearly_avg() mask_years = (years >= year_from) & (years <= year_to) - for varname in VARNAMES: + for varname in VARNAMES[:-1]: masked_data = yearly_avg[varname].loc[mask_years] masked_years = masked_data.index.values.astype('int') From ecc067d0161380725502c6f218e7d32a1d587fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 14:24:50 -0400 Subject: [PATCH 23/31] Fix tests --- pyhelp/tests/test_helpmanager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyhelp/tests/test_helpmanager.py b/pyhelp/tests/test_helpmanager.py index 9f0fca8..68b3bb2 100644 --- a/pyhelp/tests/test_helpmanager.py +++ b/pyhelp/tests/test_helpmanager.py @@ -22,7 +22,7 @@ # ---- Local library imports from pyhelp import __rootdir__ from pyhelp.managers import HelpManager -from pyhelp.output import HelpOutput +from pyhelp.output import HelpOutput, VARNAMES EXAMPLE_FOLDER = osp.join(osp.dirname(__rootdir__), 'example') INPUT_FILES = { @@ -165,9 +165,7 @@ def test_save_output_to_csv(output_dir, output_file): # Assert that the content of the csv is as expected. df = pd.read_csv(csvfilename, dtype={'cid': 'str'}) df = df.set_index('cid', drop=True) - assert list(df.columns) == [ - 'lat_dd', 'lon_dd', 'precip', 'runoff', 'evapo', 'perco', - 'subrun1', 'subrun2', 'rechg'] + assert list(df.columns) == ['lat_dd', 'lon_dd'] + VARNAMES assert df.index.name == 'cid' assert len(df) == 98 From 89ac8de8c5856c2558960145f29f9666ecce490e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 15:23:19 -0400 Subject: [PATCH 24/31] round text instead of floor --- pyhelp/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index b16ed03..1d0acfe 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -333,7 +333,7 @@ def plot_area_yearly_avg(self, figname: str = None, ax.bar(x, var_avg_yearly, 0.85, align='center', label=LABELS[varname], color=COLORS[varname]) text_handles.append( - ax.text(x, var_avg_yearly, "%d\nmm/an" % var_avg_yearly, + ax.text(x, var_avg_yearly, "%d\nmm/an" % round(var_avg_yearly), ha='center', va='bottom', transform=ax.transData + text_offset)) fig.canvas.draw() From 3f84d70c8c3439d54c3b702165b8bd83e6934b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 15:24:12 -0400 Subject: [PATCH 25/31] Add test_plot_area_yearly_avg --- pyhelp/tests/test_helpmanager.py | 36 ++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/pyhelp/tests/test_helpmanager.py b/pyhelp/tests/test_helpmanager.py index 68b3bb2..839a037 100644 --- a/pyhelp/tests/test_helpmanager.py +++ b/pyhelp/tests/test_helpmanager.py @@ -93,14 +93,39 @@ def test_plot_water_budget(output_dir, output_file): output.plot_area_monthly_avg(figfilename) assert osp.exists(figfilename) - figfilename = osp.join(output_dir, 'area_yearly_avg.pdf') - output.plot_area_yearly_avg(figfilename) + figfilename = osp.join(output_dir, 'area_yearly_series.pdf') + fig = output.plot_area_yearly_series(figfilename) + assert fig is not None assert osp.exists(figfilename) - figfilename = osp.join(output_dir, 'area_yearly_series.pdf') - output.plot_area_yearly_series(figfilename) + +def test_plot_area_yearly_avg(output_dir, output_file): + """ + Test that plotting the yearly averages is working expected. + """ + output = HelpOutput(output_file) + + figfilename = osp.join(output_dir, 'area_yearly_avg.pdf') + fig = output.plot_area_yearly_avg( + figfilename, year_from=2003, year_to=2009) + + assert fig is not None assert osp.exists(figfilename) + children = fig.axes[0].get_children() + assert (children[0].get_height() - 1086.8448950125246) < 0.1 # precip + assert children[1].get_text() == '1087\nmm/an' + assert (children[2].get_height() - 136.12068516893297) < 0.1 # rechg + assert children[3].get_text() == '136\nmm/an' + assert (children[4].get_height() - 226.9635476845988) < 0.1 # runoff + assert children[5].get_text() == '227\nmm/an' + assert (children[6].get_height() - 550.11140519815) < 0.1 # evapo + assert children[7].get_text() == '550\nmm/an' + assert (children[8].get_height() == 47.97935577404126) < 0.1 # subrun1 + assert children[9].get_text() == '48\nmm/an' + assert (children[10].get_height() - 121.66539490800443) < 0.1 # subrun2 + assert children[11].get_text() == '122\nmm/an' + def test_calc_cells_yearly_avg(output_file): """ @@ -148,6 +173,9 @@ def test_calc_cells_yearly_avg(output_file): 'runoff': 164.32582637467374, 'subrun1': 56.33706154407843, 'subrun2': 140.96849990912418} + for varname in list(expected_results.keys()): + result = np.sum(yearly_avg[varname]) / len(yearly_avg[varname]) + assert abs(result - expected_results[varname]) < 1, varname def test_save_output_to_csv(output_dir, output_file): From 1463257b61ab0f6d5ba76cacad116e759b867142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Tue, 26 Apr 2022 15:42:09 -0400 Subject: [PATCH 26/31] Add test_plot_area_monthly_avg and test_plot_area_yearly_series --- pyhelp/tests/test_helpmanager.py | 52 +++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/pyhelp/tests/test_helpmanager.py b/pyhelp/tests/test_helpmanager.py index 839a037..0ccf340 100644 --- a/pyhelp/tests/test_helpmanager.py +++ b/pyhelp/tests/test_helpmanager.py @@ -81,23 +81,53 @@ def test_calc_help_cells(helpm, output_file): assert abs(np.sum(area_yrly_avg[key]) - expected_results[key]) < 1, key -def test_plot_water_budget(output_dir, output_file): +def test_plot_area_monthly_avg(output_dir, output_file): """ Test that the water budget plots are created and saved as expected. - - Regression test for Issue #29. """ output = HelpOutput(output_file) figfilename = osp.join(output_dir, 'area_monthly_avg.pdf') - output.plot_area_monthly_avg(figfilename) + fig = output.plot_area_monthly_avg( + figfilename, year_from=2003, year_to=2009) + + assert fig is not None assert osp.exists(figfilename) + children = fig.axes[0].get_children() + assert (children[0].get_ydata().sum() - 1086.8448950125246) < 0.01 # precip + assert (children[1].get_ydata().sum() - 136.12068516893297) < 0.01 # rechg + assert (children[2].get_ydata().sum() - 226.9635476845988) < 0.01 # runoff + assert (children[3].get_ydata().sum() - 550.11140519815) < 0.01 # evapo + assert (children[4].get_ydata().sum() - 47.97935577404126) < 0.01 # subrun1 + assert (children[5].get_ydata().sum() - 121.66539490800443) < 0.01 # subrun2 + + +def test_plot_area_yearly_series(output_dir, output_file): + """ + Test that plotting the yearly values is working expected. + """ + output = HelpOutput(output_file) + figfilename = osp.join(output_dir, 'area_yearly_series.pdf') - fig = output.plot_area_yearly_series(figfilename) + fig = output.plot_area_yearly_series( + figfilename, year_from=2003, year_to=2009) + assert fig is not None assert osp.exists(figfilename) + expected_xdata = [2003, 2004, 2005, 2006, 2007, 2008, 2009] + + children = fig.axes[0].get_children() + for i in range(12): + assert list(children[i].get_xdata()) == expected_xdata + assert (children[0].get_ydata().mean() - 1086.8448950125246) < 0.01 # precip + assert (children[2].get_ydata().mean() - 136.12068516893297) < 0.01 # rechg + assert (children[4].get_ydata().mean() - 226.9635476845988) < 0.01 # runoff + assert (children[6].get_ydata().mean() - 550.11140519815) < 0.01 # evapo + assert (children[8].get_ydata().mean() - 47.97935577404126) < 0.01 # subrun1 + assert (children[10].get_ydata().mean() - 121.66539490800443) < 0.01 # subrun2 + def test_plot_area_yearly_avg(output_dir, output_file): """ @@ -113,17 +143,17 @@ def test_plot_area_yearly_avg(output_dir, output_file): assert osp.exists(figfilename) children = fig.axes[0].get_children() - assert (children[0].get_height() - 1086.8448950125246) < 0.1 # precip + assert (children[0].get_height() - 1086.8448950125246) < 0.01 # precip assert children[1].get_text() == '1087\nmm/an' - assert (children[2].get_height() - 136.12068516893297) < 0.1 # rechg + assert (children[2].get_height() - 136.12068516893297) < 0.01 # rechg assert children[3].get_text() == '136\nmm/an' - assert (children[4].get_height() - 226.9635476845988) < 0.1 # runoff + assert (children[4].get_height() - 226.9635476845988) < 0.01 # runoff assert children[5].get_text() == '227\nmm/an' - assert (children[6].get_height() - 550.11140519815) < 0.1 # evapo + assert (children[6].get_height() - 550.11140519815) < 0.01 # evapo assert children[7].get_text() == '550\nmm/an' - assert (children[8].get_height() == 47.97935577404126) < 0.1 # subrun1 + assert (children[8].get_height() - 47.97935577404126) < 0.01 # subrun1 assert children[9].get_text() == '48\nmm/an' - assert (children[10].get_height() - 121.66539490800443) < 0.1 # subrun2 + assert (children[10].get_height() - 121.66539490800443) < 0.01 # subrun2 assert children[11].get_text() == '122\nmm/an' From 521245996f5476ea65e0586b374457b759da72bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Wed, 27 Apr 2022 09:06:36 -0400 Subject: [PATCH 27/31] Reduce marke size to 5 It looks better --- pyhelp/output.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 1d0acfe..ee8179a 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -262,7 +262,7 @@ def plot_area_monthly_avg(self, figname: str = None, (vardataf.index >= year_from) & (vardataf.index <= year_to)) ax.plot(months, vardataf.loc[yearmask, :].mean(axis=0), - marker='o', mec='white', clip_on=False, lw=2, + marker='o', ms=5, mec='white', clip_on=False, lw=2, label=LABELS[varname], color=COLORS[varname]) ax.set_ylabel('Moyennes mensuelles (mm/mois)', @@ -403,7 +403,7 @@ def plot_area_yearly_series(self, figname: str = None, masked_data = yearly_avg[varname].loc[mask_years] masked_years = masked_data.index.values.astype('int') - ax.plot(masked_years, masked_data, marker='o', mec='white', + ax.plot(masked_years, masked_data, marker='o', mec='white', ms=5, clip_on=False, lw=2, color=COLORS[varname], label=LABELS[varname]) From 6e0efa1ce7fec227541e8298ccbcb9d44356f923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Wed, 27 Apr 2022 09:07:15 -0400 Subject: [PATCH 28/31] Rework ylabels --- pyhelp/output.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index ee8179a..ebc0629 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -265,8 +265,9 @@ def plot_area_monthly_avg(self, figname: str = None, marker='o', ms=5, mec='white', clip_on=False, lw=2, label=LABELS[varname], color=COLORS[varname]) - ax.set_ylabel('Moyennes mensuelles (mm/mois)', - fontsize=16, labelpad=10) + ax.set_ylabel( + 'Composantes mensuelles moyennes\ndu bilan hydrologique (mm/mois)', + fontsize=16, labelpad=10) ax.set_xlabel('Mois', fontsize=16, labelpad=10) ax.axis(ymin=-5) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) @@ -352,7 +353,9 @@ def plot_area_yearly_avg(self, figname: str = None, ax.tick_params(axis='y', direction='out', labelsize=12) ax.tick_params(axis='x', direction='out', length=0) - ax.set_ylabel('Moyennes annuelles (mm/an)', fontsize=16, labelpad=10) + ax.set_ylabel( + 'Composantes annuelles moyennes\ndu bilan hydrologique (mm/an)', + fontsize=16, labelpad=10) ax.set_xticklabels([]) ax.legend( From 1ee64d7806fae2e0c5ef70f7dd79d93bb76326b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Wed, 27 Apr 2022 09:43:59 -0400 Subject: [PATCH 29/31] Increase vertical gap above larger bar --- pyhelp/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index ebc0629..f559c87 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -345,7 +345,7 @@ def plot_area_yearly_avg(self, figname: str = None, bbox = handle.get_window_extent(fig.canvas.get_renderer()) bbox = bbox.transformed(ax.transData.inverted()) ymax = max(ymax, bbox.y1) - ymax = np.ceil(ymax * 1.025) + ymax = np.ceil(ymax * 1.05) ax.axis(ymin=0, ymax=ymax, xmin=0.25, xmax=6.75) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) From f292ba6fe12386733e6c20c9b1bc30abcace1b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Wed, 27 Apr 2022 09:46:02 -0400 Subject: [PATCH 30/31] Add year period as xlabel when appropriate --- pyhelp/output.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index f559c87..296e79d 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -255,20 +255,19 @@ def plot_area_monthly_avg(self, figname: str = None, fig, ax = self._create_figure(fsize=(9, 6.5)) + mask_years = ( + (self.data['years'] >= year_from) & + (self.data['years'] <= year_to)) months = list(range(1, 13)) for varname in VARNAMES[:-1]: vardataf = avg_monthly[varname] - yearmask = ( - (vardataf.index >= year_from) & - (vardataf.index <= year_to)) - ax.plot(months, vardataf.loc[yearmask, :].mean(axis=0), + ax.plot(months, vardataf.loc[mask_years, :].mean(axis=0), marker='o', ms=5, mec='white', clip_on=False, lw=2, label=LABELS[varname], color=COLORS[varname]) ax.set_ylabel( 'Composantes mensuelles moyennes\ndu bilan hydrologique (mm/mois)', fontsize=16, labelpad=10) - ax.set_xlabel('Mois', fontsize=16, labelpad=10) ax.axis(ymin=-5) ax.grid(axis='y', color=[0.35, 0.35, 0.35], ls='-', lw=0.5) ax.set_xticks(months) @@ -282,8 +281,19 @@ def plot_area_monthly_avg(self, figname: str = None, numpoints=1, fontsize=12, frameon=False, borderaxespad=0, loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1), ncol=2) + # Setup xlabel. + masked_years = self.data['years'][mask_years] + year_min = masked_years.min() + year_max = masked_years.max() + if year_min == year_max: + text = f"{year_min:0.0f}" + else: + text = f"{year_min:0.0f} - {year_max:0.0f}" + ax.set_xlabel(text, fontsize=16, labelpad=10) + fig.tight_layout() + # Save figure to file. if figname is not None: fig.savefig(figname) @@ -320,16 +330,17 @@ def plot_area_yearly_avg(self, figname: str = None, 0, 3/72, fig.dpi_scale_trans) area_yearly_avg = self.calc_area_yearly_avg() + mask_years = ( + (self.data['years'] >= year_from) & + (self.data['years'] <= year_to)) + x = 0 text_handles = [] for varname in VARNAMES[:-1]: x += 1 vardataf = area_yearly_avg[varname] - yearmask = ( - (vardataf.index >= year_from) & - (vardataf.index <= year_to)) - var_avg_yearly = vardataf.loc[yearmask].mean() + var_avg_yearly = vardataf.loc[mask_years].mean() ax.bar(x, var_avg_yearly, 0.85, align='center', label=LABELS[varname], color=COLORS[varname]) @@ -358,6 +369,16 @@ def plot_area_yearly_avg(self, figname: str = None, fontsize=16, labelpad=10) ax.set_xticklabels([]) + # Setup xlabel. + masked_years = self.data['years'][mask_years] + year_min = masked_years.min() + year_max = masked_years.max() + if year_min == year_max: + text = f"{year_min:0.0f}" + else: + text = f"{year_min:0.0f} - {year_max:0.0f}" + ax.set_xlabel(text, fontsize=16, labelpad=10) + ax.legend( numpoints=1, fontsize=12, frameon=False, borderaxespad=0, loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1, 1, 1), From 907a267145942acc262342dfb920d5b3bca2a751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Wed, 27 Apr 2022 11:04:55 -0400 Subject: [PATCH 31/31] Add year considered as a note instead of xlabel --- pyhelp/output.py | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/pyhelp/output.py b/pyhelp/output.py index 296e79d..ca504d7 100644 --- a/pyhelp/output.py +++ b/pyhelp/output.py @@ -281,15 +281,23 @@ def plot_area_monthly_avg(self, figname: str = None, numpoints=1, fontsize=12, frameon=False, borderaxespad=0, loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1), ncol=2) - # Setup xlabel. + # Add note about year considered for the hydrologic budget. masked_years = self.data['years'][mask_years] year_min = masked_years.min() year_max = masked_years.max() if year_min == year_max: - text = f"{year_min:0.0f}" + text = f"Année considérée pour le bilan : {year_min:0.0f}" else: - text = f"{year_min:0.0f} - {year_max:0.0f}" - ax.set_xlabel(text, fontsize=16, labelpad=10) + text = "Années considérées pour le bilan : " + text += f"{year_min:0.0f} - {year_max:0.0f}" + + fig.canvas.draw() + bbox_bottom, _ = ax.xaxis.get_ticklabel_extents( + fig.canvas.get_renderer()) + y0 = ax.transAxes.inverted().transform(bbox_bottom)[0][1] + offset = transforms.ScaledTranslation(0, -12/72, fig.dpi_scale_trans) + ax.text(0, y0, text, transform=ax.transAxes + offset, + va='top', ha='left') fig.tight_layout() @@ -369,20 +377,28 @@ def plot_area_yearly_avg(self, figname: str = None, fontsize=16, labelpad=10) ax.set_xticklabels([]) - # Setup xlabel. + ax.legend( + numpoints=1, fontsize=12, frameon=False, borderaxespad=0, + loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1, 1, 1), + ncol=2) + + # Add note about year considered for the hydrologic budget. masked_years = self.data['years'][mask_years] year_min = masked_years.min() year_max = masked_years.max() if year_min == year_max: - text = f"{year_min:0.0f}" + text = f"Année considérée pour le bilan : {year_min:0.0f}" else: - text = f"{year_min:0.0f} - {year_max:0.0f}" - ax.set_xlabel(text, fontsize=16, labelpad=10) + text = "Années considérées pour le bilan : " + text += f"{year_min:0.0f} - {year_max:0.0f}" - ax.legend( - numpoints=1, fontsize=12, frameon=False, borderaxespad=0, - loc='lower left', borderpad=0.5, bbox_to_anchor=(0, 1, 1, 1), - ncol=2) + fig.canvas.draw() + bbox_bottom, _ = ax.xaxis.get_ticklabel_extents( + fig.canvas.get_renderer()) + y0 = ax.transAxes.inverted().transform(bbox_bottom)[0][1] + offset = transforms.ScaledTranslation(0, -6/72, fig.dpi_scale_trans) + ax.text(0, y0, text, transform=ax.transAxes + offset, + va='top', ha='left') fig.tight_layout()