Exemplo n.º 1
0
Arquivo: ui.py Projeto: pchj/nmrbrew
class AnnotatePeaks(GenericDialog):
    def __init__(self, parent, config=None, *args, **kwargs):
        super(AnnotatePeaks, self).__init__(parent, *args, **kwargs)

        self.setWindowTitle('Annotate Peaks')

        if config:
            # Copy in starting state
            self.config = ConfigManager()
            self.config.hooks.update(custom_pyqtconfig_hooks.items())

            self.config.set_defaults(config)

        self.fwd_map_cache = {}

        # Correlation variables
        gb = QGroupBox('Peaks')
        vbox = QVBoxLayout()
        # Populate the list boxes
        self.lw_peaks = QListWidgetAddRemove()
        self.lw_peaks.setSelectionMode(QAbstractItemView.ExtendedSelection)
        vbox.addWidget(self.lw_peaks)

        vboxh = QHBoxLayout()

        self.add_label = QLineEdit()
        self.add_start = QDoubleSpinBox()
        self.add_start.setRange(-1, 12)
        self.add_start.setDecimals(3)
        self.add_start.setSuffix('ppm')
        self.add_start.setSingleStep(0.001)

        self.add_end = QDoubleSpinBox()
        self.add_end.setRange(-1, 12)
        self.add_end.setDecimals(3)
        self.add_end.setSuffix('ppm')
        self.add_end.setSingleStep(0.001)

        addc = QPushButton('Add')
        addc.clicked.connect(self.onPeakAdd)

        remc = QPushButton('Remove selected')
        remc.clicked.connect(self.onPeakAdd)

        loadc = QPushButton("Import from file")
        loadc.setIcon(
            QIcon(
                os.path.join(utils.scriptdir, 'icons',
                             'folder-open-document.png')))
        loadc.clicked.connect(self.onPeakImport)

        metabh = QPushButton("Auto match via MetaboHunter")
        metabh.setIcon(
            QIcon(os.path.join(utils.scriptdir, 'icons', 'metabohunter.png')))
        metabh.clicked.connect(self.onPeakImportMetabohunter)

        vboxh.addWidget(self.add_label)
        vboxh.addWidget(self.add_start)
        vboxh.addWidget(self.add_end)

        vboxh.addWidget(addc)

        vbox.addWidget(remc)
        vbox.addLayout(vboxh)
        vbox.addWidget(loadc)
        vbox.addWidget(metabh)

        gb.setLayout(vbox)

        self.layout.addWidget(gb)

        self.config.add_handler('annotation/peaks', self.lw_peaks,
                                (self.map_list_fwd, self.map_list_rev))

        self.dialogFinalise()

    def onPeakAdd(self):
        c = self.config.get(
            'annotation/peaks'
        )[:]  # Create new list to force refresh on reassign
        c.append((self.add_label.text(), float(self.add_start.value()),
                  float(self.add_end.value())))
        self.config.set('annotation/peaks', c)

    def onPeakRemove(self):
        i = self.lw_peaks.removeItemAt(self.lw_peaks.currentRow())
        # c = self.map_list_fwd(i.text())

    def onPeakImport(self):
        filename, _ = QFileDialog.getOpenFileName(
            self.parent(), 'Load peak annotations from file', '',
            "All compatible files (*.csv *.txt *.tsv);;Comma Separated Values (*.csv);;Plain Text Files (*.txt);;Tab Separated Values (*.tsv);;All files (*.*)"
        )
        if filename:
            c = self.config.get(
                'annotation/peaks'
            )[:]  # Create new list to force refresh on reassign

            with open(filename, 'rU') as f:
                reader = csv.reader(f, delimiter=b',', dialect='excel')
                for row in reader:
                    if row not in c:
                        c.append(row[0], float(row[1]), float(row[2]))

            self.config.set('annotation/peaks', c)

    def onPeakImportMetabohunter(self):
        c = self.config.get(
            'annotation/peaks'
        )[:]  # Create new list to force refresh on reassign
        t = self.parent().current_tool

        dlg = MetaboHunter(self)
        if dlg.exec_():

            if 'spc' in t.data:
                # We have a spectra; calcuate mean; reduce size if required
                spc = t.data['spc']
                n = spc.data.shape[1]
                ppm = spc.ppm
                spcd = np.mean(spc.data, axis=0)

                # Set a hard limit on the size of data we submit to be nice.
                if n > 3000:
                    # Calculate the division required to be under the limit
                    d = np.ceil(float(n) / 3000)
                    # Trim axis to multiple of divisor
                    trim = (n // d) * d
                    spcd = spcd[:trim]
                    ppm = ppm[:trim]
                    # Mean d shape
                    spcd = np.mean(spcd.reshape(-1, d), axis=1)
                    ppm = np.mean(ppm.reshape(-1, d), axis=1)

            # Submit with settings
            hmdbs = metabohunter.request(
                ppm,
                spcd,
                metabotype=dlg.config.get('Metabotype'),
                database=dlg.config.get('Database Source'),
                ph=dlg.config.get('Sample pH'),
                solvent=dlg.config.get('Solvent'),
                frequency=dlg.config.get('Frequency'),
                method=dlg.config.get('Method'),
                noise=dlg.config.get('Noise Threshold'),
                confidence=dlg.config.get('Confidence Threshold'),
                tolerance=dlg.config.get('Tolerance'))

            ha = np.array(hmdbs)
            unique_hmdbs = set(hmdbs)
            if None in unique_hmdbs:
                unique_hmdbs.remove(None)

            # Extract out regions
            for hmdb in unique_hmdbs:
                hb = np.diff(ha == hmdb)

                # These are needed to ensure markers are there for objects starting and ending on array edge
                if ha[0] == hmdb:
                    hb[0] == True

                if ha[-1] == hmdb:
                    hb[-1] == True

                idx = np.nonzero(hb)[0]
                idx = idx.reshape(-1, 2)

                if dlg.config.get(
                        'convert_hmdb_ids_to_names'
                ) and hmdb in METABOHUNTER_HMDB_NAME_MAP.keys():
                    label = METABOHUNTER_HMDB_NAME_MAP[hmdb]
                else:
                    label = hmdb

                # Now we have an array of all start, stop positions for this item
                for start, stop in idx:
                    c.append((label, ppm[start], ppm[stop]))

        self.config.set('annotation/peaks', c)

    def map_list_fwd(self, s):
        " Receive text name, return the indexes "
        return self.fwd_map_cache[s]

    def map_list_rev(self, x):
        " Receive the indexes, return the label"
        s = "%s\t%.2f\t%.2f" % tuple(x)
        self.fwd_map_cache[s] = x
        return s
Exemplo n.º 2
0
class QGraphicsSceneExtend(QGraphicsScene):

    def __init__(self, parent, *args, **kwargs):
        super(QGraphicsSceneExtend, self).__init__(parent, *args, **kwargs)

        self.m = parent.m

        self.config = ConfigManager()
        # These config settings are transient (ie. not stored between sessions)
        self.config.set_defaults({
            'mode': EDITOR_MODE_NORMAL,
            'font-family': 'Arial',
            'font-size': '12',
            'text-bold': False,
            'text-italic': False,
            'text-underline': False,
            'text-color': '#000000',
            'color-border': None,  # '#000000',
            'color-background': None,
        })

        # Pre-set these values (will be used by default)
        self.config.set('color-background', '#5555ff')

        self.background_image = QImage(os.path.join(utils.scriptdir, 'icons', 'grid100.png'))
        if settings.get('Editor/Show_grid'):
            self.showGrid()
        else:
            self.hideGrid()

        self.mode = EDITOR_MODE_NORMAL
        self.mode_current_object = None

        self.annotations = []

    def mousePressEvent(self, e):
    
        if self.config.get('mode') != EDITOR_MODE_NORMAL:

            for i in self.selectedItems():
                i.setSelected(False)

            if self.config.get('mode') == EDITOR_MODE_TEXT:
                tw = AnnotationTextItem(position=e.scenePos())

            elif self.config.get('mode') == EDITOR_MODE_REGION:
                tw = AnnotationRegionItem(position=e.scenePos())

            elif self.config.get('mode') == EDITOR_MODE_ARROW:
                tw = AnnotationRegionItem(position=e.scenePos())

            self.addItem(tw)
            self.mode_current_object = tw
            tw._createFromMousePressEvent(e)
            tw.importStyleConfig(self.config)

            self.annotations.append(tw)

        else:
            for i in self.selectedItems():
                i.setSelected(False)
        
            super(QGraphicsSceneExtend, self).mousePressEvent(e)

    def mouseMoveEvent(self, e):
        if self.config.get('mode') == EDITOR_MODE_TEXT and self.mode_current_object:
            self.mode_current_object._resizeFromMouseMoveEvent(e)

        elif self.config.get('mode') == EDITOR_MODE_REGION and self.mode_current_object:
            self.mode_current_object._resizeFromMouseMoveEvent(e)

        else:
            super(QGraphicsSceneExtend, self).mouseMoveEvent(e)

    def mouseReleaseEvent(self, e):
        if self.config.get('mode'):
            self.mode_current_object.setSelected(True)
            self.mode_current_object.setFocus()

            self.config.set('mode', EDITOR_MODE_NORMAL)
            self.mode_current_object = None

        super(QGraphicsSceneExtend, self).mouseReleaseEvent(e)

    def showGrid(self):
        self.setBackgroundBrush(QBrush(self.background_image))

    def hideGrid(self):
        self.setBackgroundBrush(QBrush(None))

    def onSaveAsImage(self):
        filename, _ = QFileDialog.getSaveFileName(self.m, 'Save current figure', '', "Tagged Image File Format (*.tif);;\
                                                                                     Portable Network Graphics (*.png)")
        if filename:
            self.saveAsImage(filename)

    def saveAsImage(self, f):
        self.image = QImage(self.sceneRect().size().toSize(), QImage.Format_ARGB32)
        self.image.fill(Qt.white)
        painter = QPainter(self.image)
        self.render(painter)
        self.image.save(f)

    def addApp(self, app, position=None):
        i = ToolItem(self, app, position=position)
        self.addItem(i)
        #i.onShow()

        return i

    def removeApp(self, app):
        i = app.editorItem
        i.hide()
        self.removeItem(i)
        app.editorItem = None

    def dragEnterEvent(self, e):
        if e.mimeData().hasFormat('application/x-pathomx-app') or e.mimeData().hasFormat('text/uri-list'):
            e.accept()
        else:
            e.ignore()

    def dragMoveEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        scenePos = e.scenePos() - QPointF(32, 32)

        if e.mimeData().hasFormat('application/x-pathomx-app'):
            try:
                app_id = str(e.mimeData().data('application/x-pathomx-app'), 'utf-8')  # Python 3 
            except:
                app_id = str(e.mimeData().data('application/x-pathomx-app'))  # Python 2

            e.setDropAction(Qt.CopyAction)
            a = app_launchers[app_id](self.m, position=scenePos, auto_focus=False)
            #self.centerOn(a.editorItem)
            e.accept()

        elif e.mimeData().hasFormat('text/uri-list'):
            for ufn in e.mimeData().urls():
                fn = ufn.path()
                fnn, ext = os.path.splitext(fn)
                ext = ext.strip('.')
                if ext in file_handlers:
                    a = file_handlers[ext](position=scenePos, auto_focus=False, filename=fn)
                    self.centerOn(a.editorItem)
                    e.accept()

    def getXMLAnnotations(self, root):

    # Iterate over the entire set (in order) creating a XML representation of the MatchDef and Style
        for annotation in self.annotations:

            ase = et.SubElement(root, "Annotation")
            ase.set('type', type(annotation).__name__)

            ase.set('x', str(annotation.x()))
            ase.set('y', str(annotation.y()))
            ase.set('width', str(annotation.rect().width()))
            ase.set('height', str(annotation.rect().height()))

            if hasattr(annotation, 'text'):
                text = et.SubElement(ase, "Text")
                text.text = annotation.text.toPlainText()

            ase = annotation.config.getXMLConfig(ase)

        return root

    def setXMLAnnotations(self, root):

        ANNOTATION_TYPES = {
            'AnnotationTextItem': AnnotationTextItem,
            'AnnotationRegionItem': AnnotationRegionItem,
        }

        for ase in root.findall('Annotation'):

            # Validate the class definition before creating it
            if ase.get('type') in ANNOTATION_TYPES:

                pos = QPointF(float(ase.get('x')), float(ase.get('y')))
                aobj = ANNOTATION_TYPES[ase.get('type')](position=pos)
                aobj.setRect(QRectF(0, 0, float(ase.get('width')), float(ase.get('height'))))

                to = ase.find('Text')
                if to is not None:
                    aobj.text.setPlainText(to.text)

                self.addItem(aobj)
                self.annotations.append(aobj)
                aobj.config.setXMLConfig(ase)
                aobj.applyStyleConfig()
Exemplo n.º 3
0
Arquivo: ui.py Projeto: pchj/nmrbrew
class MetaboHunter(GenericDialog):

    options = {
        'Metabotype': {
            'All': 'All',
            'Drug': 'Drug',
            'Food additive': 'Food additive',
            'Mammalian': 'Mammalian',
            'Microbial': 'Microbial',
            'Plant': 'Plant',
            'Synthetic/Industrial chemical': 'Synthetic/Industrial chemical',
        },
        'Database Source': {
            'Human Metabolome Database (HMDB)': 'HMDB',
            'Madison Metabolomics Consortium Database (MMCD)': 'MMCD',
        },
        'Sample pH': {
            '10.00 - 10.99': 'ph7',
            '7.00 - 9.99': 'ph7',
            '6.00 - 6.99': 'ph6',
            '5.00 - 5.99': 'ph5',
            '4.00 - 4.99': 'ph4',
            '3.00 - 3.99': 'ph3',
        },
        'Solvent': {
            'All': 'all',
            'Water': 'water',
            'CDCl3': 'cdcl3',
            'CD3OD': '5d3od',
            '5% DMSO': '5dmso',
        },
        'Frequency': {
            'All': 'all',
            '600 MHz': '600',
            '500 MHz': '500',
            '400 MHz': '400',
        },
        'Method': {
            'MH1: Highest number of matched peaks':
            'HighestNumber',
            'MH2: Highest number of matched peaks with shift tolerance':
            'HighestNumberNeighbourhood',
            'MH3: Greedy selection of metabolites with disjoint peaks':
            'Greedy2',
            'MH4: Highest number of matched peaks with intensities':
            'HighestNumberHeights',
            'MH5: Greedy selection of metabolites with disjoint peaks and heights':
            'Greedy2Heights',
        },
    }

    def __init__(self, *args, **kwargs):
        super(MetaboHunter, self).__init__(*args, **kwargs)

        self.setWindowTitle('MetaboHunter')
        # Copy in starting state
        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())

        self.config.set_defaults({
            'Metabotype': 'All',
            'Database Source': 'HMDB',
            'Sample pH': 'ph7',
            'Solvent': 'water',
            'Frequency': 'all',
            'Method': 'HighestNumberNeighbourhood',
            'Noise Threshold': 0.0001,
            'Confidence Threshold': 0.5,
            'Tolerance': 0.1,
            'convert_hmdb_ids_to_names': True,
        })

        self.lw_combos = {}

        for o in [
                'Metabotype', 'Database Source', 'Sample pH', 'Solvent',
                'Frequency', 'Method'
        ]:
            row = QVBoxLayout()
            cl = QLabel(o)
            cb = QComboBox()

            cb.addItems(list(self.options[o].keys()))
            row.addWidget(cl)
            row.addWidget(cb)
            self.config.add_handler(o, cb, self.options[o])

            self.layout.addLayout(row)

        row = QGridLayout()
        self.lw_spin = {}
        for n, o in enumerate(
            ['Noise Threshold', 'Confidence Threshold', 'Tolerance']):
            cl = QLabel(o)
            cb = QDoubleSpinBox()
            cb.setDecimals(4)
            cb.setRange(0, 1)
            cb.setSingleStep(0.01)
            cb.setValue(float(self.config.get(o)))
            row.addWidget(cl, 0, n)
            row.addWidget(cb, 1, n)

            self.config.add_handler(o, cb)

        self.layout.addLayout(row)

        row = QHBoxLayout()
        row.addWidget(QLabel("Convert HMDB IDs to chemical names?"))
        conv = QCheckBox()
        self.config.add_handler('convert_hmdb_ids_to_names', conv)
        row.addWidget(conv)

        self.layout.addLayout(row)

        self.dialogFinalise()
