analysisview.py 26.6 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)
JosefBrandt's avatar
 
JosefBrandt committed
232
        self.transpAct.triggered.connect(self.updateContours)
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)
JosefBrandt's avatar
 
JosefBrandt committed
265 266
        self.overlayActGroup.triggered.connect(self.updateContours)
        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()
Hackmet's avatar
Hackmet committed
388
            
JosefBrandt's avatar
 
JosefBrandt committed
389 390
    def updateDisplays(self):  
        t0 = time.time()
JosefBrandt's avatar
 
JosefBrandt committed
391
        self.updateTypeHistogram()
JosefBrandt's avatar
 
JosefBrandt committed
392 393
        print('update type hist:', round((time.time()-t0)*1000))
        t0 = time.time()
JosefBrandt's avatar
 
JosefBrandt committed
394
        self.updateSizeHistogram()
JosefBrandt's avatar
 
JosefBrandt committed
395 396 397 398 399 400 401
        print('update size hist:', round((time.time()-t0)*1000))
        t0 = time.time()
        self.updateContours()
        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
402
        self.dataset.save()
JosefBrandt's avatar
 
JosefBrandt committed
403 404 405 406
    
    def initializeSpecPlot(self):
        self.specPlot.loadSpectraAndInitializeSpecPlot()
        self.updateSpecPlot()
407
    
JosefBrandt's avatar
 
JosefBrandt committed
408 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
    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
461
    def updateSpecPlot(self, centerOn=True, highlightContour=True):
JosefBrandt's avatar
 
JosefBrandt committed
462 463 464 465 466 467 468
        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
469 470 471
        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
472
            self.specPlot.updateReferenceSpectrum(ref[:, 0], ref[:, 1])
JosefBrandt's avatar
 
JosefBrandt committed
473 474 475 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
    
    def updateContours(self):
        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
504 505 506 507 508 509 510 511
#    @QtCore.pyqtSlot(int)     #TODO: Connect to widget that allows jumping to particular particle
#    def selectParticleIndex(self, particleIndex, centerOn=True):
#        assignment = self.particleContainer.getParticleAssignmentByIndex(particleIndex)
#        self.typeSelectorCombo.setCurrentText(assignment)
#        particleIndices = self.particleContainer.getIndicesOfParticleType(assignment)
#        self.particleSelector.setValue(particleIndices.index(particleIndex)+1)
#        
#        self.updateToSelectedParticle(resetSpectrumCount=True, centerOn=False)
512
        
513 514
    
    def displayNewPolymerType(self, resetCurrentIndex=True):
JosefBrandt's avatar
 
JosefBrandt committed
515 516 517 518 519 520 521 522 523 524 525 526
        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()
        self.spectrumSelector.setMaximum(self.particleContainer.getNumberOfSpectraOfParticle(self.currentParticleIndex))
        self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
        self.updateSpecPlot(centerOn=False)
527
    
JosefBrandt's avatar
 
JosefBrandt committed
528
    def updateToSelectedParticle(self, resetSpectrumCount=True, centerOn=True):
JosefBrandt's avatar
 
JosefBrandt committed
529 530 531 532 533 534
        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')
535 536
            if resetSpectrumCount:
                self.spectrumSelector.setValue(1)
JosefBrandt's avatar
 
JosefBrandt committed
537 538
            
            self.currentSpectrumIndex = self.getSpectrumIndexFromSpectrumSelector()
JosefBrandt's avatar
 
JosefBrandt committed
539
            self.updateSpecPlot(centerOn)
540 541
    
    def selectSpectrum(self):
JosefBrandt's avatar
 
JosefBrandt committed
542 543 544 545 546 547 548 549 550 551 552 553 554
        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]
555 556
            
    def darkenBackground(self):
Hackmet's avatar
Hackmet committed
557
        self.parent.darkenPixmap = self.darkenAct.isChecked()
558
        
Hackmet's avatar
Hackmet committed
559
        if self.darkenAct.isChecked():
560 561 562 563 564 565 566
            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
567
        text, ok = QtWidgets.QInputDialog.getText(self, 'Color Seed', 'Enter New Seed here', text=self.dataset.colorSeed)
568
        if ok:
JosefBrandt's avatar
 
JosefBrandt committed
569
            self.dataset.colorSeed = text
JosefBrandt's avatar
 
JosefBrandt committed
570
            self.updateDisplays()
571 572
            
    def show_hide_labels(self):
Hackmet's avatar
Hackmet committed
573
        hidden = self.hideLabelAct.isChecked()
574 575 576
        for scanIndicator in self.parent.ramanscanitems:
            scanIndicator.hidden = hidden
            scanIndicator.update()
JosefBrandt's avatar
 
JosefBrandt committed
577 578 579 580 581 582 583 584
    
    def exportToExcel(self):
        expWin = ExpExcelDialog(self.particleContainer, self)
        expWin.exec()
            
    def exportToSQL(self):
        sqlexp = SQLExport(self.particleContainer, self)
        sqlexp.exec()
585 586
    
    def closeEvent(self, event):
JosefBrandt's avatar
 
JosefBrandt committed
587
        for window in [self.importWindow, self.dbWin]:
588 589
            try: window.close()
            except: pass
Hackmet's avatar
Hackmet committed
590
        self.parent.imparent.particelAnalysisAct.setChecked(False)
591 592 593 594
        event.accept()


if __name__ == '__main__':
595
    from ..dataset import DataSet
596 597
    def run():
        app = QtWidgets.QApplication(sys.argv)
598
        meas = ParticleAnalysis(DataSet("dummydata"))
599
        meas.showMaximized()
600
        return app.exec_()
601 602
    
    run()