From f945cac13cbf43c1fae51bb7d6acc302373c8221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:26:30 -0500 Subject: [PATCH 01/21] Codestyle --- gwhat/HydroCalc2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index cbd548d25..ec987d23d 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -21,9 +21,9 @@ from PyQt5.QtCore import Qt from PyQt5.QtCore import pyqtSlot as QSlot from PyQt5.QtCore import pyqtSignal as QSignal -from PyQt5.QtWidgets import (QGridLayout, QComboBox, QTextEdit, - QSizePolicy, QPushButton, QLabel, QTabWidget, - QApplication, QWidget) +from PyQt5.QtWidgets import ( + QGridLayout, QComboBox, QTextEdit, QSizePolicy, QPushButton, QLabel, + QTabWidget, QApplication, QWidget) import matplotlib as mpl from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg From d3f3b614a155105f7f15a00d75b96d16b8e069a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:28:07 -0500 Subject: [PATCH 02/21] Rename self.mouse_vguide to on_mouse_move --- gwhat/HydroCalc2.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index ec987d23d..c72f46866 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -131,9 +131,8 @@ def _setup_mpl_canvas(self): self.canvas.mpl_connect('button_press_event', self.onclick) self.canvas.mpl_connect('button_release_event', self.onrelease) self.canvas.mpl_connect('resize_event', self.setup_ax_margins) - self.canvas.mpl_connect('motion_notify_event', self.mouse_vguide) + self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move) self.canvas.mpl_connect('figure_leave_event', self.on_fig_leave) - # ---- Setup the canvas frame # Put figure canvas in a QFrame widget. @@ -1158,7 +1157,7 @@ def on_fig_leave(self, event): """Handle when the mouse cursor leaves the graph.""" self.draw() - def mouse_vguide(self, event): + def on_mouse_move(self, event): """ Draw the vertical mouse guideline and the x and y coordinates of the mouse cursor on the graph. @@ -1249,7 +1248,7 @@ def onrelease(self, event): return self.__addPeakVisible = True self.draw_mrc() - self.mouse_vguide(event) + self.on_mouse_move(event) def onclick(self, event): """Handle when the graph is clicked with the mouse.""" From 3e7d5769a177917f805359231c432ca12470ca42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:28:18 -0500 Subject: [PATCH 03/21] if __name__ == '__main__': --- gwhat/HydroCalc2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index c72f46866..363bcd678 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1943,6 +1943,7 @@ def mrc2rechg(t, ho, A, B, z, Sy): import sys from projet.manager_data import DataManager from projet.reader_projet import ProjetReader + from gwhat import __rootdir__ app = QApplication(sys.argv) @@ -1951,7 +1952,7 @@ def mrc2rechg(t, ho, A, B, z, Sy): ft.setPointSize(11) app.setFont(ft) - pf = 'C:/Users/jsgosselin/GWHAT/Projects/Example/Example.gwt' + pf = osp.join(__rootdir__, '../Projects/Example/Example.gwt') pr = ProjetReader(pf) dm = DataManager() From f10f5cd8a8531224000790d9bd2a510ace88c366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:28:31 -0500 Subject: [PATCH 04/21] Codestyle --- gwhat/HydroCalc2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 363bcd678..9b54f0b7a 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1321,7 +1321,7 @@ def onclick(self, event): if xclic is None: return - xclic = xclic - self.dt4xls2mpl*self.dformat + xclic = xclic - (self.dt4xls2mpl * self.dformat) argmin = np.argmin(np.abs(xclic - self.time)) i = 0 if self.selected_brfperiod[0] is None else 1 self.selected_brfperiod[i] = self.time[argmin] From 9ed902d9f1c82dd15bb6d4de1a40093264942f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:28:53 -0500 Subject: [PATCH 05/21] Codestyle --- gwhat/HydroCalc2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 9b54f0b7a..c36589a5b 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1195,8 +1195,7 @@ def on_mouse_move(self, event): self.xycoord.set_visible(False) # ---- Remove Peak Cursor - - if not self.btn_delpeak.autoRaise() and len(self.peak_indx) > 0: + if self.btn_delpeak.value() and len(self.peak_indx) > 0: # For deleting peak in the graph. Will put a cross on top of the # peak to delete if some proximity conditions are met. From 00e18b1a60f2998d73b9f096f6f4634ddee29f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 00:29:39 -0500 Subject: [PATCH 06/21] Remove aToolbarBtn_isClicked completely --- gwhat/HydroCalc2.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index c36589a5b..0701316c0 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -369,7 +369,7 @@ def _setup_mrc_tool(self): self.btn_save_mrc.clicked.connect(self.save_mrc_tofile) self.btn_MRCalc = QPushButton('Compute MRC') - self.btn_MRCalc.clicked.connect(self.aToolbarBtn_isClicked) + self.btn_MRCalc.clicked.connect(self.btn_MRCalc_isClicked) self.btn_MRCalc.setToolTip('