Exemplo n.º 4
0
Arquivo: ui.py Projeto: pchj/nmrbrew
class AnnotateClasses(GenericDialog):
    def __init__(self, parent, config=None, *args, **kwargs):
        super(AnnotateClasses, self).__init__(parent, *args, **kwargs)

        self.setWindowTitle('Annotate Classes')

        if config:
            # Copy in starting state
            self.config = ConfigManager()
            self.config.hooks.update(custom_pyqtconfig_hooks.items())

            self.config.set_defaults(config)

        self.fwd_map_cache = {}

        # Correlation variables
        gb = QGroupBox('Sample classes')
        vbox = QVBoxLayout()
        # Populate the list boxes
        self.lw_classes = QListWidgetAddRemove()
        self.lw_classes.setSelectionMode(QAbstractItemView.ExtendedSelection)
        vbox.addWidget(self.lw_classes)

        vboxh = QHBoxLayout()

        self.add_label = QLineEdit()
        self.add_class = QLineEdit()

        addc = QPushButton('Add')
        addc.clicked.connect(self.onClassAdd)

        remc = QPushButton('Remove selected')
        remc.clicked.connect(self.onClassAdd)

        loadc = QPushButton('Import from file')
        loadc.setIcon(
            QIcon(
                os.path.join(utils.scriptdir, 'icons',
                             'folder-open-document.png')))
        loadc.clicked.connect(self.onClassImport)

        vboxh.addWidget(self.add_label)
        vboxh.addWidget(self.add_class)
        vboxh.addWidget(addc)

        vbox.addWidget(remc)
        vbox.addLayout(vboxh)
        vboxh.addWidget(loadc)

        gb.setLayout(vbox)

        self.layout.addWidget(gb)

        self.config.add_handler('annotation/sample_classes', self.lw_classes,
                                (self.map_list_fwd, self.map_list_rev))

        self.dialogFinalise()

    def onClassAdd(self):
        c = self.config.get(
            'annotation/sample_classes'
        )[:]  # Create new list to force refresh on reassign
        c.append((self.add_label.text(), self.add_class.text()))
        self.config.set('annotation/sample_classes', c)

    def onClassRemove(self):
        i = self.lw_classes.removeItemAt(self.lw_classes.currentRow())
        # c = self.map_list_fwd(i.text())

    def onClassImport(self):
        filename, _ = QFileDialog.getOpenFileName(
            self.parent(), 'Load classifications from file', '',
            "All compatible files (*.csv *.txt *.tsv);;Comma Separated Values (*.csv);;Plain Text Files (*.txt);;Tab Separated Values (*.tsv);;All files (*.*)"
        )
        if filename:
            c = self.config.get(
                'annotation/sample_classes'
            )[:]  # Create new list to force refresh on reassign

            with open(filename, 'rU') as f:
                reader = csv.reader(f, delimiter=b',', dialect='excel')
                for row in reader:
                    if row not in c:
                        c.append(row[:2])

            self.config.set('annotation/sample_classes', c)

    def map_list_fwd(self, s):
        " Receive text name, return the indexes "
        return self.fwd_map_cache[s]

    def map_list_rev(self, x):
        " Receive the indexes, return the label"
        s = "%s\t%s" % tuple(x)
        self.fwd_map_cache[s] = x
        return s
