Skip to content

Commit

Permalink
PR: Refactor the code to save the MRC results to file (#221)
Browse files Browse the repository at this point in the history
* Change name of an icon

* Create a Save file mixin class

* Move function to calcul RMSE and support nan

* Use new mixin class in ExportDataButton

* Move fileio from utils to widgets

* Improve methods to savefiles

* Emit signal when workdir changed

* Move the code to save mrc to reader_projet

* codestyle

* rework code to save mrc
  • Loading branch information
jnsebgosselin authored May 16, 2018
1 parent d552141 commit f50bb4b
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 152 deletions.
111 changes: 38 additions & 73 deletions gwhat/HydroCalc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,45 @@

# ---- Standard library imports

from time import clock, sleep
from time import clock
import csv
import os
import os.path as osp
import datetime


# ---- Third party imports

import numpy as np
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtCore import pyqtSignal as QSignal
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSlot as QSlot
from PyQt5.QtWidgets import (QGridLayout, QComboBox, QTextEdit,
QSizePolicy, QPushButton, QLabel, QTabWidget,
QApplication, QFileDialog)
QApplication)

import matplotlib as mpl
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT

from xlrd import xldate_as_tuple
from xlrd.xldate import xldate_from_date_tuple
import xlsxwriter


# ---- Local imports

from gwhat.gwrecharge.gwrecharge_gui import RechgEvalWidget
import gwhat.common.widgets as myqt
from gwhat.common.widgets import DialogWindow
from gwhat.common import StyleDB, QToolButtonNormal
from gwhat.common import icons
from gwhat.widgets.buttons import ToolBarWidget
from gwhat.brf_mod import BRFManager
from gwhat.widgets.buttons import OnOffToolButton
from gwhat.widgets.layout import VSep
from gwhat.widgets.fileio import SaveFileMixin

# mpl.rc('font', **{'family': 'sans-serif', 'sans-serif': ['Arial']})


class WLCalc(myqt.DialogWindow):
class WLCalc(DialogWindow, SaveFileMixin):
"""
This is the interface where are plotted the water level time series. It is
possible to dynamically zoom and span the data, change the display,
Expand All @@ -56,10 +55,13 @@ class WLCalc(myqt.DialogWindow):
"""

def __init__(self, datamanager, parent=None):
super(WLCalc, self).__init__(parent, maximize=True)
DialogWindow.__init__(self, parent, maximize=True)
SaveFileMixin.__init__(self)

self.dmngr = datamanager
self.dmngr.wldsetChanged.connect(self.set_wldset)
self.dmngr.wxdsetChanged.connect(self.set_wxdset)
self.dmngr.sig_workdir_changed.connect(self.set_dialog_dir)

self.rechg_eval_widget = RechgEvalWidget(parent=self)
self.rechg_eval_widget.sig_new_gluedf.connect(self.draw_glue_wl)
Expand All @@ -68,7 +70,7 @@ def __init__(self, datamanager, parent=None):
self.config_brf.btn_seldata.clicked.connect(self.aToolbarBtn_isClicked)

self.isGraphExists = False
self.__figbckground = None # figure background
self.__figbckground = None
self.__addPeakVisible = True
self.__mouse_btn_is_pressed = False

Expand All @@ -79,15 +81,14 @@ def __init__(self, datamanager, parent=None):
self.tmpl = [] # time in matplotlib format
self.water_lvl = []

# Date System :
# Calcul the delta between the datum of Excel and Maplotlib numeric
# date system.
t_xls = xldate_from_date_tuple((2000, 1, 1), 0)
t_mpl = mpl.dates.date2num(datetime.datetime(2000, 1, 1))
self.dt4xls2mpl = t_mpl - t_xls

t1 = xldate_from_date_tuple((2000, 1, 1), 0) # time in Excel
t2 = mpl.dates.date2num(datetime.datetime(2000, 1, 1)) # Time in
self.dt4xls2mpl = t2-t1 # Delta between the datum of both date system

# Date format: can either be 0 for Excel format or 1 for Matplotlib
# The date format can either be 0 for Excel format or 1 for Matplotlib
# format.

self.dformat = 1

# Recession Curve Parameters :
Expand Down Expand Up @@ -527,62 +528,26 @@ def load_MRC_interp(self):
self.RMSE = np.mean(err[~np.isnan(err)])**0.5

self.plot_peak()
self.draw_MRC()

# -------------------------------------------------------------------------

def save_mrc_tofile(self):
filename = self.wldset['Well'] + '.xlsx'

