Esempio n. 1
0
class ColorButton(QToolButton):
    def __init__(self, color, parent=None):
        QToolButton.__init__(self, parent)
        self.setIconSize(QSize(50, 25))
        self.pix = QPixmap(self.iconSize())
        self._color = QColor('#' + color)
        self.pix.fill(self._color)
        self.setIcon(QIcon(self.pix))
        self.clicked.connect(self.choose_color)

    @dynamic_property
    def color(self):
        def fget(self):
            return self._color.name(QColor.HexRgb)[1:]

        def fset(self, val):
            self._color = QColor('#' + val)

        return property(fget=fget, fset=fset)

    def update_display(self):
        self.pix.fill(self._color)
        self.setIcon(QIcon(self.pix))

    def choose_color(self):
        c = QColorDialog.getColor(self._color, self, _('Choose color'))
        if c.isValid():
            self._color = c
            self.update_display()
Esempio n. 2
0
class ColorButton(QToolButton):
    def __init__(self, color, parent=None):
        QToolButton.__init__(self, parent)
        self.setIconSize(QSize(50, 25))
        self.pix = QPixmap(self.iconSize())
        self._color = QColor('#' + color)
        self.pix.fill(self._color)
        self.setIcon(QIcon(self.pix))
        self.clicked.connect(self.choose_color)

    @property
    def color(self):
        return self._color.name(QColor.NameFormat.HexRgb)[1:]

    @color.setter
    def color(self, val):
        self._color = QColor('#' + val)

    def update_display(self):
        self.pix.fill(self._color)
        self.setIcon(QIcon(self.pix))

    def choose_color(self):
        c = QColorDialog.getColor(self._color, self, _('Choose color'))
        if c.isValid():
            self._color = c
            self.update_display()