Exemplo n.º 5
0
class ToolBase(QObject):
    '''
    Base tool definition for inclusion in the UI. Define specific config settings;
    attach a panel widget for configuration.
    '''

    is_manual_runnable = True
    is_auto_runnable = False
    is_auto_rerunnable = True
    is_disableable = True

    progress = pyqtSignal(float)
    status = pyqtSignal(str)
    complete = pyqtSignal()

    config_panel_size = 150
    view = None

    def __init__(self, parent, *args, **kwargs):
        super(ToolBase, self).__init__(parent, *args, **kwargs)


        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())
        self.config.set_defaults({
            'auto_run_on_config_change': True
            })
        self.current_status = 'inactive'
        self.config.updated.connect(self.auto_run_on_config_change)

        self.buttonBar = QWidget()

        self.configPanels = QWidget()
        self.configLayout = QVBoxLayout()
        self.configLayout.setContentsMargins(0,0,0,0)

        self.configPanels.setLayout(self.configLayout)

        self._previous_config_backup_ = {}

        self._worker_thread_ = None
        self._worker_thread_lock_ = False

        self.view = MplView(self.parent())

        self.setup()

        self.current_progress = 0

        self.progress.connect(self.progress_callback)
        self.status.connect(self.status_callback)


    def setup(self):
        self.data = {
            'data': None,
        }
        self.view.figure.clear()
        self.view.redraw()
        self.status.emit('inactive' if self.current_status == 'inactive' else 'ready')



    def addConfigPanel(self, panel):
        self.configLayout.addWidget( panel(self) )

    def addButtonBar(self, buttons):
        '''
        Create a button bar

        Supplied with a list of QPushButton objects (already created using helper stubs; see below)

        :param buttons:
        :return:
        '''

        btnlayout = QHBoxLayout()
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))
        for btn in buttons:
            btnlayout.addWidget(btn)

        self.configLayout.addLayout(btnlayout)
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))

    def run_manual(self):
        pass


    def disable(self):
        self.status.emit('inactive')
        self.item.setFlags(Qt.NoItemFlags)

    def reset(self):
        self.config.set_many( self.config.defaults )

    def undo(self):
        self.config.set_many(self._config_backup_)

    def defaultButtons(self):

        buttons = []

        reset = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'arrow-turn-180-left.png')), 'Reset to defaults')
        reset.setToolTip('Reset to defaults')
        reset.pressed.connect(self.reset)
        buttons.append(reset)

        apply = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'play.png')), 'Apply')
        apply.setToolTip('Apply current settings to spectra')
        apply.pressed.connect(self.run_manual)
        buttons.append(apply)

        return buttons

    def enable(self):
        if self.current_status == 'inactive':
            self.current_status = 'ready'
            self.status.emit('ready')
            self.item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)

    def activate(self):
        self.parent().current_tool = self
        self.enable()

        self._config_backup_ = self.config.as_dict()

        self._refresh_plot_timer_ = QTimer.singleShot(0, self.plot)

        if self.view:
            self.parent().viewStack.setCurrentWidget(self.view)

        self.parent().configstack.setCurrentWidget(self.configPanels)
        self.parent().configstack.setMaximumHeight(self.config_panel_size)

    def set_active(self, active):
        self.config.set('is_active', active)

    def get_previous_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n-1::-1]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None

    def get_next_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n+1:]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None



    def get_previous_data(self):
        t = self.get_previous_tool()
        if t and 'data' in t.data:
            return t.data['data']
        else:
            return None

    def plot(self, **kwargs):
        pass
        #if 'spc' in self.data:
        #    self.parent().spectraViewer.plot(self.data['spc'], **kwargs)

    def get_plotitem(self):
        return self.parent().spectraViewer.spectraViewer.plotItem

    def auto_run_on_config_change(self):
        if self.is_auto_runnable and self.current_status == 'ready' and self.config.get('auto_run_on_config_change'):
            self.run_manual()

    def run(self, fn):
        '''
        Run the target function, passing in the current spectra, and config settings (as dict)
        :param fn:
        :return:
        '''
        if self._worker_thread_lock_:
            return False # Can't run

        self.progress.emit(0)
        self.status.emit('active')

        data = self.get_previous_data()

        self._worker_thread_lock_ = True

        kwargs = {
            'config': self.config.as_dict(),
            'progress_callback': self.progress.emit,
        }
        if data:
            kwargs.update(deepcopy(data))

        # Close any open figures; ensure new axes.
        plt.close()

        self._worker_thread_ = Worker(fn = fn, **kwargs)

        self._worker_thread_.signals.finished.connect(self.finished)
        self._worker_thread_.signals.result.connect(self.result)
        self._worker_thread_.signals.error.connect(self.error)

        self.parent().threadpool.start(self._worker_thread_)


    def error(self, error):
        self.progress.emit(1.0)
        self.status.emit('error')
        logging.error(error)
        self._worker_thread_lock_ = False



    def result(self, result):

        # Apply post-processing
        if 'fig' in result and result['fig']:
            fig = result['fig']
            fig.set_size_inches(self.view.get_size_inches(fig.get_dpi()))
            fig.set_tight_layout(False)
            fig.tight_layout(pad=0.5, rect=[0.25, 0.10, 0.75, 0.90])
            self.view.figure = fig
            self.view.redraw()

        self.data = result
        self.plot()

        self.progress.emit(1)
        self.status.emit('complete')

    def finished(self):
        # Cleanup
        self._worker_thread_lock_ = False
        self.complete.emit()


    def progress_callback(self, progress):
        self.current_progress = progress
        self.item.setData(Qt.UserRole + 2, progress)

    def status_callback(self, status):
        self.current_status = status
        self.item.setData(Qt.UserRole + 3, status)
