Loading analysis/analysisWidgets.py +5 −7 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ along with this program, see COPYING. If not, see <https://www.gnu.org/licenses/>. """ from PyQt5 import QtCore, QtWidgets, QtGui from PIL import ImageFont import numpy as np Loading Loading @@ -60,14 +59,13 @@ class Legend(QtWidgets.QMdiSubWindow): if numEntries > 0: def getSize(fontsize, text, tileSize, spacer): # font = ImageFont.truetype('arial.ttf', fontsize) # size = font.getsize(text) size = 5*len(text), fontsize+2 width, height = size[0]*1.5 + tileSize + spacer, numEntries * (tileSize+1*spacer) + 2*spacer font = QtGui.QFont() font.setPixelSize(fontSize) fm = QtGui.QFontMetrics(font) pixelwidth = fm.width(text) width, height = pixelwidth + tileSize + 3*spacer, numEntries * (tileSize+1*spacer) + 2*spacer return width, height fontSize, tileSize, spacer = self.fontSize, self.tileSize, self.spacer longestEntry = max([i[0] for i in self.items], key=len) width, height = getSize(fontSize, longestEntry, tileSize, spacer) Loading analysis/analysisview.py +44 −8 Original line number Diff line number Diff line Loading @@ -40,8 +40,12 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio import pandas as pd from analysis.loadresults import LoadWITecResults from analysis.sqlexport import SQLExport from analysis.editParticles import ParticleEditor try: from analysis.sqlexport import SQLExport sqlEnabled = True except: sqlEnabled = False class ParticleAnalysis(QtWidgets.QWidget): Loading Loading @@ -263,7 +267,6 @@ class ParticleAnalysis(QtWidgets.QWidget): self.layout_SArea.addWidget(self.resultCheckBoxes) # self.layout_SArea.addStretch(1) self.exportbtn= QtWidgets.QPushButton('Export Results') self.exportbtn.clicked.connect(self.exportData) self.exportbtn.setDisabled(True) Loading @@ -286,7 +289,23 @@ class ParticleAnalysis(QtWidgets.QWidget): def loadSpectra(self, fname): try: return np.loadtxt(fname) specs = np.loadtxt(fname) #if spectra are already in correct format (WITec, first column: wavenumbers, other columns, intensities), #we take them, otherwise we have to convert from Renishaw export format... if len(np.unique(specs[:, 0])) == len(specs[:, 0]): #--> only unique numbers -> this is the wavenumber column, we have the witec format return specs else: #columns 0 and 1 are x and y coordinates. We dont need them... startWavenumber = specs[0, 2] startIndices = np.where(specs[:, 2] == startWavenumber)[0] spectra = np.zeros((startIndices[1], len(startIndices)+1)) #create array with shape (numWavenumbers, numSpectra+1) (first column holds wavenumbers) spectra[:, 0] = specs[startIndices[0]:startIndices[1], 2] for i in range(len(startIndices)-1): spectra[:, i+1] = specs[startIndices[i]:startIndices[i+1], 3] #aaand the last spectrum: spectra[:, -1] = specs[startIndices[-1]:, 3] return np.flip(spectra, 0) #Renishaw goes from highest to lowest wavenumber, out of whatever reason... except: return None Loading @@ -301,14 +320,25 @@ class ParticleAnalysis(QtWidgets.QWidget): self.colorSeed = 'default' #load Spectra self.spectra = self.loadSpectra(os.path.join(self.parent.dataset.path, self.parent.dataset.name + '_000_Spec.Data 1.txt')) if self.parent.dataset.spectraPath is None: fname = os.path.join(self.parent.dataset.path, self.parent.dataset.name + '_000_Spec.Data 1.txt') else: fname = self.parent.dataset.spectraPath self.spectra = self.loadSpectra(fname) if self.spectra is None: fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Spectra File', self.parent.dataset.path, 'text file (*.txt)')[0] self.spectra = self.loadSpectra(fname) if self.spectra is None: QtWidgets.QMessageBox.critical(self, 'ERROR!', 'spectra file could not be opened with np.loadtxt...') return self.parent.dataset.spectraPath = fname self.spec_ax.set_xbound(100, (3400 if self.spectra[-1, 0] > 3400 else self.spectra[-1, 0])) self.specCanvas.draw() ####fake data!!! if self.spectraResults is None: self.spectraResults = ['empty']*(self.spectra.shape[1]-1) self.hqis = [100]*(self.spectra.shape[1]-1) self.loadParticleData() Loading Loading @@ -380,7 +410,9 @@ class ParticleAnalysis(QtWidgets.QWidget): self.particleResults = [None]*len(self.particlestats) self.typehistogram = {i: 0 for i in self.uniquePolymers} assert len(self.particles2spectra) == len(self.particlestats), 'inconsistent data!!' if len(self.particles2spectra) != len(self.particlestats): QtWidgets.QMessageBox.critical(self, 'Error', 'Inconsistent particle data. Please restore backup!') return for particleID, specList in enumerate(self.particles2spectra): assignment = self.currentPolymers[specList[0]] #we take the first result as particle result. Hence, all spectra per particle have to have the same result Loading Loading @@ -498,6 +530,7 @@ class ParticleAnalysis(QtWidgets.QWidget): self.spec_ax.set_xlabel('Wavenumber (cm-1)', fontsize = 15) self.spec_ax.set_ylabel('Counts', fontsize = 15) self.spec_ax.set_title('ScanPoint Number {}, Size = {} µm'.format(specIndex+1, np.round(self.particlestats[self.currentParticleIndex][2], 1))) self.spec_ax.set_xbound(100, (3400 if self.spectra[-1, 0] > 3400 else self.spectra[-1, 0])) self.spec_ax.figure.canvas.draw() self.parent.centerOnRamanIndex(specIndex, centerOn=centerOn, highlightContour=highlightContour) self.parent.highLightRamanIndex(specIndex) Loading Loading @@ -805,7 +838,10 @@ class ExportDialog(QtWidgets.QWidget): self.sqlbtn = QtWidgets.QPushButton('Export to SQL Database') self.sqlbtn.resize(self.sqlbtn.sizeHint()) if sqlEnabled: self.sqlbtn.clicked.connect(self.toSQL) else: self.sqlbtn.setDisabled(True) self.sqlExport = None Loading analysis/editParticles.py +24 −8 Original line number Diff line number Diff line Loading @@ -26,16 +26,33 @@ If not, see <https://www.gnu.org/licenses/>. """ import numpy as np import cv2 from PyQt5 import QtWidgets #import matplotlib.pyplot as plt class ParticleEditor(object): def __init__(self, parent): self.parent = parent #the assigned analysis widget self.backupFreq = 3 #save a backup every n actions self.neverBackedUp = True self.actionCounter = 0 def createSafetyBackup(self): self.actionCounter += 1 if self.actionCounter == self.backupFreq-1 or self.neverBackedUp: print('backing up') self.parent.parent.dataset.saveBackup() self.neverBackedUp = False self.actionCounter = 0 def getNewEntry(self): text, okClicked = QtWidgets.QInputDialog.getText(self.parent.parent, "Custom assignment", "Enter new assignment") if okClicked and text != '': return text def combineParticles(self, contourIndices, new_assignment): if new_assignment == 'other': new_assignment = self.getNewEntry() contourIndices = sorted(contourIndices) #we want to keep the contour with lowest index print('selected contours:', contourIndices) self.createSafetyBackup() Loading Loading @@ -76,7 +93,6 @@ class ParticleEditor(object): sortindices = self.parent.parent.dataset.ramanscansortindex self.parent.parent.dataset.particles2spectra = [[int(np.where(sortindices == i)[0])] for i in range(len(sortindices))] #Contour indices are the same as the original particlestats, which are contained in the dataset. #We have to modify that and reload in the analysisview #first, overwrite first index with new particlestats Loading @@ -89,7 +105,6 @@ class ParticleEditor(object): self.parent.parent.dataset.particlecontours[contourIndices[0]] = newContour self.parent.parent.dataset.particlecontours = [i for ind, i in enumerate(self.parent.parent.dataset.particlecontours) if ind not in contourIndices[1:]] #update particle2spectra_list #what is the current particle index?? specIndices = [] Loading @@ -98,13 +113,12 @@ class ParticleEditor(object): specIndices.append(self.parent.particles2spectra[index]) #flatten index list (in case, that a nested list was created...) specIndices = list(np.unique(np.array(specIndices))) specIndices = list(np.concatenate(specIndices)) for i in specIndices: self.parent.spectraResults[i] = new_assignment self.parent.hqis[i] = 100 #avoid sorting them out again by hqi-filter... print(f'spectrum {i} of particle{contourIndices[0]} is now {new_assignment}') #modify particles2spectra.. self.parent.parent.dataset.particles2spectra[contourIndices[0]] = specIndices for index in reversed(contourIndices[1:]): Loading @@ -116,11 +130,13 @@ class ParticleEditor(object): #update contours in sampleview self.parent.parent.contouritem.resetContours(self.parent.parent.dataset.particlecontours) self.parent.loadParticleData() def reassignParticles(self, contourindices, new_assignment): if new_assignment == 'other': new_assignment = self.getNewEntry() self.createSafetyBackup() for partIndex in contourindices: for specIndex in self.parent.particles2spectra[partIndex]: Loading @@ -128,7 +144,7 @@ class ParticleEditor(object): self.parent.spectraResults[specIndex] = new_assignment self.parent.hqis[specIndex] = 100 self.parent.createHistogramData() self.parent.loadParticleData() def deleteParticles(self): Loading dataset.py +4 −4 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ class DataSet(object): self.resultParams = {'minHQI': None, 'compHQI': None} self.spectraPath = None self.particles2spectra = None #links idParticle to corresponding idSpectra (i.e., first measured particle (ID=0) is linked to spectra indices 0 and 1) self.colorSeed = 'default' self.resultsUploadedToSQL = [] Loading Loading @@ -177,12 +177,12 @@ class DataSet(object): print('pixelscale was', self.pixelscale) self.pixelscale_bf = self.pixelscale self.pixelscale_df = self.pixelscale # del self.pixelscale del self.pixelscale if hasattr(self, 'imagedim'): self.imagedim_bf = self.imagedim self.imagedim_df = self.imagedim # del self.imagedim del self.imagedim self.version = 2 Loading gepard.py +9 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ from ramancom.ramancontrol import defaultPath from ramancom.ramanSwitch import RamanSwitch from analysis.analysisWidgets import Legend import os from pathlib import Path class MeasureParticleWindow(QtWidgets.QMainWindow): Loading Loading @@ -287,12 +288,17 @@ if __name__ == '__main__': import sys from time import localtime, strftime logpath = os.path.join(Path.home(),'gepard') if not os.path.exists(logpath): os.mkdir(logpath) logname = os.path.join(logpath, 'logfile.txt') # logname = os.path.join(os.path.split(__file__)[0], os.path.join("logfile.txt")) # fp = open(logname, "a") # sys.stderr = fp # sys.stdout = fp fp = open(logname, "a") sys.stderr = fp sys.stdout = fp print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime())) sys.stdout.flush() app = QtWidgets.QApplication(sys.argv) meas = MeasureParticleWindow() meas.showMaximized() Loading Loading
analysis/analysisWidgets.py +5 −7 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ along with this program, see COPYING. If not, see <https://www.gnu.org/licenses/>. """ from PyQt5 import QtCore, QtWidgets, QtGui from PIL import ImageFont import numpy as np Loading Loading @@ -60,14 +59,13 @@ class Legend(QtWidgets.QMdiSubWindow): if numEntries > 0: def getSize(fontsize, text, tileSize, spacer): # font = ImageFont.truetype('arial.ttf', fontsize) # size = font.getsize(text) size = 5*len(text), fontsize+2 width, height = size[0]*1.5 + tileSize + spacer, numEntries * (tileSize+1*spacer) + 2*spacer font = QtGui.QFont() font.setPixelSize(fontSize) fm = QtGui.QFontMetrics(font) pixelwidth = fm.width(text) width, height = pixelwidth + tileSize + 3*spacer, numEntries * (tileSize+1*spacer) + 2*spacer return width, height fontSize, tileSize, spacer = self.fontSize, self.tileSize, self.spacer longestEntry = max([i[0] for i in self.items], key=len) width, height = getSize(fontSize, longestEntry, tileSize, spacer) Loading
analysis/analysisview.py +44 −8 Original line number Diff line number Diff line Loading @@ -40,8 +40,12 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio import pandas as pd from analysis.loadresults import LoadWITecResults from analysis.sqlexport import SQLExport from analysis.editParticles import ParticleEditor try: from analysis.sqlexport import SQLExport sqlEnabled = True except: sqlEnabled = False class ParticleAnalysis(QtWidgets.QWidget): Loading Loading @@ -263,7 +267,6 @@ class ParticleAnalysis(QtWidgets.QWidget): self.layout_SArea.addWidget(self.resultCheckBoxes) # self.layout_SArea.addStretch(1) self.exportbtn= QtWidgets.QPushButton('Export Results') self.exportbtn.clicked.connect(self.exportData) self.exportbtn.setDisabled(True) Loading @@ -286,7 +289,23 @@ class ParticleAnalysis(QtWidgets.QWidget): def loadSpectra(self, fname): try: return np.loadtxt(fname) specs = np.loadtxt(fname) #if spectra are already in correct format (WITec, first column: wavenumbers, other columns, intensities), #we take them, otherwise we have to convert from Renishaw export format... if len(np.unique(specs[:, 0])) == len(specs[:, 0]): #--> only unique numbers -> this is the wavenumber column, we have the witec format return specs else: #columns 0 and 1 are x and y coordinates. We dont need them... startWavenumber = specs[0, 2] startIndices = np.where(specs[:, 2] == startWavenumber)[0] spectra = np.zeros((startIndices[1], len(startIndices)+1)) #create array with shape (numWavenumbers, numSpectra+1) (first column holds wavenumbers) spectra[:, 0] = specs[startIndices[0]:startIndices[1], 2] for i in range(len(startIndices)-1): spectra[:, i+1] = specs[startIndices[i]:startIndices[i+1], 3] #aaand the last spectrum: spectra[:, -1] = specs[startIndices[-1]:, 3] return np.flip(spectra, 0) #Renishaw goes from highest to lowest wavenumber, out of whatever reason... except: return None Loading @@ -301,14 +320,25 @@ class ParticleAnalysis(QtWidgets.QWidget): self.colorSeed = 'default' #load Spectra self.spectra = self.loadSpectra(os.path.join(self.parent.dataset.path, self.parent.dataset.name + '_000_Spec.Data 1.txt')) if self.parent.dataset.spectraPath is None: fname = os.path.join(self.parent.dataset.path, self.parent.dataset.name + '_000_Spec.Data 1.txt') else: fname = self.parent.dataset.spectraPath self.spectra = self.loadSpectra(fname) if self.spectra is None: fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Spectra File', self.parent.dataset.path, 'text file (*.txt)')[0] self.spectra = self.loadSpectra(fname) if self.spectra is None: QtWidgets.QMessageBox.critical(self, 'ERROR!', 'spectra file could not be opened with np.loadtxt...') return self.parent.dataset.spectraPath = fname self.spec_ax.set_xbound(100, (3400 if self.spectra[-1, 0] > 3400 else self.spectra[-1, 0])) self.specCanvas.draw() ####fake data!!! if self.spectraResults is None: self.spectraResults = ['empty']*(self.spectra.shape[1]-1) self.hqis = [100]*(self.spectra.shape[1]-1) self.loadParticleData() Loading Loading @@ -380,7 +410,9 @@ class ParticleAnalysis(QtWidgets.QWidget): self.particleResults = [None]*len(self.particlestats) self.typehistogram = {i: 0 for i in self.uniquePolymers} assert len(self.particles2spectra) == len(self.particlestats), 'inconsistent data!!' if len(self.particles2spectra) != len(self.particlestats): QtWidgets.QMessageBox.critical(self, 'Error', 'Inconsistent particle data. Please restore backup!') return for particleID, specList in enumerate(self.particles2spectra): assignment = self.currentPolymers[specList[0]] #we take the first result as particle result. Hence, all spectra per particle have to have the same result Loading Loading @@ -498,6 +530,7 @@ class ParticleAnalysis(QtWidgets.QWidget): self.spec_ax.set_xlabel('Wavenumber (cm-1)', fontsize = 15) self.spec_ax.set_ylabel('Counts', fontsize = 15) self.spec_ax.set_title('ScanPoint Number {}, Size = {} µm'.format(specIndex+1, np.round(self.particlestats[self.currentParticleIndex][2], 1))) self.spec_ax.set_xbound(100, (3400 if self.spectra[-1, 0] > 3400 else self.spectra[-1, 0])) self.spec_ax.figure.canvas.draw() self.parent.centerOnRamanIndex(specIndex, centerOn=centerOn, highlightContour=highlightContour) self.parent.highLightRamanIndex(specIndex) Loading Loading @@ -805,7 +838,10 @@ class ExportDialog(QtWidgets.QWidget): self.sqlbtn = QtWidgets.QPushButton('Export to SQL Database') self.sqlbtn.resize(self.sqlbtn.sizeHint()) if sqlEnabled: self.sqlbtn.clicked.connect(self.toSQL) else: self.sqlbtn.setDisabled(True) self.sqlExport = None Loading
analysis/editParticles.py +24 −8 Original line number Diff line number Diff line Loading @@ -26,16 +26,33 @@ If not, see <https://www.gnu.org/licenses/>. """ import numpy as np import cv2 from PyQt5 import QtWidgets #import matplotlib.pyplot as plt class ParticleEditor(object): def __init__(self, parent): self.parent = parent #the assigned analysis widget self.backupFreq = 3 #save a backup every n actions self.neverBackedUp = True self.actionCounter = 0 def createSafetyBackup(self): self.actionCounter += 1 if self.actionCounter == self.backupFreq-1 or self.neverBackedUp: print('backing up') self.parent.parent.dataset.saveBackup() self.neverBackedUp = False self.actionCounter = 0 def getNewEntry(self): text, okClicked = QtWidgets.QInputDialog.getText(self.parent.parent, "Custom assignment", "Enter new assignment") if okClicked and text != '': return text def combineParticles(self, contourIndices, new_assignment): if new_assignment == 'other': new_assignment = self.getNewEntry() contourIndices = sorted(contourIndices) #we want to keep the contour with lowest index print('selected contours:', contourIndices) self.createSafetyBackup() Loading Loading @@ -76,7 +93,6 @@ class ParticleEditor(object): sortindices = self.parent.parent.dataset.ramanscansortindex self.parent.parent.dataset.particles2spectra = [[int(np.where(sortindices == i)[0])] for i in range(len(sortindices))] #Contour indices are the same as the original particlestats, which are contained in the dataset. #We have to modify that and reload in the analysisview #first, overwrite first index with new particlestats Loading @@ -89,7 +105,6 @@ class ParticleEditor(object): self.parent.parent.dataset.particlecontours[contourIndices[0]] = newContour self.parent.parent.dataset.particlecontours = [i for ind, i in enumerate(self.parent.parent.dataset.particlecontours) if ind not in contourIndices[1:]] #update particle2spectra_list #what is the current particle index?? specIndices = [] Loading @@ -98,13 +113,12 @@ class ParticleEditor(object): specIndices.append(self.parent.particles2spectra[index]) #flatten index list (in case, that a nested list was created...) specIndices = list(np.unique(np.array(specIndices))) specIndices = list(np.concatenate(specIndices)) for i in specIndices: self.parent.spectraResults[i] = new_assignment self.parent.hqis[i] = 100 #avoid sorting them out again by hqi-filter... print(f'spectrum {i} of particle{contourIndices[0]} is now {new_assignment}') #modify particles2spectra.. self.parent.parent.dataset.particles2spectra[contourIndices[0]] = specIndices for index in reversed(contourIndices[1:]): Loading @@ -116,11 +130,13 @@ class ParticleEditor(object): #update contours in sampleview self.parent.parent.contouritem.resetContours(self.parent.parent.dataset.particlecontours) self.parent.loadParticleData() def reassignParticles(self, contourindices, new_assignment): if new_assignment == 'other': new_assignment = self.getNewEntry() self.createSafetyBackup() for partIndex in contourindices: for specIndex in self.parent.particles2spectra[partIndex]: Loading @@ -128,7 +144,7 @@ class ParticleEditor(object): self.parent.spectraResults[specIndex] = new_assignment self.parent.hqis[specIndex] = 100 self.parent.createHistogramData() self.parent.loadParticleData() def deleteParticles(self): Loading
dataset.py +4 −4 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ class DataSet(object): self.resultParams = {'minHQI': None, 'compHQI': None} self.spectraPath = None self.particles2spectra = None #links idParticle to corresponding idSpectra (i.e., first measured particle (ID=0) is linked to spectra indices 0 and 1) self.colorSeed = 'default' self.resultsUploadedToSQL = [] Loading Loading @@ -177,12 +177,12 @@ class DataSet(object): print('pixelscale was', self.pixelscale) self.pixelscale_bf = self.pixelscale self.pixelscale_df = self.pixelscale # del self.pixelscale del self.pixelscale if hasattr(self, 'imagedim'): self.imagedim_bf = self.imagedim self.imagedim_df = self.imagedim # del self.imagedim del self.imagedim self.version = 2 Loading
gepard.py +9 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ from ramancom.ramancontrol import defaultPath from ramancom.ramanSwitch import RamanSwitch from analysis.analysisWidgets import Legend import os from pathlib import Path class MeasureParticleWindow(QtWidgets.QMainWindow): Loading Loading @@ -287,12 +288,17 @@ if __name__ == '__main__': import sys from time import localtime, strftime logpath = os.path.join(Path.home(),'gepard') if not os.path.exists(logpath): os.mkdir(logpath) logname = os.path.join(logpath, 'logfile.txt') # logname = os.path.join(os.path.split(__file__)[0], os.path.join("logfile.txt")) # fp = open(logname, "a") # sys.stderr = fp # sys.stdout = fp fp = open(logname, "a") sys.stderr = fp sys.stdout = fp print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime())) sys.stdout.flush() app = QtWidgets.QApplication(sys.argv) meas = MeasureParticleWindow() meas.showMaximized() Loading