Measurements2Use.py 12.48 KiB
"""
QRame
Copyright (C) 2023  INRAE

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
"""
import copy
from datetime import datetime
import numpy as np
import pandas as pd
from PyQt5 import QtWidgets, QtCore, QtGui
import wMeasurements2Use
from Controller.common_functions import scientific_notation

class Measurements2Use(QtWidgets.QDialog, wMeasurements2Use.Ui_Measurements2Use):
    """Dialog to allow users to select and deselect transects to use in the discharge computation.

    Parameters
    ----------
    wTransects2Use.Ui_Transects2Use : QDialog
        Dialog window with options for users

    Attributes
    ----------
    _pressed_key: str
        Get the current pressed key button
    _selected_row: int
        Get index of the current selected row

    parent:
        Identifies parent GUI.
    previous_checked: list[str]
        List of previously checked measurements name
    current_checked: list[str]
        List of current checked measurements name
    """

    def __init__(self, parent=None):
        """Initialize dialog
        """
        super(Measurements2Use, self).__init__(parent)
        self.setupUi(self)
        self._pressed_key = None
        self._selected_row = 0

        self.parent = parent
        # self.all_meas_names = None
        self.previous_checked = list(parent.meas_checked)
        self.current_checked = copy.deepcopy(self.previous_checked)

        # Populate table
        self.summary_table()

        # # Setup connections for buttons
        self.pb_check_all.clicked.connect(self.check_all)
        self.pb_uncheck_invalid.clicked.connect(self.uncheck_invalid)
        self.tableSelect.cellClicked.connect(self.meas_table_clicked)

    def check_all(self):
        """Checks all measurements for use.
        """
        self.current_checked = list(self.parent.meas_name)
        self.summary_table()

    def uncheck_all(self):
        """Unchecks all measurements for user.
        """
        self.current_checked = []
        self.summary_table()

    def uncheck_invalid(self):
        """Unchecks all invalid measurements.
        """

        invalid_cochran = list(self.parent.mean_meas[self.parent.mean_meas['cochran_test'] == -1].index)
        invalid_grubbs = list(self.parent.mean_meas[self.parent.mean_meas['grubbs_test'] == -1].index)
        drop = invalid_cochran + list(set(invalid_grubbs) - set(invalid_cochran))

        for i in range(self.tableSelect.rowCount()):
            item_name = self.tableSelect.item(i, 0).text()
            if item_name in self.current_checked and item_name in drop:
                self.tableSelect.item(i, 0).setCheckState(QtCore.Qt.Unchecked)
                self.current_checked.remove(item_name)

    def summary_table(self):
        """Create and populate main summary table.
        """
        parent = self.parent
        translate = parent._translate
        tbl = self.tableSelect
        nrows = len(parent.meas_name)
        parent_index = parent.mean_meas.index
        raw_transects = pd.DataFrame()
        if parent.worker_extract is not None:
            raw_transects = parent.worker_extract.raw_transects_df

        if parent.results_import_df is not None:
            raw_transects = pd.concat([raw_transects, parent.results_import_df], ignore_index=True)

        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)

        mean_meas = raw_transects.groupby(by=['meas_name']).mean()
        for name in mean_meas.index:
            if name in parent.mean_meas.index:
                mean_meas.loc[name] = parent.mean_meas.loc[name]

        mean_meas[['start_time', 'end_time', 'navref_quality', 'water_quality']] = raw_transects.groupby(
            by='meas_name').agg({'start_time': 'min', 'end_time': 'max',
                                 'navref_quality': 'first',
                                 'water_quality': 'first'}
                                )

        summary_header = [translate("Main", 'Select Measurement'), translate("Main", 'Discharge'),
                          translate("Main", 'Cochran test'), translate("Main", 'Grubbs test'),
                          translate("Main", 'Nav. Quality'), translate("Main", 'Water Quality'),
                          translate("Main", 'Start time')]

        ncols = len(summary_header)

        tbl.setRowCount(nrows)
        tbl.setColumnCount(ncols)
        tbl.setHorizontalHeaderLabels(summary_header)
        tbl.verticalHeader().hide()

        header = tbl.horizontalHeader()
        # header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        for i in range(0, ncols):
            header.setSectionResizeMode(i, QtWidgets.QHeaderView.Interactive)

        # tbl.setEditTriggers(QtWidgets.QTableWidget.NoEditTriggers)
        for row in range(nrows):
            print(row)
            col = 0
            meas_id = parent.meas_name[row]
            checked = QtWidgets.QTableWidgetItem(meas_id)
            if meas_id in self.current_checked:
                checked.setCheckState(QtCore.Qt.Checked)
            else:
                checked.setCheckState(QtCore.Qt.Unchecked)
            checked.setFlags(QtCore.Qt.ItemIsEnabled)
            tbl.setItem(row, col, checked)
            tbl.item(row, col).setFont(font)

            # Discharge (color by score)
            col += 1
            value = mean_meas.iloc[row]['meas_mean_q']
            unit = parent.units['label_Q']
            tbl.setItem(row, col, QtWidgets.QTableWidgetItem(f'{scientific_notation(value, 3)} {unit}'))
            tbl.item(row, col).setFont(font)
            if meas_id in parent_index and \
                    parent.mean_meas.loc[meas_id]['score'] is not None:
                if parent.mean_meas.loc[meas_id]['score'] <= 2:
                    tbl.item(row, col).setBackground(QtGui.QColor(54, 237, 0))
                elif parent.mean_meas.loc[meas_id]['score'] <= 3:
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 204, 0))
                else:
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 0, 77))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

            # Cochran test
            col += 1
            if parent.intercomparison_process and meas_id in parent_index:

                if parent.mean_meas.loc[meas_id]['cochran_test'] == 1:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Valid')))
                    tbl.item(row, col).setBackground(QtGui.QColor(54, 237, 0))
                elif parent.mean_meas.loc[meas_id]['cochran_test'] == 0:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Isolated')))
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 204, 0))
                elif parent.mean_meas.loc[meas_id]['cochran_test'] == -1:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Invalid')))
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 0, 77))
                else:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            else:
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

            # Grubbs test
            col += 1
            if parent.intercomparison_process and meas_id in parent_index:
                if parent.mean_meas.loc[meas_id]['grubbs_test'] == 1:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Valid')))
                    tbl.item(row, col).setBackground(QtGui.QColor(54, 237, 0))
                elif parent.mean_meas.loc[meas_id]['grubbs_test'] == 0:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Isolated')))
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 204, 0))
                elif parent.mean_meas.loc[meas_id]['grubbs_test'] == -1:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Invalid')))
                    tbl.item(row, col).setBackground(QtGui.QColor(255, 0, 77))
                else:
                    tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            else:
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

            # Nav. Quality
            col += 1
            nav_quality = mean_meas.loc[meas_id]['navref_quality']
            if nav_quality == 'good':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Good')))
                tbl.item(row, col).setBackground(QtGui.QColor(54, 237, 0))
            elif nav_quality == 'caution':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Caution')))
                tbl.item(row, col).setBackground(QtGui.QColor(255, 204, 0))
            elif nav_quality == 'warning':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Warning')))
                tbl.item(row, col).setBackground(QtGui.QColor(255, 0, 77))
            else:
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

            # Water Quality
            col += 1
            water_quality = mean_meas.loc[meas_id]['water_quality']
            if water_quality == 'good':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Good')))
                tbl.item(row, col).setBackground(QtGui.QColor(54, 237, 0))
            elif water_quality == 'caution':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Caution')))
                tbl.item(row, col).setBackground(QtGui.QColor(255, 204, 0))
            elif water_quality == 'warning':
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'Warning')))
                tbl.item(row, col).setBackground(QtGui.QColor(255, 0, 77))
            else:
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(translate("Main", 'None')))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

            # Start time
            col += 1
            if not np.isnan(mean_meas.iloc[row]['start_time']):
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem(datetime.utcfromtimestamp(
                    mean_meas.iloc[row]['start_time']).strftime('%Y-%m-%d %H:%M')))
            else:
                tbl.setItem(row, col, QtWidgets.QTableWidgetItem('0000-00-00 00:00'))
            tbl.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled)

        tbl.setSortingEnabled(True)

    def keyPressEvent(self, event):
        self._pressed_key = event.key()

    def keyReleaseEvent(self, event):
        self._pressed_key = None

    @QtCore.pyqtSlot(int, int)
    def meas_table_clicked(self, row, column):
        """ Manages actions caused by the user clicking in selected columns
            of the table.

            Parameters
            ----------
            row: int
                row in table clicked by user
            column: int
                column in table clicked by user
        """
        tbl = self.tableSelect
        if column == 0:
            if self._pressed_key == 16777248:
                start = min(row, self._selected_row)
                end = max(row, self._selected_row) + 1
                if tbl.item(row, 0).checkState():
                    for id_row in range(start, end):
                        tbl.item(id_row, 0).setCheckState(QtCore.Qt.Unchecked)
                else:
                    for id_row in range(start, end):
                        tbl.item(id_row, 0).setCheckState(QtCore.Qt.Checked)
            else:
                if tbl.item(row, 0).checkState():
                    tbl.item(row, 0).setCheckState(QtCore.Qt.Unchecked)
                else:
                    tbl.item(row, 0).setCheckState(QtCore.Qt.Checked)

            self._selected_row = row