Exemplo n.º 6
0
class QGraphicsSceneExtend(QGraphicsScene):
    def __init__(self, parent, *args, **kwargs):
        super(QGraphicsSceneExtend, self).__init__(parent, *args, **kwargs)

        self.m = parent.m

        self.config = ConfigManager()
        # These config settings are transient (ie. not stored between sessions)
        self.config.set_defaults({
            'mode': EDITOR_MODE_NORMAL,
            'font-family': 'Arial',
            'font-size': '12',
            'text-bold': False,
            'text-italic': False,
            'text-underline': False,
            'text-color': '#000000',
            'color-border': None,  # '#000000',
            'color-background': None,
        })

        # Pre-set these values (will be used by default)
        self.config.set('color-background', '#5555ff')

        self.background_image = QImage(
            os.path.join(utils.scriptdir, 'icons', 'grid100.png'))
        if settings.get('Editor/Show_grid'):
            self.showGrid()
        else:
            self.hideGrid()

        self.mode = EDITOR_MODE_NORMAL
        self.mode_current_object = None

        self.annotations = []

    def mousePressEvent(self, e):
        if self.config.get('mode') != EDITOR_MODE_NORMAL:

            for i in self.selectedItems():
                i.setSelected(False)

            if self.config.get('mode') == EDITOR_MODE_TEXT:
                tw = AnnotationTextItem(position=e.scenePos())

            elif self.config.get('mode') == EDITOR_MODE_REGION:
                tw = AnnotationRegionItem(position=e.scenePos())

            elif self.config.get('mode') == EDITOR_MODE_ARROW:
                tw = AnnotationRegionItem(position=e.scenePos())

            self.addItem(tw)
            self.mode_current_object = tw
            tw._createFromMousePressEvent(e)
            tw.importStyleConfig(self.config)

            self.annotations.append(tw)

        else:
            super(QGraphicsSceneExtend, self).mousePressEvent(e)

    def mouseMoveEvent(self, e):
        if self.config.get(
                'mode') == EDITOR_MODE_TEXT and self.mode_current_object:
            self.mode_current_object._resizeFromMouseMoveEvent(e)

        elif self.config.get(
                'mode') == EDITOR_MODE_REGION and self.mode_current_object:
            self.mode_current_object._resizeFromMouseMoveEvent(e)

        else:
            super(QGraphicsSceneExtend, self).mouseMoveEvent(e)

    def mouseReleaseEvent(self, e):
        if self.config.get('mode'):
            self.mode_current_object.setSelected(True)
            self.mode_current_object.setFocus()

            self.config.set('mode', EDITOR_MODE_NORMAL)
            self.mode_current_object = None

        super(QGraphicsSceneExtend, self).mouseReleaseEvent(e)

    def showGrid(self):
        self.setBackgroundBrush(QBrush(self.background_image))

    def hideGrid(self):
        self.setBackgroundBrush(QBrush(None))

    def onSaveAsImage(self):
        filename, _ = QFileDialog.getSaveFileName(
            self.m, 'Save current figure', '',
            "Tagged Image File Format (*.tif);;\
                                                                                     Portable Network Graphics (*.png)"
        )
        if filename:
            self.saveAsImage(filename)

    def saveAsImage(self, f):
        self.image = QImage(self.sceneRect().size().toSize(),
                            QImage.Format_ARGB32)
        self.image.fill(Qt.white)
        painter = QPainter(self.image)
        self.render(painter)
        self.image.save(f)

    def addApp(self, app, position=None):
        i = ToolItem(self, app, position=position)
        self.addItem(i)
        return i

    def removeApp(self, app):
        i = app.editorItem
        i.hide()
        self.removeItem(i)
        app.editorItem = None

    def dragEnterEvent(self, e):
        if e.mimeData().hasFormat('application/x-pathomx-app') or e.mimeData(
        ).hasFormat('text/uri-list'):
            e.accept()
        else:
            e.ignore()

    def dragMoveEvent(self, e):
        e.accept()

    def dropEvent(self, e):
        scenePos = e.scenePos() - QPointF(32, 32)

        if e.mimeData().hasFormat('application/x-pathomx-app'):
            try:
                app_id = str(e.mimeData().data('application/x-pathomx-app'),
                             'utf-8')  # Python 3
            except:
                app_id = str(
                    e.mimeData().data('application/x-pathomx-app'))  # Python 2

            e.setDropAction(Qt.CopyAction)
            a = app_launchers[app_id](self.m,
                                      position=scenePos,
                                      auto_focus=False)
            #self.centerOn(a.editorItem)
            e.accept()

        elif e.mimeData().hasFormat('text/uri-list'):
            for ufn in e.mimeData().urls():
                fn = ufn.path()
                fnn, ext = os.path.splitext(fn)
                ext = ext.strip('.')
                if ext in file_handlers:
                    a = file_handlers[ext](position=scenePos,
                                           auto_focus=False,
                                           filename=fn)
                    self.centerOn(a.editorItem)
                    e.accept()

    def getXMLAnnotations(self, root):

        # Iterate over the entire set (in order) creating a XML representation of the MatchDef and Style
        for annotation in self.annotations:

            ase = et.SubElement(root, "Annotation")
            ase.set('type', type(annotation).__name__)

            ase.set('x', str(annotation.x()))
            ase.set('y', str(annotation.y()))
            ase.set('width', str(annotation.rect().width()))
            ase.set('height', str(annotation.rect().height()))

            if hasattr(annotation, 'text'):
                text = et.SubElement(ase, "Text")
                text.text = annotation.text.toPlainText()

            ase = annotation.config.getXMLConfig(ase)

        return root

    def setXMLAnnotations(self, root):

        ANNOTATION_TYPES = {
            'AnnotationTextItem': AnnotationTextItem,
            'AnnotationRegionItem': AnnotationRegionItem,
        }

        for ase in root.findall('Annotation'):

            # Validate the class definition before creating it
            if ase.get('type') in ANNOTATION_TYPES:

                pos = QPointF(float(ase.get('x')), float(ase.get('y')))
                aobj = ANNOTATION_TYPES[ase.get('type')](position=pos)
                aobj.setRect(
                    QRectF(0, 0, float(ase.get('width')),
                           float(ase.get('height'))))

                to = ase.find('Text')
                if to is not None:
                    aobj.text.setPlainText(to.text)

                self.addItem(aobj)
                self.annotations.append(aobj)
                aobj.config.setXMLConfig(ase)
                aobj.applyStyleConfig()
