#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ GEPARD - Gepard-Enabled PARticle Detection Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für Polymerforschung Dresden e. V. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program, see COPYING. If not, see . """ import numpy as np from PyQt5 import QtWidgets class LoadTrueMatchResults(QtWidgets.QDialog): def __init__(self, particleContainer, parent): super(LoadTrueMatchResults, self).__init__() self.setGeometry(400, 400, 200, 300) self.setWindowTitle('Get Truematch Results') self.layout = QtWidgets.QGridLayout() self.setLayout(self.layout) self.particleContainer = particleContainer self.parent = parent self.parent.setDisabled(True) self.trueMatchResults = None self.polymertypes = None self.additives = None self.hqis = None self.addhqis = None self.loadBtn = QtWidgets.QPushButton('LoadTrueMatchResults') self.loadBtn.resize(self.loadBtn.sizeHint()) self.loadBtn.clicked.connect(self.loadFileManually) self.reviewGroup = QtWidgets.QGroupBox('Review Changes') self.reviewGroup.setDisabled(True) reviewLayout = QtWidgets.QVBoxLayout() self.otherBtn = QtWidgets.QPushButton('manual overwrite') self.otherBtn.clicked.connect(self.show3FlagsReview) reviewLayout.addWidget(self.otherBtn) reviewLayout.addStretch() self.reviewGroup.setLayout(reviewLayout) self.layout.addWidget(self.loadBtn, 0, 0) self.layout.addWidget(self.reviewGroup, 2, 0) self.manualPolymers = {} self.manualAdditives = {} self.expWindow = None self.additivePlot = None self.editEntryWindow = None self.numFlagForTakeSpectrum = 1 self.numFlagForSetUnknown = 2 self.numFlagForPrompt = 3 def show3FlagsReview(self): self.editEntryWindow = ModifyManualEdits(self, self.manualPolymers, self.manualAdditives) self.editEntryWindow.show() def loadFileManually(self): dsetpath = self.parent.dataset.path fnames =QtWidgets.QFileDialog.getOpenFileNames(self, 'Select TrueMatch result file', dsetpath, 'text file (*.txt)')[0] if len(fnames) > 1: QtWidgets.QMessageBox.about(self, 'Info', 'The following order of files was loaded. If incorrect, please call a coder!\n{}'.format('\n'.join([fname for fname in fnames]))) self.trueMatchResults = [] for fileindex, fname in enumerate(fnames): with open(fname) as file: if fileindex == 0: for line in file: self.trueMatchResults.append(line) else: ##for additional files skip first line (header..) for lineindex, line in enumerate(file): if lineindex > 0: self.trueMatchResults.append(line) self.runCalculations() def formatResults(self, rawResults): #get rid of header line, first data interpretation results = [] for index, line in enumerate(rawResults): if index == 0: line = line.strip().split(';')[:-1] #disregard the last entry of each line, as each line ends with ; <- that produces an empty entry... assert line[0] == 'Search Spectrum Name', 'Assertion Error in loadTrueMatchResults' #detect, whether one- or multicomponent-search was done if line[-1] == 'IsMarked': numhits = np.int(line[-2].split(' ')[-1]) numcomps = 1 else: numhits = np.int(line[-1].split(' ')[-1]) numcomps = np.int(line[-1].split(' ')[-3]) else: results.append(line) numspectra = len(results) if numspectra > 0: print('{} components, {} hits per sample, {} spectra'.format(numcomps, numhits, numspectra)) return results, numspectra, numcomps, numhits def interpretEntry(self, entry, numhits, numcomps): entry = entry.split(';') specIndex, polymertype, additive, hqi, addhqi = None, None, None, None, 0 #assign defaults #specNameFormat is: SampleName_000_Spec.Data 1 (SpecIndex) specName = entry[0] indexOpenBracket = specName.find('(') indexCloseBracket = specName.find(')') inbrackets = specName[indexOpenBracket+1:indexCloseBracket] try: specIndex = int(inbrackets) except: print(inbrackets) raise #find yes-flags flags = np.where(np.array(entry) == 'yes')[0] if len(flags) == 0: #take highest HQI entry if numcomps == 1: polymertype = entry[2] hqi = entry[1] else: polymertype = entry[5] hqi = entry[1] additive = entry[7] addhqi = entry[6] elif len(flags) == 1: #exactly one flag was placed, take this entry if numcomps == 1: polymertype = entry[int(flags[0])-1] hqi = 100 else: polymertype = entry[int(flags[0])+2] additive = entry[int(flags[0])+4] hqi = 100 addhqi = 100 elif len(flags) == 2: polymertype = 'unknown' hqi = 0 if numcomps > 1: additive = 'none' addhqi = 0 elif len(flags) == 3: hqi = 100 if specIndex not in self.manualPolymers: polymertype, ok = QtWidgets.QInputDialog.getText(self, 'Name of main component', 'Spectrum at index {} is:'.format(specIndex)) self.manualPolymers[specIndex] = polymertype else: polymertype = self.manualPolymers[specIndex] if numcomps > 1: addhqi = 100 if entry[0] not in self.manualAdditives: additive, ok = QtWidgets.QInputDialog.getText(self, 'Name of additive', 'Additive at index {} is:'.format(specIndex)) self.manualAdditives[specIndex] = additive else: additive = self.manualAdditives[specIndex] else: QtWidgets.QMessageBox.about(self, 'Error!', 'No rule for {} flags, found at spectrum index {}'.format(len(flags), specIndex)) return specIndex, polymertype, additive, float(hqi), float(addhqi) def runCalculations(self): self.resultList, numspectra, numcomps, numhits = self.formatResults(self.trueMatchResults) self.polymertypes = [None]*numspectra self.hqis = [None]*numspectra if numcomps == 1: #####SINGLE COMPONENT SEARCH self.additives = None self.addhqis = None for index, entry in enumerate(self.resultList): if len(entry) == 0: del self.resultList[index] else: specIndex, polymertype, additive, hqi, addhqi = self.interpretEntry(entry, numhits, numcomps) self.polymertypes[specIndex] = polymertype self.hqis[specIndex] = hqi else: #####MULTI-COMPONENT SEARCH self.additives = [None]*numspectra self.addhqis = [None]*numspectra for index, entry in enumerate(self.resultList): if len(entry) > 0: specIndex, polymertype, additive, hqi = self.interpretEntry(entry, numhits, numcomps) self.polymertypes[specIndex] = polymertype self.hqis[specIndex] = hqi self.additives[specIndex] = additive self.addhqis[specIndex] = addhqi assert len(self.polymertypes) == len(self.resultList), 'incorrect number of polymer types added...' assert not None in self.polymertypes, 'wrong assignments in loadResults' assert not None in self.hqis, 'wrong assignments in loadResults' self.particleContainer.applyAssignmentListToParticleMeasurements(self.polymertypes) self.particleContainer.applyHQIListToParticleMeasurements(self.hqis) if len(self.manualPolymers) > 0: self.reviewGroup.setDisabled(False) self.parent.applyHQIThresholdToResults() self.loadBtn.setText('Data loaded') QtWidgets.QMessageBox.about(self, 'Success', 'Results were imported successfully.\nYou can close this window or modify manual edits.') def closeEvent(self, event): #TODO: SANITY CHECK FOR DATA CONSISTENCY!! self.parent.setEnabled(True) event.accept() class ModifyManualEdits(QtWidgets.QWidget): def __init__(self, parentWindow, polymerEdits, additiveEdits = None): super(ModifyManualEdits, self).__init__() self.setWindowTitle('Edit Manual Changes') self.setGeometry(200, 200, 800, 500) layout = QtWidgets.QVBoxLayout() self.setLayout(layout) self.parent = parentWindow self.polymerEdits = polymerEdits self.additiveEdits = additiveEdits self.labels = [] self.polymerLineEdits = [] self.additiveLineEdits = [] groupBox = QtWidgets.QGroupBox('Manually entered edits') groupLayout = QtWidgets.QGridLayout() #create Labels and LineEdits for index in self.polymerEdits: self.labels.append(QtWidgets.QLabel('Spectrum index:' + str(index))) print(self.labels[-1].text()) self.polymerLineEdits.append(QtWidgets.QLineEdit()) self.polymerLineEdits[-1].setText(self.polymerEdits[index]) if len(self.additiveEdits) > 0: self.additiveLineEdits.append(QtWidgets.QLineEdit()) self.additiveLineEdits[-1].setText(self.additiveEdits[index]) for i in range(len(self.labels)): groupLayout.addWidget(self.labels[i], i, 0) groupLayout.addWidget(self.polymerLineEdits[i], i, 1) if len(self.additiveEdits) > 0: groupLayout.addWidget(self.additiveLineEdits[i], i, 2) groupBox.setLayout(groupLayout) scrollarea = QtWidgets.QScrollArea() scrollarea.setWidget(groupBox) scrollarea.setMaximumHeight(600) layout.addWidget(scrollarea) saveAndCloseBtn = QtWidgets.QPushButton('Save and Exit') saveAndCloseBtn.clicked.connect(self.closeEvent) layout.addWidget(saveAndCloseBtn) def closeEvent(self, event): #read out LineEdits: for index, key in enumerate(self.polymerEdits): self.polymerEdits[key] = self.polymerLineEdits[index].text() if len(self.additiveEdits) > 0: self.additiveEdits[key] = self.additiveLineEdits[index].text() #copy values to parent Window self.parent.manualPolymers, self.parent.manualAdditives = self.polymerEdits, self.additiveEdits self.parent.runCalculations() self.close()