# ---- get filename ----
def save_mrc_tofile(self, savefilename=None):
"""Save the master recession curve results to a file."""
if savefilename is None:
savefilename = osp.join(
self.dialog_dir,
"Well_%s_mrc_results.xlsx" % self.wldset['Well'])

dialog = QFileDialog()
filename, ftype = dialog.getSaveFileName(
self, "Save Results Summary", filename, '*.xlsx')
savefilename = self.select_savefilename(
"Save MRC results", savefilename, "*.xlsx;;*.xls;;*.csv")

if not filename:
return

root, ext = os.path.splitext(filename)
if ext not in ['.xlsx', '.xls']:
filename += '.xlsx'

# ---- save MRC to file ----

with xlsxwriter.Workbook(filename) as wb:
ws = wb.add_worksheet()

ws.set_column('A:A', 35)
ws.set_column('B:B', 35)
ws.set_column('C:C', 35)

ws.write(0, 0, 'Well Name : %s' % self.wldset['Well'])
ws.write(1, 0, 'Latitude : %f' % self.wldset['Latitude'])
ws.write(2, 0, 'Longitude : %f' % self.wldset['Longitude'])
ws.write(3, 0, 'Altitude : %f' % self.wldset['Elevation'])
ws.write(4, 0, 'Municipality : %s' % self.wldset['Municipality'])

A, B = self.wldset['mrc/params']

ws.write(6, 0, 'dh/dt(mm/d) = -%f*h(mbgs) + %f' % (self.A, self.B))
ws.write(7, 0, 'A (1/d)')
ws.write(7, 1, self.A)
ws.write(8, 0, 'B (m/d)')
ws.write(8, 1, self.B)
ws.write(9, 0, 'RMSE (m)')
ws.write(9, 1, self.RMSE)

ws.write(11, 0, 'Observed and Predicted Water Level')
ws.write_row(12, 0, ['Time', 'hrecess(mbgs)', 'hobs(mbgs)'])
print(len(self.time), len(self.hrecess), len(self.water_lvl))
for i in range(len(self.time)):
if np.isnan(self.hrecess[i]):
row = [self.time[i], 'nan', self.water_lvl[i]]
else:
row = [self.time[i], self.hrecess[i], self.water_lvl[i]]
ws.write_row(i+13, 0, row)

print('MRC info saved sucessfully to file.')
if savefilename:
QApplication.setOverrideCursor(Qt.WaitCursor)
QApplication.processEvents()
try:
self.wldset.save_mrc_tofile(savefilename)
except PermissionError:
self.show_permission_error()
self.save_mrc_tofile(savefilename)
QApplication.restoreOverrideCursor()

def btn_mrc2rechg_isClicked(self):
if not self.A and not self.B:
Expand Down Expand Up @@ -1019,7 +984,7 @@ def display_soil_layer(self):
try:
self.soilColor[i] = reader[i][3]
print(reader[i][3])
except:
except Exception:
self.soilColor[i] = '#FFFFFF'

print(self.soilColor)
Expand All @@ -1043,7 +1008,7 @@ def display_soil_layer(self):
try:
self.layers[i] = self.ax0.fill_between(
[0, 99999], up, down, color=self.soilColor[i], zorder=0)
except:
except Exception:
self.layers[i] = self.ax0.fill_between(
[0, 99999], up, down, color='#FFFFFF', zorder=0)

Expand Down Expand Up @@ -1884,7 +1849,7 @@ def load_info(self, filename):
self.Sy[i] = reader[i][2]
try:
self.color[i] = reader[i][3]
except:
except Exception:
self.color[i] = '#FFFFFF'


Expand Down
2 changes: 1 addition & 1 deletion gwhat/common/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
'undo': 'undo',
'clear_search': 'clear-search',
'home': 'home',
'MRCalc': 'MRCalc',
'mrc_calc': 'MRCalc',
'edit': 'edit',
'pan': 'pan',
'add_point': 'add_point',
Expand Down
7 changes: 1 addition & 6 deletions gwhat/gwrecharge/gwrecharge_calc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

# ---- Imports: local

from gwhat.utils.math import clip_time_series
from gwhat.utils.math import clip_time_series, calcul_rmse
from gwhat.gwrecharge.glue import GLUEDataFrame
from gwhat.gwrecharge.gwrecharge_calculs import (calcul_surf_water_budget,
calc_hydrograph_forward)
Expand Down Expand Up @@ -520,11 +520,6 @@ def strdate_to_datetime(strdates):
for s in strdates]


def calcul_rmse(Xobs, Xpre):
"""Compute the root-mean square error."""
return (np.mean((Xobs - Xpre)**2))**0.5


def calcul_nash_sutcliffe(Xobs, Xpre):
"""
Compute the Nash–Sutcliffe model efficiency coefficient.
Expand Down
37 changes: 23 additions & 14 deletions gwhat/gwrecharge/gwrecharge_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# Licensed under the terms of the GNU General Public License.

import time
import os.path as osp

# ---- Imports: third parties

Expand Down Expand Up @@ -345,37 +346,45 @@ def setup_menu(self):
# ---- Export data

@QSlot()
def save_water_budget_tofile(self):
def save_water_budget_tofile(self, savefilename=None):
"""
Prompt a dialog to select a file and save the GLUE water budget.
"""
fname = self.select_savefilename("Save GLUE water budget",
"glue_water_budget.xlsx",
"*.xlsx;;*.xls;;*.csv")
if fname:
if savefilename is None:
savefilename = osp.join(self.dialog_dir, "glue_water_budget.xlsx")

savefilename = self.select_savefilename(
"Save GLUE water budget", savefilename, "*.xlsx;;*.xls;;*.csv")

if savefilename:
QApplication.setOverrideCursor(Qt.WaitCursor)
QApplication.processEvents()
try:
self.model.save_mly_glue_budget_to_file(fname)
self.model.save_mly_glue_budget_to_file(savefilename)
except PermissionError:
self.show_permission_error()
self.save_water_budget_tofile()
self.save_water_budget_tofile(savefilename)
QApplication.restoreOverrideCursor()

@QSlot()
def save_water_levels_tofile(self):
def save_water_levels_tofile(self, savefilename=None):
"""
Prompt a dialog to select a file and save the GLUE water levels.
"""
fname = self.select_savefilename("Save GLUE water levels",
"glue_water_levels.xlsx",
"*.xlsx;;*.xls;;*.csv")
if fname:
if savefilename is None:
savefilename = osp.join(self.dialog_dir, "glue_water_levels.xlsx")

savefilename = self.select_savefilename(
"Save GLUE water levels", savefilename, "*.xlsx;;*.xls;;*.csv")

if savefilename:
QApplication.setOverrideCursor(Qt.WaitCursor)
QApplication.processEvents()
try:
self.model.save_glue_waterlvl_to_file(fname)
self.model.save_glue_waterlvl_to_file(savefilename)
except PermissionError:
self.show_permission_error()
self.save_water_levels_tofile()
self.save_water_levels_tofile(savefilename)
QApplication.restoreOverrideCursor()


Expand Down
21 changes: 12 additions & 9 deletions gwhat/meteo/weather_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,24 +909,27 @@ def setup_menu(self):
# ---- Export Time Series

@QSlot(str)
def select_export_file(self, time_frame):
def select_export_file(self, time_frame, savefilename=None):
"""
Prompt a dialog to select a file and save the weather data time series
to a file in the specified format and time frame.
"""
fname = self.select_savefilename(
'Export %s' % time_frame,
'Weather%s_%s' % (time_frame.capitalize(),
self.model['Station Name']),
'*.xlsx;;*.xls;;*.csv')
if savefilename is None:
savefilename = osp.join(
self.dialog_dir, 'Weather%s_%s' % (time_frame.capitalize(),
self.model['Station Name']))

if fname:
savefilename = self.select_savefilename(
'Export %s' % time_frame, savefilename, '*.xlsx;;*.xls;;*.csv')

if savefilename:
QApplication.setOverrideCursor(Qt.WaitCursor)
QApplication.processEvents()
try:
self.model.export_dataset_to_file(fname, time_frame)
self.model.export_dataset_to_file(savefilename, time_frame)
except PermissionError:
self.show_permission_error()
self.select_export_file(time_frame)
self.select_export_file(time_frame, savefilename)
QApplication.restoreOverrideCursor()


Expand Down
3 changes: 3 additions & 0 deletions gwhat/projet/manager_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class DataManager(QWidget):

wldsetChanged = QSignal(object)
wxdsetChanged = QSignal(object)
sig_workdir_changed = QSignal(str)

def __init__(self, parent=None, projet=None, pm=None, pytesting=False):
super(DataManager, self).__init__(parent)
Expand Down Expand Up @@ -196,6 +197,8 @@ def set_projet(self, projet):
self.new_waterlvl_win.set_projet(projet)
self.new_weather_win.set_projet(projet)

self.sig_workdir_changed.emit(self.workdir)

# ---- Utilities

def emit_warning(self, msg):
Expand Down
Loading

0 comments on commit f50bb4b

Please sign in to comment.