Exemplo n.º 7
0
class Automaton(QStandardItem):
    def __init__(self, *args, **kwargs):
        super(Automaton, self).__init__(*args, **kwargs)

        self.setData(self, Qt.UserRole)
        self.watcher = QFileSystemWatcher()
        self.timer = QTimer()

        self.watch_window = {}

        self.latest_run = {}
        self.is_running = False

        self.config = ConfigManager()
        self.config.set_defaults({
            'mode': MODE_WATCH_FOLDER,
            'is_active': True,
            'trigger_hold': 1,
            'notebook_paths': '',
            'output_path': '{home}/{notebook_filename}_{datetime}_',
            'output_format': 'html',
            'watched_files': [],
            'watched_folder': '',
            'watch_window': 15,
            'iterate_watched_folder': True,
            'iterate_wildcard': '.csv',
            'timer_seconds': 60,
        })

        self.runner = None
        self.lock = None

        self.latest_run = {
            'timestamp': None,
            'success': None,
        }

        # Set up all the triggers
        self.watcher.fileChanged.connect(self.file_trigger_accumulator)
        self.watcher.directoryChanged.connect(self.trigger)
        self.timer.timeout.connect(self.trigger)

    def startup(self):
        if self.config.get('is_active') == False:
            return False

        if self.config.get('mode') == MODE_TIMER:
            self.timer.setInterval(self.config.get('timer_seconds') * 1000)
            self.timer.start()

        elif self.config.get('mode') == MODE_WATCH_FILES:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watch_window = {}
            self.watcher.addPaths(self.config.get('watched_files'))

        elif self.config.get('mode') == MODE_WATCH_FOLDER:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watcher.addPath(self.config.get('watched_folder'))

    def shutdown(self):
        if self.config.get('mode') == MODE_TIMER:
            self.timer.stop()

        elif self.config.get('mode') == MODE_WATCH_FILES or self.config.get(
                'mode') == MODE_WATCH_FOLDER:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watch_window = {}

    def load_notebook(self, filename):
        try:
            with open(filename) as f:
                nb = reads(f.read(), 'json')
        except:
            return None
        else:
            return nb

    def file_trigger_accumulator(self, f):
        # Accumulate triggers from changed files: if 3 files are specified to watch
        # we only want to fire once _all_ files have changed (within the given watch window)
        current_time = datetime.now()
        self.watch_window[f] = current_time  # timestamp
        self.watch_window = {
            k: v
            for k, v in self.watch_window.items() if current_time -
            timedelta(seconds=self.config.get('watch_window')) < v
        }

        if set(self.watch_window.keys()) == set(self.watcher.files() +
                                                self.watcher.directories()):
            self.trigger()

    def trigger(self, e=None):
        if self.config.get('is_active') == False:
            return False
        # Filesystemwatcher triggered
        # Get the file and folder information; make available in vars object for run
        if self.lock is None:
            self.is_running = True
            self.update()
            self.lock = QTimer.singleShot(
                self.config.get('trigger_hold') * 1000, self.run)
            # Shutdown so we don't get in infinite loops
            self.shutdown()

    def run(self, vars={}):

        default_vars = {
            'home': os.path.expanduser('~'),
            'version': VERSION_STRING,
        }

        default_vars_and_config = dict(
            list(default_vars.items()) + list(self.config.config.items()))

        if self.runner == None:
            # Postpone init to trigger for responsiveness on add/remove
            self.runner = NotebookRunner(None, pylab=True, mpl_inline=True)

        if self.config.get('mode') == MODE_WATCH_FOLDER and self.config.get(
                'iterate_watched_folder'):
            for (dirpath, dirnames,
                 filenames) in os.walk(self.config.get('watched_folder')):
                break

            filenames = [
                f for f in filenames
                if self.config.get('iterate_wildcard') in f
            ]
            logging.info('Watched folder contains %d files; looping' %
                         len(filenames))
            # Filenames contains the list of files in the folder
        else:
            filenames = [None]

        self.latest_run['timestamp'] = datetime.now()

        try:
            for f in filenames:
                now = datetime.now()
                current_vars = {
                    'datetime': now.strftime("%Y-%m-%d %H.%M.%S"),
                    'date': now.date().strftime("%Y-%m-%d"),
                    'time': now.time().strftime("%H.%M.%S"),
                    'filename': f,
                }
                vars = dict(
                    list(default_vars_and_config.items()) +
                    list(current_vars.items()))

                for nb_path in self.config.get('notebook_paths'):
                    nb = self.load_notebook(nb_path)

                    if nb:
                        # Add currently running notebook path to vars
                        vars['notebook_path'] = nb_path
                        vars['notebook_filename'] = os.path.basename(nb_path)

                        vars['output_path'] = self.config.get(
                            'output_path').format(**vars)
                        parent_folder = os.path.dirname(vars['output_path'])
                        if parent_folder:
                            try:
                                utils.mkdir_p(parent_folder)
                            except:  # Can't create folder
                                self.latest_run['success'] = False
                                raise

                        self.run_notebook(nb, vars)

                    else:
                        raise NotebookNotFound(nb_path)

        except:
            self.latest_run['success'] = False
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]
            logging.error("%s\n%s\n%s" %
                          (exctype, value, traceback.format_exc()))

        finally:
            self.is_running = False
            self.lock = None
            self.update()
            # Restart
            self.startup()

    def run_notebook(self, nb, vars={}):
        if len(nb['worksheets']) == 0:
            nb['worksheets'] = [NotebookNode({'cells': [], 'metadata': {}})]

        start = nb['worksheets'][0]['cells']
        start.insert(
            0,
            Struct(
                **{
                    'cell_type': 'code',
                    'language': 'python',
                    'outputs': [],
                    'collapsed': False,
                    'prompt_number': -1,
                    'input': 'qtipy=%s' % vars,
                    'metadata': {},
                }))
        self.runner.nb = nb

        try:
            self.runner.run_notebook()
        except:
            self.latest_run['success'] = False
            raise
        else:
            self.latest_run['success'] = True
        finally:
            ext = dict(
                html='html',
                slides='slides',
                latex='latex',
                markdown='md',
                python='py',
                rst='rst',
            )

            output, resources = IPyexport(
                IPyexporter_map[self.config.get('output_format')],
                self.runner.nb)
            output_path = vars['output_path'] + 'notebook.%s' % ext[
                self.config.get('output_format')]
            logging.info("Exporting updated notebook to %s" % output_path)
            with open(output_path, "w") as f:
                f.write(output)

    def update(self):
        global _w
        _w.viewer.update(self.index())
