def generateLegendMenu(self): self.menuLegend = QtGui.QMenu(self.menubar) self.menuLegend.setTitle('Legend') self.actionGenerateLegend = QtGui.QAction(self) self.actionGenerateLegend.setText('Generate Draggable Legend') self.menuLegend.addAction(self.actionGenerateLegend) self.menubar.addAction(self.menuLegend.menuAction()) self.connect(self.actionGenerateLegend, QtCore.SIGNAL('triggered()'), self.generateLegend)
def __init__(self, canvas, parent, coordinates=True): NavigationToolbar2QT.__init__(self, canvas, parent, coordinates) self.setIconSize(QtCore.QSize(16, 16)) self.ct = None self.mw = None self._idPress1 = None self._idPress2 = None self._idPress3 = None
def add_QDateTimeEdit(self, spec): widget = QtWidgets.QDateTimeEdit(spec.get('default', datetime.utcnow())) self.fields[spec['name']] = widget widget.setTime(QtCore.QTime(0, 0, 0)) widget.setCalendarPopup(True) label_text = spec.get('label', spec['name']) self.layout.addWidget(QtWidgets.QLabel(label_text)) self.layout.addWidget(widget)
class DimensionWidget(QW.QWidget): """ Widget to select dimensions """ #: Signal emitted when value is changed valueChanged = QtCore.Signal(int) def __init__(self, dimension): """ Construct the widget Args: dimension: xarray.DataArray """ super().__init__() main_layout = QW.QHBoxLayout(self) #: The dimension represented by this widget self.dimension = dimension self.title = QW.QLabel(dimension.name) self.textbox = QW.QLineEdit() self.slider = QW.QSlider(orientation=QtCore.Qt.Horizontal) self.slider.setMinimum(0) self.slider.setMaximum(dimension.size - 1) self.slider.valueChanged.connect(self._update_from_slider) self.textbox.returnPressed.connect(self._update_from_value) self.slider.setValue(0) self.textbox.setText(str(self.dimension[0].values)) main_layout.addWidget(self.title) main_layout.addWidget(self.textbox) main_layout.addWidget(self.slider) def _update_from_value(self): value = self.textbox.text() value = numpy.asscalar(numpy.array(value, dtype=self.dimension.dtype)) index = self.dimension.to_index().get_loc(value, method='nearest') self.slider.setValue(index) def _update_from_slider(self, value): self.textbox.setText(str(self.dimension[value].values)) self.valueChanged.emit(value) def value(self): """ The current slider index """ return self.slider.value()
class ComponentsList(QtCore.QObject): ''' Keep track of Components in a list and emit signals. Methods 'append' and 'remove' are provided and emit signals, direct access to the list is allowed with 'ComponentList.list', but not recommended.''' componentAppended = QtCore.pyqtSignal(object, name="ComponentAppended") componentRemoved = QtCore.pyqtSignal(object, name="ComponentRemoved") def __init__(self): super(ComponentsList, self).__init__() self.list = [] def append(self, item): self.list.append(item) self.componentAppended.emit(item) def remove(self, item): self.list.remove(item) self.componentRemoved.emit(item) def index(self, item): return self.list.index(item) def __delitem__(self, key): self.list.__delitem__(key) def __getitem__(self, key): return self.list.__getitem__(key) def __setitem__(self, key, value): self.list.__setitem__(key, value) def __len__(self): return len(self.list) def __repr__(self): return self.list.__repr__()
def __init__(self): self.blocksr80comm = False self.blockv80comm = False #True self.blockmotorcomm = False super().__init__() # # self.title = 'Ny-Ålesund Emission Measurements' self.setWindowTitle(self.title) # self.checkbox = False # self.emailsent = 0 # self.initUI() # # self._update_canvas() # self.bck = QtCore.QTimer() self.bck.setInterval(1000) self.bck.timeout.connect(self.Update_StatusBox) self.bck.start() self.rseq = QtCore.QTimer() self.rseq.setInterval(1000) self.rseq.timeout.connect(self.run_sequence) self.rseq.start() self.check_cond = QtCore.QTimer() self.check_cond.setInterval(1000) self.check_cond.timeout.connect(self.check_conditions) self.check_cond.start() self.timer_al = QtCore.QTimer() self.timer_al.setInterval(100) self.timer_al.timeout.connect(self._update_actual_line) self.timer_al.start()
def __init__(self, wib_server='127.0.0.1', config='femb0.json', grid=False): super().__init__() self.wib = WIB(wib_server) self.config = config self._main = QtWidgets.QWidget() self._main.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCentralWidget(self._main) layout = QtWidgets.QVBoxLayout(self._main) self.grid = QtWidgets.QGridLayout() if grid: self.views = [Hist2DView(), FFTView(), MeanView(), RMSView()] for i, v in enumerate(self.views): self.grid.addWidget(v, i % 2, i // 2) else: self.views = [Hist2DView(), MeanRMSView(), FFTView()] for i, v in enumerate(self.views): self.grid.addWidget(v, 0, i) layout.addLayout(self.grid) nav_layout = QtWidgets.QHBoxLayout() button = QtWidgets.QPushButton('Configure') nav_layout.addWidget(button) button.setToolTip('Configure WIB and front end') button.clicked.connect(self.configure_wib) button = QtWidgets.QPushButton('Acquire') nav_layout.addWidget(button) button.setToolTip('Read WIB Spy Buffer') button.clicked.connect(self.acquire_data) button = QtWidgets.QPushButton('Continuous') nav_layout.addWidget(button) button.setToolTip('Repeat acquisitions until stopped') button.clicked.connect(self.toggle_continuous) self.continuious_button = button self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.acquire_data) layout.addLayout(nav_layout) self.plot()
class Trace(QtCore.QThread): """ timer for the IOC measurement""" ##--------Signal Definition--------## started = QtCore.pyqtSignal() finished = QtCore.pyqtSignal('PyQt_PyObject') ##--------CONSTRUCTOR--------## def __init__(self,interval): # t--interval call the hFunction QtCore.QThread.__init__(self) self.interval = interval self.evented = threading.Event() # 引入事件进行定时器的设置 self.trace_points = None self.trace_time = None self.trace_value = {} self.trace_triggerlevel = None self.trace_offsettime = None #Execute def run(self): self.started.emit() while not self.evented.is_set(): self.evented.wait(self.interval) #self.trace_points = caget('SRFLab-010:RFS-PM-01:Trace_points.VAL', as_string=False) self.trace_time = caget('SRFLab-010:RFS-PM-01:Trace_time.VAL', as_string=False) self.trace_value = caget('SRFLab-010:RFS-PM-01:Value_trace.VAL', as_string=False) self.trace_triggerlevel = caget('SRFLab-010:RFS-PM-01:Trace_level_callback_DBM.VAL', as_string=False) self.trace_offsettime = caget('SRFLab-010:RFS-PM-01:Trace_offset_time_callback.VAL',as_string=False) self.trace_points = len(self.trace_value) psen = TraceMeasure() psen._array = self.trace_value psen._points = self.trace_points psen._time = self.trace_time psen._triggerlevel = self.trace_triggerlevel psen._offsetTime = self.trace_offsettime self.finished.emit(psen) #STOP def cancel(self): self.evented.set()
def save(self): self.frame_no = self.frame_no - np.int(self.frame_no != 0) self.save_btns.setText("Saving Progressing") self.directory = self.get_video_directory() if self.directory == None: self.directory = "kimo" frame = cv2.imread(f"imgs/img{self.graph_index}_0.jpeg") height, width, layers = frame.shape self.save_progress.show() self.video = cv2.VideoWriter(f"{self.directory}.avi", 0, 5, (width, height)) self.index = 0 self.timer = QtCore.QTimer() self.timer.setInterval(20) self.timer.timeout.connect( lambda: self.save_video_iterate(width, height)) self.timer.start()
def _init_toolbar(self): # ! Choose icon theme if self.darkMode == True: self.basedir = os.path.join(self.main_dir, 'data', 'resources', 'images_dark', 'matplotlib-dark-images') else: self.basedir = os.path.join(matplotlib.rcParams['datapath'], 'images') for text, tooltip_text, image_file, callback in self.toolitems: if text is None: self.addSeparator() else: a = self.addAction(self._icon(image_file + '.png'), text, getattr(self, callback)) self._actions[callback] = a if callback in ['zoom', 'pan']: a.setCheckable(True) if tooltip_text is not None: a.setToolTip(tooltip_text) if text == 'Subplots': a = self.addAction(self._icon("qt4_editor_options.png"), 'Customize', self.edit_parameters) a.setToolTip('Edit axis, curve and image parameters') # Add the x,y location widget at the right side of the toolbar # The stretch factor is 1 which means any resizing of the toolbar # will resize this label instead of the buttons. if self.coordinates: self.locLabel = QtWidgets.QLabel("", self) self.locLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop) self.locLabel.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Ignored)) labelAction = self.addWidget(self.locLabel) labelAction.setVisible(True) # Esthetic adjustments - we need to set these explicitly in PyQt5 # otherwise the layout looks different - but we don't want to set it if # not using HiDPI icons otherwise they look worse than before. if is_pyqt5() and self.canvas._dpi_ratio > 1: self.setIconSize(QtCore.QSize(24, 24)) self.layout().setSpacing(12)
def _init_toolbar(self): self.basedir = resource_filename('VisualPIC.Icons.mpl', '') for text, tooltip_text, image_file, callback in self.toolitems: if text is None: self.addSeparator() else: a = self.addAction(self._icon(image_file + '.svg'), text, getattr(self, callback)) self._actions[callback] = a if callback in ['zoom', 'pan']: a.setCheckable(True) if tooltip_text is not None: a.setToolTip(tooltip_text) if text == 'Subplots': a = self.addAction(self._icon("qt4_editor_options.svg"), 'Customize', self.edit_parameters) a.setToolTip('Edit axis, curve and image parameters') self.buttons = {} # Add the x,y location widget at the right side of the toolbar # The stretch factor is 1 which means any resizing of the toolbar # will resize this label instead of the buttons. if self.coordinates: self.locLabel = QtWidgets.QLabel("", self) self.locLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop) self.locLabel.setSizePolicy( QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Ignored)) labelAction = self.addWidget(self.locLabel) labelAction.setVisible(True) # reference holder for subplots_adjust window self.adj_window = None # Esthetic adjustments - we need to set these explicitly in PyQt5 # otherwise the layout looks different - but we don't want to set it if # not using HiDPI icons otherwise they look worse than before. if is_pyqt5(): self.setIconSize(QtCore.QSize(24, 24)) self.layout().setSpacing(12)
def initialize_map(self, restart=0): if restart == 1: if self.index > 0: self.timer.stop() self.pc.remove() self.cax.cla() self.index = 0 self.fig.delaxes(self.cax) divider = make_axes_locatable(self.ax) self.cax = divider.append_axes('right', size='3%', pad=0) self.timer.start() else: self.fig, self.ax = plt.subplots() self.divider = make_axes_locatable(self.ax) self.cax = self.divider.append_axes('right', size='3%', pad=0) self.map = Basemap(projection='cyl', resolution='h', llcrnrlat=-90, urcrnrlat=90, llcrnrlon=-180, urcrnrlon=180, ax=self.ax) self.map.drawmapboundary(fill_color='aqua') self.map.fillcontinents(color='darkblue', lake_color='aqua') self.map.drawcoastlines() self.map.readshapefile( 'ne_10m_admin_0_countries/ne_10m_admin_0_countries', 'countries') plotWidget = FigureCanvas(self.fig) cid = self.fig.canvas.mpl_connect('button_press_event', self.on_press) self.index = 0 self.ui.map_layout.addWidget(plotWidget) self.save_map_v = save_video(self, self.index, 0, self.ui.save_li[0], self.ui.prpgress_li[0]) self.timer = QtCore.QTimer() self.timer.setInterval(80) self.timer.timeout.connect(self.update_map) self.timer_li.append(self.timer) self.timer.start()
def initialize_bubble(self, restart=0): if restart == 1: self.timer1.stop() self.ax1.cla() self.index1 = 0 self.timer1.start() else: self.fig1, self.ax1 = plt.subplots() plotWidget = FigureCanvas(self.fig1) self.ui.buble_layout.addWidget(plotWidget) self.index1 = 0 self.last_values = [[0] * self.countries_no] * 3 self.save_buble_v = save_video(self, self.index1, 1, self.ui.save_li[1], self.ui.prpgress_li[1]) self.timer1 = QtCore.QTimer() self.timer1.setInterval(15) self.timer1.timeout.connect(self.update_bubble) self.timer_li.append(self.timer1) self.timer1.start()
def __init__(self, model, interactive, data=None): """ :param model: model.Model :param interactive: bool Boolean indicating if we are running in an interactive setting such as an ipython session. Helpful for deciding to parse CLI args, or not. :param data: Some type of array container, e.g. pandas.DataFrame, see `View.load_seria` """ super(View, self).__init__() self.actions = {} self.model = model self.avail_slots_by_signal = {} self.avail_slots_by_signal['sig_new_data'] = [self.model.add_dataitem] self.avail_slots_by_signal['sig_new_markings'] = [ self.model.new_markings_from_description ] self.avail_slots_by_signal['sig_apply_on_visible'] = [ self.model.apply_on_visible, ] self.avail_signals = {} # Populate initially with signals from model for k, v in self.model.signals.items(): self.avail_signals[k] = v self.draw_timer = QtCore.QTimer() self.init_ui() self.canvas_redraw() if not interactive: QtCore.QTimer.singleShot(0, self.parse_sysargs) if data is not None: logger.debug('Scheduling load-data callback') QtCore.QTimer.singleShot(0, lambda: self.load_seria(data))
def __init__(self, publisher, *args, **kwargs): self.pub = publisher # Initialise the different maps for the display of the mems surface self.map_index, self.map_index_h = fits.getdata(FCTRLV2_PATH + MEMS_INDEX_NAME, header=True) self.map_height, self.map_width = np.shape(self.map_index) self.map_opd = np.ones((self.map_height, self.map_width)) self.map_opd[self.map_index == 0] = 0 self.map_centers = np.loadtxt(FCTRLV2_PATH + MEMS_CENTERS_NAME, dtype=np.int) self.map_radius_x = np.ones((self.map_height, self.map_width)) self.map_radius_y = np.ones((self.map_height, self.map_width)) self.compute_radii() # Initialise the figure (canvas) MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) timer.timeout.connect(self.update_figure) timer.start(100) self.mems = Mems(self.pub) self.mems.connect() self.mems.flat()
def setup(self): for label, value in self.data: if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtWidgets.QLabel(" "), QtWidgets.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtWidgets.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif (label.lower() not in BLACKLIST and mcolors.is_color_like(value)): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, str): field = QtWidgets.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) # Note: get() below checks the type of value[0] in self.data so # it is essential that value gets modified in-place. # This means that the code is actually broken in the case where # value is a tuple, but fortunately we always pass a list... selindex = value.pop(0) field = QtWidgets.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, Integral): _log.warning( "index '%s' is invalid (label: %s, value: %s)", selindex, label, value) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtWidgets.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, Integral): field = QtWidgets.QSpinBox(self) field.setRange(-10**9, 10**9) field.setValue(value) elif isinstance(value, Real): field = QtWidgets.QLineEdit(repr(value), self) field.setCursorPosition(0) field.setValidator(QtGui.QDoubleValidator(field)) field.validator().setLocale(QtCore.QLocale("C")) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, datetime.datetime): field = QtWidgets.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtWidgets.QDateEdit(self) field.setDate(value) else: field = QtWidgets.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field)
class FormWidget(QtWidgets.QWidget): update_buttons = QtCore.Signal() def __init__(self, data, comment="", with_margin=False, parent=None): """ Parameters ---------- data : list of (label, value) pairs The data to be edited in the form. comment : str, optional with_margin : bool, optional, default: False If False, the form elements reach to the border of the widget. This is the desired behavior if the FormWidget is used as a widget alongside with other widgets such as a QComboBox, which also do not have a margin around them. However, a margin can be desired if the FormWidget is the only widget within a container, e.g. a tab in a QTabWidget. parent : QWidget or None The parent widget. """ QtWidgets.QWidget.__init__(self, parent) self.data = copy.deepcopy(data) self.widgets = [] self.formlayout = QtWidgets.QFormLayout(self) if not with_margin: self.formlayout.setContentsMargins(0, 0, 0, 0) if comment: self.formlayout.addRow(QtWidgets.QLabel(comment)) self.formlayout.addRow(QtWidgets.QLabel(" ")) def get_dialog(self): """Return FormDialog instance""" dialog = self.parent() while not isinstance(dialog, QtWidgets.QDialog): dialog = dialog.parent() return dialog def setup(self): for label, value in self.data: if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtWidgets.QLabel(" "), QtWidgets.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtWidgets.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif (label.lower() not in BLACKLIST and mcolors.is_color_like(value)): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, str): field = QtWidgets.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) # Note: get() below checks the type of value[0] in self.data so # it is essential that value gets modified in-place. # This means that the code is actually broken in the case where # value is a tuple, but fortunately we always pass a list... selindex = value.pop(0) field = QtWidgets.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, Integral): _log.warning( "index '%s' is invalid (label: %s, value: %s)", selindex, label, value) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtWidgets.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, Integral): field = QtWidgets.QSpinBox(self) field.setRange(-10**9, 10**9) field.setValue(value) elif isinstance(value, Real): field = QtWidgets.QLineEdit(repr(value), self) field.setCursorPosition(0) field.setValidator(QtGui.QDoubleValidator(field)) field.validator().setLocale(QtCore.QLocale("C")) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, datetime.datetime): field = QtWidgets.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtWidgets.QDateEdit(self) field.setDate(value) else: field = QtWidgets.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field) def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): field = self.widgets[index] if label is None: # Separator / Comment continue elif tuple_to_qfont(value) is not None: value = field.get_font() elif isinstance(value, str) or mcolors.is_color_like(value): value = str(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) if isinstance(value[0], (list, tuple)): value = value[index][0] else: value = value[index] elif isinstance(value, bool): value = field.checkState() == QtCore.Qt.Checked elif isinstance(value, Integral): value = int(field.value()) elif isinstance(value, Real): value = float(str(field.text())) elif isinstance(value, datetime.datetime): value = field.dateTime().toPyDateTime() elif isinstance(value, datetime.date): value = field.date().toPyDate() else: value = eval(str(field.text())) valuelist.append(value) return valuelist
def __init__(self,wib_server='127.0.0.1',config='default.json',rows=1,cols=1,layout=None): super().__init__() plot_layout = layout self.context = zmq.Context() self.socket = self.context.socket(zmq.REQ) self.socket.connect('tcp://%s:1234'%wib_server) self.config = config self.samples = None self.timestamps = None self._main = QtWidgets.QWidget() self._main.setFocusPolicy(QtCore.Qt.StrongFocus) self.setCentralWidget(self._main) layout = QtWidgets.QVBoxLayout(self._main) button_layout = QtWidgets.QHBoxLayout() button = QtWidgets.QPushButton('Reshape') button_layout.addWidget(button) button.setToolTip('Change the plot grid shape') button.clicked.connect(self.reshape_prompt) button = QtWidgets.QPushButton('Load Layout') button_layout.addWidget(button) button.setToolTip('Save plot layout and selected signals') button.clicked.connect(self.load_layout) button = QtWidgets.QPushButton('Save Layout') button_layout.addWidget(button) button.setToolTip('Load plot layout and selected signals') button.clicked.connect(self.save_layout) layout.addLayout(button_layout) self.grid = QtWidgets.QGridLayout() self.views = [] self.reshape(rows,cols) layout.addLayout(self.grid) nav_layout = QtWidgets.QHBoxLayout() button = QtWidgets.QPushButton('Configure') nav_layout.addWidget(button) button.setToolTip('Configure WIB and front end') button.clicked.connect(self.configure_wib) button = QtWidgets.QPushButton('Enable Pulser') nav_layout.addWidget(button) button.setToolTip('Toggle calibration pulser') button.clicked.connect(self.toggle_pulser) self.pulser_button = button button = QtWidgets.QPushButton('Acquire') nav_layout.addWidget(button) button.setToolTip('Read WIB Spy Buffer') button.clicked.connect(self.acquire_data) button = QtWidgets.QPushButton('Continuous') nav_layout.addWidget(button) button.setToolTip('Repeat acquisitions until stopped') button.clicked.connect(self.toggle_continuious) self.continuious_button = button self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.acquire_data) layout.addLayout(nav_layout) if plot_layout: self.load_layout(plot_layout) self.plot_selected()
import time import pickle import argparse import numpy as np import zmq import json from collections import deque import wib_pb2 as wib try: from matplotlib.backends.qt_compat import QtCore, QtWidgets, QtGui except: from matplotlib.backends.backend_qt4agg import QtCore, QtWidgets, QtGui if int(QtCore.qVersion().split('.')[0]) >= 5: from matplotlib.backends.backend_qt5agg import ( FigureCanvas, NavigationToolbar2QT as NavigationToolbar) else: from matplotlib.backends.backend_qt4agg import ( FigureCanvas, NavigationToolbar2QT as NavigationToolbar) class CustomNavToolbar(NavigationToolbar): NavigationToolbar.toolitems = ( ('Signals','Choose signal traces to show', 'choose', 'choose'), ('Autoscale', 'Autoscale axes for each new event', 'autoscale','autoscale'), ('Legend', 'Toggle legend', 'legend','legend'), (None, None, None, None), ('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous view', 'back', 'back'), ('Forward', 'Forward to next view', 'forward', 'forward'),
import sys import time import numpy as np from matplotlib.backends.qt_compat import QtCore, QtWidgets if QtCore.qVersion() >= "5.": from matplotlib.backends.backend_qt5agg import ( FigureCanvas, NavigationToolbar2QT as NavigationToolbar) else: from matplotlib.backends.backend_qt4agg import ( FigureCanvas, NavigationToolbar2QT as NavigationToolbar) from matplotlib.figure import Figure class ApplicationWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self._main = QtWidgets.QWidget() self.setCentralWidget(self._main) layout = QtWidgets.QVBoxLayout(self._main) static_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(static_canvas) self.addToolBar(NavigationToolbar(static_canvas, self)) dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(dynamic_canvas) self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(dynamic_canvas, self))
def setup(self): for label, value in self.data: if DEBUG: print("value:", value) if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtWidgets.QLabel(" "), QtWidgets.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtWidgets.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif label.lower() not in BLACKLIST and is_color_like(value): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, six.string_types): field = QtWidgets.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) selindex = value.pop(0) field = QtWidgets.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, int): print("Warning: '%s' index is invalid (label: " "%s, value: %s)" % (selindex, label, value), file=STDERR) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtWidgets.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, float): field = QtWidgets.QLineEdit(repr(value), self) field.setCursorPosition(0) field.setValidator(QtGui.QDoubleValidator(field)) field.validator().setLocale(QtCore.QLocale("C")) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, int): field = QtWidgets.QSpinBox(self) field.setRange(-1e9, 1e9) field.setValue(value) elif isinstance(value, datetime.datetime): field = QtWidgets.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtWidgets.QDateEdit(self) field.setDate(value) else: field = QtWidgets.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field)
class Start(QMainWindow): clicked = QtCore.pyqtSignal() def __init__(self, parent=None): super(Start, self).__init__() self.ui = parent self.sens_objects = { } ## Collection of Sensor objects for station for one month self.home() def home(self): print("HOME CALLED") # print("static_canvas",self.static_canvas) self.ui.mplwidget_top.canvas.figure.clf() self.ui.mplwidget_bottom.canvas.figure.clf() self._static_ax = self.ui.mplwidget_top.canvas.figure.subplots() self._static_fig = self.ui.mplwidget_top.canvas.figure self.pid = -99 self.cid = -98 self.toolbar1 = self._static_fig.canvas.toolbar # Get the toolbar handler self.toolbar1.update() # Update the toolbar memory # self._residual_fig = self.ui.mplwidget_bottom.canvas.figure self._residual_ax = self.ui.mplwidget_bottom.canvas.figure.subplots() self.ui.save_btn.clicked.connect(self.save_to_ts_files) self.ui.ref_level_btn.clicked.connect(self.show_ref_dialog) def make_sensor_buttons(self, sensors): # Remove all sensor checkbox widgets from the layout # every time new data is loaded for i in range(self.ui.verticalLayout_left_top.count()): item = self.ui.verticalLayout_left_top.itemAt(i) # self.verticalLayout_left_top.removeWidget(item.widget()) widget = item.widget() if widget is not None: widget.deleteLater() for i in range(self.ui.verticalLayout_bottom.count()): item = self.ui.verticalLayout_bottom.itemAt(i) # self.verticalLayout_left_top.removeWidget(item.widget()) widget = item.widget() if widget is not None: widget.deleteLater() # sensors' keys are names of all sensors which carry # all of the data associated with it # Make copy of it so we can use its keys and assign radio buttons to it # If we do not make a copy then the sensors values would get # overwritten by radio button objects self.sensor_dict = dict(sensors) self.sensor_dict2 = dict(sensors) # Counter added to figure out when the last item was added # Set alignment of the last item to push all the radio buttons up counter = len(sensors.items()) for key, value in sensors.items(): counter -= 1 self.sensor_radio_btns = QtWidgets.QRadioButton(key, self) self.sensor_check_btns = QtWidgets.QCheckBox(key, self) self.sensor_dict[key] = self.sensor_radio_btns self.sensor_dict2[key] = self.sensor_check_btns self.ui.buttonGroup_data.addButton(self.sensor_dict[key]) self.ui.buttonGroup_residual.addButton(self.sensor_dict2[key]) if (counter > 0): self.ui.verticalLayout_left_top.addWidget( self.sensor_dict[key]) self.ui.verticalLayout_bottom.addWidget(self.sensor_dict2[key]) else: self.ui.verticalLayout_left_top.addWidget( self.sensor_dict[key], 0, QtCore.Qt.AlignTop) self.ui.verticalLayout_bottom.addWidget( self.sensor_dict2[key], 0, QtCore.Qt.AlignTop) self.sensor_dict[key].setText(key) # radio_btn_HF = QtWidgets.QRadioButton("Minute", self) # radio_btn_HF.setChecked(True) self.mode = self.ui.radioButton_Minute.text() self.sensor_dict["PRD"].setChecked(True) self.sens_str = "PRD" # self.sensor_dict2["PRD"].setEnabled(False) self.sensor_dict2["ALL"].setEnabled(False) self.plot(all=False) self.ui.buttonGroup_data.buttonClicked.connect(self.on_sensor_changed) self.ui.buttonGroup_residual.buttonClicked.connect( self.on_residual_sensor_changed) self.ui.buttonGroup_resolution.buttonClicked.connect( self.on_frequency_changed) def on_sensor_changed(self, btn): print(btn.text()) if (btn.text() == "ALL"): # TODO: plot_all and plot should be merged to one function self.ui.save_btn.setEnabled(False) self.ui.ref_level_btn.setEnabled(False) self.plot(all=True) else: self.ui.save_btn.setEnabled(True) self.ui.ref_level_btn.setEnabled(True) self.sens_str = btn.text() self._update_top_canvas(btn.text()) self.ui.lineEdit.setText( self.sens_objects[self.sens_str].header[0]) self.update_graph_values() # Update residual buttons and graph when the top sensor is changed # self.on_residual_sensor_changed(None) # Clear residual buttons and graph when the top sensor is changed for button in self.ui.buttonGroup_residual.buttons(): button.setChecked(False) self._residual_ax.cla() self._residual_ax.figure.canvas.draw() # print("ref height:",self.sens_objects[self.sens_str].height) def on_frequency_changed(self, btn): print("Frequency changed", btn.text()) self.mode = btn.text() if (self.mode == "Minute"): self.sensor_dict2["PRD"].setEnabled(True) else: self.sensor_dict2["PRD"].setEnabled(False) self.on_residual_sensor_changed() def update_graph_values(self): # convert 'nans' back to 9999s nan_ind = np.argwhere(np.isnan(self.browser.data)) self.browser.data[nan_ind] = 9999 # we want the sensor data object to point to self.browser.data and not self.browser.data.copy() # because when the self.browser.data is modified on the graph # the sensor data object will automatically be modified as well self.sens_objects[self.sens_str].data = self.browser.data def on_residual_sensor_changed(self): self._residual_ax.cla() self._residual_ax.figure.canvas.draw() checkedItems = [ button for button in self.ui.buttonGroup_residual.buttons() if button.isChecked() ] if (checkedItems): for button in checkedItems: self.calculate_and_plot_residuals(self.sens_str, button.text(), self.mode) else: self._residual_ax.cla() self._residual_ax.figure.canvas.draw() def plot(self, all=False): # Set the data browser object to NoneType on every file load self.browser = None self._static_ax.cla() self._residual_ax.cla() self._residual_ax.figure.canvas.draw() if all: lineEditText = 'No Header -- Plotting all sensors' sens_objects = self.sens_objects title = 'Relative levels = signal - average over selected period' else: lineEditText = self.sens_objects[self.sens_str].header[0] sens_objects = [self.sens_str] title = 'Tide Prediction' self.ui.lineEdit.setText(lineEditText) for sens in sens_objects: ## Set 9999s to NaN so they don't show up on the graph ## when initially plotted ## nans are converted back to 9999s when file is saved if sens == "ALL": pass else: data_flat = self.sens_objects[sens].get_flat_data() time = self.sens_objects[sens].get_time_vector() nines_ind = np.where(data_flat == 9999) data_flat[nines_ind] = float('nan') if all: mean = np.nanmean(data_flat) else: mean = 0 # t = np.linspace(0, 10, 501) # t = np.arange(data.size) t = time y = data_flat - mean # self._static_ax.plot(t, np.tan(t), ".") line, = self._static_ax.plot( t, y, '-', picker=5, lw=0.5, markersize=3) # 5 points tolerance # self._static_fig = self.static_canvas.figure if all: line.set_label(sens) self._static_ax.legend() self._static_ax.set_title(title) self._static_ax.autoscale(enable=True, axis='both', tight=True) self._static_ax.set_xlim([t[0], t[-1]]) self._static_ax.margins(0.05, 0.05) self.ui.mplwidget_top.canvas.setFocusPolicy( QtCore.Qt.ClickFocus) self.ui.mplwidget_top.canvas.setFocus() self.ui.mplwidget_top.canvas.figure.tight_layout() # self.toolbar1 = self._static_fig.canvas.toolbar #Get the toolbar handler self.toolbar1.update() # Update the toolbar memory self.ui.mplwidget_top.canvas.draw() def calculate_and_plot_residuals(self, sens_str1, sens_str2, mode): # resample_freq = min(int(self.sens_objects[sens_str1].rate), int(self.sens_objects[sens_str2].rate)) # _freq = str(resample_freq)+'min' # # # Get a date range to create pandas time Series # # using the sampling frequency of the sensor # rng1 = date_range(self.sens_objects[sens_str1].date, periods = self.sens_objects[sens_str1].data.size, freq=_freq) # ts1 = Series(self.sens_objects[sens_str1].data, rng1) # # rng2 = date_range(self.sens_objects[sens_str2].date, periods = self.sens_objects[sens_str2].data.size, freq=_freq) # ts2 = Series(self.sens_objects[sens_str2].data, rng2) # resample the data and linearly interpolate the missing values # upsampled = ts.resample(_freq) # interp = upsampled.interpolate() if mode == "Hourly": data_obj = {} # data_obj["prd"]={'time':filt.datenum2(self.sens_objects["PRD"].get_time_vector()), 'station':'014', 'sealevel':self.sens_objects["PRD"].get_flat_data().copy()} # for key in self.sens_objects.keys(): # print("KEY", key) sl_data = self.sens_objects[sens_str1].get_flat_data().copy() sl_data = self.remove_9s(sl_data) sl_data = sl_data - int(self.sens_objects[sens_str1].height) data_obj[sens_str1.lower()] = { 'time': filt.datenum2(self.sens_objects[sens_str1].get_time_vector()), 'station': '014', 'sealevel': sl_data } sl_data2 = self.sens_objects[sens_str2].get_flat_data().copy() sl_data2 = self.remove_9s(sl_data2) sl_data2 = sl_data2 - int(self.sens_objects[sens_str2].height) data_obj[sens_str2.lower()] = { 'time': filt.datenum2(self.sens_objects[sens_str2].get_time_vector()), 'station': '014', 'sealevel': sl_data2 } year = self.sens_objects[sens_str2].date.astype(object).year month = self.sens_objects[sens_str2].date.astype(object).month data_hr = filt.hr_process_2( data_obj, filt.datetime(year, month, 1, 0, 0, 0), filt.datetime(year, month + 1, 1, 0, 0, 0)) if sens_str1 != "PRD": hr_resid = data_hr[sens_str1.lower()]["sealevel"] - data_hr[ sens_str2.lower()]["sealevel"] time = [ filt.matlab2datetime(tval[0]) for tval in data_hr[list(data_hr.keys())[0]]['time'] ] self.generic_plot(self.ui.mplwidget_bottom.canvas, time, hr_resid, sens_str1, sens_str2, "Hourly Residual", is_interactive=False) else: self.show_custom_message( "Warning", "For hourly residual an actual channel needs to be selected in the top plot." ) self.generic_plot( self.ui.mplwidget_bottom.canvas, [0], [0], sens_str1, sens_str2, "Choose a channel in the top plot other than PRD", is_interactive=False) else: newd1 = self.resample2(sens_str1) newd2 = self.resample2(sens_str2) # newd1 = ts1.resample(_freq).interpolate() # newd2 = ts2.resample(_freq).interpolate() if (newd1.size > newd2.size): resid = newd2 - newd1[:newd2.size] else: resid = newd1 - newd2[:newd1.size] # time = np.array([self.sens_objects[sens_str1].date + np.timedelta64(i*int(1), 'm') for i in range(resid.size)]) # time = np.arange(resid.size) time = date_range(self.sens_objects[sens_str1].date, periods=resid.size, freq='1min') self.generic_plot(self.ui.mplwidget_bottom.canvas, time, resid, sens_str1, sens_str2, "Residual", is_interactive=False) def generic_plot(self, canvas, x, y, sens1, sens2, title, is_interactive): print("GENERIC PLOT CALLED") # self._residual_ax = canvas.figure.subplots() line, = self._residual_ax.plot(x, y, '-', picker=5, lw=0.5, markersize=3) # 5 points tolerance line.set_gid(sens2) self._residual_fig = canvas.figure self._residual_ax.set_title(title) line.set_label(title + ": " + sens1 + " - " + sens2) self._residual_ax.autoscale(enable=True, axis='both', tight=True) self._residual_ax.set_xlim([x[0], x[-1]]) self._residual_ax.margins(0.05, 0.05) self._residual_ax.legend() if (is_interactive): self.browser = PointBrowser(x, y, self._residual_ax, line, self._residual_fig, self.find_outliers(x, y, sens1)) self.browser.onDataEnd += self.show_message canvas.mpl_connect('pick_event', self.browser.onpick) canvas.mpl_connect('key_press_event', self.browser.onpress) ## need to activate focus onto the mpl canvas so that the keyboard can be used canvas.setFocusPolicy(QtCore.Qt.ClickFocus) canvas.setFocus() self._residual_ax.figure.tight_layout() self.toolbar2 = self._residual_fig.canvas.toolbar # Get the toolbar handler self.toolbar2.update() # Update the toolbar memory self._residual_ax.figure.canvas.draw() def _update_top_canvas(self, sens): data_flat = self.sens_objects[sens].get_flat_data() nines_ind = np.where(data_flat == 9999) # nonines_data = data_flat.copy() # nonines_data[nines_ind] = float('nan') # data_flat = nonines_data # data_flat =data_flat - np.nanmean(data_flat) if (len(nines_ind[0]) < data_flat.size): # data_flat[nines_ind] = float('nan') pass else: self.show_custom_message("Warning", "The following sensor has no data") self._static_ax.clear() # disconnect canvas pick and press events when a new sensor is selected # to eliminate multiple callbacks on sensor change # self.static_canvas.mpl_disconnect(self.pidP) # self.static_canvas.mpl_disconnect(self.cidP) self.ui.mplwidget_top.canvas.mpl_disconnect(self.pid) self.ui.mplwidget_top.canvas.mpl_disconnect(self.cid) if self.browser: self.browser.onDataEnd -= self.show_message self.browser.disconnect() # time = np.arange(data_flat.size) time = self.sens_objects[sens].get_time_vector() self.line, = self._static_ax.plot(time, data_flat, '-', picker=5, lw=0.5, markersize=3) self._static_ax.set_title( 'select a point you would like to remove and press "D"') self.browser = PointBrowser(time, data_flat, self._static_ax, self.line, self._static_fig, self.find_outliers(time, data_flat, sens)) self.browser.onDataEnd += self.show_message self.browser.on_sensor_change_update() # update event ids so that they can be disconnect on next sensor change self.pid = self.ui.mplwidget_top.canvas.mpl_connect( 'pick_event', self.browser.onpick) self.cid = self.ui.mplwidget_top.canvas.mpl_connect( 'key_press_event', self.browser.onpress) ## need to activate focus onto the mpl canvas so that the keyboard can be used self.toolbar1.update() self.ui.mplwidget_top.canvas.setFocusPolicy(QtCore.Qt.ClickFocus) self.ui.mplwidget_top.canvas.setFocus() def find_outliers(self, t, data, sens): channel_freq = self.sens_objects[sens].rate _freq = channel_freq + 'min' nines_ind = np.where(data == 9999) nonines_data = data.copy() nonines_data[nines_ind] = float('nan') # Get a date range to create pandas time Series # using the sampling frequency of the sensor rng = date_range(t[0], t[-1], freq=_freq) ts = Series(nonines_data, rng) # resample the data and linearly interpolate the missing values upsampled = ts.resample(_freq) interp = upsampled.interpolate() # calculate a window size for moving average routine so the window # size is always 60 minutes long window_size = 60 // int(channel_freq) # calculate moving average including the interolated data # moving_average removes big outliers before calculating moving average y_av = self.moving_average(np.asarray(interp.tolist()), window_size) # y_av = self.moving_average(data, 30) # missing=np.argwhere(np.isnan(y_av)) # y_av[missing] = np.nanmean(y_av) # calculate the residual between the actual data and the moving average # and then find the data that lies outside of sigma*std residual = nonines_data - y_av std = np.nanstd(residual) sigma = 3.0 itemindex = np.where((nonines_data > y_av + (sigma * std)) | (nonines_data < y_av - (sigma * std))) return itemindex def moving_average(self, data, window_size): """ Computes moving average using discrete linear convolution of two one dimensional sequences. Args: ----- data (pandas.Series): independent variable window_size (int): rolling window size Returns: -------- ndarray of linear convolution References: ------------ [1] Wikipedia, "Convolution", http://en.wikipedia.org/wiki/Convolution. [2] API Reference: https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html """ # REMOVE GLOBAL OUTLIERS FROM MOVING AVERAGE CALCULATION nk filtered_data = data.copy() # my_mad=np.nanmedian(np.abs(filtered_data-np.nanmedian(filtered_data))) # my_mean=np.nanmean(filtered_data) my_mean = np.nanmean(filtered_data) my_std = np.nanstd(filtered_data) # itemindex = np.where(((filtered_data>my_mean+4*my_mad ) | (filtered_data<my_mean-4*my_mad))) itemindex = np.where(((filtered_data > my_mean + 3 * my_std) | (filtered_data < my_mean - 3 * my_std))) filtered_data[itemindex] = np.nanmean(filtered_data) # Fix boundary effects by adding prepending and appending values to the data filtered_data = np.insert( filtered_data, 0, np.ones(window_size) * np.nanmean(filtered_data[:window_size // 2])) filtered_data = np.insert( filtered_data, filtered_data.size, np.ones(window_size) * np.nanmean(filtered_data[-window_size // 2:])) window = np.ones(int(window_size)) / float(window_size) # return (np.convolve(filtered_data, window, 'same')[window_size:-window_size],itemindex) return np.convolve(filtered_data, window, 'same')[window_size:-window_size] def resample2(self, sens_str): data = self.sens_objects[sens_str].data.copy() nines_ind = np.where(data == 9999) data[nines_ind] = float('nan') ave = np.nanmean(data) datas = data[0:-1] - ave # int(self.sens_objects[sens_str].height) datae = data[1:] - ave # int(self.sens_objects[sens_str].height) yc = (datae - datas) / int(self.sens_objects[sens_str].rate) min_data = [] for j in range(0, len(datas)): for i in range(0, int(self.sens_objects[sens_str].rate)): min_data.append(float(datas[j] + yc[j])) # nan_ind = np.argwhere(np.isnan(min_data)) # min_data[nan_ind] = 9999 return np.asarray(min_data) def show_message(self, *args): print("SHOW MESSAGE", *args) # choice = QtWidgets.QMessageBox.information(self, 'The end of data has been reached', 'The end of data has been reached', QtWidgets.QMessageBox.Ok) self.show_custom_message(*args, *args) def show_ref_dialog(self): try: self.browser except AttributeError: self.show_custom_message("Error!", "Data needs to be loaded first.") return else: if (self.is_digit(str(self.ui.refLevelEdit.text()))): # text, result = QtWidgets.QInputDialog.getText(self, 'My Input Dialog', 'Enter start date and time:') date, time, result = DateDialog.getDateTime(self) ISOstring = date.toString('yyyy-MM-dd') + 'T' + time.toString( "HH:mm") if result: REF_diff = int(str(self.ui.refLevelEdit.text())) - int( self.sens_objects[self.sens_str].height) new_REF = REF_diff + int( self.sens_objects[self.sens_str].height) # offset the data self.browser.offset_data(ISOstring, REF_diff) # format the new reference to a 4 character string (i.e add leading zeros if necessary) # update the header new_header = self.sens_objects[self.sens_str].header[0][:60] + '{:04d}'.format(new_REF) + \ self.sens_objects[self.sens_str].header[0][64:] self.sens_objects[self.sens_str].header[0] = new_header self.ui.lineEdit.setText( self.sens_objects[self.sens_str].header[0]) print("Succesfully changed to: ", str(self.ui.refLevelEdit.text())) else: self.show_custom_message("Error!", "The value entered is not a number.") return def is_digit(self, n): try: int(n) return True except ValueError: return False def remove_9s(self, data): nines_ind = np.where(data == 9999) data[nines_ind] = float('nan') return data def show_custom_message(self, title, descrip): choice = QtWidgets.QMessageBox.information(self, title, descrip, QtWidgets.QMessageBox.Ok) def save_to_ts_files(self): # Deleting tkey "ALL" from the list of sensors if "ALL" in self.sens_objects: del self.sens_objects["ALL"] if (self.sens_objects): months = len( self.sens_objects["PRD"].line_num) # amount of months loaded # print("Amount of months loaded", months) assem_data = [ [] for j in range(months) ] # initial an empty list of lists with the number of months nan_ind = np.argwhere(np.isnan(self.browser.data)) # print("NAN INDICES",nan_ind) # self.browser.data[nan_ind] = 9999 # self.sens_objects[self.sens_str].data = self.browser.data # separate PRD from the rest because it has to be saved on the top file # Because dictionaries are unordered prd_list = [[] for j in range(months)] # Cycle through each month loaded for m in range(months): # Cycle through each month loaded, where key is the sensor name # Use value instead of self.sens_objects[key]? for key, value in self.sens_objects.items(): # Add header # separate PRD from the rest because it has to be saved on the top file if (key == "PRD"): prd_list[m].append( self.sens_objects[key].header[m].strip("\n")) else: assem_data[m].append( self.sens_objects[key].header[m].strip("\n")) # The ugly range is calculating start and end line numbers for each month that was Loaded # so that the data can be saved to separate, monthly files for i in range( sum(self.sens_objects[key].line_num[:]) - sum(self.sens_objects[key].line_num[m:]), sum(self.sens_objects[key].line_num[:]) - sum(self.sens_objects[key].line_num[m:]) + self.sens_objects[key].line_num[m]): # File formatting is differs based on the sampling rate of a sensor if (int(self.sens_objects[key].rate) >= 5): # Get only sealevel reading, without anything else (no time/date etc) data = ''.join( '{:5.0f}'.format(e) for e in self.sens_objects[key].data.flatten() [i * 12:12 + i * 12].tolist()) # The columns/rows containing only time/data and no sealevel measurements it_col_formatted = ' ' + self.sens_objects[key].type + ' ' + \ self.sens_objects[key].time_info[i][8:12].strip()[-2:] + \ self.sens_objects[key].time_info[i][12:20] # assem_data.append(info_time_col[i][0:]+data) if (key == "PRD"): prd_list[m].append(''.join(it_col_formatted) + data) else: assem_data[m].append( ''.join(it_col_formatted) + data) else: data = ''.join( '{:4.0f}'.format(e) for e in self.sens_objects[key].data.flatten() [i * 15:15 + i * 15].tolist()) it_col_formatted = ' ' + self.sens_objects[key].type + ' ' + \ self.sens_objects[key].time_info[i][8:12].strip()[-2:] + \ self.sens_objects[key].time_info[i][12:20] # assem_data.append(info_time_col[i][0:]+data) assem_data[m].append(''.join(it_col_formatted) + data) if (key == "PRD"): prd_list[m].append('9' * 80) else: assem_data[m].append('9' * 80) del data # find the start date lines of each monp file that was loaded date_str = self.sens_objects[key].time_info[ sum(self.sens_objects[key].line_num[:]) - sum(self.sens_objects[key].line_num[m:])] month_int = int(date_str[12:14][-2:]) month_str = "{:02}".format(month_int) year_str = date_str[8:12][-2:] station_num = self.sens_objects[key].type[0:-3] file_name = 't' + station_num + year_str + month_str file_extension = '.dat' try: with open( st.get_path(st.SAVE_KEY) + '/' + file_name + file_extension, 'w') as the_file: for lin in prd_list[m]: the_file.write(lin + "\n") for line in assem_data[m]: the_file.write(line + "\n") # Each file ends with two lines of 80 9s that's why adding an additional one the_file.write('9' * 80 + "\n") self.show_custom_message( "Success", "Success \n" + file_name + file_extension + " Saved to " + st.get_path(st.SAVE_KEY) + "\n") except IOError as e: self.show_custom_message( "Error", "Cannot Save to " + st.get_path(st.SAVE_KEY) + "\n" + str(e) + "\n Please select a different path to save to") self.save_fast_delivery(self.sens_objects) self.save_mat_high_fq(file_name) # if result == True: # print("Succesfully changed to: ", str(self.refLevelEdit.text())) else: self.show_custom_message("Warning", "You haven't loaded any data.") # this function is called for every month of data loaded def save_mat_high_fq(self, file_name): import scipy.io as sio if st.get_path(st.HF_PATH): save_path = st.get_path(st.HF_PATH) else: self.show_custom_message( "Warning", "Please select a location where you would like your high " "frequency matlab data " "to be saved. Click save again once selected.") return for key, value in self.sens_objects.items(): sl_data = self.sens_objects[key].get_flat_data().copy() sl_data = self.remove_9s(sl_data) sl_data = sl_data - int(self.sens_objects[key].height) time = filt.datenum2(self.sens_objects[key].get_time_vector()) data_obj = [time, sl_data] # transposing the data so that it matches the shape of the UHSLC matlab format matlab_obj = { 'NNNN': file_name + key.lower(), file_name + key.lower(): np.transpose(data_obj, (1, 0)) } try: sio.savemat(save_path + '/' + file_name + key.lower() + '.mat', matlab_obj) self.show_custom_message( "Success", "Success \n" + file_name + key.lower() + '.mat' + " Saved to " + st.get_path(st.HF_PATH) + "\n") except IOError as e: self.show_custom_message( "Error", "Cannot Save to high frequency (.mat) data to" + st.get_path(st.HF_PATH) + "\n" + str(e) + "\n Please select a different path to save to") def save_fast_delivery(self, _data): import scipy.io as sio # 1. Check if the .din file was added and that it still exist at that path # b) also check that a save folder is set up # 2. If it does. load in the primary channel for our station # 3. If it does not exist, display a warning message on how to add it and that the FD data won't be saved # 4. Perform filtering and save din_path = None save_path = None if st.get_path(st.DIN_PATH): din_path = st.get_path(st.DIN_PATH) else: self.show_custom_message( "Warning", "The fast delivery data cannot be processed because you haven't selected" "the .din file location. Press F1 to access the menu to select it. And " "then click the save button again.") return if st.get_path(st.FD_PATH): save_path = st.get_path(st.FD_PATH) else: self.show_custom_message( "Warning", "Please select a location where you would like your hourly and daily data" "to be saved. Click save again once selected.") return data_obj = {} station_num = _data["PRD"].type[0:-3] primary_sensor = filt.get_channel_priority( din_path, station_num)[0].upper( ) # returns multiple sensor in order of importance if primary_sensor not in _data: self.show_custom_message( "Error", f"Your .din file says that {primary_sensor} " f"is the primary sensor but the file you have loaded does " f"not contain that sensor. Hourly and daily data will not be saved." ) return sl_data = _data[primary_sensor].get_flat_data().copy() sl_data = self.remove_9s(sl_data) sl_data = sl_data - int(_data[primary_sensor].height) data_obj[primary_sensor.lower()] = { 'time': filt.datenum2(_data[primary_sensor].get_time_vector()), 'station': station_num, 'sealevel': sl_data } year = _data[primary_sensor].date.astype(object).year month = _data[primary_sensor].date.astype(object).month # Filter to hourly data_hr = filt.hr_process_2(data_obj, filt.datetime(year, month, 1, 0, 0, 0), filt.datetime(year, month + 1, 1, 0, 0, 0)) # for channel parameters see filt.channel_merge function # We are not actually merging channels here (not needed for fast delivery) # But we still need to run the data through the merge function, even though we are only using one channel # in order to get the correct output data format suitable for the daily filter ch_params = [{primary_sensor.lower(): 0}] hourly_merged = filt.channel_merge(data_hr, ch_params) # Note that hourly merged returns a channel attribute which is an array of integers representing channel type. # used for a particular day of data. In Fast delivery, all the number should be the same because no merge # int -> channel name mapping is inside of filtering.py var_flag function data_day = filt.day_119filt(hourly_merged, _data[primary_sensor].location[0]) month_str = "{:02}".format(month) hourly_filename = save_path + '/' + 'th' + str(station_num) + str( year)[-2:] + month_str + '.mat' daily_filename = save_path + '/' + 'da' + str(station_num) + str( year)[-2:] + month_str + '.mat' sio.savemat(hourly_filename, data_hr) sio.savemat(daily_filename, data_day) self.show_custom_message( "Success", "Success \n Hourly and Daily Date Saved to " + st.get_path(st.FD_PATH) + "\n") monthly_mean = np.round(np.nanmean(data_day['sealevel'])).astype(int) # Remove nans, replace with 9999 to match the legacy files nan_ind = np.argwhere(np.isnan(data_day['sealevel'])) data_day['sealevel'][nan_ind] = 9999 sl_round_up = np.round(data_day['sealevel']).astype( int) # round up sealevel data and convert to int # right justify with 5 spaces sl_str = [str(x).rjust(5, ' ') for x in sl_round_up] # convert data to string daily_filename = save_path + '/' + 'da' + str(station_num) + str( year)[-2:] + month_str + '.dat' # format the date and name strings to match the legacy .dat format month_str = str(month).rjust(2, ' ') station_name = _data[primary_sensor].name.ljust(7) line_begin_str = f'{station_name}WOC {year}{month_str}' counter = 1 try: with open(daily_filename, 'w') as the_file: for i, sl in enumerate(sl_str): if i % 11 == 0: line_str = line_begin_str + str( counter) + " " + ''.join(sl_str[i:i + 11]) if counter == 3: line_str = line_str.ljust(75) final_str = line_str[:-5] + str(monthly_mean) line_str = final_str the_file.write(line_str + "\n") counter += 1 except IOError as e: self.show_custom_message( "Error", "Cannot Save to " + daily_filename + "\n" + str(e) + "\n Please select a different path to save to")
def __init__(self, parent=None): super().__init__(parent) self.setFixedSize(20, 20) self.setIconSize(QtCore.QSize(12, 12)) self.clicked.connect(self.choose_color) self._color = QtGui.QColor()
class FormWidget(QtWidgets.QWidget): update_buttons = QtCore.Signal() def __init__(self, data, comment="", parent=None): QtWidgets.QWidget.__init__(self, parent) self.data = copy.deepcopy(data) self.widgets = [] self.formlayout = QtWidgets.QFormLayout(self) if comment: self.formlayout.addRow(QtWidgets.QLabel(comment)) self.formlayout.addRow(QtWidgets.QLabel(" ")) def get_dialog(self): """Return FormDialog instance""" dialog = self.parent() while not isinstance(dialog, QtWidgets.QDialog): dialog = dialog.parent() return dialog def setup(self): for label, value in self.data: if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtWidgets.QLabel(" "), QtWidgets.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtWidgets.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif (label.lower() not in BLACKLIST and mcolors.is_color_like(value)): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, str): field = QtWidgets.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) # Note: get() below checks the type of value[0] in self.data so # it is essential that value gets modified in-place. # This means that the code is actually broken in the case where # value is a tuple, but fortunately we always pass a list... selindex = value.pop(0) field = QtWidgets.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, Integral): _log.warning( "index '%s' is invalid (label: %s, value: %s)", selindex, label, value) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtWidgets.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, Integral): field = QtWidgets.QSpinBox(self) field.setRange(-1e9, 1e9) field.setValue(value) elif isinstance(value, Real): field = QtWidgets.QLineEdit(repr(value), self) field.setCursorPosition(0) field.setValidator(QtGui.QDoubleValidator(field)) field.validator().setLocale(QtCore.QLocale("C")) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, datetime.datetime): field = QtWidgets.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtWidgets.QDateEdit(self) field.setDate(value) else: field = QtWidgets.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field) def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): field = self.widgets[index] if label is None: # Separator / Comment continue elif tuple_to_qfont(value) is not None: value = field.get_font() elif isinstance(value, str) or mcolors.is_color_like(value): value = str(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) if isinstance(value[0], (list, tuple)): value = value[index][0] else: value = value[index] elif isinstance(value, bool): value = field.checkState() == QtCore.Qt.Checked elif isinstance(value, Integral): value = int(field.value()) elif isinstance(value, Real): value = float(str(field.text())) elif isinstance(value, datetime.datetime): value = field.dateTime().toPyDateTime() elif isinstance(value, datetime.date): value = field.date().toPyDate() else: value = eval(str(field.text())) valuelist.append(value) return valuelist
def __init__(self, *args, **kwargs): MyMplCanvas.__init__(self, *args, **kwargs) timer = QtCore.QTimer(self) timer.timeout.connect(self.update_figure) timer.start(20)
class ColorBarWidget(QW.QWidget): """ Contains the colour bar and controls to change bounds """ valueChanged = QtCore.Signal(float, float) def __init__(self): super().__init__() main_layout = QW.QVBoxLayout(self) figure = Figure() figure.set_frameon(False) self.canvas = FigureCanvas(figure) self.canvas.setStyleSheet("background-color:transparent;") self.axis = self.canvas.figure.add_axes([0, 0.05, 0.2, 0.9]) self.upperTextBox = QW.QLineEdit() self.lowerTextBox = QW.QLineEdit() main_layout.addWidget(self.upperTextBox) main_layout.addWidget(self.canvas) main_layout.addWidget(self.lowerTextBox) self.upperTextBox.returnPressed.connect(self._update_bounds) self.lowerTextBox.returnPressed.connect(self._update_bounds) #: Colour bar limits self.bounds = [numpy.nan, numpy.nan] self.setFixedWidth(80) def setBounds(self, bounds): self.bounds = bounds self.lowerTextBox.setText("%.2e" % bounds[0]) self.upperTextBox.setText("%.2e" % bounds[1]) def redraw(self, plot): """ Redraw the colour bar """ self.axis.clear() if plot is not None: plt.colorbar(plot, cax=self.axis) self.canvas.draw() def get_plot_args(self): kwargs = {} if self.bounds[0] < 0 < self.bounds[1]: kwargs['vmax'] = numpy.abs(self.bounds).max() kwargs['vmin'] = -kwargs['vmax'] else: kwargs['vmin'] = self.bounds[0] kwargs['vmax'] = self.bounds[1] return kwargs def _update_bounds(self): values = [self.lowerTextBox.text(), self.upperTextBox.text()] self.bounds = numpy.array(values, dtype=self.bounds.dtype) self.valueChanged.emit(self.bounds[0], self.bounds[1])
def __init__(self, parent=None): QtWidgets.QPushButton.__init__(self, parent) self.setFixedSize(20, 20) self.setIconSize(QtCore.QSize(12, 12)) self.clicked.connect(self.choose_color) self._color = QtGui.QColor()
class FormWidget(QtWidgets.QWidget): update_buttons = QtCore.Signal() def __init__(self, data, comment="", parent=None): QtWidgets.QWidget.__init__(self, parent) from copy import deepcopy self.data = deepcopy(data) self.widgets = [] self.formlayout = QtWidgets.QFormLayout(self) if comment: self.formlayout.addRow(QtWidgets.QLabel(comment)) self.formlayout.addRow(QtWidgets.QLabel(" ")) if DEBUG: print("\n" + ("*" * 80)) print("DATA:", self.data) print("*" * 80) print("COMMENT:", comment) print("*" * 80) def get_dialog(self): """Return FormDialog instance""" dialog = self.parent() while not isinstance(dialog, QtWidgets.QDialog): dialog = dialog.parent() return dialog def setup(self): for label, value in self.data: if DEBUG: print("value:", value) if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtWidgets.QLabel(" "), QtWidgets.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtWidgets.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif label.lower() not in BLACKLIST and is_color_like(value): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, six.string_types): field = QtWidgets.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) selindex = value.pop(0) field = QtWidgets.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, int): print("Warning: '%s' index is invalid (label: " "%s, value: %s)" % (selindex, label, value), file=STDERR) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtWidgets.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, float): field = QtWidgets.QLineEdit(repr(value), self) field.setCursorPosition(0) field.setValidator(QtGui.QDoubleValidator(field)) field.validator().setLocale(QtCore.QLocale("C")) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, int): field = QtWidgets.QSpinBox(self) field.setRange(-1e9, 1e9) field.setValue(value) elif isinstance(value, datetime.datetime): field = QtWidgets.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtWidgets.QDateEdit(self) field.setDate(value) else: field = QtWidgets.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field) def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): field = self.widgets[index] if label is None: # Separator / Comment continue elif tuple_to_qfont(value) is not None: value = field.get_font() elif isinstance(value, six.string_types) or is_color_like(value): value = six.text_type(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) if isinstance(value[0], (list, tuple)): value = value[index][0] else: value = value[index] elif isinstance(value, bool): value = field.checkState() == QtCore.Qt.Checked elif isinstance(value, float): value = float(str(field.text())) elif isinstance(value, int): value = int(field.value()) elif isinstance(value, datetime.datetime): value = field.dateTime().toPyDateTime() elif isinstance(value, datetime.date): value = field.date().toPyDate() else: value = eval(str(field.text())) valuelist.append(value) return valuelist
class Teleporter(QtCore.QObject): name_doc_escape = QtCore.Signal(str, dict, object)
class HelpScreen(QMainWindow): clicked = QtCore.pyqtSignal() def __init__(self, parent=None): super(HelpScreen, self).__init__() # Object for data persistence # self.settings = QtCore.QSettings('UHSLC', 'com.uhslc.qcsoft') # st.SETTINGS.remove("savepath") self.ui = parent # If a save path hasn't been defined, give it a home directory if (st.get_path(st.SAVE_KEY)): self.ui.lineEditPath.setPlaceholderText(st.get_path(st.SAVE_KEY)) else: st.SETTINGS.setValue(st.SAVE_KEY, os.path.expanduser('~')) self.ui.lineEditPath.setPlaceholderText(os.path.expanduser('~')) self.ui.lineEditLoadPath.setPlaceholderText(st.get_path(st.LOAD_KEY)) # If a fast delivery save path hasn't been defined, give it a home directory if (st.get_path(st.FD_PATH)): self.ui.lineEditFDPath.setPlaceholderText(st.get_path(st.FD_PATH)) else: st.SETTINGS.setValue(st.FD_PATH, os.path.expanduser('~')) self.ui.lineEditFDPath.setPlaceholderText(os.path.expanduser('~')) # If a high frequency data save path hasn't been defined, give it a home directory if (st.get_path(st.HF_PATH)): self.ui.lineEditHFPath.setPlaceholderText(st.get_path(st.HF_PATH)) else: st.SETTINGS.setValue(st.HF_PATH, os.path.expanduser('~')) self.ui.lineEditHFPath.setPlaceholderText(os.path.expanduser('~')) if st.get_path(st.DIN_PATH): self.ui.lineEdit_din.setPlaceholderText(st.get_path(st.DIN_PATH)) saveButton = self.ui.pushButton_save_folder loadButton = self.ui.pushButton_load_folder dinSave = self.ui.pushButton_din FDSave = self.ui.pushButton_fd_folder hf_save = self.ui.pushButton_hf_data saveButton.clicked.connect( lambda: self.savePath(self.ui.lineEditPath, st.SAVE_KEY)) loadButton.clicked.connect( lambda: self.savePath(self.ui.lineEditLoadPath, st.LOAD_KEY)) dinSave.clicked.connect( lambda: self.saveDIN(self.ui.lineEdit_din, st.DIN_PATH)) FDSave.clicked.connect( lambda: self.savePath(self.ui.lineEditFDPath, st.FD_PATH)) hf_save.clicked.connect( lambda: self.savePath(self.ui.lineEditFDPath, st.HF_PATH)) def savePath(self, lineEditObj, setStr): folder_name = QtWidgets.QFileDialog.getExistingDirectory( self, 'Select a Folder') if (folder_name): st.SETTINGS.setValue(setStr, folder_name) st.SETTINGS.sync() lineEditObj.setPlaceholderText(st.get_path(setStr)) lineEditObj.setText("") else: pass def saveDIN(self, lineEditObj, setStr): filters = "*.din" if st.DIN_PATH: path = st.DIN_PATH else: path = os.path.expanduser('~') file_name = QtWidgets.QFileDialog.getOpenFileNames( self, 'Open File', path, filters) if (file_name): st.SETTINGS.setValue(setStr, file_name[0][0]) st.SETTINGS.sync() lineEditObj.setPlaceholderText(st.get_path(setStr)) lineEditObj.setText("") else: pass