#!/usr/bin/env python3 from PyQt5 import QtCore from PyQt5 import QtWidgets from PyQt5 import QtGui from PyQt5 import QtPrintSupport from rawprasslib import load_raw from rawprasslib import rawprasslib from prasopes.predictmz import predict as getmzpattern try: from rawautoparams import load_params autoparams = True except ImportError: autoparams = False import numpy as np import prasopes.config as cf import prasopes.datatools as dt import prasopes.drltools as drl import prasopes.filetools as ft import prasopes.graphtools as gt import prasopes.imagetools as imgt import prasopes.zcetools as zce import prasopes.docks as docks import prasopes.tangoicons import sys import logging import os.path class update_signal(QtCore.QObject): signal = QtCore.pyqtSignal() class QStatusBarLogger(logging.Handler): def __init__(self, parent=None): super().__init__() self.statusBar = QtWidgets.QStatusBar(parent) self.trigger = update_signal() self.msg = str("") def emit(self, record): self.msg = self.format(record) self.trigger.signal.emit() def load_file(parent, augCanvas, update, settings, loadthread, filename=None): """populates dataset and plots it""" directory = augCanvas.filename or settings.value("open_folder") filename = filename or QtWidgets.QFileDialog.getOpenFileName( caption="Open spectrum", directory=directory, filter="Finnigan RAW files (*.raw, *.RAW)")[0] if filename != '' and os.path.isfile(filename)\ and not os.path.isdir(filename): error = update_signal() errormsg = [] def runfnc(): try: [i.clear() for i in ( augCanvas.ds, augCanvas.chrom['timesarg'], augCanvas.ms['params'], augCanvas.ms['headers'])] [augCanvas.ds.append(dict( chrom_dat=i[0], masses=i[1], matrix=i[2])) for i in load_raw(filename, settings.value("tmp_location"))] except rawprasslib.ParsingException as pex: errormsg.append("Opening of the file has failed!") errormsg.append( "File is incompatible with the rawprasslib, " "canceling request!\n\n" "Error message:\n{}".format(pex.args[0])) error.signal.emit() return if autoparams: try: (augCanvas.ms['params'], rawheaders, augCanvas.chrom['machtype']) = load_params(filename) segments = [len(subset['chrom_dat'][0]) for subset in augCanvas.ds] indicies = [sum(segments[:i+1]) for i in range(len(segments))] augCanvas.ms['headers'] = np.split( rawheaders, indicies)[:-1] except Exception as pex: errormsg.append( "File is incompatible with the rawautoparams,") errormsg.append( "no parameters loaded!\n\n" "Error message:\n{}".format(pex.args[0])) error.signal.emit() gt.populate(augCanvas) augCanvas.filename = filename parent.setWindowTitle("Prasopes - {}".format( os.path.basename(filename))) oldrecents = settings.value("recents") oldrecents.remove(filename) if filename in oldrecents else None settings.setValue("recents", [filename, *oldrecents]) update.signal.emit() loadthread.quit() error.signal.connect(lambda: QtWidgets.QMessageBox.critical( parent, errormsg[0], errormsg[1])) loadthread.run = runfnc loadthread.start() def print_graph(augCanvas): def printimage(printdevice, img): printer.setResolution(600) painter = QtGui.QPainter(printdevice) font = painter.font() linesize = printer.resolution()/15 font.setPixelSize(linesize) painter.setFont(font) painter.drawImage(0, 0, img) offset = img.size().height() line = 1 spacing = 1.5 for row in range(augCanvas.paramstable.rowCount()): if augCanvas.paramstable.cellWidget(row, 0).checkState() == 2: text = augCanvas.paramstable.item(row, 1).text() +\ augCanvas.paramstable.item(row, 2).text() painter.drawText(300, int(offset+line*linesize*spacing), text) line += 1 painter.end() # TODO: substitute the QPrintPreviewDialog with QPrintPreviewWidget printPreview = QtPrintSupport.QPrintPreviewDialog() printer = printPreview.printer() printer.setPageSize(printer.A5) printer.setDuplex(printer.DuplexNone) image = imgt.paint_image(augCanvas.ms, augCanvas.spectplot, augCanvas.filename, printer) printPreview.paintRequested.connect(lambda: printimage(printer, image)) printPreview.exec() def update_spectrum(augCanvas, config): if augCanvas.filename: slims = [augCanvas.spectplot.get_xlim(), augCanvas.spectplot.get_ylim()] augCanvas.ds.clear() [augCanvas.ds.append(dict(chrom_dat=i[0], masses=i[1], matrix=i[2])) for i in load_raw(augCanvas.filename, config.value("tmp_location"))] gt.populate(augCanvas) augCanvas.spectplot.set_xlim(slims[0]) augCanvas.spectplot.set_ylim(slims[1]) gt.ann_spec(augCanvas.spectplot, augCanvas.ms) augCanvas.draw() def update_recents(rcm, main_window, augCanvas, update, config, loadthread): rcm.clear() # Actions need to be stored somewhere. Otherwise they end up in garbage. rcm.actionCache = [] for i, j in enumerate(config.value("recents"), start=1): rcm.actionCache.append(QtWidgets.QAction("&{}. {}".format(i, j), None)) rcm.actionCache[-1].triggered.connect(lambda _, fn=j: load_file( main_window, augCanvas, update, config, loadthread, filename=fn)) rcm.actionCache.append(rcm.addSeparator()) rcm.actionCache.append(QtWidgets.QAction("Clear Recents", None)) [rcm.actionCache[-1].triggered.connect(i) for i in ( lambda: config.setValue("recents", ""), lambda: update_recents( rcm, main_window, augCanvas, update, config, loadthread))] rcm.addActions(rcm.actionCache) def dropped(event, parent, augCanvas, update, config, loadthread): dropurl = event.mimeData().urls()[0].toLocalFile() load_file(parent, augCanvas, update, config, loadthread, filename=dropurl) def drag_entered(event): if event.mimeData().hasUrls() and event.mimeData().urls()[0]\ .toLocalFile().lower().endswith('.raw'): event.accept() def predictmz(form, augCanvas): text = form.text() if text == "": augCanvas.ms["predict"] = None return slims = [augCanvas.spectplot.get_xlim(), augCanvas.spectplot.get_ylim()] augCanvas.ms["predict"] = getmzpattern(text) gt.populate(augCanvas) augCanvas.spectplot.set_xlim(slims[0]) augCanvas.spectplot.set_ylim(slims[1]) augCanvas.draw() def oddeven_changed(augCanvas, config, oddevenact): config.setValue("view/oddeven", oddevenact.isChecked()) update_spectrum(augCanvas, config) def key_pressed(event, augCanvas, config): if event.key() == QtCore.Qt.Key_F5: update_spectrum(augCanvas, config) if event.key() == QtCore.Qt.Key_C: if event.modifiers().__int__() == QtCore.Qt.ControlModifier: if augCanvas.paramstable.underMouse(): dt.clip_tablestr(augCanvas) else: imgt.clip_spect_img(augCanvas.ms, augCanvas.spectplot, augCanvas.filename) if event.modifiers().__int__() == QtCore.Qt.ControlModifier + \ QtCore.Qt.ShiftModifier: dt.clip_spectstr(augCanvas) if event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right): gt.shift_times(event, augCanvas) def about(parent): """constructs window with "about" info""" QtWidgets.QMessageBox.information( parent, "About Prasopes", "Prasopes Finnigan raw file viewer\n\n" "Version: 0.0.13 (alpha)") def main(): app = QtWidgets.QApplication(sys.argv) loadthread = QtCore.QThread() augCanvas = gt.AugFigureCanvas() update = update_signal() config = cf.settings() barHandler = QStatusBarLogger() barHandler.trigger.signal.connect( lambda: barHandler.statusBar.showMessage(barHandler.msg)) p_logger = logging.getLogger('parseLogger') params_logger = logging.getLogger('acqLogLogger') drl_logger = logging.getLogger('drlLogger') zce_logger = logging.getLogger('zceLogger') logging.basicConfig() # p_logger.setLevel("WARN") p_logger.setLevel("DEBUG") # drl_logger.setLevel("INFO") drl_logger.setLevel("DEBUG") zce_logger.setLevel("DEBUG") # params_logger.setLevel("DEBUG") p_logger.addHandler(barHandler) zce_logger.addHandler(barHandler) params_logger.addHandler(barHandler) barHandler.setLevel("DEBUG") main_window = QtWidgets.QMainWindow(windowTitle="Prasopes") if QtGui.QIcon.themeName() == "": QtGui.QIcon.setThemeName("TangoMFK") consoledock = docks.consoleDockWidget( locals(), "&Console", "view/consolevisible") treedock = docks.treeDockWidget( "&File browser", "view/filebrowservisible", update, load_file, main_window, augCanvas, config, loadthread) paramsdock = docks.AugDock("Acquisition parameters", "&Acq parameters", "view/acqparvisible") update.signal.connect(lambda: gt.update_paramstable(augCanvas)) paramsdock.setWidget(augCanvas.paramstable) openact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "document-open"), "&Open...", None) openact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_O) openact.triggered.connect(lambda: load_file( main_window, augCanvas, update, config, loadthread)) exportact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "document-save-as"), "&Export...", None) exportact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_E) exportact.triggered.connect(lambda: ft.export_dial( augCanvas, main_window)) printact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "document-print"), "&Print", None) printact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_P) printact.triggered.connect(lambda: print_graph(augCanvas)) settingsact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "preferences-system"), "&Settings...", None) settingsact.triggered.connect(lambda: cf.dial(main_window)) quitact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "application-exit"), "&Quit", None) quitact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_Q) quitact.triggered.connect(main_window.close) zceact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "applications-utilities"), "&TSQ zce...", None) zceact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_T) zceact.triggered.connect(lambda: zce.dialog( main_window, augCanvas, update)) drlact = QtWidgets.QAction(QtGui.QIcon.fromTheme( "applications-utilities"), "&DRL...", None) drlact.setShortcut(QtCore.Qt.CTRL + QtCore.Qt.Key_D) drlact.triggered.connect(lambda: drl.main_window( main_window, augCanvas, update)) aboutact = QtWidgets.QAction("&About Prasopes", None) aboutact.triggered.connect(lambda: about(main_window)) autozoomy = QtWidgets.QAction(QtGui.QIcon.fromTheme( "zoom-original"), "Auto Zoom Y", None, checkable=True, checked=config.value("view/autozoomy", type=bool)) autozoomy.triggered.connect(lambda: config.setValue( "view/autozoomy", autozoomy.isChecked())) autozoomy.triggered.connect(lambda: gt.autozoomy(augCanvas.spectplot)) intensitiesact = QtWidgets.QAction( "&Show intensities", None, checkable=True, checked=config.value("view/intensities", type=bool)) intensitiesact.triggered.connect(lambda: config.setValue( "view/intensities", intensitiesact.isChecked())) intensitiesact.triggered.connect(lambda: gt.ann_spec( augCanvas.spectplot, augCanvas.ms)) intensitiesact.triggered.connect(lambda: augCanvas.draw()) oddevenact = QtWidgets.QAction( "&Odd / even", None, checkable=True, checked=config.value("view/oddeven", type=bool)) oddevenact.triggered.connect( lambda: oddeven_changed(augCanvas, config, oddevenact)) predictform = QtWidgets.QLineEdit(maximumWidth=150) predictform.editingFinished.connect(lambda: predictmz( predictform, augCanvas)) recents_menu = QtWidgets.QMenu('Open &Recent', main_window) update_recents(recents_menu, main_window, augCanvas, update, config, loadthread) update.signal.connect(lambda: update_recents( recents_menu, main_window, augCanvas, update, config, loadthread)) file_menu = QtWidgets.QMenu('&File', main_window) main_window.menuBar().addMenu(file_menu) file_menu.addAction(openact) file_menu.addMenu(recents_menu) file_menu.addAction(exportact) file_menu.addSeparator() file_menu.addAction(printact) file_menu.addSeparator() file_menu.addAction(settingsact) file_menu.addSeparator() file_menu.addAction(quitact) tools_menu = QtWidgets.QMenu('&Tools', main_window) main_window.menuBar().addMenu(tools_menu) tools_menu.addAction(zceact) tools_menu.addAction(drlact) tools_menu.addSeparator() view_menu = QtWidgets.QMenu('&View', main_window) [view_menu.addAction(i.action) for i in (treedock, paramsdock, consoledock)] [view_menu.addAction(i) for i in (autozoomy, intensitiesact)] view_menu.addSeparator() view_menu.addAction(oddevenact) main_window.menuBar().addMenu(view_menu) help_menu = QtWidgets.QMenu('&Help', main_window) main_window.menuBar().addMenu(help_menu) help_menu.addAction(aboutact) main_window.setCentralWidget(augCanvas) toolBar = QtWidgets.QToolBar(main_window) toolBar.setAllowedAreas(QtCore.Qt.TopToolBarArea) toolBar.setFloatable(False) toolBar.setMovable(False) toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) toolBar.addAction(openact) toolBar.addAction(exportact) toolBar.addSeparator() toolBar.addWidget(QtWidgets.QLabel("Predict Formula:")) toolBar.addWidget(predictform) toolBar.addSeparator() toolBar.addAction(zceact) toolBar.addAction(drlact) toolBar.addSeparator() toolBar.addAction(autozoomy) main_window.dragEnterEvent = lambda event: drag_entered(event) main_window.dropEvent = lambda event: dropped( event, main_window, augCanvas, update, config, loadthread) main_window.setAcceptDrops(True) main_window.keyPressEvent = lambda event: key_pressed( event, augCanvas, config) main_window.addToolBar(QtCore.Qt.TopToolBarArea, toolBar) main_window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, treedock) main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, paramsdock) main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, consoledock) main_window.setStatusBar(barHandler.statusBar) main_window.setFocus() if len(sys.argv) == 2: load_file(main_window, augCanvas, update, config, loadthread, filename=sys.argv[1]) else: gt.pop_plot(0, 0, augCanvas.spectplot, augCanvas.ms) gt.pop_plot(0, 0, augCanvas.chromplot, augCanvas.chrom) main_window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()