Exemplo n.º 8
0
class Automaton(QStandardItem):

    def __init__(self, *args, **kwargs):
        super(Automaton, self).__init__(*args, **kwargs)

        self.setData(self, Qt.UserRole)
        self.watcher = QFileSystemWatcher()
        self.timer = QTimer()

        self.watch_window = {}

        self.latest_run = {}
        self.is_running = False

        self.config = ConfigManager()
        self.config.set_defaults({
            'mode': MODE_WATCH_FOLDER,
            'is_active': True,
            'trigger_hold': 1,
            'notebook_paths': '',
            'output_path': '{home}/{notebook_filename}_{datetime}_',
            'output_format': 'html',

            'watched_files': [],
            'watched_folder': '',
            'watch_window': 15,

            'iterate_watched_folder': True,
            'iterate_wildcard': '.csv',

            'timer_seconds': 60,
        })

        self.runner = None
        self.lock = None

        self.latest_run = {
            'timestamp': None,
            'success': None,
        }

        # Set up all the triggers
        self.watcher.fileChanged.connect(self.file_trigger_accumulator)
        self.watcher.directoryChanged.connect(self.trigger)
        self.timer.timeout.connect(self.trigger)

    def startup(self):
        if self.config.get('is_active') == False:
            return False
    
        if self.config.get('mode') == MODE_TIMER:
            self.timer.setInterval(self.config.get('timer_seconds') * 1000)
            self.timer.start()

        elif self.config.get('mode') == MODE_WATCH_FILES:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watch_window = {}
            self.watcher.addPaths(self.config.get('watched_files'))

        elif self.config.get('mode') == MODE_WATCH_FOLDER:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watcher.addPath(self.config.get('watched_folder'))

    def shutdown(self):
        if self.config.get('mode') == MODE_TIMER:
            self.timer.stop()

        elif self.config.get('mode') == MODE_WATCH_FILES or self.config.get('mode') == MODE_WATCH_FOLDER:
            current_paths = self.watcher.files() + self.watcher.directories()
            if current_paths:
                self.watcher.removePaths(current_paths)
            self.watch_window = {}
        
    def load_notebook(self, filename):
        try:
            with open(filename) as f:
                nb = reads(f.read(), 'json')
        except:
            return None
        else:
            return nb

    def file_trigger_accumulator(self, f):
        # Accumulate triggers from changed files: if 3 files are specified to watch
        # we only want to fire once _all_ files have changed (within the given watch window)
        current_time = datetime.now()
        self.watch_window[f] = current_time  # timestamp
        self.watch_window = {k: v for k, v in self.watch_window.items() if current_time - timedelta(seconds=self.config.get('watch_window')) < v}

        if set(self.watch_window.keys()) == set(self.watcher.files() + self.watcher.directories()):
            self.trigger()

    def trigger(self, e=None):
        if self.config.get('is_active') == False:
            return False
        # Filesystemwatcher triggered
        # Get the file and folder information; make available in vars object for run
        if self.lock is None:
            self.is_running = True
            self.update()
            self.lock = QTimer.singleShot(self.config.get('trigger_hold') * 1000, self.run)
            # Shutdown so we don't get in infinite loops
            self.shutdown()

    def run(self, vars={}):

        default_vars = {
            'home': os.path.expanduser('~'),
            'version': VERSION_STRING,
        }

        default_vars_and_config = dict(list(default_vars.items()) + list(self.config.config.items()))

        if self.runner == None:
            # Postpone init to trigger for responsiveness on add/remove
            self.runner = NotebookRunner(None, pylab=True, mpl_inline=True)

        if self.config.get('mode') == MODE_WATCH_FOLDER and self.config.get('iterate_watched_folder'):
            for (dirpath, dirnames, filenames) in os.walk(self.config.get('watched_folder')):
                break

            filenames = [f for f in filenames if self.config.get('iterate_wildcard') in f]
            logging.info('Watched folder contains %d files; looping' % len(filenames))
            # Filenames contains the list of files in the folder
        else:
            filenames = [None]

        self.latest_run['timestamp'] = datetime.now()

        try:
            for f in filenames:
                now = datetime.now()
                current_vars = {
                    'datetime': now.strftime("%Y-%m-%d %H.%M.%S"),
                    'date': now.date().strftime("%Y-%m-%d"),
                    'time': now.time().strftime("%H.%M.%S"),
                    'filename': f,
                }
                vars = dict(list(default_vars_and_config.items()) + list(current_vars.items()))

                for nb_path in self.config.get('notebook_paths'):
                    nb = self.load_notebook(nb_path)

                    if nb:
                        # Add currently running notebook path to vars
                        vars['notebook_path'] = nb_path
                        vars['notebook_filename'] = os.path.basename(nb_path)

                        vars['output_path'] = self.config.get('output_path').format(**vars)
                        parent_folder = os.path.dirname(vars['output_path'])
                        if parent_folder:
                            try:
                                utils.mkdir_p(parent_folder)
                            except:  # Can't create folder
                                self.latest_run['success'] = False
                                raise

                        self.run_notebook(nb, vars)

                    else:
                        raise NotebookNotFound(nb_path)

        except:
            self.latest_run['success'] = False
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]
            logging.error("%s\n%s\n%s" % (exctype, value, traceback.format_exc()))

        finally:
            self.is_running = False
            self.lock = None
            self.update()
            # Restart
            self.startup()            

    def run_notebook(self, nb, vars={}):
        if len(nb['worksheets']) == 0:
            nb['worksheets'] = [NotebookNode({'cells': [], 'metadata': {}})]

        start = nb['worksheets'][0]['cells']
        start.insert(0, Struct(**{
            'cell_type': 'code',
            'language': 'python',
            'outputs': [],
            'collapsed': False,
            'prompt_number': -1,
            'input': 'qtipy=%s' % vars,
            'metadata': {},
        }))
        self.runner.nb = nb

        try:
            self.runner.run_notebook()
        except:
            self.latest_run['success'] = False
            raise
        else:
            self.latest_run['success'] = True
        finally:
            ext = dict(
                html='html',
                slides='slides',
                latex='latex',
                markdown='md',
                python='py',
                rst='rst',
            )

            output, resources = IPyexport(IPyexporter_map[self.config.get('output_format')], self.runner.nb)
            output_path = vars['output_path'] + 'notebook.%s' % ext[self.config.get('output_format')]
            logging.info("Exporting updated notebook to %s" % output_path)
            with open(output_path, "w") as f:
                f.write(output)

    def update(self):
        global _w
        _w.viewer.update(self.index())
