From 2833a438036a170a4ceb43d905837aada50c50e7 Mon Sep 17 00:00:00 2001 From: Lan Dam <ldam@passcal.nmt.edu> Date: Mon, 24 Apr 2023 07:27:01 -0600 Subject: [PATCH] I86 bug click point --- sohstationviewer/database/soh.db | Bin 61440 -> 61440 bytes .../view/plotting/plotting_widget/plotting.py | 12 +++-- .../plotting_widget/plotting_widget.py | 40 ++++++++++----- .../search_message/search_message_dialog.py | 6 ++- sohstationviewer/view/util/functions.py | 33 ++++++++++++ tests/test_view/test_util_functions.py | 48 +++++++++++++++++- 6 files changed, 118 insertions(+), 21 deletions(-) diff --git a/sohstationviewer/database/soh.db b/sohstationviewer/database/soh.db index 0acbb88d0804d0404f79192aa7ea5726900c54da..e522c9a9679a98018fb101a42bf3aa1165335ffe 100755 GIT binary patch delta 200 zcmZp8z})bFd4e?K%84@0tScGxyeBS9iPtx<)X%9X$~LdE$TK%HjW0~gOUp1SEHX_u zwlDyK^g{g*{gT{*$`s>@)H1XD&6DHv5_lOH7<`#H8Tc>oZ{(janeV`qjT6%uH*+3p z=T($v<`ia7XW-=L6!#6V_f0G=Rw&3X&Me8y&npWGF*G*VyzzX102{~zuC0^V9|W@S wpXFnj9P_|!v!Z}7*XH$A{7joYdb}7n^S#^8$j8efEY1it2&|QP^6mGk0CP@1p8x;= delta 254 zcmZp8z})bFd4e?KzKJr<tos=B;-wd+#OtS<>Zg@iW*HbKr5I%unwq7X6y;S~8W$L+ zWf%ZKdZB)Zeo1bDX-Z|KL3(c4=E?DS3B3Fh7<?HYGw@&F-^loQGT(tIO#I6>PPAuK zQ(@+mWl(3}<mVLkO)M@B$S<}B(Fz6m#hE3U`FUkQA%?~Vn>i1)^C~hhFet**2EdhZ z`f&m!z+m&n^8o^E{AU?_xfV@ke-OyR#{y);JaAjQ-~ktp5R0rhBh-@3E2_kpHhc7V dF>dC2x1W&@sGX0|H^82ig@J+5Z}RQ;ssN6AOnd+U diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting.py b/sohstationviewer/view/plotting/plotting_widget/plotting.py index ad32f12be..13ac3e189 100644 --- a/sohstationviewer/view/plotting/plotting_widget/plotting.py +++ b/sohstationviewer/view/plotting/plotting_widget/plotting.py @@ -80,6 +80,7 @@ class Plotting: if c == '_': prev_val = val continue + points = [] for times, data in zip(c_data['times'], c_data['data']): if v.startswith('+'): points = [times[i] @@ -258,7 +259,6 @@ class Plotting: for cStr in color_parts: obj, c = cStr.split(':') colors[obj] = c - l_color = 'G' has_dot = False if 'L' in colors: @@ -266,12 +266,15 @@ class Plotting: if 'D' in colors: d_color = colors['D'] has_dot = True - for x, y in zip(x_list, y_list): if not has_dot: - ax.myPlot = ax.plot(x, y, + # set marker to be able to click point for info + # but marker's size is small to not show dot. + ax.myPlot = ax.plot(x, y, marker='o', markersize=0.01, linestyle='-', linewidth=0.7, - color=clr[l_color]) + zorder=constants.Z_ORDER['LINE'], + color=clr[l_color], + picker=True, pickradius=2) else: ax.myPlot = ax.plot(x, y, marker='s', markersize=1.5, linestyle='-', linewidth=0.7, @@ -280,6 +283,7 @@ class Plotting: mfc=clr[d_color], mec=clr[d_color], picker=True, pickradius=3) + if linked_ax is None: ax.x_list = x_list ax.y_list = y_list diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py index e009e7de9..d7d1519ca 100755 --- a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py +++ b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py @@ -2,14 +2,15 @@ Class of which object is used to plot data """ from typing import List -import numpy as np from PySide2.QtCore import QTimer from matplotlib import pyplot as pl from PySide2 import QtCore, QtWidgets from sohstationviewer.conf import constants from sohstationviewer.view.util.color import set_color_mode -from sohstationviewer.view.util.functions import get_total_miny_maxy +from sohstationviewer.view.util.functions import ( + get_total_miny_maxy, get_index_from_time +) from sohstationviewer.view.plotting.plotting_widget.plotting_axes import ( PlottingAxes) from sohstationviewer.view.plotting.plotting_widget.plotting import Plotting @@ -279,18 +280,24 @@ class PlottingWidget(QtWidgets.QScrollArea): chan_data = self.plotting_data1[chan_id] # list of x values of the plot x_list = artist.get_xdata() + # list of y values of the plot + y_list = artist.get_ydata() + # index of the clicked point on the plot click_plot_index = event.ind[0] - # time value of the clicked point + + # time, val of the clicked point clicked_time = x_list[click_plot_index] - # indexes of the clicked time in data (one value only) - clicked_indexes = np.where(chan_data['times'] == clicked_time) - """ - clicked_indexes and click_plot_index can be different if there - are different plots for a channel. - """ - clicked_data = chan_data['data'][clicked_indexes][0] + clicked_val = y_list[click_plot_index] + + list_idx, section_idx = get_index_from_time( + chan_data, clicked_time, clicked_val) + if list_idx is None: + display_tracking_info(self.tracking_box, "Point not found.") + return + + clicked_data = chan_data['data'][list_idx][section_idx] if hasattr(ax, 'unit_bw'): clicked_data = ax.unit_bw.format(clicked_data) formatted_clicked_time = format_time( @@ -300,12 +307,17 @@ class PlottingWidget(QtWidgets.QScrollArea): f"Time: {formatted_clicked_time} " f"Value: {clicked_data}</pre>") display_tracking_info(self.tracking_box, info_str) - if 'logIdx' in chan_data.keys(): + # For Reftek, need to hightlight the corresponding + # SOH message line based on the log_idx of the clicked point self.parent.search_message_dialog.show() - clicked_log_idx = chan_data['logIdx'][clicked_indexes][0] - self.parent.search_message_dialog. \ - show_log_entry_from_data_index(clicked_log_idx) + clicked_log_idx = chan_data['logIdx'][0][section_idx] + try: + self.parent.search_message_dialog. \ + show_log_entry_from_data_index(clicked_log_idx) + except ValueError as e: + QtWidgets.QMessageBox.warning(self, "Not found", + str(e)) def on_button_press_event(self, event): """ diff --git a/sohstationviewer/view/search_message/search_message_dialog.py b/sohstationviewer/view/search_message/search_message_dialog.py index de0eaaa56..56b4b2355 100644 --- a/sohstationviewer/view/search_message/search_message_dialog.py +++ b/sohstationviewer/view/search_message/search_message_dialog.py @@ -299,7 +299,9 @@ class SearchMessageDialog(QtWidgets.QWidget): count = 0 for log_line in self.soh_dict[chan_id]: self.add_line( - self.soh_tables_dict[chan_id], text1=count, text2=log_line) + self.soh_tables_dict[chan_id], + text1=str(count), + text2=log_line) count += 1 def add_nav_button(self, nav: QtWidgets.QToolBar, @@ -510,7 +512,7 @@ class SearchMessageDialog(QtWidgets.QWidget): self.search_rowidx = 0 ret = self.search(col=0, start_search=True) if ret is None: - raise ValueError(f'Not found line: ({data_index})') + raise ValueError(f'Not found line: {data_index}') it, r = ret self.on_log_entry_clicked(it) self._show_log_message(it) diff --git a/sohstationviewer/view/util/functions.py b/sohstationviewer/view/util/functions.py index 316fda615..50332b76d 100644 --- a/sohstationviewer/view/util/functions.py +++ b/sohstationviewer/view/util/functions.py @@ -292,5 +292,38 @@ def extract_netcodes(data_obj): return '\n\t'.join(net_info_list) +def get_index_from_time(chan_data: List[np.ndarray], tm: float, val: float) \ + -> Tuple[int, int]: + """ + Get index of tm in chan_data['time'] which is a list of np.ndarray + :param chan_data: dict of data to plot that includes 'times' key + :param tm: epoch time of a clicked point + :param val: data value of a clicked point + :return list_idx: index of the np.ndarray in the list + :return section_idx: index of tm inside np.ndarray found + """ + list_idx = None + section_idx = None + for i in range(len(chan_data['times'])): + section_indexes = np.where(chan_data['times'][i] == tm)[0] + if len(section_indexes) != 0: + if (chan_data['chan_db_info']['plotType'] not in + ['linesDots', 'linesSRate']): + # don't check val because the plotting value of some plot + # is for displaying only, not actual value. And this type + # of data isn't under the effect of overlap. + section_idx = section_indexes[0] + list_idx = i + break + else: + # to prevent 2 values with the same times in case of overlap + for j in section_indexes: + if chan_data['data'][i][j] == val: + list_idx = i + section_idx = j + break + return list_idx, section_idx + + if __name__ == '__main__': create_table_of_content_file(Path('../../../documentation')) diff --git a/tests/test_view/test_util_functions.py b/tests/test_view/test_util_functions.py index b501a4ef4..bc59a4123 100644 --- a/tests/test_view/test_util_functions.py +++ b/tests/test_view/test_util_functions.py @@ -9,7 +9,7 @@ from sohstationviewer.view.util.functions import ( get_soh_messages_for_view, log_str, is_doc_file, create_search_results_file, create_table_of_content_file, check_chan_wildcards_format, check_masspos, get_total_miny_maxy, - extract_netcodes + extract_netcodes, get_index_from_time ) from sohstationviewer.view.util.enums import LogType @@ -455,3 +455,49 @@ class TestExtractNetcodes(TestCase): data_obj = MockObj({'3734': {'XX', 'NA'}}) ret = extract_netcodes(data_obj) self.assertEqual(ret, "NA,XX") + + +class TestGetIndexFromTime(TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.plotting_data = { + 'CH1': { + 'times': [np.array([1, 2, 3]), np.array([4, 5, 6])], + 'data': [np.array([6, 9, 7]), np.array([4, 3, 9])], + 'chan_db_info': {'plotType': 'upDownDots'} + }, + 'CH2': { + 'times': [np.array([1, 2, 3]), np.array([3, 5, 6])], + 'data': [np.array([6, 9, 7]), np.array([4, 3, 9])], + 'chan_db_info': {'plotType': 'linesDots'} + } + } + + def test_time_not_included(self): + list_idx, section_idx = get_index_from_time( + self.plotting_data['CH1'], 7, 6) + self.assertIsNone(list_idx) + + def test_type_not_need_data_info(self): + # CH1 has plotType='upDownDots' not in ['linesDots', 'linesSRate'] + list_idx, section_idx = get_index_from_time( + self.plotting_data['CH1'], 4, 4) + self.assertEqual(list_idx, 1) + self.assertEqual(section_idx, 0) + + def test_type_need_data_info(self): + # CH2 has plotType='linesDots in ['linesDots', 'linesSRate'] + with self.subTest('data not match time'): + list_idx, section_idx = get_index_from_time( + self.plotting_data['CH2'], 3, 5) + self.assertIsNone(list_idx) + with self.subTest('data match 1st value'): + list_idx, section_idx = get_index_from_time( + self.plotting_data['CH2'], 3, 7) + self.assertEqual(list_idx, 0) + self.assertEqual(section_idx, 2) + with self.subTest('data match 2nd value'): + list_idx, section_idx = get_index_from_time( + self.plotting_data['CH2'], 3, 4) + self.assertEqual(list_idx, 1) + self.assertEqual(section_idx, 0) -- GitLab