diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py deleted file mode 100755 index ebd19591d5cbde5e61ba41c7fe0cd2d180b06f87..0000000000000000000000000000000000000000 --- a/sohstationviewer/view/main_window.py +++ /dev/null @@ -1,379 +0,0 @@ -import pathlib -import os -from datetime import datetime -from copy import deepcopy -from PySide2 import QtCore, QtWidgets - -from sohstationviewer.view.ui.main_ui import UIMainWindow -from sohstationviewer.view.calendar_dialog import CalendarDialog -from sohstationviewer.view.core.file_list_widget import FileListItem -from sohstationviewer.controller.processing import loadData, detectDataType -from sohstationviewer.view.data_type_dialog import DataTypeDialog -from sohstationviewer.view.param_dialog import ParamDialog -from sohstationviewer.view.channel_dialog import ChannelDialog -from sohstationviewer.view.plot_type_dialog import PlotTypeDialog -from sohstationviewer.view.channel_prefer_dialog import ChannelPreferDialog -from sohstationviewer.database.proccessDB import executeDB_dict -from sohstationviewer.view.waveform_dialog import WaveformDialog -from sohstationviewer.view.time_power_squared_dialog import ( - TimePowerSquaredDialog) -from sohstationviewer.conf.constants import TM_FORMAT - - -class MainWindow(QtWidgets.QMainWindow, UIMainWindow): - - current_directory_changed = QtCore.Signal(str) - - def __init__(self, parent=None): - super().__init__(parent) - self.setup_ui(self) - """ - dir_names: [PosixPath,] - list of absolute path of data set directory - """ - self.dir_names = [] - """ - data_type: str - type of data set - """ - self.data_type = 'Unknown' - """ - req_soh_chans: [str,] - list of State-Of-Health channels to read data - from. For Reftek, the list of channels is fixed => may not need - """ - self.req_soh_chans = [] - """ - req_wf_chans: [str,] - list of waveform channels to read data from. - For Reftek, it is [int,] which is list of index of data stream - to read data from. - """ - self.req_wf_chans = [] - """ - start_tm: float - start time of data to read - end_tm: float - end time of data to read - """ - self.start_tm = 0 - self.end_tm = 0 - """ - data_object: DataTypeModel - Object that keep data read from data set - for plotting - """ - self.data_object = None - """ - min_gap: float - minimum minutes of gap length to be display on gap bar - """ - self.min_gap = None - """ - ids_name: str - name of selected preferred channels list - """ - self.ids_name = '' - """ - ids: [str,] - selected preferred channels - """ - self.ids = [] - """ - ids_data_type: str - data type of the preferred channels list - """ - self.ids_data_type = 'Unknown' - # Options - """ - date_format: str - format for date - """ - self.date_format = 'YYYY-MM-DD' - """ - mass_pos_volt_range_opt: str - option for map value/color of - mass position - """ - self.mass_pos_volt_range_opt = 'regular' - """ - bit_weight_opt: str - option for bitweight - """ - self.bit_weight_opt = '' # currently only need one option - self.get_channel_prefer() - self.yyyy_mm_dd_action.triggered.emit() - - """ - waveform_dlg: PlottingWidget - widget to display waveform channels' - plotting - """ - self.waveform_dlg = WaveformDialog(self) - """ - tps_dlg: PlottingWidget - widget to display time-power-squared of - waveform channels - """ - self.tps_dlg = TimePowerSquaredDialog(self) - - @QtCore.Slot() - def open_data_type(self): - """ - Open a dialog to add/edit data types in DB - """ - win = DataTypeDialog(self) - win.show() - - @QtCore.Slot() - def open_param(self): - """ - Open a dialog to add/edit parameters in DB - """ - win = ParamDialog(self) - win.show() - - @QtCore.Slot() - def open_channel(self): - """ - Open a dialog to add/edit channels in DB - """ - win = ChannelDialog(self) - win.show() - - @QtCore.Slot() - def open_plot_type(self): - """ - Open a dialog to view plot types and their description - """ - win = PlotTypeDialog(self) - win.show() - - @QtCore.Slot() - def open_calendar(self): - """ - Open calendar tool - """ - calendar = CalendarDialog(self) - calendar.show() - - @QtCore.Slot() - def open_channel_preferences(self): - """ - Open a dialog to view, select, add, edit, scan for preferred channels - list. - """ - dir_names = [os.path.join(self.cwd_line_edit.text(), item.text()) - for item in self.open_files_list.selectedItems()] - if dir_names == []: - msg = "No directories has been selected." - QtWidgets.QMessageBox.warning(self, "Select directory", msg) - return - win = ChannelPreferDialog(self, dir_names) - win.show() - - @QtCore.Slot() - def all_chan_clicked(self): - """ - When "All SOH" is checked, - + If checked, clear current IDs textbox - + If unchecked, set current IDs textbox if there is a preferred - channels list selected. If no list selected, re-check "All SOH" - """ - if not self.all_soh_chan_check_box.isChecked(): - if self.ids == []: - self.all_soh_chan_check_box.setChecked(True) - else: - self.curr_soh_ids_name_line_edit.setText(self.ids_name) - else: - self.curr_soh_ids_name_line_edit.setText('') - - @QtCore.Slot() - def set_date_format(self, display_format): - """ - Sets the calendar format used by the QDateEdit text boxes. - :param display_format: str - A valid display format to be used for date - conversion. - """ - self.time_to_date_edit.setDisplayFormat(display_format) - self.time_from_date_edit.setDisplayFormat(display_format) - self.date_format = display_format - - @QtCore.Slot() - def open_files_list_item_double_clicked(self, item): - """ - Handles the double-click event emitted when a user double-clicks on an - item contained within openFilesList - - :param item: FileListItem - The item contained within openFilesList - which was clicked. - """ - print(f'Opening {item.text()}') - - # TODO: Do something with the Path object, - # i.e., path.open(), or path.iterdir() ... - - @QtCore.Slot() - def change_current_directory(self): - """ - Constructs a QFileDialog to select a new working directory from which - the user can load data. The starting directory is taken from - cwdLineEdit. - """ - fd = QtWidgets.QFileDialog(self) - fd.setFileMode(QtWidgets.QFileDialog.Directory) - fd.setDirectory(self.cwd_line_edit.text()) - fd.exec_() - new_path = fd.selectedFiles()[0] - self.set_current_directory(new_path) - - @QtCore.Slot() - def read_selected_files(self): - """ - Read data from selected files/directories, process and plot channels - read from those according to current options set on the GUI - """ - try: - del self.data_object - except AttributeError: - pass - - self.req_soh_chans = (self.ids - if not self.all_soh_chan_check_box.isChecked() - else []) - - self.dir_names = [os.path.join(self.cwd_line_edit.text(), item.text()) - for item in self.open_files_list.selectedItems()] - if self.dir_names == []: - msg = "No directories has been selected." - QtWidgets.QMessageBox.warning(self, "Select directory", msg) - return - self.data_type, _ = detectDataType(self, self.dir_names) - if self.data_type is None: - return - - # get req_soh_chans - if (not self.all_soh_chan_check_box.isChecked() and - self.data_type != self.ids_data_type): - msg = (f"DataType detected for the selected data set is " - f"{self.data_type} which is different to IDs' " - f"{self.ids_data_type}.\n" - f"SOHStationViewer will read all data available.\n" - f"Do you want to continue?") - result = QtWidgets.QMessageBox.question( - self, "Confirmation", msg, - QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) - if result == QtWidgets.QMessageBox.No: - return - self.all_soh_chan_check_box.setChecked(True) - self.curr_soh_ids_name_line_edit.setText('') - self.req_soh_chans = [] - self.req_wf_chans = [] - if self.data_type == 'RT130': - req_dss = [] - for idx, DSCheckbox in enumerate(self.ds_check_boxes): - if DSCheckbox.isChecked(): - req_dss.append(idx + 1) - self.req_wf_chans = req_dss - else: - if self.wf_all_check_box.isChecked(): - self.req_wf_chans = ['*'] - elif self.wf_chans_line_edit.text().strip() != "": - self.req_wf_chans = self.wf_chans_line_edit.text().split(",") - start_tm_str = self.time_from_date_edit.date().toString( - QtCore.Qt.ISODate) - end_tm_str = self.time_to_date_edit.date().toString(QtCore.Qt.ISODate) - self.start_tm = datetime.strptime(start_tm_str, TM_FORMAT).timestamp() - self.end_tm = datetime.strptime(end_tm_str, TM_FORMAT).timestamp() - self.data_object = loadData(self.data_type, - self.tracking_info_text_browser, - self.dir_names, - reqWFChans=self.req_wf_chans, - reqSOHChans=self.req_soh_chans, - readStart=self.start_tm, - readEnd=self.end_tm) - self.replot_loaded_data() - - @QtCore.Slot() - def replot_loaded_data(self): - """ - Plot using data from self.data_object with the current options set - from GUI - """ - if self.detect_gap_check_box.isChecked(): - self.min_gap = self.gap_len_line_edit.text() - else: - self.min_gap = None - do = self.data_object - - time_tick_total = 5 # TODO: let user choose max ticks to be displayed - - sel_key = do.selectedKey - soh_data = deepcopy(do.SOHData[sel_key]) - soh_chans = list(soh_data.keys()) - mp_data = deepcopy(do.massPosData[sel_key]) - if len(self.req_wf_chans) != 0: - wf_data = deepcopy(do.waveformData[sel_key]['readData']) - else: - wf_data = [] - self.plotting_widget.plot_channels( - self.start_tm, self.end_tm, sel_key, - do.dataTime[sel_key], soh_chans, time_tick_total, - soh_data, mp_data, do.gaps[sel_key]) - - peer_plotting_widgets = [self.plotting_widget] - - if self.tps_check_box.isChecked(): - peer_plotting_widgets.append(self.tps_dlg.plotting_widget) - self.tps_dlg.set_data( - self.data_type, ','.join([str(d) for d in self.dir_names])) - self.tps_dlg.show() - self.tps_dlg.plotting_widget.plot_tps_channels( - self.start_tm, self.end_tm, sel_key, - do.dataTime[sel_key], - wf_data) - else: - self.tps_dlg.hide() - - if self.req_wf_chans != []: - # waveformPlot - peer_plotting_widgets.append(self.waveform_dlg.plotting_widget) - self.waveform_dlg.set_data( - self.data_type, ','.join([str(d) for d in self.dir_names])) - self.waveform_dlg.show() - wf_chans = list(do.waveformData[do.selectedKey].keys()) - self.waveform_dlg.plotting_widget.plot_channels( - self.start_tm, self.end_tm, sel_key, - do.dataTime[sel_key], wf_chans, time_tick_total, - wf_data, mp_data) - else: - self.waveform_dlg.hide() - - self.plotting_widget.set_peer_plotting_widgets(peer_plotting_widgets) - self.waveform_dlg.plotting_widget.set_peer_plotting_widgets( - peer_plotting_widgets) - self.tps_dlg.plotting_widget.set_peer_plotting_widgets( - peer_plotting_widgets) - - def set_current_directory(self, path=''): - """ - Set all directories under current directory to self.open_files_list - :param path: str - absolute path to current directory - """ - # Remove entries when cwd changes - self.open_files_list.clear() - # Signal cwd changed, and gather list of files in new cwd - self.current_directory_changed.emit(path) - for dent in pathlib.Path(path).iterdir(): - if not dent.is_dir() or dent.name.startswith('.'): - continue - - self.open_files_list.addItem(FileListItem(dent)) - - def get_channel_prefer(self): - """ - Read the current preferred channel list from database to set ids_name, - ids, self.ids_data_type - """ - self.ids_name = '' - self.ids = [] - self.data_type = 'Unknown' - rows = executeDB_dict('SELECT name, IDs, dataType FROM ChannelPrefer ' - 'WHERE current=1') - if len(rows) > 0: - self.ids_name = rows[0]['name'] - self.ids = [t.strip() for t in rows[0]['IDs'].split(',')] - self.ids_data_type = rows[0]['dataType'] - - def resizeEvent(self, event): - """ - When MainWindow is resized, its plotting_widget need to initialize - its size to fit the viewport. - - :param event: QResizeEvent - resize event - """ - self.plotting_widget.init_size() diff --git a/sohstationviewer/view/select_buttons_dialog.py b/sohstationviewer/view/select_buttons_dialog.py deleted file mode 100644 index b34c45cb50f5cfae46a8c883656b19aff269f0b2..0000000000000000000000000000000000000000 --- a/sohstationviewer/view/select_buttons_dialog.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys -import platform -import os - -from PySide2 import QtWidgets, QtCore -from functools import partial - - -""" -Dialog includes buttons. -Click on a button will close the dialog and the index of the clicked button -can be retrieved in obj.ret -""" - - -class SelectButtonDialog(QtWidgets.QDialog): - def __init__(self, parent=None, message='', - button_labels=['test1', 'test2']): - """ - Create dialog that have buttons from the given labels and show the - givven message. - - :param parent: QMainWindow/QWidget - the parent widget - :param message: str - Instruction for user - :param button_labels: [str,] - list of buttons' labels - """ - super(SelectButtonDialog, self).__init__(parent) - self.ret = -1 - height = int(50 * (1 + len(button_labels) / 3)) - self.setGeometry(100, 100, 900, height) - main_layout = QtWidgets.QVBoxLayout() - self.setLayout(main_layout) - - label = QtWidgets.QLabel(message) - main_layout.addWidget(label, 0) - - buttons_layout = QtWidgets.QGridLayout() - main_layout.addLayout(buttons_layout) - buttons = [] - r = -1 - for idx, label in enumerate(button_labels): - c = idx % 3 - if c == 0: - r += 1 - buttons.append(QtWidgets.QPushButton(label)) - buttons[idx].clicked.connect(partial(self.button_click, idx)) - buttons_layout.addWidget(buttons[idx], r, c) - - @QtCore.Slot() - def button_click(self, idx): - """ - When a button is clicked, assign self.ret to the index of the button. - and close the dialog - - :param idx: int - index of the button - """ - self.ret = idx - self.close() - - -if __name__ == '__main__': - os_name, version, *_ = platform.platform().split('-') - if os_name == 'macOS': - os.environ['QT_MAC_WANTS_LAYER'] = '1' - app = QtWidgets.QApplication(sys.argv) - - test = SelectButtonDialog(None, "Testing result from buttons", - ['test01', 'test02', 'test03', - 'test11', 'test12', 'test13']) - test.exec_() - - print("return Code:", test.ret) - sys.exit(app.exec_()) diff --git a/sohstationviewer/view/time_power_squared_dialog.py b/sohstationviewer/view/time_power_squared_dialog.py deleted file mode 100755 index f4557b204e66963607bd30151d6db7249e4088dc..0000000000000000000000000000000000000000 --- a/sohstationviewer/view/time_power_squared_dialog.py +++ /dev/null @@ -1,471 +0,0 @@ -# UI and connectSignals for MainWindow -from math import sqrt -import numpy as np - -from PySide2 import QtWidgets, QtCore - -from sohstationviewer.view.core import plotting_widget as plottingWidget -from sohstationviewer.controller.plottingData import ( - getTitle, getDayTicks, formatTime) -from sohstationviewer.model.handling_data import ( - get_trimTPSData, get_eachDay5MinList, findTPSTm) -from sohstationviewer.database.extractData import ( - getColorDef, getColorRanges, getChanLabel) -from sohstationviewer.conf.colorSettings import Clr -from sohstationviewer.conf import constants as const -from sohstationviewer.controller.util import displayTrackingInfo, fmti - - -class TimePowerSquaredWidget(plottingWidget.PlottingWidget): - """ - Widget to display time power square data for waveform channels - """ - def __init__(self, *args, **kwarg): - """ - rulers: [matplotlib.lines.Line2D,] - list of squares on each waveform - channels to highlight the five-minute at the mouse click on - TimePowerSquaredWidget or the five-minute corresponding to the - time at the mouse click on other plotting widgets - """ - self.rulers = [] - """ - zoom_marker1s: [matplotlib.lines.Line2D,] - list of line markers to - mark the five-minute corresponding to the start of the zoom area - """ - self.zoom_marker1s = [] - """ - zoom_marker2s: [matplotlib.lines.Line2D,] - list of line markers to - mark the five-minute corresponding to the end of the zoom area - """ - self.zoom_marker2s = [] - """ - every_day_5_min_list: [[288 of floats], ] - the list of all starts - of five minutes for every day in which each day has 288 of - 5 minutes. - """ - self.each_day5_min_list = [] - - super().__init__(*args, **kwarg) - self.fig.canvas.mpl_connect('pick_event', self.on_pick_event) - - def plot_tps_channels(self, start_tm=None, end_tm=None, key=None, - data_time=None, waveform_data=None): - """ - Recursively plot each channels for waveform_data and mass_pos_data. - - :param start_tm: float - requested start time to read - :param end_tm: float - requested end time to read - :param key: str or (str, str) station name for mseed, - or (device's experiment number, experiment number ) for reftek - :param data_time: [float, float] - time range of the selected data set - :param waveform_data: dict - read waveform data of selected data set, - refer to DataTypeModel.__init__.waveform_data[key]['read_data'] - """ - self.processing_log = [] # [(message, type)] - self.gap_bar = None - self.min_x = max(data_time[0], start_tm) - self.max_x = min(data_time[1], end_tm) - - if self.axes: - self.fig.clear() - self.date_mode = self.parent.date_format.upper() - if waveform_data is not None: - self.plotting_data1 = waveform_data - self.min_x = max(data_time[0], start_tm) - self.max_x = min(data_time[1], end_tm) - self.plot_total = len(waveform_data) - title = getTitle(key, self.min_x, self.max_x, self.date_mode) - self.plotting_bot = const.BOTTOM - self.plotting_bot_pixel = const.BOTTOM_PX - self.axes = [] - self.rulers = [] - self.zoom_marker1s = [] - self.zoom_marker2s = [] - - self.timestamp_bar_top = self.add_timestamp_bar(0.) - self.set_title(title, y=0, v_align='bottom') - self.each_day5_min_list = get_eachDay5MinList(self.min_x, self.max_x) - for chanID in self.plotting_data1: - ax = self.get_plot_data(self.plotting_data1[chanID], chanID) - self.axes.append(ax) - self.set_legend() - # Set view size fit with the given data - if self.main_widget.geometry().height() < self.plotting_bot_pixel: - self.main_widget.setFixedHeight(self.plotting_bot_pixel) - self.set_lim_markers() - self.draw() - - def get_plot_data(self, c_data, chan_id): - """ - Trim data to minx, max_x and calculate time-power-square for each 5 - minute into c_data['tps_data'] then draw each 5 minute with the - color corresponding to value - Create ruler, zoom_marker1, zoom_marker2 for the channel. - - :param c_data: dict - data of the channel which includes down-sampled - data in keys 'times' and 'data'. Refer to - DataTypeModel.__init__.waveform_data[key]['read_data'][chan_id] - :param chan_id: str - name of channel - :return ax: matplotlib.axes.Axes - axes of the channel - """ - if 'tps_data' not in c_data: - # get new minX, maxX according to exact start time of days - get_trimTPSData(c_data, self.min_x, self.max_x, - self.each_day5_min_list) - total_days = c_data['tps_data'].shape[0] - plot_h = self.get_height(1.5 * total_days, bw_plots_distance=0.003) - ax = self.create_axes(self.plotting_bot, plot_h) - ax.text( - -0.1, 1.2, - f"{getChanLabel(chan_id)} {c_data['samplerate']}", - horizontalalignment='left', - verticalalignment='top', - rotation='horizontal', - transform=ax.transAxes, - color=self.display_color['plot_label'], - size=self.font_size + 2 - ) - - zoom_marker1 = ax.plot( - [], [], marker='|', markersize=10, - markeredgecolor=self.display_color['zoom_marker'])[0] - self.zoom_marker1s.append(zoom_marker1) - - zoom_marker2 = ax.plot( - [], [], marker='|', markersize=10, - markeredgecolor=self.display_color['zoom_marker'])[0] - self.zoom_marker2s.append(zoom_marker2) - - ruler = ax.plot( - [], [], marker='s', markersize=5, - markeredgecolor=self.display_color['time_ruler'], - markerfacecolor='None')[0] - self.rulers.append(ruler) - - x = np.array([i for i in range(const.NO_5M_DAY)]) - square_counts = self.parent.sel_square_counts # square counts range - color_codes = self.parent.color_def # colordef - - for dayIdx, y in enumerate(c_data['tps_data']): - # not draw data out of day range - color_set = self.get_color_set(y, square_counts, color_codes) - # (- dayIdx): each day is a line, increase from top to bottom - ax.scatter(x, [- dayIdx] * len(x), marker='|', - c=color_set, s=7, alpha=0.8) - # extra to show highlight square - ax.set_ylim(-(c_data['tps_data'].shape[0] + 1), 1) - - return ax - - def set_legend(self): - """ - Plot one dot for each color and assign label to it. The dots are - plotted outside of xlim to not show up in plotting area. xlim is - set so that it has some extra space to show full hightlight square - of the ruler. - ax.legend will create one label for each dot. - """ - # set height of legend and distance bw legend and upper ax - plot_h = self.get_height(7, bw_plots_distance=0.003) - ax = self.canvas.figure.add_axes( - [self.plotting_l, self.plotting_bot, self.plotting_w, plot_h], - picker=True - ) - ax.patch.set_alpha(0) - c_labels = self.parent.sel_col_labels - clrs = self.parent.color_def # colordef - for idx in range(len(c_labels)): - # draw a dot out of xlim so it isn't displayed in plotting area - ax.scatter([300], [1], - c=Clr[clrs[idx]], - s=0.1, - label=c_labels[idx], - edgecolor=self.display_color['basic'], - alpha=0.8, - zorder=1, - picker=True) - # extra to show highlight square - ax.set_xlim(-2, const.NO_5M_DAY + 1) - ax.legend(loc="upper left", framealpha=0.2, - markerscale=25, - labelcolor=self.display_color['basic']) - - def get_color_set(self, y, square_counts, colors): - """ - Create array of color (col) according to value of y compare with - square_counts (square count range) - - :param y: np.array of float - tps values for all 5-minutes of a day - :param square_counts: [int, ] - list of square count ranges - :param colors: [str,] - list of color codes based on colorSettings.Clr - :return: np.array of color hex for each 5-minutes of a day - """ - return ( - np.where( - y == square_counts[0], Clr[colors[0]], np.where( - y < square_counts[1], Clr[colors[1]], np.where( - y < square_counts[2], Clr[colors[2]], np.where( - y < square_counts[3], Clr[colors[3]], np.where( - y < square_counts[4], Clr[colors[4]], np.where( - y < square_counts[5], Clr[colors[5]], np.where( # noqa: E501 - y < square_counts[6], Clr[colors[6]], Clr[colors[7]] # noqa: E501 - ))))))) - ) - - def create_axes(self, plot_b, plot_h, has_min_max_lines=False): - """ - Create axes for 288 of 5m in a day in which minor tick for every hour, - major tick for every 4 hour - - :param plot_b: float - bottom of the plot - :param plot_h: float - height of the plot - :param has_min_max_lines: bool - flag showing if the plot need min/max - lines - :return ax: matplotlib.axes.Axes - axes of tps of a waveform channel - """ - ax = self.canvas.figure.add_axes( - [self.plotting_l, plot_b, self.plotting_w, plot_h], - picker=True - ) - ax.spines['right'].set_visible(False) - ax.spines['left'].set_visible(False) - ax.xaxis.grid(True, which='major', - color=self.display_color['basic'], linestyle='-') - ax.xaxis.grid(True, which='minor', - color=self.display_color['sub_basic'], linestyle='-') - ax.set_yticks([]) - - times, major_times, major_time_labels = getDayTicks() - ax.set_xticks(times, minor=True) - ax.set_xticks(major_times) - ax.set_xticklabels(major_time_labels, fontsize=self.font_size, - color=self.display_color['basic']) - # extra to show highlight square - ax.set_xlim(-2, const.NO_5M_DAY + 1) - ax.patch.set_alpha(0) - return ax - - def on_pick_event(self, event): - """ - When a plot is select, the corresponding point on each plot will - be highlighted and their time and counts will be displayed. - :param event: pick event - event when object of canvas is selected. - The event happens before button_press_event. - """ - info_str = "" - if event.artist in self.axes: - xdata = event.mouseevent.xdata - if xdata is None: - return - xdata = round(xdata) - # when click on outside xrange that close to edge, adjust to edge - if xdata in [-2, -1]: - xdata = 0 - if xdata in [288, 289]: - xdata = 287 - ydata = round(event.mouseevent.ydata) - - y_idx = - ydata - x_idx = xdata - # identify time for rulers on other plotting widget - self.tps_t = self.each_day5_min_list[y_idx, x_idx] - format_t = formatTime(self.tps_t, self.date_mode, 'HH:MM:SS') - info_str += f"{format_t}:" - for chanID in self.plotting_data1: - c_data = self.plotting_data1[chanID] - data = c_data['tps_data'][y_idx, x_idx] - info_str += f" {chanID}:{fmti(sqrt(data))}" - info_str += " (counts)" - displayTrackingInfo(self.tracking_box, info_str) - self.draw() - - def on_ctrl_cmd_click(self, xdata): - """ - Ctrl + cmd: base on xdata to find indexes of x an y - in self.each_day_5_min_list to display ruler for each channel, then - set time for each ruler in self.rulers to place them in correct - position. - - :param xdata: float - time value in other plot - """ - self.zoom_marker1_shown = False - x_idx, y_idx = findTPSTm(xdata, self.each_day5_min_list) - for rl in self.rulers: - rl.set_data(x_idx, y_idx) - - def on_shift_click(self, xdata): - """ - Shift + right click on other plot widget, this function will be called - to show marker for place when it is zoomed. - On the fist of zoom_marker, make ruler disappeared, set min_x. - On the second of zoom_maker, call set_lim_markers to mark the new - limit. - - :param xdata: float - time value in other plot - """ - - if not self.zoom_marker1_shown: - self.set_rulers_invisible() - self.min_x = xdata - self.zoom_marker1_shown = True - else: - [self.min_x, self.max_x] = sorted( - [self.min_x, xdata]) - self.set_lim_markers() - self.zoom_marker1_shown = False - - def set_rulers_invisible(self): - """ - Clear data for self.rulers to make them disappeared. - """ - for rl in self.rulers: - rl.set_data([], []) - - def set_lim_markers(self): - """ - Find x index (which index in five minutes of a day) and - y index (which day) of self.min_x and self.min_y, and set data for - all markers in self.zoom_marker1s and self.zoom_marker2s. - """ - x_idx, y_idx = findTPSTm(self.min_x, self.each_day5_min_list) - for zm1 in self.zoom_marker1s: - zm1.set_data(x_idx, y_idx) - x_idx, y_idx = findTPSTm(self.max_x, self.each_day5_min_list) - for zm2 in self.zoom_marker2s: - zm2.set_data(x_idx, y_idx) - - -class TimePowerSquaredDialog(QtWidgets.QWidget): - def __init__(self, parent): - """ - Dialog to display time power square data for waveform channels. Users - are allowed to select different Color Ranges (antarctica, low, - medium, high) for differences values vs. colors map to draw - time power square for each 5-minute data - - :param parent: QMainWindow/QWidget - the parent widget - """ - super().__init__() - self.parent = parent - """ - date_format: str - format to display date/time - """ - self.date_format = self.parent.date_format - """ - data_type: str - type of data being plotted - """ - self.data_type = None - self.setGeometry(50, 50, 1200, 700) - self.setWindowTitle("TPS Plot") - - main_layout = QtWidgets.QVBoxLayout() - self.setLayout(main_layout) - main_layout.setContentsMargins(5, 5, 5, 5) - main_layout.setSpacing(0) - - """ - trackingInfoTextBrowser: QTextBrowser - to display info text - """ - self.info_text_browser = QtWidgets.QTextBrowser(self) - """ - plotting_widget: PlottingWidget - the widget to draw time-power-square - for each 5-minute of data - """ - self.plotting_widget = TimePowerSquaredWidget( - self, self.info_text_browser, "timepowersquaredwidget") - main_layout.addWidget(self.plotting_widget, 2) - - bottom_layout = QtWidgets.QHBoxLayout() - bottom_layout.addSpacing(20) - main_layout.addLayout(bottom_layout) - - # ################ Color range ################# - bottom_layout.addWidget(QtWidgets.QLabel("Color Range")) - - """ - color_def: [str,] - list of color codes in order of values to be - displayed - """ - self.color_def = getColorDef() - """ - sel_square_counts: [int,] - selected time-power-square ranges - """ - self.sel_square_counts = [] - """ - sel_col_labels: [str,] - color label for each range - """ - self.sel_col_labels = [] - """ - color_ranges: [str,] - name of color:value map for user to choose - 'antarctica'/'low'/'med'/'high' - all_square_counts: [[int,],] - time-power-squared values - color_label: [str,] - labels that define count range for colors to show - in the legend of the tps plotting widget - """ - (self.color_ranges, - self.all_square_counts, - self.color_label) = getColorRanges() - - """ - color_range_choice: QComboBox - dropdown box for user to choose a - color:value map name - """ - self.color_range_choice = QtWidgets.QComboBox(self) - self.color_range_choice.addItems(self.color_ranges) - self.color_range_choice.setCurrentText('high') - bottom_layout.addWidget(self.color_range_choice) - ################################################ - self.save_button = QtWidgets.QPushButton('Save', self) - bottom_layout.addWidget(self.save_button) - - self.info_text_browser.setFixedHeight(60) - bottom_layout.addWidget(self.info_text_browser) - - self.connect_signals() - self.color_range_changed() - - def set_data(self, data_type, file_name): - """ - Set data_type and the window's title. - - :param data_type: str - data type of data being plotted - :param file_name: str - name of the file/folder of the data set to be - displayed - """ - self.data_type = data_type - self.setWindowTitle("TPS Plot %s - %s" % (data_type, file_name)) - - def resizeEvent(self, event): - """ - When TimePowerDialog is resized, its plotting_widget need to initialize - its size to fit the viewport. - - :param event: QResizeEvent - resize event - """ - self.plotting_widget.init_size() - - def connect_signals(self): - """ - Connect functions to widgets - """ - self.save_button.clicked.connect(self.save) - self.color_range_choice.currentTextChanged.connect( - self.color_range_changed) - - @QtCore.Slot() - def color_range_changed(self): - """ - When selecting a different color range from the drop down menu, set - new value for sel_square_counts and sel_col_labels - """ - color_range = self.color_range_choice.currentText() - cr_index = self.color_ranges.index(color_range) - self.sel_square_counts = self.all_square_counts[cr_index] - self.sel_col_labels = self.color_label[cr_index] - - @QtCore.Slot() - def save(self): - """ - Save the plotting to a file - """ - print("save")