# -*- coding: utf-8 -*- #!/usr/bin/env python3 """ 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 . """ from PyQt5 import QtCore, QtGui, QtWidgets import numpy as np import sys import random import colorsys from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from .analysiswidgets import ExpExcelDialog, AdditiveViewer from .loadresults import LoadWITecResults from .particleeditor import ParticleEditor from .database import DataBaseWindow from .datastats import DataStats try: from .sqlexport import SQLExport sqlEnabled = True except: sqlEnabled = False class ParticleAnalysis(QtWidgets.QMainWindow): def __init__(self, dataset, parent=None): super(ParticleAnalysis, self).__init__(parent) self.setGeometry(100, 100, 1680, 1050) self.setWindowTitle('Results of polymer analysis') self.layout = QtWidgets.QHBoxLayout() self.widget = QtWidgets.QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) self.parent = parent self.datastats = DataStats(dataset) self.editor = ParticleEditor(self.datastats, self) self.additivePlot = None self.importWindow = None self.polymerCheckBoxes = [] self.lastSelectedCheckBoxNames = [] self.currentParticleIndex = 0 self.currentSpectrumIndex = 0 self.lastSpectrumInFocus = None self.typeHistogramCanvas = FigureCanvas(Figure()) self.sizeHistogramCanvas = FigureCanvas(Figure()) self.typeHist_ax = self.typeHistogramCanvas.figure.subplots() self.typeHist_ax.axis('off') sizeHistGroup = QtWidgets.QGroupBox() sizeHistLayout = QtWidgets.QHBoxLayout() self.sizeHist_ax = self.sizeHistogramCanvas.figure.subplots() self.sizeHist_ax.axis('off') self.sizeHistogramCanvas.figure.subplots_adjust(left=0.1, top=0.93, bottom=0.15, right=0.995) histNavigation = NavigationToolbar(self.sizeHistogramCanvas, self) histNavigation.setOrientation(QtCore.Qt.Vertical) histNavigation.setFixedWidth(50) sizeHistLayout.addWidget(histNavigation) sizeHistLayout.addWidget(self.sizeHistogramCanvas) sizeHistGroup.setLayout(sizeHistLayout) specGroup = QtWidgets.QGroupBox() specLayout = QtWidgets.QHBoxLayout() self.specCanvas = FigureCanvas(Figure()) self.spec_ax = self.specCanvas.figure.subplots() self.spec_ax.axis("off") self.ref_ax = self.spec_ax.twinx() self.specCanvas.figure.subplots_adjust(left=0.1, top=0.93, bottom=0.15, right=0.9) specNavigation = NavigationToolbar(self.specCanvas, self) specNavigation.setOrientation(QtCore.Qt.Vertical) specNavigation.setFixedWidth(50) specLayout.addWidget(specNavigation) specLayout.addWidget(self.specCanvas) specGroup.setLayout(specLayout) viewLayout = QtWidgets.QVBoxLayout() self.menuLayout = QtWidgets.QVBoxLayout() splitter1 = QtWidgets.QSplitter(QtCore.Qt.Vertical) splitter1.addWidget(specGroup) splitter1.addWidget(sizeHistGroup) splitter2 = QtWidgets.QSplitter(QtCore.Qt.Horizontal) splitter2.addWidget(splitter1) splitter2.addWidget(self.typeHistogramCanvas) splitter2.setSizes([300, 150]) self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers') self.navigationGroup.setDisabled(True) navigationLayout = QtWidgets.QHBoxLayout() self.polymerComboBox = QtWidgets.QComboBox() self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType) self.polymerComboBox.setMinimumWidth(150) self.particleSelector = QtWidgets.QSpinBox() self.particleSelector.valueChanged.connect(self.selectParticle) self.spectrumSelector = QtWidgets.QSpinBox() self.spectrumSelector.valueChanged.connect(self.selectSpectrum) for spinbox in [self.particleSelector, self.spectrumSelector]: spinbox.setMinimum(1) spinbox.setSingleStep(1) spinbox.setValue(1) navigationLayout.addWidget(QtWidgets.QLabel('Select Polymer Type:')) navigationLayout.addWidget(self.polymerComboBox) navigationLayout.addStretch() navigationLayout.addWidget(QtWidgets.QLabel('Select Particle')) navigationLayout.addWidget(self.particleSelector) navigationLayout.addWidget(QtWidgets.QLabel('Select Spectrum')) navigationLayout.addWidget(self.spectrumSelector) navigationLayout.addStretch() self.navigationGroup.setLayout(navigationLayout) referenceGroup = QtWidgets.QGroupBox('Reference Spectra') referenceLayout = QtWidgets.QHBoxLayout() self.refSelector = QtWidgets.QComboBox() self.refSelector.setDisabled(True) self.dbWin = DataBaseWindow(self) self.dbWin.selectDataBase(refreshParent=True) #this includes updating the refSelector self.refSelector.currentIndexChanged.connect(self.updateSpecPlot) referenceLayout.addWidget(QtWidgets.QLabel('Select Reference')) referenceLayout.addWidget(self.refSelector) referenceGroup.setLayout(referenceLayout) topLayout = QtWidgets.QHBoxLayout() topLayout.addWidget(self.navigationGroup) topLayout.addWidget(referenceGroup) topLayout.addStretch() viewLayout.addLayout(topLayout) viewLayout.addWidget(splitter2) viewLayout.setStretch(1, 1) self.optionsGroup = QtWidgets.QGroupBox('Further Options') optionsLayout = QtWidgets.QFormLayout() self.hqiSpinBox = QtWidgets.QDoubleSpinBox() self.hqiSpinBox.setValue(75.0) self.hqiSpinBox.setDecimals(1) self.hqiSpinBox.setMinimum(0) optionsLayout.addRow(QtWidgets.QLabel('min HQI:'), self.hqiSpinBox) self.compHqiSpinBox = QtWidgets.QDoubleSpinBox() self.compHqiSpinBox.setValue(30.0) self.compHqiSpinBox.setDecimals(1) self.compHqiSpinBox.setMinimum(0) self.compHqiSpinBox.setDisabled(True) optionsLayout.addRow(QtWidgets.QLabel('min component HQI'), self.compHqiSpinBox) self.dispResultSpinBox = QtWidgets.QSpinBox() self.dispResultSpinBox.setValue(20) self.dispResultSpinBox.setMinimum(1) self.dispResultSpinBox.valueChanged.connect(self.updateHistogram) optionsLayout.addRow(QtWidgets.QLabel('Max. items in display:'), self.dispResultSpinBox) for spinbox in [self.hqiSpinBox, self.compHqiSpinBox]: spinbox.setMaximum(100) spinbox.setMaximumWidth(45) self.updateBtn = QtWidgets.QPushButton('Update Results') self.updateBtn.setDisabled(True) optionsLayout.addRow(self.updateBtn) self.optionsGroup.setLayout(optionsLayout) self.optionsGroup.setMinimumWidth(175) self.optionsGroup.setDisabled(True) self.resultScrollarea = QtWidgets.QScrollArea(self) self.resultScrollarea.setFixedWidth(250) self.resultScrollarea.setWidgetResizable(True) widget = QtWidgets.QWidget() self.resultScrollarea.setWidget(widget) self.layout_SArea = QtWidgets.QVBoxLayout(widget) self.resultCheckBoxes = QtWidgets.QGroupBox('Display Polymer Types:') self.resultCheckBoxesLayout = QtWidgets.QVBoxLayout() self.showTotalSelector = QtWidgets.QCheckBox('Show Total Distribution') self.showTotalSelector.setChecked(True) self.showTotalSelector.setDisabled(True) self.resultCheckBoxesLayout.addWidget(self.showTotalSelector) self.resultCheckBoxesLayout.addStretch() self.resultCheckBoxes.setLayout(self.resultCheckBoxesLayout) self.layout_SArea.addWidget(self.resultCheckBoxes) # self.layout_SArea.addStretch(1) # self.menuLayout.addWidget(reloadGroup) self.menuLayout.addWidget(self.optionsGroup) self.menuLayout.addWidget(self.resultScrollarea) self.layout.addLayout(self.menuLayout) self.layout.addLayout(viewLayout) minHQI = self.datastats.dataset.resultParams['minHQI'] compHQI = self.datastats.dataset.resultParams['compHQI'] if minHQI is not None: self.hqiSpinBox.setValue(minHQI) self.compHqiSpinBox.setValue(compHQI) self.createActions() self.createMenus() self.updateData() def createActions(self): self.loadTrueMatchAct = QtWidgets.QAction("Load &TrueMatch Results", self) self.loadTrueMatchAct.triggered.connect(self.importTrueMatchResults) self.loadTextFileAct = QtWidgets.QAction("Load &ordered Text File", self) self.loadTextFileAct.setDisabled(True) self.noOverlayAct = QtWidgets.QAction("&No Overlay", self) self.selOverlayAct = QtWidgets.QAction("&Selected Overlay", self) self.fullOverlayAct = QtWidgets.QAction("&Full Overlay", self) self.transpAct = QtWidgets.QAction("&Transparent Overlay") self.transpAct.triggered.connect(self.createPolymerOverlay) self.hideLabelAct = QtWidgets.QAction('&Hide Polymer Numbers', self) self.hideLabelAct.triggered.connect(self.show_hide_labels) self.darkenAct = QtWidgets.QAction("&Darken Image", self) self.darkenAct.triggered.connect(self.darkenBackground) for act in [self.noOverlayAct, self.selOverlayAct, self.fullOverlayAct, self.hideLabelAct, self.transpAct, self.darkenAct]: act.setCheckable(True) self.fullOverlayAct.setChecked(True) self.seedAct = QtWidgets.QAction("&Set Color Seed", self) self.seedAct.triggered.connect(self.updateColorSeed) self.databaseAct = QtWidgets.QAction("&ManageDatabase", self) self.databaseAct.triggered.connect(self.launchDBManager) self.expExcelAct= QtWidgets.QAction("Export &Excel List", self) self.expExcelAct.setDisabled(True) self.expExcelAct.triggered.connect(self.exportToExcel) self.expSQLAct = QtWidgets.QAction("Export to &SQL Database", self) self.expSQLAct.setDisabled(True) self.expSQLAct.triggered.connect(self.exportToSQL) def createMenus(self): self.importMenu = QtWidgets.QMenu("&Import Results") self.importMenu.addActions([self.loadTrueMatchAct, self.loadTextFileAct]) self.dispMenu = QtWidgets.QMenu("&Display", self) self.overlayActGroup = QtWidgets.QActionGroup(self.dispMenu) self.overlayActGroup.setExclusive(True) self.overlayActGroup.triggered.connect(self.createPolymerOverlay) self.overlayActGroup.triggered.connect(self.updateHistogram) for act in [self.noOverlayAct, self.selOverlayAct, self.fullOverlayAct]: self.dispMenu.addAction(act) self.overlayActGroup.addAction(act) self.dispMenu.addSeparator() self.dispMenu.addActions([self.transpAct, self.hideLabelAct, self.darkenAct, self.seedAct]) self.refMenu = QtWidgets.QMenu("&References") self.refMenu.addAction(self.databaseAct) self.exportMenu = QtWidgets.QMenu("&Export", self) self.exportMenu.addAction(self.expExcelAct) self.exportMenu.addAction(self.expSQLAct) self.menuBar().addMenu(self.importMenu) self.menuBar().addMenu(self.dispMenu) self.menuBar().addMenu(self.refMenu) self.menuBar().addMenu(self.exportMenu) def launchDBManager(self): if self.dbWin.isHidden(): self.dbWin.show() def populateRefSelector(self): #delete all present entries: self.refSelector.clear() if self.dbWin.activeDatabase is None: self.refSelector.setDisabled(True) else: self.refSelector.addItem('') self.refSelector.addItems(self.dbWin.activeDatabase.spectraNames) self.refSelector.setDisabled(False) def updateData(self): spectra = self.datastats.update() if spectra is None: fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Select Spectra File', self.datastats.dataset.path, 'text file (*.txt)')[0] spectra = self.datastats.loadSpectra(fname) if spectra is None: QtWidgets.QMessageBox.critical(self, 'ERROR!', 'spectra file could not be opened with np.loadtxt...') return self.specCanvas.draw() self.loadParticleData() def loadParticleData(self): #check, if dataset already contains results. Otherwise load them... if not self.datastats.loadParticleData(): self.show() answer = QtWidgets.QMessageBox.question(self, 'Warning', 'No (or inconsistent) spectra results found, please run import dialog.\nPress OK to import or cancel to set to empty.', QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) if answer == QtWidgets.QMessageBox.Ok: self.importTrueMatchResults() elif answer == QtWidgets.QMessageBox.Cancel: self.datastats.invalidateSpectra() self.updateBtn.clicked.connect(self.formatResults) self.formatResults() else: self.updateBtn.clicked.connect(self.formatResults) self.formatResults() def importTrueMatchResults(self): self.importWindow = LoadWITecResults(self.datastats, self) self.importWindow.exec() def getAdditivePlot(self, event): clickedindex = int(np.round(event.xdata)) polymer = self.datastats.typehistogram[clickedindex][0] #get the polymer name, that was clicked on if len(self.datastats.sorted_additives[clickedindex]) > 0: self.additivePlot = AdditiveViewer(polymer, self.datastats.sorted_additives[clickedindex]) self.additivePlot.show() @QtCore.pyqtSlot() def formatResults(self): if self.datastats.spectraResults is not None: print('formatResults') self.updateBtn.setDisabled(False) self.optionsGroup.setDisabled(False) self.datastats.formatResults(self.hqiSpinBox.value(), self.compHqiSpinBox.value()) if self.datastats.additiveResults is not None: self.compHqiSpinBox.setDisabled(False) self.createHistogramData() def createHistogramData(self): if not self.datastats.createHistogramData(): QtWidgets.QMessageBox.critical(self, 'Error', 'Inconsistent particle data. Please restore backup!') return ###Handle Checkboxes for all polymers... self.menuLayout.removeWidget(self.resultScrollarea) for i in [self.resultCheckBoxes, self.resultCheckBoxesLayout, self.resultScrollarea, self.layout_SArea]: i.setParent(None) del i for i in self.polymerCheckBoxes: #remove present boxlabels i.setParent(None) del i self.showTotalSelector.setParent(None) self.showTotalSelector.setDisabled(False) self.showTotalSelector.stateChanged.connect(self.updateHistogram) del self.resultCheckBoxes del self.resultCheckBoxesLayout del self.resultScrollarea del self.layout_SArea self.resultScrollarea = QtWidgets.QScrollArea(self) self.resultScrollarea.setFixedWidth(250) self.resultScrollarea.setWidgetResizable(True) widget = QtWidgets.QWidget() self.resultScrollarea.setWidget(widget) self.layout_SArea = QtWidgets.QVBoxLayout(widget) self.resultCheckBoxes = QtWidgets.QGroupBox('Show Polymer Types:') self.resultCheckBoxesLayout = QtWidgets.QVBoxLayout() self.resultCheckBoxesLayout.addWidget(self.showTotalSelector) #generate new checkboxes self.polymerCheckBoxes = [] uniquePolymers = self.datastats.getUniquePolymers() for index, polymer in enumerate(uniquePolymers): self.polymerCheckBoxes.append(QtWidgets.QCheckBox(self)) self.polymerCheckBoxes[index].setText(polymer) self.resultCheckBoxesLayout.addWidget(self.polymerCheckBoxes[index]) if polymer in self.lastSelectedCheckBoxNames: self.polymerCheckBoxes[index].setChecked(True) self.polymerCheckBoxes[index].stateChanged.connect(self.updateHistogram) self.polymerCheckBoxes[index].stateChanged.connect(self.createPolymerOverlay) self.resultCheckBoxesLayout.addStretch() self.resultCheckBoxes.setLayout(self.resultCheckBoxesLayout) self.layout_SArea.addWidget(self.resultCheckBoxes) self.menuLayout.addWidget(self.resultScrollarea) if self.datastats.currentAdditives is not None: self.typeHistogramCanvas.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor)) self.typeHistogramCanvas.mpl_connect('button_press_event', self.getAdditivePlot) self.expExcelAct.setDisabled(False) if sqlEnabled: self.expSQLAct.setDisabled(False) self.navigationGroup.setEnabled(True) self.polymerComboBox.currentIndexChanged.disconnect() self.polymerComboBox.clear() self.polymerComboBox.addItems(uniquePolymers) self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType) self.polymerIndex = self.polymerComboBox.currentIndex() if self.lastSpectrumInFocus is not None: self.currentSpectrumIndex = self.lastSpectrumInFocus self.displayNewPolymerType(resetCurrentIndex=False) else: self.displayNewPolymerType() self.updateHistogram() self.createPolymerOverlay() def exportToExcel(self): expWin = ExpExcelDialog(self.datastats, self) expWin.exec() def exportToSQL(self): sqlexp = SQLExport(self.datastats, self) sqlexp.exec() def updateSpecPlot(self, centerOn=True, highlightContour=True): #draw Sample Spectrum specIndex = self.currentSpectrumIndex spectra = self.datastats.spectra particlestats = self.datastats.getParticleStats() self.spec_ax.axis("on") self.spec_ax.clear() self.spec_ax.plot(spectra[:, 0], spectra[:, specIndex+1]) self.spec_ax.tick_params(axis='both', which='both', labelsize=15) 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(particlestats[self.currentParticleIndex][2], 1))) self.spec_ax.set_xbound(100, (3400 if spectra[-1, 0] > 3400 else spectra[-1, 0])) wavenumber_diff = list(spectra[:, 0]-100) y_start = wavenumber_diff.index(min(wavenumber_diff)) y_min = min(spectra[y_start:, specIndex+1]) y_max = max(spectra[y_start:, specIndex+1]) self.spec_ax.set_ybound(0.9*y_min, 1.1*y_max) #draw Reference self.ref_ax.clear() if self.refSelector.isEnabled() and self.refSelector.currentText() != '': self.ref_ax.tick_params(axis='both', which='both', labelsize=15) refID = self.dbWin.activeDatabase.spectraNames.index(self.refSelector.currentText()) ref = self.dbWin.activeDatabase.spectra[refID] self.ref_ax.plot(ref[:, 0], ref[:, 1], color = 'r') self.ref_ax.set_ylabel('Ref. Intensity', fontsize = 15, color = 'r') self.ref_ax.tick_params('y', colors = 'r') self.ref_ax.set_xbound(100, (3400 if spectra[-1, 0] > 3400 else spectra[-1, 0])) # wavenumber_diff = list(ref[:, 0]-100) # y_start = wavenumber_diff.index(min(wavenumber_diff)) # y_min = min(ref[y_start:, specIndex+1]) # y_max = max(ref[y_start:, specIndex+1]) self.spec_ax.figure.canvas.draw() self.parent.centerOnRamanIndex(specIndex, centerOn=centerOn, highlightContour=highlightContour) self.parent.highLightRamanIndex(specIndex) self.lastSpectrumInFocus = specIndex def selectContour(self, index, centerOn=True): uniquePolymers = self.datastats.getUniquePolymers() if uniquePolymers is not None: #the index is the contour index, find particle index: specIndex = self.datastats.particles2spectra[index][0] #select first spectrum of partoicle self.currentParticleIndex = index self.currentSpectrumIndex = specIndex selectedPolymer = self.datastats.currentPolymers[specIndex] try: self.polymerIndex = uniquePolymers.index(selectedPolymer) except: print(selectedPolymer) raise #subparticleIndex partIndicesOfThatPolymer = self.datastats.indices[self.polymerIndex] subPartInd = partIndicesOfThatPolymer.index(index) #disconnect analysis widgets: self.particleSelector.valueChanged.disconnect() self.spectrumSelector.valueChanged.disconnect() self.polymerComboBox.currentIndexChanged.disconnect() #set widgets... self.particleSelector.setValue(subPartInd+1) self.particleSelector.setMaximum(len(partIndicesOfThatPolymer)) self.spectrumSelector.setValue(1) self.spectrumSelector.setMaximum(len(self.datastats.particles2spectra[index])) selectedPolymer = self.datastats.currentPolymers[specIndex] self.polymerIndex = uniquePolymers.index(selectedPolymer) self.polymerComboBox.setCurrentIndex(self.polymerIndex) #reconnect all widgets: self.particleSelector.valueChanged.connect(self.selectParticle) self.spectrumSelector.valueChanged.connect(self.selectSpectrum) self.polymerComboBox.currentIndexChanged.connect(self.displayNewPolymerType) self.updateSpecPlot(centerOn=centerOn) def displayNewPolymerType(self, resetCurrentIndex=True): self.polymerIndex = self.polymerComboBox.currentIndex() self.particleSelector.setMaximum(len(self.datastats.indices[self.polymerIndex])) if resetCurrentIndex: self.particleSelector.setValue(1) self.spectrumSelector.setValue(1) self.spectrumSelector.setMaximum(len(self.datastats.particles2spectra[self.currentParticleIndex])) self.currentParticleIndex = self.datastats.indices[self.polymerIndex][self.particleSelector.value()-1] self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot(centerOn=True) else: self.currentParticleIndex = self.datastats.indices[self.polymerIndex][self.particleSelector.value()-1] self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot(centerOn=False) def selectParticle(self, resetSpectrumCount=True): if self.datastats.particles2spectra is not None: self.currentParticleIndex = self.datastats.indices[self.polymerIndex][self.particleSelector.value()-1] self.spectrumSelector.setMaximum(len(self.datastats.particles2spectra[self.currentParticleIndex])) if resetSpectrumCount: self.spectrumSelector.setValue(1) self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot() else: print('no spectrum assignment found...') def selectSpectrum(self): if self.datastats.particles2spectra is not None: self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot() def updateHistogram(self): self.sizeHist_ax.clear() self.typeHist_ax.clear() self.typeHist_ax.axis('on') self.sizeHist_ax.axis('on') #draw the general histogram colorList = [] if self.selOverlayAct.isChecked(): abundancyList = [] for index, checkbox in enumerate(self.polymerCheckBoxes): if checkbox.isChecked(): abundancyList.append(self.datastats.typehistogram[index][1]) curColor = self.getColorFromName(self.datastats.typehistogram[index][0], base255 = False) colorList.append(curColor) else: abundancyList = [i[1] for i in self.datastats.typehistogram] for polymer in self.datastats.typehistogram: curColor = self.getColorFromName(polymer[0], base255 = False) colorList.append(curColor) self.typeHist_ax.barh(range(len(abundancyList)), abundancyList, color=colorList) itemsInPlot = (len(abundancyList) if len(abundancyList) < self.dispResultSpinBox.value() else self.dispResultSpinBox.value()) self.typeHist_ax.set_ylim([itemsInPlot, -1]) #plot in inverse order (have index 0 (highest abundancy) at top) ###add text labels self.histPlotTextLabels = [] y_label_position = 0 for index, i in enumerate(self.datastats.typehistogram): if not self.selOverlayAct.isChecked() or self.polymerCheckBoxes[index].isChecked(): if self.datastats.sorted_additives is None: numads = '' else: numads = len(np.unique(self.datastats.sorted_additives[index])) if numads == 0: numads = '' else: numads = '(' + str(numads) + ')' numpolymers = i[1] label = ('{} x ' + self.datastats.typehistogram[index][0] + ' {}').format(numpolymers, numads) x_label_position = self.typeHist_ax.get_xlim()[1]*0.05 self.histPlotTextLabels.append(self.typeHist_ax.text(x_label_position, y_label_position, label, fontsize = 15, rotation = 0, verticalalignment = 'bottom')) y_label_position += 1 for label in self.histPlotTextLabels: pos = label.get_position() curLimits = self.typeHist_ax.get_ylim() if curLimits[1] < pos[1] < curLimits[0]: label.set_alpha(1) else: label.set_alpha(0) self.typeHist_ax.set_title('Polymer Type Distribution', fontsize = 15) self.typeHist_ax.tick_params(axis='y', which='both', left=False, labelleft=False) self.typeHist_ax.tick_params(axis='both', which='both', labelsize=15) self.typeHist_ax.set_ylabel('Polymer Type', fontsize = 15) self.typeHist_ax.set_xlabel('Number', fontsize = 15) if len(self.datastats.typehistogram) > self.dispResultSpinBox.value(): def wheelScroll(event): step = -0.05*event.step*self.dispResultSpinBox.value() ymin, ymax = self.typeHist_ax.get_ylim() if ymin > ymax: ymin, ymax = ymax, ymin self.typeHist_ax.set_ylim([ymax+step, ymin+step]) for label in self.histPlotTextLabels: pos = label.get_position() if ymin+step < pos[1] < ymax+step: label.set_alpha(1) else: label.set_alpha(0) self.typeHist_ax.figure.canvas.draw() self.typeHistogramCanvas.mpl_connect('scroll_event', wheelScroll) self.typeHist_ax.figure.canvas.draw() #general size histogram self.bins = np.logspace(0.1, 3, 20) self.sizes = [i[0] if np.isnan(i[2]) else i[2] for i in self.datastats.getParticleStats()] #extract long size (if ellipse fit is nan -> box fit) sizehist = np.histogram(self.sizes, self.bins) self.totalhistx = [] for i in range(19): self.totalhistx.append(np.mean((sizehist[1][i], sizehist[1][i+1]))) self.totalhisty = sizehist[0] self.sizeHist_ax.tick_params(axis='both', which='both', labelsize=15) self.sizeHist_ax.set_xlabel('Size (µm)', fontsize = 15) self.sizeHist_ax.set_ylabel('Number', fontsize = 15) self.sizeHist_ax.set_xlim(3, 1100) self.sizeHist_ax.figure.canvas.draw() if self.showTotalSelector.isChecked(): self.sizeHist_ax.semilogx(self.totalhistx, self.totalhisty, label = 'total') #get selected boxes selected = [] for i in self.polymerCheckBoxes: if i.isChecked() == True: selected.append(i.text()) for i in selected: sizes = [self.sizes[index] for index in range(len(self.sizes)) if self.datastats.currentPolymers[index] == i] sizehist = np.histogram(sizes, self.bins) self.sizeHist_ax.semilogx(self.totalhistx, sizehist[0], label = i, color = self.getColorFromName(i, base255 = False)) self.sizeHist_ax.legend(prop = {'size': 15}) self.sizeHist_ax.tick_params(axis='both', which='both', labelsize=15) self.sizeHist_ax.set_xlabel('Size (µm)', fontsize = 15) self.sizeHist_ax.set_ylabel('Number', fontsize = 15) self.sizeHist_ax.set_xlim(3, 1100) self.sizeHist_ax.figure.canvas.draw() self.lastSelectedCheckBoxNames = [checkbox.text() for checkbox in self.polymerCheckBoxes if checkbox.isChecked()] def darkenBackground(self): self.parent.darkenPixmap = self.darkenAct.isChecked() if self.darkenAct.isChecked(): self.parent.scene().setBackgroundBrush(QtGui.QColor(5, 5, 5)) self.parent.item.setOpacity(0.2) else: self.parent.scene().setBackgroundBrush(QtCore.Qt.darkGray) self.parent.item.setOpacity(1) def updateColorSeed(self): text, ok = QtWidgets.QInputDialog.getText(self, 'Color Seed', 'Enter New Seed here', text=self.datastats.colorSeed) if ok: self.datastats.colorSeed = text self.datastats.dataset.colorSeed = text self.updateHistogram() self.createPolymerOverlay() def getColorFromName(self, name, base255=True): random.seed(self.datastats.colorSeed + name) hue = random.random() random.seed((self.datastats.colorSeed + name)*2) saturation = random.random()/4 + 0.75 #i.e., between 0.75 and 1 random.seed((self.datastats.colorSeed + name)*3) value = random.random()/5 + 0.8 #i.e., between 0.8 and 1 color = colorsys.hsv_to_rgb(hue, saturation, value) if base255: color = list(color) for i in range(3): color[i] = np.round(color[i]*255) color = tuple(color) return color def createPolymerOverlay(self): uniquePolymers = self.datastats.getUniquePolymers() if not self.noOverlayAct.isChecked() and self.datastats.indices is not None: if len(self.datastats.indices) > 0: alpha = (128 if self.transpAct.isChecked() else 255) #get colors for each polymer type colorList = [QtGui.QColor(255, 255, 255, alpha=50)]*len(self.datastats.particleResults) legendItems = [] for index, indexList in enumerate(self.datastats.indices): if self.fullOverlayAct.isChecked() or (self.selOverlayAct.isChecked() and self.polymerCheckBoxes[index].isChecked()): color = self.getColorFromName(uniquePolymers[index], base255=True) color = QtGui.QColor(color[0], color[1], color[2], alpha=alpha) legendItems.append((uniquePolymers[index], color)) for i in indexList: colorList[i] = color self.parent.contouritem.colorList = colorList self.parent.contouritem.update() self.parent.imparent.legend.setTextColorItems(legendItems) self.parent.imparent.legend.show() else: self.parent.contouritem.colorList = [] self.parent.contouritem.update() self.parent.imparent.legend.setTextColorItems([]) self.parent.imparent.legend.hide() def show_hide_labels(self): hidden = self.hideLabelAct.isChecked() for scanIndicator in self.parent.ramanscanitems: scanIndicator.hidden = hidden scanIndicator.update() def closeEvent(self, event): for window in [self.additivePlot, self.importWindow, self.dbWin]: try: window.close() except: pass self.parent.imparent.particelAnalysisAct.setChecked(False) event.accept() if __name__ == '__main__': from ..dataset import DataSet def run(): app = QtWidgets.QApplication(sys.argv) meas = ParticleAnalysis(DataSet("dummydata")) meas.showMaximized() return app.exec_() run()