analysisview.py 27 KB
Newer Older
1
# -*- coding: utf-8 -*-
2
#!/usr/bin/env python3
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018  Lars Bittrich and Josef Brandt, Leibniz-Institut für 
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>    

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 <https://www.gnu.org/licenses/>.
"""

from PyQt5 import QtCore, QtGui, QtWidgets
24
import numpy as np
JosefBrandt's avatar
 
JosefBrandt committed
25
import sys
JosefBrandt's avatar
 
JosefBrandt committed
26
import time
27 28 29 30 31

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar

JosefBrandt's avatar
 
JosefBrandt committed
32 33
from .analysiswidgets import ExpExcelDialog
from .analysisplots import TypeHistogramView, SpectraPlot
JosefBrandt's avatar
 
JosefBrandt committed
34
from .loadresults import LoadTrueMatchResults
35
from .particleeditor import ParticleEditor
36
from .database import DataBaseWindow
JosefBrandt's avatar
 
JosefBrandt committed
37
from .colorlegend import getColorFromNameWithSeed
JosefBrandt's avatar
 
JosefBrandt committed
38

Hackmet's avatar
Hackmet committed
39
try:
40
    from .sqlexport import SQLExport
Hackmet's avatar
Hackmet committed
41 42 43
    sqlEnabled = True
except:
    sqlEnabled = False
44 45


Hackmet's avatar
Hackmet committed
46
class ParticleAnalysis(QtWidgets.QMainWindow):
47 48
    def __init__(self, dataset, parent=None):
        super(ParticleAnalysis, self).__init__(parent)
49 50 51
        self.setGeometry(100, 100, 1680, 1050)
        self.setWindowTitle('Results of polymer analysis')
        self.layout = QtWidgets.QHBoxLayout()
Hackmet's avatar
Hackmet committed
52 53 54 55
        self.widget = QtWidgets.QWidget()
        self.widget.setLayout(self.layout)
        self.setCentralWidget(self.widget)
        
56
        self.parent = parent
JosefBrandt's avatar
JosefBrandt committed
57 58
        self.dataset = dataset
        self.particleContainer = dataset.particleContainer
JosefBrandt's avatar
 
JosefBrandt committed
59
        self.editor = ParticleEditor(self.particleContainer, self)
60
        
JosefBrandt's avatar
JosefBrandt committed
61
#        self.additivePlot = None
62
        self.importWindow = None
63
        
64 65 66 67 68
        self.polymerCheckBoxes = []
        self.lastSelectedCheckBoxNames = []
        
        self.currentParticleIndex = 0
        self.currentSpectrumIndex = 0
JosefBrandt's avatar
 
JosefBrandt committed
69
#        self.lastSpectrumInFocus = None
70
        
JosefBrandt's avatar
 
JosefBrandt committed
71
        self.typeHistogramPlot = TypeHistogramView(self)
JosefBrandt's avatar
JosefBrandt committed
72
#        self.typeHistogramPlot.indexClicked.connect(self.getAdditivePlot)
73 74 75 76 77 78 79 80 81
        self.sizeHistogramCanvas = FigureCanvas(Figure())
       
        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)
Hackmet's avatar
Hackmet committed
82
        histNavigation.setFixedWidth(50)
83 84 85 86
        sizeHistLayout.addWidget(histNavigation)
        sizeHistLayout.addWidget(self.sizeHistogramCanvas)
        sizeHistGroup.setLayout(sizeHistLayout)
        
JosefBrandt's avatar
 
JosefBrandt committed
87
        self.specPlot = SpectraPlot(self.dataset)
88 89
        
        splitter1 = QtWidgets.QSplitter(QtCore.Qt.Vertical)
JosefBrandt's avatar
 
JosefBrandt committed
90
        splitter1.addWidget(self.specPlot)
91 92 93
        splitter1.addWidget(sizeHistGroup)
        splitter2 = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        splitter2.addWidget(splitter1)
JosefBrandt's avatar
JosefBrandt committed
94
        splitter2.addWidget(self.typeHistogramPlot)
95 96
        splitter2.setSizes([300, 150])
       
JosefBrandt's avatar
 
JosefBrandt committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
        referenceGroup = QtWidgets.QGroupBox('Reference Spectra')
        referenceLayout = QtWidgets.QHBoxLayout()
        
        self.refSelector = QtWidgets.QComboBox()
        self.refSelector.setMinimumWidth(200)
        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)
        referenceLayout.addStretch()
        referenceGroup.setLayout(referenceLayout)
        

113 114 115
        self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers')
        self.navigationGroup.setDisabled(True)
        navigationLayout = QtWidgets.QHBoxLayout()
JosefBrandt's avatar
 
JosefBrandt committed
116 117 118
        self.typeSelectorCombo = QtWidgets.QComboBox()
        self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType)
        self.typeSelectorCombo.setMinimumWidth(150)
119
        self.particleSelector = QtWidgets.QSpinBox()
JosefBrandt's avatar
 
JosefBrandt committed
120
        self.particleSelector.valueChanged.connect(self.updateToSelectedParticle)
JosefBrandt's avatar
 
JosefBrandt committed
121 122
        self.particleNumberLabel = QtWidgets.QLabel('of xx particles; ')
        
123 124
        self.spectrumSelector = QtWidgets.QSpinBox()
        self.spectrumSelector.valueChanged.connect(self.selectSpectrum)
JosefBrandt's avatar
 
JosefBrandt committed
125
        self.spectrumNumberLabel = QtWidgets.QLabel('of xx spectra')
126 127 128 129 130 131
        for spinbox in [self.particleSelector, self.spectrumSelector]:
            spinbox.setMinimum(1)
            spinbox.setSingleStep(1)
            spinbox.setValue(1)
        
        navigationLayout.addWidget(QtWidgets.QLabel('Select Polymer Type:'))
JosefBrandt's avatar
 
JosefBrandt committed
132
        navigationLayout.addWidget(self.typeSelectorCombo)
133 134 135
        navigationLayout.addStretch()
        navigationLayout.addWidget(QtWidgets.QLabel('Select Particle'))
        navigationLayout.addWidget(self.particleSelector)
JosefBrandt's avatar
 
JosefBrandt committed
136 137
        navigationLayout.addWidget(self.particleNumberLabel)
        navigationLayout.addStretch()
138 139
        navigationLayout.addWidget(QtWidgets.QLabel('Select Spectrum'))
        navigationLayout.addWidget(self.spectrumSelector)
JosefBrandt's avatar
 
JosefBrandt committed
140 141
        navigationLayout.addWidget(self.spectrumNumberLabel)
#        navigationLayout.addStretch()
142 143 144 145 146
        
        self.navigationGroup.setLayout(navigationLayout)
        
        topLayout = QtWidgets.QHBoxLayout()
        topLayout.addWidget(self.navigationGroup)
Hackmet's avatar
Hackmet committed
147
        topLayout.addWidget(referenceGroup)
148
        
JosefBrandt's avatar
 
JosefBrandt committed
149
        viewLayout = QtWidgets.QVBoxLayout()
150 151 152 153
        viewLayout.addLayout(topLayout)
        viewLayout.addWidget(splitter2)
        viewLayout.setStretch(1, 1)

JosefBrandt's avatar
 
JosefBrandt committed
154
        self.optionsGroup = QtWidgets.QGroupBox('Set HQI Threshold')
155 156 157
        optionsLayout = QtWidgets.QFormLayout()
        
        self.hqiSpinBox = QtWidgets.QDoubleSpinBox()
JosefBrandt's avatar
 
JosefBrandt committed
158
        self.hqiSpinBox.setValue(self.dataset.resultParams['minHQI'])
159 160
        self.hqiSpinBox.setDecimals(1)
        self.hqiSpinBox.setMinimum(0)
JosefBrandt's avatar
JosefBrandt committed
161
        self.hqiSpinBox.setMaximum(100)
JosefBrandt's avatar
 
JosefBrandt committed
162 163
        self.hqiSpinBox.setMaximumWidth(100)
        self.hqiSpinBox.valueChanged.connect(self.applyHQIThresholdToResults)
JosefBrandt's avatar
 
JosefBrandt committed
164
        optionsLayout.addRow(QtWidgets.QLabel('minimum HQI:'), self.hqiSpinBox)
165
        
JosefBrandt's avatar
JosefBrandt committed
166 167 168 169 170 171
#        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)
172 173 174
        
        self.optionsGroup.setLayout(optionsLayout)
        self.optionsGroup.setMinimumWidth(175)
JosefBrandt's avatar
JosefBrandt committed
175
#        self.optionsGroup.setDisabled(True)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
        
        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)
JosefBrandt's avatar
 
JosefBrandt committed
196 197
        
        self.menuLayout = QtWidgets.QVBoxLayout()
198 199 200 201 202 203
        self.menuLayout.addWidget(self.optionsGroup)
        self.menuLayout.addWidget(self.resultScrollarea)
        
        self.layout.addLayout(self.menuLayout)
        self.layout.addLayout(viewLayout)
        
JosefBrandt's avatar
JosefBrandt committed
204 205
        minHQI = self.dataset.resultParams['minHQI']
#        compHQI = self.dataset.resultParams['compHQI']
Lars Bittrich's avatar
Lars Bittrich committed
206 207
        if minHQI is not None:
            self.hqiSpinBox.setValue(minHQI)
JosefBrandt's avatar
JosefBrandt committed
208
#            self.compHqiSpinBox.setValue(compHQI)
209
         
Hackmet's avatar
Hackmet committed
210 211
        self.createActions()
        self.createMenus()
JosefBrandt's avatar
JosefBrandt committed
212
        self.applyHQIThresholdToResults()
JosefBrandt's avatar
 
JosefBrandt committed
213
        self.createHistogramData()
JosefBrandt's avatar
 
JosefBrandt committed
214
        self.updateDisplays()
JosefBrandt's avatar
 
JosefBrandt committed
215 216
        self.initializeSpecPlot()
        self.displayNewPolymerType()
JosefBrandt's avatar
 
JosefBrandt committed
217
        self.updateToSelectedParticle()
JosefBrandt's avatar
 
JosefBrandt committed
218
#        self.createPolymerOverlay()
Hackmet's avatar
Hackmet committed
219 220 221 222 223 224 225 226 227 228 229 230
    
    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)
        
JosefBrandt's avatar
JosefBrandt committed
231
        self.transpAct = QtWidgets.QAction("&Transparent Overlay", self)
232
        self.transpAct.triggered.connect(self.updateContourColors)
Hackmet's avatar
Hackmet committed
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
            
        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)
265
        self.overlayActGroup.triggered.connect(self.updateContourColors)
JosefBrandt's avatar
 
JosefBrandt committed
266
        self.overlayActGroup.triggered.connect(self.updateDisplays)
Hackmet's avatar
Hackmet committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        
        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)
JosefBrandt's avatar
 
JosefBrandt committed
286
        
Hackmet's avatar
Hackmet committed
287 288 289 290 291 292 293 294 295 296 297
    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:
Hackmet's avatar
Hackmet committed
298
            self.refSelector.addItem('')
Hackmet's avatar
Hackmet committed
299 300 301 302
            self.refSelector.addItems(self.dbWin.activeDatabase.spectraNames)
            self.refSelector.setDisabled(False)
            
    def importTrueMatchResults(self):
JosefBrandt's avatar
 
JosefBrandt committed
303
        self.importWindow = LoadTrueMatchResults(self.particleContainer, self)
304
        self.importWindow.exec()
305
    
JosefBrandt's avatar
JosefBrandt committed
306 307 308 309 310 311 312 313
#    @QtCore.pyqtSlot(int)
#    def getAdditivePlot(self, clickedindex):
#        polymer = self.datastats.typehistogram[clickedindex][0]        #get the polymer name, that was clicked on
#      
#        if self.datastats.sorted_additives is not None and \
#           len(self.datastats.sorted_additives[clickedindex]) > 0:            
#            self.additivePlot = AdditiveViewer(polymer, self.datastats.sorted_additives[clickedindex])
#            self.additivePlot.show()
314
    
315
    @QtCore.pyqtSlot()
JosefBrandt's avatar
JosefBrandt committed
316
    def applyHQIThresholdToResults(self):
JosefBrandt's avatar
 
JosefBrandt committed
317 318 319 320
        hqi = self.hqiSpinBox.value()
        self.particleContainer.applyHQITresholdToParticles(hqi)
        self.dataset.resultParams['minHQI'] = hqi
        self.dataset.save()
JosefBrandt's avatar
JosefBrandt committed
321
        self.createHistogramData()
JosefBrandt's avatar
 
JosefBrandt committed
322
        self.updateDisplays()
323 324 325 326 327 328 329 330 331 332 333 334 335
            
    def createHistogramData(self):
        ###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)
JosefBrandt's avatar
 
JosefBrandt committed
336
        self.showTotalSelector.stateChanged.connect(self.updateDisplays)
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        
        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)
JosefBrandt's avatar
JosefBrandt committed
352
        
353
        #generate new checkboxes 
JosefBrandt's avatar
 
JosefBrandt committed
354
        self.polymerCheckBoxes = []#
JosefBrandt's avatar
JosefBrandt committed
355
        uniquePolymers = self.particleContainer.getUniquePolymers()
356
        for index, polymer in enumerate(uniquePolymers):
357 358 359 360 361 362
            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)
            
JosefBrandt's avatar
 
JosefBrandt committed
363
            self.polymerCheckBoxes[index].stateChanged.connect(self.updateDisplays)
364 365 366 367 368 369

        self.resultCheckBoxesLayout.addStretch()
        self.resultCheckBoxes.setLayout(self.resultCheckBoxesLayout)
        self.layout_SArea.addWidget(self.resultCheckBoxes)
        self.menuLayout.addWidget(self.resultScrollarea)
        
Hackmet's avatar
Hackmet committed
370 371 372
        self.expExcelAct.setDisabled(False)
        if sqlEnabled:
            self.expSQLAct.setDisabled(False)
373 374
        
        self.navigationGroup.setEnabled(True)
JosefBrandt's avatar
 
JosefBrandt committed
375 376 377 378
        self.typeSelectorCombo.currentIndexChanged.disconnect()
        self.typeSelectorCombo.clear()
        self.typeSelectorCombo.addItems(uniquePolymers)
        self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType)
Hackmet's avatar
Hackmet committed
379
                
JosefBrandt's avatar
 
JosefBrandt committed
380 381 382 383 384 385 386 387
        self.polymerIndex = self.typeSelectorCombo.currentIndex()
#        if self.lastSpectrumInFocus is not None:
#            self.currentSpectrumIndex = self.lastSpectrumInFocus
#            self.displayNewPolymerType(resetCurrentIndex=False)
#            print('displaying new type without resetting index')
#        else:
#            print('displaying new type with resetting index')
#            self.displayNewPolymerType()
388
    
JosefBrandt's avatar
 
JosefBrandt committed
389
    def updateDisplays(self):  
390
        self.createHistogramData()
JosefBrandt's avatar
 
JosefBrandt committed
391
        t0 = time.time()
JosefBrandt's avatar
 
JosefBrandt committed
392
        self.updateTypeHistogram()
JosefBrandt's avatar
 
JosefBrandt committed
393 394
        print('update type hist:', round((time.time()-t0)*1000))
        t0 = time.time()
JosefBrandt's avatar
 
JosefBrandt committed
395
        self.updateSizeHistogram()
JosefBrandt's avatar
 
JosefBrandt committed
396 397
        print('update size hist:', round((time.time()-t0)*1000))
        t0 = time.time()
398
        self.updateContourColors()
JosefBrandt's avatar
 
JosefBrandt committed
399 400 401 402
        print('update contours:', round((time.time()-t0)*1000))
        t0 = time.time()
        self.updateLegend()
        print('update legend:', round((time.time()-t0)*1000))
JosefBrandt's avatar
 
JosefBrandt committed
403
        self.dataset.save()
JosefBrandt's avatar
 
JosefBrandt committed
404 405 406 407
    
    def initializeSpecPlot(self):
        self.specPlot.loadSpectraAndInitializeSpecPlot()
        self.updateSpecPlot()
408
    
JosefBrandt's avatar
 
JosefBrandt committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    def updateTypeHistogram(self):
        colorList = []
        abundancyList = []
        labelList = []
        typeHistogram = self.particleContainer.getTypeHistogram()
        for index, polymType in enumerate(typeHistogram):
            if not self.selOverlayAct.isChecked() or self.polymerCheckBoxes[index].isChecked():
                text = f'{typeHistogram[polymType]} x {polymType}'
                labelList.append(text)
                abundancyList.append(typeHistogram[polymType])
                curColor = getColorFromNameWithSeed(polymType, self.dataset.colorSeed)
                colorList.append(QtGui.QColor(*curColor))
            
        self.typeHistogramPlot.updateTypeHistogram(list(zip(abundancyList, labelList, colorList)))
    
    def updateSizeHistogram(self):
        if self.particleContainer.getNumberOfParticles() > 0:
            #general size histograms
            self.sizeHist_ax.clear()
            self.sizeHist_ax.axis('on')
            self.bins = np.logspace(0.1, 3, 20)
            self.sizes = self.particleContainer.getSizesOfAllParticles()
                
            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')
                
            for polymType in self.getSelectedPolymers():
                sizes = self.particleContainer.getSizesOfParticleType(polymType)
                sizehist = np.histogram(sizes, self.bins)
                color = getColorFromNameWithSeed(polymType, self.dataset.colorSeed, base255=False)
                self.sizeHist_ax.semilogx(self.totalhistx, sizehist[0], label=polymType, color=color)    
            
            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 = self.getSelectedPolymers()
    
Hackmet's avatar
Hackmet committed
462
    def updateSpecPlot(self, centerOn=True, highlightContour=True):
JosefBrandt's avatar
 
JosefBrandt committed
463 464 465 466 467 468 469
        particleSize = self.particleContainer.getSizeOfParticleByIndex(self.currentParticleIndex)
        hqi = self.particleContainer.getHQIOfSpectrumIndex(self.currentSpectrumIndex)
        self.specPlot.updateParticleSpectrum(self.currentSpectrumIndex, particleSize, hqi)
        self.parent.centerOnRamanIndex(self.currentSpectrumIndex, centerOn=centerOn, highlightContour=highlightContour)  #TODO: is this reasonable to do in that way???
        self.parent.highLightRamanIndex(self.currentSpectrumIndex)
#        self.lastSpectrumInFocus = self.currentSpectrumIndex
            
Hackmet's avatar
Hackmet committed
470 471 472
        if self.refSelector.isEnabled() and self.refSelector.currentText() != '':
            refID = self.dbWin.activeDatabase.spectraNames.index(self.refSelector.currentText())
            ref = self.dbWin.activeDatabase.spectra[refID]
JosefBrandt's avatar
 
JosefBrandt committed
473
            self.specPlot.updateReferenceSpectrum(ref[:, 0], ref[:, 1])
JosefBrandt's avatar
 
JosefBrandt committed
474
    
475
    def updateContourColors(self):
JosefBrandt's avatar
 
JosefBrandt committed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
        contours = self.parent.contourItems
        alpha = (128 if self.transpAct.isChecked() else 255)
        selectedPolymers = self.getSelectedPolymers()

        for particleIndex, contour in enumerate(contours):
            assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex)
            hidden = self.noOverlayAct.isChecked() or (not self.fullOverlayAct.isChecked() and assignment not in selectedPolymers)
            color = getColorFromNameWithSeed(assignment, self.dataset.colorSeed)
            color = QtGui.QColor(color[0], color[1], color[2], alpha=alpha)
            
            contour.setHidden(hidden)
            contour.setColor(color)
            contour.update()
            
    def updateLegend(self):
        if not self.noOverlayAct.isChecked():
            legendItems = []
            selectedPolymers = self.getSelectedPolymers()
            for polymer in self.particleContainer.getUniquePolymers():
                if self.fullOverlayAct.isChecked() or polymer in selectedPolymers:                
                    color = getColorFromNameWithSeed(polymer, self.dataset.colorSeed)
                    color = QtGui.QColor(color[0], color[1], color[2], 255)
                    legendItems.append((polymer, color))
            self.parent.updateLegend(legendItems)

                        
    def getSelectedPolymers(self):
        return [checkbox.text() for checkbox in self.polymerCheckBoxes if checkbox.isChecked()]
        
JosefBrandt's avatar
 
JosefBrandt committed
505 506 507 508 509 510 511 512 513 514 515 516 517
    #TODO: Connect to widget that allows jumping to particular particle
    def selectParticleIndex(self, particleIndex, centerOn=True):
        self.typeSelectorCombo.currentIndexChanged.disconnect()
        assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex)
        self.typeSelectorCombo.setCurrentText(assignment)
        self.typeSelectorCombo.currentIndexChanged.connect(self.displayNewPolymerType)
        
        self.particleSelector.valueChanged.disconnect()
        particleIndices = self.particleContainer.getIndicesOfParticleType(assignment)
        self.particleSelector.setValue(particleIndices.index(particleIndex)+1)
        self.particleSelector.valueChanged.connect(self.updateToSelectedParticle)
        
        self.updateToSelectedParticle(resetSpectrumCount=True, centerOn=centerOn)
518
        
519
    def displayNewPolymerType(self, resetCurrentIndex=True):
JosefBrandt's avatar
 
JosefBrandt committed
520 521 522 523 524 525 526 527 528
        polymerName = self.typeSelectorCombo.currentText()
        numParticles = self.particleContainer.getNumberOfParticlesOfAssignment(polymerName)
        self.particleSelector.setMaximum(numParticles)
        self.particleNumberLabel.setText(f'of {numParticles} Particles; ')
        
        self.particleSelector.setValue(1)
        self.spectrumSelector.setValue(1)
        
        self.currentParticleIndex = self.getParticleIndexFromParticleSelector()
529 530 531
        numSpectra = self.particleContainer.getNumberOfSpectraOfParticle(self.currentParticleIndex)
        self.spectrumSelector.setMaximum(numSpectra)
        self.spectrumNumberLabel.setText(f'of {numSpectra} Spectra')
JosefBrandt's avatar
 
JosefBrandt committed
532 533
        self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
        self.updateSpecPlot(centerOn=False)
534
    
JosefBrandt's avatar
 
JosefBrandt committed
535
    def updateToSelectedParticle(self, resetSpectrumCount=True, centerOn=True):
JosefBrandt's avatar
 
JosefBrandt committed
536 537 538 539 540 541
        polymerName = self.typeSelectorCombo.currentText()
        if polymerName != '':
            self.currentParticleIndex = self.getParticleIndexFromParticleSelector()
            numSpectra = self.particleContainer.getNumberOfSpectraOfParticle(self.currentParticleIndex)
            self.spectrumSelector.setMaximum(numSpectra)
            self.spectrumNumberLabel.setText(f'of {numSpectra} Spectra')
542 543
            if resetSpectrumCount:
                self.spectrumSelector.setValue(1)
JosefBrandt's avatar
 
JosefBrandt committed
544 545
            
            self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
JosefBrandt's avatar
 
JosefBrandt committed
546
            self.updateSpecPlot(centerOn)
547 548
    
    def selectSpectrum(self):
JosefBrandt's avatar
 
JosefBrandt committed
549 550 551 552 553 554 555 556 557 558 559 560 561
        self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
        self.updateSpecPlot()
        
    def getSpectrumIndexFromSpectrumSelector(self):
        specIndicesOfParticle = self.particleContainer.getSpectraIndicesOfParticle(self.currentParticleIndex)
        try:
            return specIndicesOfParticle[self.spectrumSelector.value()-1]
        except IndexError:
            print(f'requested specIndex {self.spectrumSelector.value()-1} for particle Index {self.currentParticleIndex} of specIndices: {specIndicesOfParticle}')
    
    def getParticleIndexFromParticleSelector(self):
        particleIndicesOfType = self.particleContainer.getIndicesOfParticleType(self.typeSelectorCombo.currentText())
        return particleIndicesOfType[self.particleSelector.value()-1]
562 563
            
    def darkenBackground(self):
Hackmet's avatar
Hackmet committed
564
        self.parent.darkenPixmap = self.darkenAct.isChecked()
565
        
Hackmet's avatar
Hackmet committed
566
        if self.darkenAct.isChecked():
567 568 569 570 571 572 573
            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):
JosefBrandt's avatar
 
JosefBrandt committed
574
        text, ok = QtWidgets.QInputDialog.getText(self, 'Color Seed', 'Enter New Seed here', text=self.dataset.colorSeed)
575
        if ok:
JosefBrandt's avatar
 
JosefBrandt committed
576
            self.dataset.colorSeed = text
JosefBrandt's avatar
 
JosefBrandt committed
577
            self.updateDisplays()
578 579
            
    def show_hide_labels(self):
Hackmet's avatar
Hackmet committed
580
        hidden = self.hideLabelAct.isChecked()
581 582 583
        for scanIndicator in self.parent.ramanscanitems:
            scanIndicator.hidden = hidden
            scanIndicator.update()
JosefBrandt's avatar
 
JosefBrandt committed
584 585 586 587 588 589 590 591
    
    def exportToExcel(self):
        expWin = ExpExcelDialog(self.particleContainer, self)
        expWin.exec()
            
    def exportToSQL(self):
        sqlexp = SQLExport(self.particleContainer, self)
        sqlexp.exec()
592 593
    
    def closeEvent(self, event):
JosefBrandt's avatar
 
JosefBrandt committed
594
        for window in [self.importWindow, self.dbWin]:
595 596
            try: window.close()
            except: pass
Hackmet's avatar
Hackmet committed
597
        self.parent.imparent.particelAnalysisAct.setChecked(False)
598 599 600 601
        event.accept()


if __name__ == '__main__':
602
    from ..dataset import DataSet
603 604
    def run():
        app = QtWidgets.QApplication(sys.argv)
605
        meas = ParticleAnalysis(DataSet("dummydata"))
606
        meas.showMaximized()
607
        return app.exec_()
608 609
    
    run()