diff --git a/sohstationviewer/database/backup.db b/sohstationviewer/database/backup.db index 447465deda3a5235ae82ac548165fdf20e297b0a..7fbabac8c3b481ad2f1e54cf36c0d9f66d788785 100755 Binary files a/sohstationviewer/database/backup.db and b/sohstationviewer/database/backup.db differ diff --git a/sohstationviewer/database/soh.db b/sohstationviewer/database/soh.db index 447465deda3a5235ae82ac548165fdf20e297b0a..7fbabac8c3b481ad2f1e54cf36c0d9f66d788785 100755 Binary files a/sohstationviewer/database/soh.db and b/sohstationviewer/database/soh.db differ diff --git a/sohstationviewer/model/reftek_data/reftek.py b/sohstationviewer/model/reftek_data/reftek.py index 561f24f54ed788baadb8cb8d255b43078cd4fc11..6872092894b7a94f1476d6a3b4529f446ed5f64e 100755 --- a/sohstationviewer/model/reftek_data/reftek.py +++ b/sohstationviewer/model/reftek_data/reftek.py @@ -269,7 +269,11 @@ class RT130(GeneralData): def read_file(self, path2file: Path, file_name: str, count: int, total: int) -> None: """ - Read data or text from file + Read data or text from file. + Skip reading data if data belong to data stream that isn't requested. + Data stream can be detected based on folder structure: + [YYYYDOY]/[das_serial_number]/[data_stream]/[filename] + :param path2file: absolute path to file :param file_name: name of file :param count: total number of file read @@ -282,6 +286,14 @@ class RT130(GeneralData): if log_text is not None: self.log_texts['TEXT'].append(log_text) return + if self.req_data_streams != ['*']: + # filter non selected data stream + ds = path2file.parts[-2] + if ds in ['1', '2', '3', '4', '5', '6', '7', '8']: + # Check if folder name match format of data stream's folder + if int(ds) not in self.req_data_streams: + # Check if data stream is required + return self.read_reftek_130(path2file) def select_data_set_id(self) -> Tuple[str, str]: diff --git a/sohstationviewer/view/channel_prefer_dialog.py b/sohstationviewer/view/channel_prefer_dialog.py index f57203ddde79eba0396dff6de427709bb7023ab1..bcfa1f486787f999a0867ec3bd26c4696487e9bf 100755 --- a/sohstationviewer/view/channel_prefer_dialog.py +++ b/sohstationviewer/view/channel_prefer_dialog.py @@ -335,7 +335,7 @@ class ChannelPreferDialog(OneWindowAtATimeDialog): self.soh_list_table_widget.item( count, COL['preferredSOHs']).setText(r['preferredSOHs']) - if r['default'] == 1: + if r['isDefault'] == 1: self.set_default_row(count) if r['current'] == 1: @@ -508,9 +508,13 @@ class ChannelPreferDialog(OneWindowAtATimeDialog): """ selected_row_idx = self.soh_list_table_widget.indexFromItem( self.soh_list_item + ).row() + row_edit_button = self.soh_list_table_widget.cellWidget( + selected_row_idx, COL['edit'] ) - # Hardcoding the check for default row because there is no time. - if selected_row_idx.row() < 4: + is_default_row = not row_edit_button.isEnabled() + + if is_default_row: err_msg = ('The selected row is a default row and cannot be ' 'overwritten. Please select a non-default row and try ' 'again.') @@ -732,6 +736,12 @@ class ChannelPreferDialog(OneWindowAtATimeDialog): row_idx, COL['dataType']).currentText() preferred_sohs = self.soh_list_table_widget.item( row_idx, COL['preferredSOHs']).text() + row_edit_button = self.soh_list_table_widget.cellWidget( + row_idx, COL['edit'] + ) + # The edit button is only disabled for default rows, so we can use its + # state to determine if a row is a default row. + is_default_row = not row_edit_button.isEnabled() if preferred_sohs.strip() == '' and name.strip() == '': return '', '', '' display_id = row_idx + 1 @@ -749,8 +759,10 @@ class ChannelPreferDialog(OneWindowAtATimeDialog): QtWidgets.QMessageBox.information(self, "Missing info", msg) return sql = (f"INSERT INTO ChannelPrefer (name, preferredSOHs, dataType, " - f"current) VALUES " - f"('{name}', '{preferred_sohs}', '{data_type}', {current})") + f"current, isDefault) VALUES " + f"('{name}', '{preferred_sohs}', '{data_type}', {current}, " + f"{is_default_row})") + print(sql) primary_key = name return primary_key, str(display_id), sql diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py index f55f0ec0ea64eb08c25911df81fc00418602c6bd..be74287e69bfae1b489ee371a310b6884fedd71e 100755 --- a/sohstationviewer/view/main_window.py +++ b/sohstationviewer/view/main_window.py @@ -1057,7 +1057,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): self.is_stopping = False try: if len(self.data_object.data_set_ids) > 1: - self.plot_diff_data_set_id.setEnabled(True) + self.plot_diff_data_set_id_button.setEnabled(True) except AttributeError: pass diff --git a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py index dfca93e2e5efe10e0585bc034d0bd38c3ef02bf7..19d5b5bd9a42aabc1e8082113666a5aa75e29eb4 100644 --- a/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py +++ b/sohstationviewer/view/plotting/plotting_widget/plotting_widget.py @@ -346,13 +346,17 @@ class PlottingWidget(QtWidgets.QScrollArea): :param xdata: float - time value in plot """ - if self.new_min_x == xdata: + self.zoom_marker1.set_visible(False) + self.zoom_marker2.set_visible(False) + if abs(self.new_min_x - xdata) < 0.001: + # to prevent weird zoom in + display_tracking_info( + self.tracking_box, "Selected range is too small to zoom in.") + self.plotting_axes.canvas.draw() return self.zoom_marker1_shown = False [self.min_x, self.max_x] = sorted([self.new_min_x, xdata]) self.set_lim() - self.zoom_marker1.set_visible(False) - self.zoom_marker2.set_visible(False) self.plotting_axes.canvas.draw() def zoom_out(self): diff --git a/sohstationviewer/view/plotting/time_power_square/time_power_squared_helper.py b/sohstationviewer/view/plotting/time_power_square/time_power_squared_helper.py index 9263e501b2e6f56ce77b12e9305f109b12d45920..6e68caa3febe381d5a0bca192b56519b0c3f716d 100644 --- a/sohstationviewer/view/plotting/time_power_square/time_power_squared_helper.py +++ b/sohstationviewer/view/plotting/time_power_square/time_power_squared_helper.py @@ -109,9 +109,10 @@ def get_tps_for_discontinuous_data( mean_squares = np.zeros_like(start_5min_blocks, dtype=float) # Calculate mean_square for each 5m block + # adding dtype=float64 to prevent integer overflow for i, d in enumerate(split_data): if len(d) != 0: - mean_squares[i] = np.mean(np.square(d)) + mean_squares[i] = np.mean(np.square(d, dtype='float64')) elif ((0 < i < len(split_data) - 1) and len(split_data[i - 1]) > 0 and len(split_data[i + 1]) > 0): """ @@ -119,7 +120,8 @@ def get_tps_for_discontinuous_data( data in the previous and next blocks if they both have data. """ mean_squares[i] = np.mean(np.square( - np.hstack((split_data[i - 1], split_data[i + 1])) + np.hstack((split_data[i - 1], split_data[i + 1])), + dtype='float64' )) # reshape 1D mean_quares into 2D array in which each row contains 288 of # 5m blocks' mean_squares of a day diff --git a/tests/view/plotting/test_time_power_square_helper.py b/tests/view/plotting/test_time_power_square_helper.py index c33e93129c1eeedca6c4f3d56cf2b2b84a77f42f..83981cd4c22fb3764999e3654a1f2141fbe46ee2 100644 --- a/tests/view/plotting/test_time_power_square_helper.py +++ b/tests/view/plotting/test_time_power_square_helper.py @@ -156,6 +156,19 @@ class TestGetTPSForDiscontinuousData(BaseTestCase): # last block of day0 has value self.assertIn(const.NUMBER_OF_5M_IN_DAY - 1, day0_indexes) + def test_overflow_data(self): + times = np.arange(self.start, self.end, 9*60) # 9m apart + # This data reproduce overflow data + data = np.random.randint(-10**6, 0, times.size, dtype='i4') + channel_data = {'tracesInfo': [{'times': times, 'data': data}]} + tps = get_tps_for_discontinuous_data( + channel_data, self.start_5mins_blocks) + self.assertEqual(len(tps), 2) + # Before adding dtype in np.square in get_tps_for_discontinuous_data, + # some tps data would be less than 0 + lessthanzero_indexes = np.where(tps[0] < 0)[0] + self.assertEqual(lessthanzero_indexes.size, 0) + class TestGetTPSTimeByColorForADay(BaseTestCase): def setUp(self):