Skip to content
Snippets Groups Projects
Commit a286221e authored by Lan Dam's avatar Lan Dam Committed by Kien Le
Browse files

rename time_power_squareddialog.py, selectbuttonsdialog.py, mainwindow.py,...

rename time_power_squareddialog.py, selectbuttonsdialog.py, mainwindow.py, filelistwidget.py to follow python naming convention
parent 1206e9e5
No related branches found
No related tags found
1 merge request!27Draft: Add tests for functions in handling_data.py
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()
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_())
# 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")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment