From dd1acda812c8a4bb7ce82b040d949334b3f3f3c9 Mon Sep 17 00:00:00 2001 From: Olivier Jossoud <olivier.jossoud@lsce.ipsl.fr> Date: Tue, 15 Oct 2019 11:28:40 +0200 Subject: [PATCH] Explo. Visibility, string variables, vline when moving => OK --- pyqt/mainwindow.ui | 2 +- src/dataprovider/exploprovider.py | 5 ++ src/gui/uimainwindow.py | 2 +- src/uim/explouim.py | 76 +++++++++++++++++++++++-------- src/utils.py | 6 ++- 5 files changed, 70 insertions(+), 21 deletions(-) diff --git a/pyqt/mainwindow.ui b/pyqt/mainwindow.ui index 4122394..e084e4a 100644 --- a/pyqt/mainwindow.ui +++ b/pyqt/mainwindow.ui @@ -36,7 +36,7 @@ <x>20</x> <y>260</y> <width>1021</width> - <height>441</height> + <height>651</height> </rect> </property> </widget> diff --git a/src/dataprovider/exploprovider.py b/src/dataprovider/exploprovider.py index 0dec51d..35387b4 100644 --- a/src/dataprovider/exploprovider.py +++ b/src/dataprovider/exploprovider.py @@ -127,6 +127,11 @@ class InstrumentInstantLog(InstrumentLog): def get_timeseries(self, variable: str) -> pd.DataFrame: timeseries_df = self.df[self.df["name"] == variable] timeseries_df = timeseries_df.drop(columns=['name']) + + try: + timeseries_df["value"] = timeseries_df["value"].astype(float) + except ValueError: + timeseries_df["value_int"] = timeseries_df["value"].astype("category").cat.codes return timeseries_df diff --git a/src/gui/uimainwindow.py b/src/gui/uimainwindow.py index 7b0c14e..2544676 100644 --- a/src/gui/uimainwindow.py +++ b/src/gui/uimainwindow.py @@ -20,7 +20,7 @@ class Ui_MainWindow(object): self.tab_explo = QtWidgets.QWidget() self.tab_explo.setObjectName("tab_explo") self.explo_graphicsview_top = PlotWidget(self.tab_explo) - self.explo_graphicsview_top.setGeometry(QtCore.QRect(20, 260, 1021, 441)) + self.explo_graphicsview_top.setGeometry(QtCore.QRect(20, 260, 1021, 651)) self.explo_graphicsview_top.setObjectName("explo_graphicsview_top") self.explo_tablewidget_variables = QtWidgets.QTableWidget(self.tab_explo) self.explo_tablewidget_variables.setGeometry(QtCore.QRect(20, 50, 1021, 201)) diff --git a/src/uim/explouim.py b/src/uim/explouim.py index ad8b48a..dc0df4f 100644 --- a/src/uim/explouim.py +++ b/src/uim/explouim.py @@ -4,6 +4,7 @@ from PyQt5.QtWidgets import * from PyQt5.QtGui import QColor from PyQt5.QtCore import * import pandas as pd +from pandas.api.types import is_numeric_dtype import numpy as np from pyqtgraph.GraphicsScene.mouseEvents import MouseClickEvent @@ -155,13 +156,17 @@ class ExploUim: visible_item = QCheckBox() visible_item.setChecked(True) table.setCellWidget(row_id, self.VISIBLE_COL, visible_item) + table.cellWidget(row_id, self.VISIBLE_COL).stateChanged.connect( + lambda state, row_id=row_id: self.__apply_variable_change__(row_id=row_id)) # X original xorig_item = QTableWidgetItem() + xorig_item.setFlags(Qt.ItemIsEnabled) # Read only table.setItem(row_id, self.XORIG_COL, xorig_item) # Y original yorig_item = QTableWidgetItem() + yorig_item.setFlags(Qt.ItemIsEnabled) # Read only table.setItem(row_id, self.YORIG_COL, yorig_item) self.__update_instruments_combobox__(row_id) @@ -237,11 +242,13 @@ class ExploUim: mult = table.cellWidget(row_id, self.MULT_COL).value() timeshift = table.cellWidget(row_id, self.TIMESHIFT_COL).value() + # Get variable visibility + visible = table.cellWidget(row_id, self.VISIBLE_COL).isChecked() try: - self.__update_plot__(timeseries, row_id, color, offset, mult, timeshift) + self.__update_plot__(timeseries, row_id, color, offset, mult, timeshift, visible) except TypeError: - print("Cannot plot that.") + self.main_ui.statusbar.showMessage("Failed to plot [" + variable_name + "]", msecs=3000) def __update_xy_original__(self, instant: datetime.datetime): table = self.main_ui.explo_tablewidget_variables @@ -253,7 +260,11 @@ class ExploUim: # Get Y orig (original non-shifted variable value) df = self.__get_row_dataframe__(row_id).copy() - y_orig = df[df["datetime"] <= instant].iloc[-1]["value"] + df = df[df["datetime"] <= instant] + if len(df.index) == 0: + y_orig = "Out of range" + else: + y_orig = df.iloc[-1]["value"] if isinstance(y_orig, float): y_orig = "{:.4f}".format(y_orig) table.item(row_id, self.YORIG_COL).setText(y_orig) @@ -272,26 +283,33 @@ class ExploUim: self.lines_items = [] # Vertical line following the cursor - self.cursor_vline = pg.InfiniteLine(angle=90, movable=False) + self.cursor_vline = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen(style=Qt.DotLine)) self.plot_item.addItem(self.cursor_vline, ignoreBounds=True) + self.measure_vline = pg.InfiniteLine(angle=90, movable=False) + self.plot_item.addItem(self.measure_vline, ignoreBounds=True) + def __update_plot__(self, timeseries: pd.DataFrame, row_id: int, color: QColor, - offset: float, mult: float, timeshift_sec: float) -> None: - try: - timeseries["value"] = timeseries["value"].astype(float) - except ValueError: - print("Value is not convertible to float") - return + offset: float, mult: float, timeshift_sec: float, + visible: bool) -> None: # Get the to-be-modified curve if row_id in self.step_curves: step_curve = self.step_curves[row_id] else: step_curve = pg.PlotCurveItem() + self.step_curves[row_id] = step_curve self.plot_item.addItem(step_curve) step_curve.scene().sigMouseClicked.connect(lambda event: self.__mouse_clicked__(event)) - self.step_curves[row_id] = step_curve + step_curve.scene().sigMouseMoved.connect(lambda event: self.__mouse_moved__(event)) + # Set curve visibility + if not visible: + step_curve.hide() + else: + step_curve.show() + + # --- X values --- # As it is a _step_ curve, add a last datetime point to determine the end of the last step. This is the datatime # of the last available data of the dataset, plus one second. last_datetime = self.current_dataset.last_data_datetime + datetime.timedelta(seconds=1) @@ -301,7 +319,12 @@ class ExploUim: # Apply time shift x_values = x_values + datetime.timedelta(seconds=timeshift_sec) - y_values = list(timeseries["value"]) + # --- Y values --- + # Get original value if it is a numeric, otherwise get its coded integer version. + if is_numeric_dtype(timeseries["value"]): + y_values = list(timeseries["value"]) + else: + y_values = list(timeseries["value_int"]) # Apply multiplicative factor y_values = [y * mult for y in y_values] @@ -315,11 +338,28 @@ class ExploUim: pen=color, stepMode=True) - def __mouse_clicked__(self, event: MouseClickEvent): + def __mouse_clicked__(self, event: MouseClickEvent) -> None: + """Function triggered when the user clicks on the plot. Display a vertical line under the mouse click and call + function ``__update_xy_original__`` + + Parameters + ---------- + event: pyqtgraph.MouseClickEvent + """ pos = event.scenePos() - mousePoint = self.step_curves[0].getViewBox().mapSceneToView(pos) - instant = datetime.datetime.fromtimestamp(mousePoint.x(), tz=datetime.timezone.utc) - # instant = datetime.datetime.fromtimestamp(mousePoint.x()) + mouse_point = self.step_curves[0].getViewBox().mapSceneToView(pos) + instant = datetime.datetime.fromtimestamp(mouse_point.x(), tz=datetime.timezone.utc) + self.measure_vline.setPos(mouse_point.x()) self.__update_xy_original__(instant) - self.cursor_vline.setPos(mousePoint.x()) - # print("x="+instant.strftime("%H:%M:%S")) + + def __mouse_moved__(self, pos: QPointF) -> None: + """Function triggered when the user's mouse cursor hovers over the plot. Display a vertical line where the + cursor is. + + Parameters + ---------- + pos: PyQt5.QtCore.QPointF + """ + # if self.step_curves[0].sceneBoundingRect().contains(pos): + mouse_point = self.step_curves[0].getViewBox().mapSceneToView(pos) + self.cursor_vline.setPos(mouse_point.x()) \ No newline at end of file diff --git a/src/utils.py b/src/utils.py index ba5d688..fda5742 100644 --- a/src/utils.py +++ b/src/utils.py @@ -36,7 +36,11 @@ class TimeAxisItem(pg.AxisItem): self.enableAutoSIPrefix(False) def tickStrings(self, values, scale, spacing): - return [datetime.datetime.fromtimestamp(value, tz=datetime.timezone.utc).strftime("%H:%M:%S") for value in values] + try: + tick_strings = [datetime.datetime.fromtimestamp(value, tz=datetime.timezone.utc).strftime("%H:%M:%S") for value in values] + except ValueError: + tick_strings = ["ERROR" for value in values] + return tick_strings def highlight_row(table: QTableWidget, highlighted_row_id: int, -- GitLab