Esempio n. 3
0
class MainWindow(QMainWindow, MainQtGui.Ui_MainWindow, QObject):
    """PyContact Application Main Window with timeline."""
    def closeEvent(self, event):
        """Closing application when Exit on MainWindow is clicked."""
        print("Closing Application")
        event.accept()
        QApplication.quit()

    def __init__(self, parent=None):
        self.config = None
        self.analysis = None
        self.maps = None
        super(MainWindow, self).__init__(parent)
        self.contacts = []
        self.filteredContacts = []
        self.setupUi(self)

        self.setWindowTitle("PyContact")

        # painter contains both labels and frame boxes for drawing
        self.painter = Canvas()
        self.scrollArea.setWidget(self.painter)
        self.actionExportData.triggered.connect(self.pushExport)
        self.actionLoad_Data.triggered.connect(self.loadDataPushed)
        self.actionExport_Session.triggered.connect(self.exportSession)
        self.actionImport_Session.triggered.connect(self.importSession)
        self.actionShow_Info.triggered.connect(self.showDeveloperInfo)
        # settings and filters
        self.settingsView = PreferencesWidget()
        self.settingsView.applySettingsButton.clicked.connect(
            self.updateSettings)
        self.applyFilterButton.clicked.connect(self.updateFilters)
        # statistics
        self.statisticsButton.clicked.connect(self.showStatistics)
        # color picker
        self.settingsView.pickColorButton.clicked.connect(self.showColorPicker)
        self.customColor = QColor(230, 50, 0)
        self.settingsView.pickColorButton.setStyleSheet(
            "QWidget { background-color: %s }" % self.customColor.name())

        # frames stride
        posIntValidator = QIntValidator()
        posIntValidator.setBottom(1)
        self.frameStrideField.setValidator(posIntValidator)

        # analysis button
        self.analysisButton.clicked.connect(self.analyzeDataPushed)
        # contact area button
        self.actionContact_Area_Calculations.triggered.connect(
            self.showContactAreaView)
        # preferences
        self.actionPreferences.triggered.connect(self.openPrefs)

        # apply color button, outdated?
        self.colorScheme = ColorScheme.bbsc

        self.actionDefault.triggered.connect(self.loadDefault)

        self.currentSelection1 = "-"
        self.currentSelection2 = "-"

        # setup of extra widgets
        self.exportWidget = ExportTabWidget()
        self.sasaView = SasaWidget()
        self.statisticsView = None

        self.analysis_state = False

        self.vismode = False
        self.visModeButton.setCheckable(True)
        self.visModeButton.setChecked(False)
        self.visModeButton.clicked.connect(self.switchedToVisMode)

        self.vmdpanel = VMDControlPanel()
        self.actionVMD_Remote_Control.triggered.connect(
            self.showVMDControlPanel)

        self.painter.clickedRowSignal.connect(self.updateVMDSelections)
        self.painter.clickedColumnSignal.connect(self.updateVMDFrame)
        self.updateSettings()
        self.updateFilters()

        # self.tableTest = Widget()
        # self.tableTest.setGeometry(100, 100, 400, 400)
        # self.tableTest.show()

        # from ..db.DbReader import read_residue_db_all
        # res = read_residue_db_all()
        # residueList = []    # 1st: name, 2nd scpolarity
        # for k in res:
        #     residueList.appen([k["name"], k["scpolarity"]])

        self.actionDefault.setText("Load sample data")

    def showVMDControlPanel(self):
        """Shows the VMD control panel, to remotely access VMD from PyContact."""
        self.vmdpanel.show()

    def showContactAreaView(self):
        """Shows the SASA computation panel."""
        self.sasaView.show()
        if self.analysis:
            self.sasaView.setFilePaths(self.analysis.getFilePaths())

    def switchedToVisMode(self):
        """Switch to vis mode, to show selected contacts directly in VMD."""
        if self.visModeButton.isChecked():
            self.vismode = True
            # conversions with clicked frames are not allowed
            self.frameStrideField.setText("1")
        else:
            self.vismode = False
        self.painter.switchToVisMode(self.vismode)
        self.updateSettings()
        self.updateFilters()

    @pyqtSlot()
    def updateVMDSelections(self):
        """Updates the selected contact in VMD via the vmd panel."""
        if self.vmdpanel.connected:
            self.vmdpanel.updateSelections(
                self.analysis.sel1text, self.analysis.sel2text,
                [self.filteredContacts[self.painter.globalClickedRow]])

    @pyqtSlot()
    def updateVMDFrame(self):
        """Updates the selected frame in VMD via the vmd panel."""
        if self.vmdpanel.connected:
            self.vmdpanel.gotoVMDFrame(self.painter.clickedColumn)

    def updateSelectionLabels(self, sel1, sel2):
        """Updates the current selection in the info labels."""
        self.currentSelection1 = sel1
        self.currentSelection2 = sel2
        self.selection1label.setText(sel1)
        self.selection2label.setText(sel2)

    def importSession(self):
        """Imports a saved session from file."""
        fnames = QFileDialog.getOpenFileNames(self, "Open file")
        importfile = ""
        for f in fnames[0]:
            importfile = f
            break
        if importfile == "" or len(fnames) == 0:
            return

        self.contacts, arguments, trajArgs, self.maps, contactResults = DataHandler.importSessionFromFile(
            importfile)
        self.analysis = Analyzer(*arguments)
        self.analysis.contactResults = contactResults
        self.analysis.setTrajectoryData(*trajArgs)
        self.analysis.finalAccumulatedContacts = self.contacts
        self.sasaView.setFilePaths(*self.analysis.getFilePaths())
        self.exportWidget.setFilePaths(*self.analysis.getFilePaths())
        self.updateSelectionLabels(arguments[5], arguments[6])
        self.updateSettings()
        self.updateFilters()

    def exportSession(self):
        """Exports the current session to file."""
        fileName = QFileDialog.getSaveFileName(self, 'Export file')
        filestring = fileName[0]
        if filestring == "":
            return
        if self.contacts is not None and self.analysis is not None:
            self.setInfoLabel("Exporting current session...")
            DataHandler.writeSessionToFile(filestring, self.analysis)
            self.cleanInfoLabel()
        else:
            box = ErrorBox(ErrorMessages.NOEXPDATA)
            box.exec_()
            return

    def loadDefault(self):
        """Loads the default session."""
        self.contacts, arguments, trajArgs, self.maps, contactResults = \
            DataHandler.importSessionFromFile(DEFAULTSESSION)
        self.analysis = Analyzer(*arguments)
        self.analysis.contactResults = contactResults
        self.analysis.setTrajectoryData(*trajArgs)
        self.analysis.finalAccumulatedContacts = self.contacts
        self.sasaView.setFilePaths(*self.analysis.getFilePaths())
        self.exportWidget.setFilePaths(*self.analysis.getFilePaths())
        self.updateSelectionLabels(arguments[5], arguments[6])
        self.updateSettings()
        self.updateFilters()

    def loadDataPushed(self):
        """Loads the trajectory data with the chosen initial parameters."""
        self.config, result = FileLoaderDialog.getConfig()
        if result == 1:
            QApplication.processEvents()
            self.setInfoLabel(
                "Loading trajectory and running atomic contact analysis...")
            nproc = int(self.settingsView.coreBox.value())
            self.analysis = Analyzer(self.config.psf, self.config.dcd,
                                     self.config.cutoff,
                                     self.config.hbondcutoff,
                                     self.config.hbondcutangle,
                                     self.config.sel1text,
                                     self.config.sel2text)
            QApplication.processEvents()
            try:
                self.analysis.runFrameScan(nproc)
            except:
                box = ErrorBox(
                    "Error while loading data: Probably you specified an atom selection with 0 atoms or invalid input files."
                )
                box.exec_()
                self.loadDataPushed()
            self.setInfoLabel("%d frames loaded." %
                              len(self.analysis.contactResults))
            self.updateSelectionLabels(self.config.sel1text,
                                       self.config.sel2text)
            self.sasaView.setFilePaths(*self.analysis.getFilePaths())
            self.exportWidget.setFilePaths(*self.analysis.getFilePaths())

    @pyqtSlot(float)
    def updateAnalyzedFrames(self, value):
        """Handles the progress bar update."""
        # print("Updating frames", value)
        self.progressBar.setValue(100 * value)
        QApplication.processEvents()

    def setInfoLabel(self, txt):
        """Sets the Info label text."""
        self.statusLabel.setText(txt)

    def cleanInfoLabel(self):
        """Clears the Info label text."""
        self.setInfoLabel("-")

    def analyzeDataPushed(self):
        """Handles the Analyzer after the Accumulation maps have been set."""
        if self.analysis is None:
            box = ErrorBox(ErrorMessages.NODATA_PROMPTLOAD)
            box.exec_()
            return

        self.maps, result = AnalysisDialog.getMapping()
        if result == 1:
            self.analysis.frameUpdate.connect(self.updateAnalyzedFrames)
            self.setInfoLabel("Analyzing contacts...")
            map1 = self.maps[0]
            map2 = self.maps[1]
            nproc = int(self.settingsView.coreBox.value())
            self.contacts = self.analysis.runContactAnalysis(map1, map2, nproc)
            self.progressBar.setValue(0)
            self.setInfoLabel("Updating timeline...")
            QApplication.processEvents()
            self.updateSettings()
            self.updateFilters()
            self.cleanInfoLabel()

    def updateSettings(self):
        """Updates the settings chosen from the settings view."""
        if self.settingsView.bbscScoreRadioButton.isChecked():
            self.colorScheme = ColorScheme.bbsc
        elif self.settingsView.customColorRadioButton.isChecked():
            self.colorScheme = ColorScheme.custom
        self.painter.nsPerFrame = float(
            self.settingsView.nsPerFrameField.text())
        self.painter.threshold = float(self.settingsView.thresholdField.text())
        self.painter.rendered = False
        self.painter.colorScheme = self.colorScheme
        self.painter.customColor = self.customColor
        self.painter.repaint()
        self.painter.update()

    def updateFilters(self):
        """Updates the chosen filters in MainWindow."""
        if self.vismode is True:
            self.frameStrideField.setText("1")
        stride = int(self.frameStrideField.text())
        if stride < 1:
            stride = 1
            QApplication.processEvents()
            self.frameStrideField.setText(str(stride))
        # print("stride: ", stride)
        self.painter.merge = stride
        self.painter.labelView.clean()
        self.painter.showHbondScores = False
        # total time filter
        totalTimeActive = self.activeTotalTimeCheckbox.isChecked()
        scoreActive = self.activeScoreCheckbox.isChecked()
        sortingActive = self.activeSortingBox.isChecked()
        onlyActive = self.onlyBoxActiveCheckbox.isChecked()
        filterActive = (totalTimeActive or scoreActive or sortingActive
                        or onlyActive)
        weightActive = False
        # only filter given range
        rangeFilterActive = self.filterRangeCheckbox.isChecked()
        if len(self.contacts) > 0:
            lower = int(self.lowerRangeField.text()) - 1
            upper = self.upperRangeField.text()
            if upper == "end":
                upper = len(self.contacts[0].scoreArray)
            else:
                upper = int(upper)

            if lower < 0:
                lower = 0
            self.painter.range = [lower, upper]
            self.painter.rangeFilterActive = False
            self.filteredContacts = copy.deepcopy(self.contacts)
            # residue range filter
            range_filter = RangeFilter("resrange")
            self.filteredContacts = range_filter.filterByRange(
                self.filteredContacts, self.residARangeField.text(),
                self.residBRangeField.text(), AccumulationMapIndex.resid)

            self.filteredContacts = range_filter.filterByRange(
                self.filteredContacts, self.atomAIndexField.text(),
                self.atomBIndexField.text(), AccumulationMapIndex.index)

            # aminoacids name filter
            name_filter = NameFilter("name")
            self.filteredContacts = name_filter.filterContactsByName(
                self.filteredContacts, self.residANameField.text(),
                self.residBNameField.text(), AccumulationMapIndex.resname)

            self.filteredContacts = name_filter.filterContactsByName(
                self.filteredContacts, self.atomANameField.text(),
                self.atomBNameField.text(), AccumulationMapIndex.name)
            # range filter
            if rangeFilterActive:
                self.painter.rangeFilterActive = True
                frameRangeFilter = FrameFilter("framer")
                self.filteredContacts = frameRangeFilter.extractFrameRange(
                    self.filteredContacts, [lower, upper])
            for c in self.filteredContacts:
                c.setScores()
                c.setContactType()
            # weight functions
            if weightActive:
                if self.currentFunctionType == FunctionType.sigmoid:
                    print("sig weight")
                    x0 = float(self.sigX0Field.text())
                    L = float(self.sigLField.text())
                    k = float(self.sigKField.text())
                    y0 = float(self.sigY0Field.text())
                    sig = SigmoidWeightFunction(
                        "sig", np.arange(0, len(self.contacts[0].scoreArray),
                                         1), x0, L, k, y0)
                    self.filteredContacts = sig.weightContactFrames(
                        self.filteredContacts)
                elif self.currentFunctionType == FunctionType.rect:
                    x0 = float(self.rectX0Field.text())
                    x1 = float(self.rectX1Field.text())
                    h = float(self.rectHField.text())
                    y0 = float(self.rectY0Field.text())
                    rect = RectangularWeightFunction(
                        "rect",
                        np.arange(0, len(self.contacts[0].scoreArray), 1), x0,
                        x1, h, y0)
                    self.filteredContacts = rect.weightContactFrames(
                        self.filteredContacts)
                elif self.currentFunctionType == FunctionType.linear:
                    y0 = float(self.linY0Field.text())
                    y1 = float(self.linY1Field.text())
                    lin = LinearWeightFunction(
                        "rect",
                        np.arange(0, len(self.contacts[0].scoreArray), 1), y0,
                        y1)
                    self.filteredContacts = lin.weightContactFrames(
                        self.filteredContacts)
            # other filters
            if filterActive:
                if totalTimeActive:
                    operator = self.compareTotalTimeDropdown.currentText()
                    value = float(self.totalTimeField.text())
                    filter = TotalTimeFilter("tottime", operator, value)
                    self.filteredContacts = filter.filterContacts(
                        self.filteredContacts)
                if scoreActive:
                    operator = self.compareScoreDropdown.currentText()
                    value = float(self.scoreField.text())
                    filter = ScoreFilter("score", operator, value,
                                         self.meanDropdown.currentText())
                    self.filteredContacts = filter.filterContacts(
                        self.filteredContacts)
                if sortingActive:
                    key = self.sortingKeyDropdown.currentText()
                    descending = SortingOrder.mapping[
                        self.sortingOrderDropdown.currentText()]
                    sorter = Sorting("sorting", key, descending)
                    sorter.setThresholdAndNsPerFrame(
                        float(self.settingsView.thresholdField.text()),
                        float(self.settingsView.nsPerFrameField.text()))
                    self.filteredContacts = sorter.sortContacts(
                        self.filteredContacts)
                if onlyActive:
                    key = self.selectOnlyToolbox.currentText()
                    only = OnlyFilter("only", key, 0)
                    self.filteredContacts = only.filterContacts(
                        self.filteredContacts)
                    if key == "hbonds":
                        self.painter.showHbondScores = True
                self.painter.contacts = self.filteredContacts
                self.painter.rendered = False
                self.painter.repaint()
                self.painter.update()
                if len(self.filteredContacts) == 0:
                    self.painter.labelView.clean()
            else:
                # no weight or filters
                self.painter.showHbondScores = False
                self.painter.contacts = self.filteredContacts
                self.painter.rendered = False
                self.painter.repaint()
                self.painter.update()

        # Update data for export
        self.exportWidget.setContacts(self.filteredContacts)
        if self.maps is not None:
            self.exportWidget.setMaps(self.maps[0], self.maps[1])
            self.exportWidget.setMapLabels(self.analysis.sel1text,
                                           self.analysis.sel2text)
        self.exportWidget.setThresholdAndNsPerFrame(self.painter.threshold,
                                                    self.painter.nsPerFrame)

    def openPrefs(self):
        """Opens the preferences panel."""
        self.settingsView.show()

    def showStatistics(self):
        """Shows general statistics of the analyzed data over all frames."""
        if len(self.contacts) == 0 or self.contacts is None:
            box = ErrorBox(ErrorMessages.NOSCORES_PROMPTANALYSIS)
            box.exec_()
            return
        self.statisticsView = Statistics(self.contacts)
        self.statisticsView.showNormal()

    def showDeveloperInfo(self):
        """Shows information about the contributing authors."""
        d = QDialog()
        grid = QGridLayout()
        d.setLayout(grid)

        info = QLabel("Developers: Maximilian Scheurer and Peter Rodenkirch")
        info2 = QLabel(
            "Departments: TCBG, University of Illinois at Urbana-Champaign; BZH Heidelberg University"
        )
        mail = QLabel(
            "Contact: [email protected], [email protected]"
        )
        copyright = QLabel("Version 1.0, May 2017")

        grid.addWidget(info, 0, 0)
        grid.addWidget(info2, 1, 0)
        grid.addWidget(mail, 2, 0)
        grid.addWidget(copyright, 3, 0)

        d.setWindowTitle("Developer Info")
        d.resize(150, 80)
        d.setWindowModality(Qt.ApplicationModal)
        d.exec_()

    def pushExport(self):
        """Opens the export panel."""
        self.exportWidget.valueUpdated.connect(self.handleExportUpdate)
        self.exportWidget.setContacts(self.filteredContacts)
        if self.maps is not None:
            self.exportWidget.setMaps(self.maps[0], self.maps[1])
            self.exportWidget.setMapLabels(self.analysis.sel1text,
                                           self.analysis.sel2text)
        self.exportWidget.setThresholdAndNsPerFrame(self.painter.threshold,
                                                    self.painter.nsPerFrame)
        self.exportWidget.show()

    @QtCore.Slot(str, str)
    def handleExportUpdate(self, fileName, fileType):
        """Handles the paint event after the export of the current view has been initiated."""
        print("test")
        if fileType == "PNG":
            if len(fileName) > 0:
                print("Saving current view to ", fileName)
                currentView = self.painter.grab()
                currentView.save(fileName)
        elif fileType == "SVG":
            if len(fileName) > 0:
                print("Saving current view to ", fileName)
                generator = QSvgGenerator()
                generator.setFileName(fileName)
                generator.setSize(self.painter.size())
                generator.setViewBox(self.painter.rect())
                self.painter.renderContact(generator)
        self.painter.rendered = False
        self.painter.repaint()
        self.painter.update()

    def showColorPicker(self):
        """Shows a color picker for the current view."""
        col = QColorDialog.getColor()
        self.customColor = col
        if col.isValid():
            self.settingsView.pickColorButton.setStyleSheet(
                "QWidget { background-color: %s }" % self.customColor.name())