Exemplo n.º 9
0
Arquivo: ui.py Projeto: mfitzp/nmrbrew
class AnnotatePeaks(GenericDialog):

    def __init__(self, parent, config=None, *args, **kwargs):
        super(AnnotatePeaks, self).__init__(parent, *args, **kwargs)

        self.setWindowTitle('Annotate Peaks')

        if config:
            # Copy in starting state
            self.config = ConfigManager()
            self.config.hooks.update(custom_pyqtconfig_hooks.items())

            self.config.set_defaults(config)

        self.fwd_map_cache = {}

        # Correlation variables
        gb = QGroupBox('Peaks')
        vbox = QVBoxLayout()
        # Populate the list boxes
        self.lw_peaks = QListWidgetAddRemove()
        self.lw_peaks.setSelectionMode(QAbstractItemView.ExtendedSelection)
        vbox.addWidget(self.lw_peaks)

        vboxh = QHBoxLayout()

        self.add_label = QLineEdit()
        self.add_start = QDoubleSpinBox()
        self.add_start.setRange(-1, 12)
        self.add_start.setDecimals(3)
        self.add_start.setSuffix('ppm')
        self.add_start.setSingleStep(0.001)

        self.add_end = QDoubleSpinBox()
        self.add_end.setRange(-1, 12)
        self.add_end.setDecimals(3)
        self.add_end.setSuffix('ppm')
        self.add_end.setSingleStep(0.001)

        addc = QPushButton('Add')
        addc.clicked.connect(self.onPeakAdd)

        remc = QPushButton('Remove selected')
        remc.clicked.connect(self.onPeakAdd)

        loadc = QPushButton("Import from file")
        loadc.setIcon(QIcon(os.path.join(utils.scriptdir, 'icons', 'folder-open-document.png')))
        loadc.clicked.connect(self.onPeakImport)


        metabh = QPushButton("Auto match via MetaboHunter")
        metabh.setIcon(QIcon(os.path.join(utils.scriptdir, 'icons', 'metabohunter.png')))
        metabh.clicked.connect(self.onPeakImportMetabohunter)

        vboxh.addWidget(self.add_label)
        vboxh.addWidget(self.add_start)
        vboxh.addWidget(self.add_end)

        vboxh.addWidget(addc)

        vbox.addWidget(remc)
        vbox.addLayout(vboxh)
        vbox.addWidget(loadc)
        vbox.addWidget(metabh)

        gb.setLayout(vbox)

        self.layout.addWidget(gb)

        self.config.add_handler('annotation/peaks', self.lw_peaks, (self.map_list_fwd, self.map_list_rev))

        self.dialogFinalise()

    def onPeakAdd(self):
        c = self.config.get('annotation/peaks')[:]  # Create new list to force refresh on reassign
        c.append( (self.add_label.text(), float(self.add_start.value()), float(self.add_end.value()) ) )
        self.config.set('annotation/peaks', c)

    def onPeakRemove(self):
        i = self.lw_peaks.removeItemAt(self.lw_peaks.currentRow())
        # c = self.map_list_fwd(i.text())

    def onPeakImport(self):
        filename, _ = QFileDialog.getOpenFileName(self.parent(), 'Load peak annotations from file', '', "All compatible files (*.csv *.txt *.tsv);;Comma Separated Values (*.csv);;Plain Text Files (*.txt);;Tab Separated Values (*.tsv);;All files (*.*)")
        if filename:
            c = self.config.get('annotation/peaks')[:]  # Create new list to force refresh on reassign

            with open(filename, 'rU') as f:
                reader = csv.reader(f, delimiter=b',', dialect='excel')
                for row in reader:
                    if row not in c:
                        c.append( row[0], float(row[1]), float(row[2]) )

            self.config.set('annotation/peaks', c)

    def onPeakImportMetabohunter(self):
        c = self.config.get('annotation/peaks')[:]  # Create new list to force refresh on reassign
        t = self.parent().current_tool

        dlg = MetaboHunter(self)
        if dlg.exec_():

            if 'spc' in t.data:
                # We have a spectra; calcuate mean; reduce size if required
                spc = t.data['spc']
                n = spc.data.shape[1]
                ppm = spc.ppm
                spcd = np.mean(spc.data, axis=0)

                # Set a hard limit on the size of data we submit to be nice.
                if n > 3000:
                    # Calculate the division required to be under the limit
                    d = np.ceil(float(n)/3000)
                    # Trim axis to multiple of divisor
                    trim = (n//d)*d
                    spcd = spcd[:trim]
                    ppm = ppm[:trim]
                    # Mean d shape
                    spcd = np.mean( spcd.reshape(-1,d), axis=1)
                    ppm = np.mean( ppm.reshape(-1,d), axis=1)

            # Submit with settings
            hmdbs = metabohunter.request(ppm, spcd,
                  metabotype=dlg.config.get('Metabotype'),
                  database=dlg.config.get('Database Source'),
                  ph=dlg.config.get('Sample pH'),
                  solvent=dlg.config.get('Solvent'),
                  frequency=dlg.config.get('Frequency'),
                  method=dlg.config.get('Method'),
                  noise=dlg.config.get('Noise Threshold'),
                  confidence=dlg.config.get('Confidence Threshold'),
                  tolerance=dlg.config.get('Tolerance')
            )

            ha = np.array(hmdbs)
            unique_hmdbs = set(hmdbs)
            if None in unique_hmdbs:
                unique_hmdbs.remove(None)

            # Extract out regions
            for hmdb in unique_hmdbs:
                hb = np.diff(ha == hmdb)

                # These are needed to ensure markers are there for objects starting and ending on array edge
                if ha[0] == hmdb:
                    hb[0] == True

                if ha[-1] == hmdb:
                    hb[-1] == True

                idx = np.nonzero(hb)[0]
                idx = idx.reshape(-1,2)

                if dlg.config.get('convert_hmdb_ids_to_names') and hmdb in METABOHUNTER_HMDB_NAME_MAP.keys():
                    label = METABOHUNTER_HMDB_NAME_MAP[hmdb]
                else:
                    label = hmdb

                # Now we have an array of all start, stop positions for this item
                for start, stop in idx:
                    c.append( (label, ppm[start], ppm[stop]) )


        self.config.set('annotation/peaks', c)

    def map_list_fwd(self, s):
        " Receive text name, return the indexes "
        return self.fwd_map_cache[s]

    def map_list_rev(self, x):
        " Receive the indexes, return the label"
        s = "%s\t%.2f\t%.2f" % tuple(x)
        self.fwd_map_cache[s] = x
        return s
Exemplo n.º 10
0
Arquivo: ui.py Projeto: mfitzp/nmrbrew
class AnnotateClasses(GenericDialog):

    def __init__(self, parent, config=None, *args, **kwargs):
        super(AnnotateClasses, self).__init__(parent, *args, **kwargs)

        self.setWindowTitle('Annotate Classes')

        if config:
            # Copy in starting state
            self.config = ConfigManager()
            self.config.hooks.update(custom_pyqtconfig_hooks.items())

            self.config.set_defaults(config)

        self.fwd_map_cache = {}

        # Correlation variables
        gb = QGroupBox('Sample classes')
        vbox = QVBoxLayout()
        # Populate the list boxes
        self.lw_classes = QListWidgetAddRemove()
        self.lw_classes.setSelectionMode(QAbstractItemView.ExtendedSelection)
        vbox.addWidget(self.lw_classes)

        vboxh = QHBoxLayout()

        self.add_label = QLineEdit()
        self.add_class = QLineEdit()

        addc = QPushButton('Add')
        addc.clicked.connect(self.onClassAdd)

        remc = QPushButton('Remove selected')
        remc.clicked.connect(self.onClassAdd)

        loadc = QPushButton('Import from file')
        loadc.setIcon(QIcon(os.path.join(utils.scriptdir, 'icons', 'folder-open-document.png')))
        loadc.clicked.connect(self.onClassImport)

        vboxh.addWidget(self.add_label)
        vboxh.addWidget(self.add_class)
        vboxh.addWidget(addc)

        vbox.addWidget(remc)
        vbox.addLayout(vboxh)
        vboxh.addWidget(loadc)

        gb.setLayout(vbox)

        self.layout.addWidget(gb)

        self.config.add_handler('annotation/sample_classes', self.lw_classes, (self.map_list_fwd, self.map_list_rev))

        self.dialogFinalise()

    def onClassAdd(self):
        c = self.config.get('annotation/sample_classes')[:]  # Create new list to force refresh on reassign
        c.append( (self.add_label.text(), self.add_class.text()) )
        self.config.set('annotation/sample_classes', c)

    def onClassRemove(self):
        i = self.lw_classes.removeItemAt(self.lw_classes.currentRow())
        # c = self.map_list_fwd(i.text())

    def onClassImport(self):
        filename, _ = QFileDialog.getOpenFileName(self.parent(), 'Load classifications from file', '', "All compatible files (*.csv *.txt *.tsv);;Comma Separated Values (*.csv);;Plain Text Files (*.txt);;Tab Separated Values (*.tsv);;All files (*.*)")
        if filename:
            c = self.config.get('annotation/sample_classes')[:]  # Create new list to force refresh on reassign

            with open(filename, 'rU') as f:
                reader = csv.reader(f, delimiter=b',', dialect='excel')
                for row in reader:
                    if row not in c:
                        c.append(row[:2])

            self.config.set('annotation/sample_classes', c)

    def map_list_fwd(self, s):
        " Receive text name, return the indexes "
        return self.fwd_map_cache[s]

    def map_list_rev(self, x):
        " Receive the indexes, return the label"
        s = "%s\t%s" % tuple(x)
        self.fwd_map_cache[s] = x
        return s
Exemplo n.º 11
0
Arquivo: ui.py Projeto: mfitzp/nmrbrew
class MetaboHunter(GenericDialog):

    options = {
    'Metabotype': {
        'All': 'All',
        'Drug': 'Drug',
        'Food additive': 'Food additive',
        'Mammalian': 'Mammalian',
        'Microbial': 'Microbial',
        'Plant': 'Plant',
        'Synthetic/Industrial chemical': 'Synthetic/Industrial chemical',
        },
    'Database Source': {
        'Human Metabolome Database (HMDB)': 'HMDB',
        'Madison Metabolomics Consortium Database (MMCD)': 'MMCD',
        },
    'Sample pH': {
        '10.00 - 10.99': 'ph7',
        '7.00 - 9.99': 'ph7',
        '6.00 - 6.99': 'ph6',
        '5.00 - 5.99': 'ph5',
        '4.00 - 4.99': 'ph4',
        '3.00 - 3.99': 'ph3',
    },
    'Solvent': {
        'All': 'all',
        'Water': 'water',
        'CDCl3': 'cdcl3',
        'CD3OD': '5d3od',
        '5% DMSO': '5dmso',
    },
    'Frequency': {
        'All': 'all',
        '600 MHz': '600',
        '500 MHz': '500',
        '400 MHz': '400',
    },
    'Method': {
        'MH1: Highest number of matched peaks': 'HighestNumber',
        'MH2: Highest number of matched peaks with shift tolerance': 'HighestNumberNeighbourhood',
        'MH3: Greedy selection of metabolites with disjoint peaks': 'Greedy2',
        'MH4: Highest number of matched peaks with intensities': 'HighestNumberHeights',
        'MH5: Greedy selection of metabolites with disjoint peaks and heights': 'Greedy2Heights',
    },
    }

    def __init__(self, *args, **kwargs):
        super(MetaboHunter, self).__init__(*args, **kwargs)

        self.setWindowTitle('MetaboHunter')
        # Copy in starting state
        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())

        self.config.set_defaults({
            'Metabotype': 'All',
            'Database Source': 'HMDB',
            'Sample pH': 'ph7',
            'Solvent': 'water',
            'Frequency': 'all',
            'Method': 'HighestNumberNeighbourhood',
            'Noise Threshold': 0.0001,
            'Confidence Threshold': 0.5,
            'Tolerance': 0.1,
            'convert_hmdb_ids_to_names': True,
        })

        self.lw_combos = {}

        for o in ['Metabotype', 'Database Source', 'Sample pH', 'Solvent', 'Frequency', 'Method']:
            row = QVBoxLayout()
            cl = QLabel(o)
            cb = QComboBox()

            cb.addItems(list(self.options[o].keys()))
            row.addWidget(cl)
            row.addWidget(cb)
            self.config.add_handler(o, cb, self.options[o])

            self.layout.addLayout(row)

        row = QGridLayout()
        self.lw_spin = {}
        for n, o in enumerate(['Noise Threshold', 'Confidence Threshold', 'Tolerance']):
            cl = QLabel(o)
            cb = QDoubleSpinBox()
            cb.setDecimals(4)
            cb.setRange(0, 1)
            cb.setSingleStep(0.01)
            cb.setValue(float(self.config.get(o)))
            row.addWidget(cl, 0, n)
            row.addWidget(cb, 1, n)

            self.config.add_handler(o, cb)

        self.layout.addLayout(row)

        row = QHBoxLayout()
        row.addWidget(QLabel("Convert HMDB IDs to chemical names?"))
        conv = QCheckBox()
        self.config.add_handler('convert_hmdb_ids_to_names', conv)
        row.addWidget(conv)

        self.layout.addLayout(row)

        self.dialogFinalise()