Calculate the Master Recession Curve' ' (MRC) for the selected time periods.

') @@ -672,18 +672,9 @@ def clear_all_peaks(self): self.peak_memory.append(self.peak_indx) self.draw_mrc() - # ---- Toolbar handlers + # ---- Navig and selec tools - def aToolbarBtn_isClicked(self): - """Handle and redirect all clicked actions from the toolbar.""" - if self.wldset is None: - self.emit_warning( - "Please import a valid water level dataset first.") - return - sender = self.sender() - if sender == self.btn_MRCalc: - self.btn_MRCalc_isClicked() @property def zoom_is_active(self): From 128a4bfeddf4b97064e9fc3e7c0b73056bdc0a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 08:49:23 -0500 Subject: [PATCH 07/21] Add a Rectangle object to ax0 --- gwhat/HydroCalc2.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 0701316c0..a1f69d538 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -18,6 +18,7 @@ # ---- Third party imports import numpy as np +from matplotlib.patches import Rectangle from PyQt5.QtCore import Qt from PyQt5.QtCore import pyqtSlot as QSlot from PyQt5.QtCore import pyqtSignal as QSignal @@ -220,6 +221,13 @@ def _setup_mpl_canvas(self): # Predicted GLUE water levels self.glue_plt, = ax0.plot([], []) + # Rectangular selection box. + self._rect_selection = [(None, None), (None, None)] + self._rect_selector = Rectangle( + (0, 0), 0, 0, edgecolor='black', facecolor='red', linestyle=':', + fill=True, alpha=0.15, visible=False) + ax0.add_patch(self._rect_selector) + # Vertical guide line under cursor : self.vguide = ax0.axvline(-1, color='red', zorder=40) self.vguide.set_visible(False) From 3ecc16894c66acc571baf99491f628075608d086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 08:51:13 -0500 Subject: [PATCH 08/21] Improve navig and select tool toggling --- gwhat/HydroCalc2.py | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index a1f69d538..f29977ce5 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -62,6 +62,8 @@ def __init__(self, datamanager, parent=None): DialogWindow.__init__(self, parent, maximize=True) SaveFileMixin.__init__(self) + self._navig_and_select_tools = [] + self.dmngr = datamanager self.dmngr.wldsetChanged.connect(self.set_wldset) self.dmngr.wxdsetChanged.connect(self.set_wxdset) @@ -78,6 +80,7 @@ def __init__(self, datamanager, parent=None): lambda: self.toggle_brfperiod_selection( self.brf_eval_widget.btn_seldata.value()) ) + self.register_navig_and_select_tool(self.brf_eval_widget.btn_seldata) self.__figbckground = None self.__addPeakVisible = True @@ -265,6 +268,7 @@ def _setup_toolbar(self): self.btn_pan.setToolTip( 'Pan axes with the left mouse button and zoom with the right') self.btn_pan.sig_value_changed.connect(self.pan_is_active_changed) + self.register_navig_and_select_tool(self.btn_pan) self.btn_zoom_to_rect = OnOffToolButton('zoom_to_rect', size='normal') self.btn_pan.setToolTip( @@ -272,6 +276,7 @@ def _setup_toolbar(self): " out with the right mouse button.") self.btn_zoom_to_rect.sig_value_changed.connect( self.zoom_is_active_changed) + self.register_navig_and_select_tool(self.btn_zoom_to_rect) self.btn_wl_style = OnOffToolButton('showDataDots', size='normal') self.btn_wl_style.setToolTip( @@ -365,12 +370,14 @@ def _setup_mrc_tool(self): self.btn_addpeak.sig_value_changed.connect(self.btn_addpeak_isclicked) self.btn_addpeak.setToolTip( "

Toggle edit mode to manually add extremums to the graph

") + self.register_navig_and_select_tool(self.btn_addpeak) self.btn_delpeak = OnOffToolButton('erase', size='normal') self.btn_delpeak.clicked.connect(self.btn_delpeak_isclicked) self.btn_delpeak.setToolTip( "

Toggle edit mode to manually remove extremums" " from the graph

") + self.register_navig_and_select_tool(self.btn_delpeak) self.btn_save_mrc = QToolButtonNormal(icons.get_icon('save')) self.btn_save_mrc.setToolTip('Save calculated MRC to file.') @@ -620,10 +627,8 @@ def toggle_brfperiod_selection(self, value): self.brf_eval_widget.btn_seldata.setValue(value, silent=True) self._select_brfperiod_flag = value if value is True: - self.btn_addpeak.setValue(False) - self.btn_delpeak.setValue(False) - self.btn_zoom_to_rect.setValue(False) - self.btn_pan.setValue(False) + self.toggle_navig_and_select_tools( + self.brf_eval_widget.btn_seldata) self.selected_brfperiod = [None, None] elif value is False: if not all(self.selected_brfperiod): @@ -656,21 +661,15 @@ def find_peak(self): def btn_addpeak_isclicked(self): """Handle when the button add_peak is clicked.""" if self.btn_addpeak.value(): + self.toggle_navig_and_select_tools(self.btn_addpeak) self.btn_show_mrc.setValue(True) - self.btn_delpeak.setValue(False) - self.btn_pan.setValue(False) - self.btn_zoom_to_rect.setValue(False) - self.toggle_brfperiod_selection(False) self.draw() def btn_delpeak_isclicked(self): """Handle when the button btn_delpeak is clicked.""" if self.btn_delpeak.value(): + self.toggle_navig_and_select_tools(self.btn_addpeak) self.btn_show_mrc.setValue(True) - self.btn_addpeak.setValue(False) - self.btn_pan.setValue(False) - self.btn_zoom_to_rect.setValue(False) - self.toggle_brfperiod_selection(False) self.draw() def clear_all_peaks(self): @@ -682,6 +681,16 @@ def clear_all_peaks(self): # ---- Navig and selec tools + def register_navig_and_select_tool(self, tool): + """ + Add the tool to the list of tools that are available to interactively + navigate and select the data. + """ + if not isinstance(tool, OnOffToolButton): + raise TypeError + + if tool not in self._navig_and_select_tools: + self._navig_and_select_tools.append(tool) @property @@ -693,10 +702,7 @@ def zoom_is_active(self): def zoom_is_active_changed(self, zoom_is_active): """Handle when the state of the button to zoom to rectangle changes.""" if self.zoom_is_active: - self.btn_pan.setValue(False) - self.btn_delpeak.setValue(False) - self.btn_addpeak.setValue(False) - self.toggle_brfperiod_selection(False) + self.toggle_navig_and_select_tools(self.btn_zoom_to_rect) if self.toolbar._active is None: self.toolbar.zoom() else: @@ -712,10 +718,7 @@ def pan_is_active(self): def pan_is_active_changed(self, pan_is_active): """Handle when the state of the button to pan the graph changes.""" if self.pan_is_active: - self.btn_zoom_to_rect.setValue(False) - self.btn_delpeak.setValue(False) - self.btn_addpeak.setValue(False) - self.toggle_brfperiod_selection(False) + self.toggle_navig_and_select_tools(self.btn_pan) if self.toolbar._active is None: self.toolbar.pan() else: From 35cdf4ee52abc2fece7d4909970f8f1750db77f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 08:54:27 -0500 Subject: [PATCH 09/21] Improve code for drawing the mouse cursor --- gwhat/HydroCalc2.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index f29977ce5..bfea6abbb 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1144,6 +1144,19 @@ def _draw_mrc_peaks(self): else: self._peaks_plt.set_visible(False) + def _draw_mouse_cursor(self, x, y): + """Draw a vertical and horizontal line at the specified xy position.""" + if not all((x, y)): + self.vguide.set_visible(False) + elif (self.pan_is_active or self.zoom_is_active or + self.rect_select_is_active): + self.vguide.set_visible(False) + else: + self.vguide.set_visible(True) + self.vguide.set_xdata(x) + self.fig.axes[0].draw_artist(self.vguide) + + # ----- Handlers: Mouse events def is_all_btn_raised(self): @@ -1172,17 +1185,13 @@ def on_mouse_move(self, event): fig = self.fig fig.canvas.restore_region(self.__figbckground) - # ---- Draw the vertical guide + # ---- Draw the cursor guide and the xy coordinates on the graph. # Trace a red vertical guide (line) that folows the mouse marker : x, y = event.xdata, event.ydata - if x: - self.vguide.set_visible( - not self.pan_is_active and not self.zoom_is_active) - self.vguide.set_xdata(x) - ax0.draw_artist(self.vguide) - + self._draw_mouse_cursor(x, y) + if all((x, y)): self.xycoord.set_visible(True) if self.dformat == 0: self.xycoord.set_text( From e0fbea4baaceed94be79bfa7a6bc92c6f63e1090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 08:57:58 -0500 Subject: [PATCH 10/21] Add prop and slot for the rect selection tool --- gwhat/HydroCalc2.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index bfea6abbb..a05c09960 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -725,6 +725,20 @@ def pan_is_active_changed(self, pan_is_active): if self.toolbar._active == 'PAN': self.toolbar.pan() + @property + def rect_select_is_active(self): + """ + Return whether the rectangle selection of water level data is + active or not. + """ + return self.btn_rect_select.value() + + @QSlot(bool) + def rect_select_is_active_changed(self, value): + """Handle the rectangular selection tool is toggled on or off.""" + if self.rect_select_is_active: + self.toggle_navig_and_select_tools(self.btn_rect_select) + def home(self): """Reset the orgininal view of the figure.""" self.toolbar.home() From 2c73c4ee57fb67032058d4adfda997c51dce07de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 08:59:02 -0500 Subject: [PATCH 11/21] Add a method to draw the rectangle --- gwhat/HydroCalc2.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index a05c09960..548097ba7 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1158,6 +1158,19 @@ def _draw_mrc_peaks(self): else: self._peaks_plt.set_visible(False) + def _draw_rect_selection(self, x2, y2): + """Draw the rectangle of the rectangular selection tool.""" + x1, y1 = self._rect_selection[0] + if not all((x1, y1, x2, y2)): + self._rect_selector.set_visible(False) + else: + self._rect_selector.set_xy((min(x1, x2), min(y1, y2))) + self._rect_selector.set_height(abs(y1 - y2)) + self._rect_selector.set_width(abs(x1 - x2)) + self._rect_selector.set_visible(True) + + self.fig.axes[0].draw_artist(self._rect_selector) + def _draw_mouse_cursor(self, x, y): """Draw a vertical and horizontal line at the specified xy position.""" if not all((x, y)): From 1e7fdfa633071764dbf4fa0e20c108cb5e8f8c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:01:29 -0500 Subject: [PATCH 12/21] Add action to onlreales, onclick, on_mouse_move --- gwhat/HydroCalc2.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 548097ba7..2519d92e5 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1231,6 +1231,9 @@ def on_mouse_move(self, event): else: self.vguide.set_visible(False) self.xycoord.set_visible(False) + + if self.rect_select_is_active and self.__mouse_btn_is_pressed: + self._draw_rect_selection(x, y) # ---- Remove Peak Cursor if self.btn_delpeak.value() and len(self.peak_indx) > 0: @@ -1277,6 +1280,9 @@ def onrelease(self, event): self.toolbar.release_pan(event) if self.zoom_is_active: self.toolbar.release_zoom(event) + if self.rect_select_is_active: + self._rect_selection[1] = (event.xdata, event.ydata) + self._rect_selector.set_visible(False) if self.is_all_btn_raised(): self.draw() @@ -1370,6 +1376,8 @@ def onclick(self, event): self.toggle_brfperiod_selection(False) else: self.plot_brfperiod() + elif self.rect_select_is_active: + self._rect_selection[0] = (event.xdata, event.ydata) else: self.draw() From 82e6d20f2dcf0859cc312a45ff8bc3d1587954d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:02:51 -0500 Subject: [PATCH 13/21] Add a method to toggle off all tool at once --- gwhat/HydroCalc2.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 2519d92e5..e7577eb50 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -692,6 +692,19 @@ def register_navig_and_select_tool(self, tool): if tool not in self._navig_and_select_tools: self._navig_and_select_tools.append(tool) + def toggle_navig_and_select_tools(self, keep_toggled=None): + """ + Toggle off all navigation and selection tool, but the ones listed + in the keep_toggled. + """ + try: + iter(keep_toggled) + except TypeError: + keep_toggled = [keep_toggled] + + for tool in self._navig_and_select_tools: + if tool not in keep_toggled: + tool.setValue(False) @property def zoom_is_active(self): From b32860e244186afcb59f49ee18058d2145fe0e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:04:14 -0500 Subject: [PATCH 14/21] Correct btn_zoom_to_rect tooltip --- gwhat/HydroCalc2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index e7577eb50..75ea8859a 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -271,8 +271,8 @@ def _setup_toolbar(self): self.register_navig_and_select_tool(self.btn_pan) self.btn_zoom_to_rect = OnOffToolButton('zoom_to_rect', size='normal') - self.btn_pan.setToolTip( - "Zoom in to the rectangle with the left mouse button and zoom" + self.btn_zoom_to_rect.setToolTip( + "Zoom into the rectangle with the left mouse button and zoom" " out with the right mouse button.") self.btn_zoom_to_rect.sig_value_changed.connect( self.zoom_is_active_changed) From ae7ead91c09fffb554acb015f5181c73a9450a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:19:05 -0500 Subject: [PATCH 15/21] Add a button for the rect select tool --- gwhat/HydroCalc2.py | 12 ++++++++++-- gwhat/utils/icons.py | 24 ++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 75ea8859a..e9646abda 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -323,13 +323,21 @@ def _setup_toolbar(self): self.btn_show_meas_wl.setValue(True, silent=True) self.btn_show_meas_wl.sig_value_changed.connect(self.draw_meas_wl) - # Setup the layout. + self.btn_rect_select = OnOffToolButton('rect_select', size='normal') + self.btn_rect_select.setToolTip( + "Select water level data by clicking with the mouse and dragging " + "the cursor over a rectangular region of the graph.") + self.btn_rect_select.sig_value_changed.connect( + self.rect_select_is_active_changed) + self.register_navig_and_select_tool(self.btn_rect_select) + # Setup the layout. toolbar = ToolBarWidget() for btn in [self.btn_home, self.btn_pan, self.btn_zoom_to_rect, None, self.btn_wl_style, self.btn_dateFormat, None, self.btn_show_glue, self.btn_show_weather, - self.btn_show_mrc, self.btn_show_meas_wl]: + self.btn_show_mrc, self.btn_show_meas_wl, + self.btn_rect_select]: toolbar.addWidget(btn) return toolbar diff --git a/gwhat/utils/icons.py b/gwhat/utils/icons.py index 19041aea9..d4c43ecbf 100644 --- a/gwhat/utils/icons.py +++ b/gwhat/utils/icons.py @@ -96,16 +96,20 @@ COLOR = '#4d4d4d' FA_ICONS = { - 'close_all': [('fa.close', 'fa.close', 'fa.close'), - {'options': [{'scale_factor': 0.6, - 'offset': (0.3, -0.3), - 'color': COLOR}, - {'scale_factor': 0.6, - 'offset': (-0.3, -0.3), - 'color': COLOR}, - {'scale_factor': 0.6, - 'offset': (0.3, 0.3), - 'color': COLOR}]}] + 'close_all': [ + ('fa.close', 'fa.close', 'fa.close'), + {'options': [{'scale_factor': 0.6, + 'offset': (0.3, -0.3), + 'color': COLOR}, + {'scale_factor': 0.6, + 'offset': (-0.3, -0.3), + 'color': COLOR}, + {'scale_factor': 0.6, + 'offset': (0.3, 0.3), + 'color': COLOR}]}], + 'rect_select': [ + ('mdi.selection-drag',), + {'color': COLOR, 'scale_factor': 1.3}] } From 227cb37d9072ba9e7b23a4dbf7c954dc6afcc0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:19:43 -0500 Subject: [PATCH 16/21] Codestyle --- gwhat/HydroCalc2.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index e9646abda..43d24738a 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1189,24 +1189,22 @@ def _draw_rect_selection(self, x2, y2): self._rect_selector.set_height(abs(y1 - y2)) self._rect_selector.set_width(abs(x1 - x2)) self._rect_selector.set_visible(True) - + self.fig.axes[0].draw_artist(self._rect_selector) - + def _draw_mouse_cursor(self, x, y): """Draw a vertical and horizontal line at the specified xy position.""" if not all((x, y)): self.vguide.set_visible(False) elif (self.pan_is_active or self.zoom_is_active or - self.rect_select_is_active): + self.rect_select_is_active): self.vguide.set_visible(False) else: self.vguide.set_visible(True) self.vguide.set_xdata(x) self.fig.axes[0].draw_artist(self.vguide) - - - # ----- Handlers: Mouse events + # ----- Handlers: Mouse events def is_all_btn_raised(self): """ Return whether all of the tool buttons that can block the panning and @@ -1252,7 +1250,7 @@ def on_mouse_move(self, event): else: self.vguide.set_visible(False) self.xycoord.set_visible(False) - + if self.rect_select_is_active and self.__mouse_btn_is_pressed: self._draw_rect_selection(x, y) From e9ddcb69e88b3456f846597909619c0fa7e9bfd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 09:20:08 -0500 Subject: [PATCH 17/21] Change cursor when entering or leaving the axes --- gwhat/HydroCalc2.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 43d24738a..27aab9a1f 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -137,6 +137,9 @@ def _setup_mpl_canvas(self): self.canvas.mpl_connect('resize_event', self.setup_ax_margins) self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move) self.canvas.mpl_connect('figure_leave_event', self.on_fig_leave) + self.canvas.mpl_connect('axes_enter_event', self.on_axes_enter) + self.canvas.mpl_connect('axes_leave_event', self.on_axes_leave) + # ---- Setup the canvas frame # Put figure canvas in a QFrame widget. @@ -1218,6 +1221,15 @@ def on_fig_leave(self, event): """Handle when the mouse cursor leaves the graph.""" self.draw() + def on_axes_enter(self, event): + """Handle when the mouse cursor enters a new axe.""" + if self.rect_select_is_active: + self.toolbar.set_cursor(2) + + def on_axes_leave(self, event): + """Handle when the mouse cursor leaves an axe.""" + self.toolbar.set_cursor(1) + def on_mouse_move(self, event): """ Draw the vertical mouse guideline and the x and y coordinates of the From be45f5a64f894976d9f587800f3a81abcbaffef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 10:07:48 -0500 Subject: [PATCH 18/21] Codestyle --- gwhat/HydroCalc2.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index 27aab9a1f..b276f1d6a 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -89,8 +89,6 @@ def __init__(self, datamanager, parent=None): # Water Level Time series : self.time = [] - self.txls = [] # time in Excel format - self.tmpl = [] # time in matplotlib format self.water_lvl = [] # Calcul the delta between the datum of Excel and Maplotlib numeric @@ -115,8 +113,7 @@ def __init__(self, datamanager, parent=None): self.soilFilename = [] self.SOILPROFIL = SoilProfil() - # ---- Initialize the GUI - + # Initialize the GUI self.precip_bwidth = 7 self._setup_mpl_canvas() self.__initUI__() @@ -139,7 +136,7 @@ def _setup_mpl_canvas(self): self.canvas.mpl_connect('figure_leave_event', self.on_fig_leave) self.canvas.mpl_connect('axes_enter_event', self.on_axes_enter) self.canvas.mpl_connect('axes_leave_event', self.on_axes_leave) - + # ---- Setup the canvas frame # Put figure canvas in a QFrame widget. @@ -189,34 +186,34 @@ def _setup_mpl_canvas(self): # ax0.grid(axis='x', color=[0.35, 0.35, 0.35], ls='--') # ax0.set_axisbelow(True) - # ---- Setup plot artists + # ---- Setup the artists - # Water level : + # Water level data. self._obs_wl_plt, = ax0.plot( [], [], color='blue', clip_on=True, ls='-', zorder=10, marker='None') - # Water levels measured manually + # Water levels measured manually. self._meas_wl_plt, = ax0.plot( [], [], clip_on=True, ls='none', zorder=10, marker='+', ms=8, mec='red', mew=2, mfc='red') - # Predicted water levels : + # Predicted water levels. self.plt_wlpre, = ax0.plot([], [], color='red', clip_on=True, ls='-', zorder=10, marker='None') - # Recession : + # Recession. self._mrc_plt, = ax0.plot([], [], color='red', clip_on=True, zorder=15, marker='None', linestyle='--') - # Rain : + # Rain. self.h_rain, = ax1.plot([], []) - # Ptot : + # Precipitation. self.h_ptot, = ax1.plot([], []) - # ETP : + # Evapotranspiration. self.h_etp, = ax1.plot([], [], color='#FF6666', lw=1.5, zorder=500, ls='-') @@ -260,6 +257,7 @@ def _setup_mpl_canvas(self): def _setup_toolbar(self): """Setup the main toolbar of the water level calc tool.""" + # ---- Navigate data. self.toolbar = NavigationToolbar2QT(self.canvas, parent=self) self.toolbar.hide() @@ -300,7 +298,6 @@ def _setup_toolbar(self): # True -> Matplotlib Date Format # ---- Show/Hide section - self.btn_show_glue = OnOffToolButton('show_glue_wl', size='normal') self.btn_show_glue.setToolTip( """Show or hide GLUE water level 05/95 envelope.""") @@ -326,6 +323,7 @@ def _setup_toolbar(self): self.btn_show_meas_wl.setValue(True, silent=True) self.btn_show_meas_wl.sig_value_changed.connect(self.draw_meas_wl) + # ---- Select and transform data. self.btn_rect_select = OnOffToolButton('rect_select', size='normal') self.btn_rect_select.setToolTip( "Select water level data by clicking with the mouse and dragging " @@ -339,7 +337,7 @@ def _setup_toolbar(self): for btn in [self.btn_home, self.btn_pan, self.btn_zoom_to_rect, None, self.btn_wl_style, self.btn_dateFormat, None, self.btn_show_glue, self.btn_show_weather, - self.btn_show_mrc, self.btn_show_meas_wl, + self.btn_show_mrc, self.btn_show_meas_wl, None, self.btn_rect_select]: toolbar.addWidget(btn) From 54d5ef1ad53788cbd2a41c509d4a2b878d0e6c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 10:08:29 -0500 Subject: [PATCH 19/21] Add an on_rect_select method Handle when a rectangular area to select water level data has been selected. --- gwhat/HydroCalc2.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index b276f1d6a..f6f1a56cf 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -1228,6 +1228,28 @@ def on_axes_leave(self, event): """Handle when the mouse cursor leaves an axe.""" self.toolbar.set_cursor(1) + def on_rect_select(self): + """ + Handle when a rectangular area to select water level data has been + selected. + """ + xy_click, xy_release = self._rect_selection + if not all(xy_click + xy_release): + # The selection area is not valid. + return + else: + x_click, y_click = xy_click + x_click = x_click - (self.dt4xls2mpl * self.dformat) + + x_rel, y_rel = xy_release + x_rel = x_rel - (self.dt4xls2mpl * self.dformat) + + self.wl_selected_i += np.where( + (self.time >= min(x_click, x_rel)) & + (self.time <= max(x_click, x_rel)) & + (self.water_lvl >= min(y_click, y_rel)) & + (self.water_lvl <= max(y_click, y_rel)) + )[0].tolist() def on_mouse_move(self, event): """ Draw the vertical mouse guideline and the x and y coordinates of the @@ -1312,6 +1334,7 @@ def onrelease(self, event): if self.rect_select_is_active: self._rect_selection[1] = (event.xdata, event.ydata) self._rect_selector.set_visible(False) + self.on_rect_select() if self.is_all_btn_raised(): self.draw() From 06b4f31d2710813ce695925ec47ea9189590f57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 10:09:03 -0500 Subject: [PATCH 20/21] Draw the selected water level --- gwhat/HydroCalc2.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index f6f1a56cf..d7dac66e3 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -105,6 +105,9 @@ def __init__(self, datamanager, parent=None): self.peak_indx = np.array([]).astype(int) self.peak_memory = [np.array([]).astype(int)] + # Selected water level data. + self.wl_selected_i = [] + # Barometric Response Function : self.selected_brfperiod = [None, None] self._select_brfperiod_flag = False @@ -193,6 +196,9 @@ def _setup_mpl_canvas(self): [], [], color='blue', clip_on=True, ls='-', zorder=10, marker='None') + self._select_wl_plt, = ax0.plot( + [], [], color='orange', clip_on=True, ls='None', zorder=10, + marker='.', mfc='orange', mec='orange', ms=5, mew=1.5) # Water levels measured manually. self._meas_wl_plt, = ax0.plot( @@ -1061,6 +1067,16 @@ def draw_meas_wl(self): self._meas_wl_plt.set_visible(False) self.draw() + def draw_select_wl(self): + """Draw the selected water level data points.""" + if self.wldset is not None: + self._select_wl_plt.set_data( + self.time[self.wl_selected_i] + + (self.dt4xls2mpl * self.dformat), + self.water_lvl[self.wl_selected_i] + ) + self.draw() + def draw_glue_wl(self): """Draw or hide the water level envelope estimated with GLUE.""" if self.wldset is not None and self.btn_show_glue.value(): @@ -1250,6 +1266,8 @@ def on_rect_select(self): (self.water_lvl >= min(y_click, y_rel)) & (self.water_lvl <= max(y_click, y_rel)) )[0].tolist() + self.draw_select_wl() + def on_mouse_move(self, event): """ Draw the vertical mouse guideline and the x and y coordinates of the From 4c0639282faf8356d7384716a1a2cb0aca9b4ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Gosselin?= Date: Sun, 3 Feb 2019 10:22:23 -0500 Subject: [PATCH 21/21] Add btn to clear selection --- gwhat/HydroCalc2.py | 11 ++++++++++- gwhat/utils/icons.py | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/gwhat/HydroCalc2.py b/gwhat/HydroCalc2.py index d7dac66e3..9887eaad6 100644 --- a/gwhat/HydroCalc2.py +++ b/gwhat/HydroCalc2.py @@ -338,13 +338,17 @@ def _setup_toolbar(self): self.rect_select_is_active_changed) self.register_navig_and_select_tool(self.btn_rect_select) + self.btn_clear_select = QToolButtonNormal('rect_select_off') + self.btn_clear_select.setToolTip("Clear selected water levels.") + self.btn_clear_select.clicked.connect(self.clear_selected_wl) + # Setup the layout. toolbar = ToolBarWidget() for btn in [self.btn_home, self.btn_pan, self.btn_zoom_to_rect, None, self.btn_wl_style, self.btn_dateFormat, None, self.btn_show_glue, self.btn_show_weather, self.btn_show_mrc, self.btn_show_meas_wl, None, - self.btn_rect_select]: + self.btn_rect_select, self.btn_clear_select]: toolbar.addWidget(btn) return toolbar @@ -767,6 +771,11 @@ def rect_select_is_active_changed(self, value): if self.rect_select_is_active: self.toggle_navig_and_select_tools(self.btn_rect_select) + def clear_selected_wl(self): + """Clear the selecte water level data.""" + self.wl_selected_i = [] + self.draw_select_wl() + def home(self): """Reset the orgininal view of the figure.""" self.toolbar.home() diff --git a/gwhat/utils/icons.py b/gwhat/utils/icons.py index d4c43ecbf..52d46c0c2 100644 --- a/gwhat/utils/icons.py +++ b/gwhat/utils/icons.py @@ -108,8 +108,9 @@ 'offset': (0.3, 0.3), 'color': COLOR}]}], 'rect_select': [ - ('mdi.selection-drag',), - {'color': COLOR, 'scale_factor': 1.3}] + ('mdi.select-drag',), {'color': COLOR, 'scale_factor': 1.3}], + 'rect_select_off': [ + ('mdi.select-off',), {'color': COLOR, 'scale_factor': 1.1}] }