analysiswidgets.py 9.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# -*- coding: utf-8 -*-
"""
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/>.
"""

22
from PyQt5 import QtWidgets, QtGui, QtCore
23 24 25 26 27 28 29 30 31 32
import numpy as np
import pandas as pd
import os
import sys

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


class ExpExcelDialog(QtWidgets.QDialog):
JosefBrandt's avatar
JosefBrandt committed
33 34
    def __init__(self, dataset, particleContainer):
        super(ExpExcelDialog, self).__init__()
35
        self.setWindowTitle('Export Options')
36
        self.setGeometry(200, 200, 300, 300)
37
        
JosefBrandt's avatar
 
JosefBrandt committed
38
        self.dataset = dataset
JosefBrandt's avatar
JosefBrandt committed
39
        self.particleContainer = particleContainer
JosefBrandt's avatar
 
JosefBrandt committed
40 41 42
        self.polymers = self.particleContainer.getListOfParticleAssignments
#        self.additives = self.datastats.currentAdditives
        self.hqis = self.particleContainer.getListOfHighestHQIs
43 44 45 46 47 48 49 50 51 52 53
        
        self.layout = QtWidgets.QHBoxLayout()
        self.setLayout(self.layout)

        excelvbox = QtWidgets.QVBoxLayout()
        excelvbox.addWidget(QtWidgets.QLabel('Select Parameters for Export'))
        excelgroup = QtWidgets.QGroupBox("Export to Excel", self)
        
        self.exportOptions = ['Polymer Type (mandatory)', 'Additives', 'Long Size (µm)', 'Short Size (µm)', 'Area (µm²)', 'HQI', 'Size Classes']
        self.checkBoxes = []
        self.sizeClasses = [5, 10, 20, 50, 100, 1e6]
JosefBrandt's avatar
 
JosefBrandt committed
54
        self.directory = self.dataset.path
55 56 57 58 59 60 61 62 63
        
        for index, option in enumerate(self.exportOptions):
            self.checkBoxes.append(QtWidgets.QCheckBox(self))
            self.checkBoxes[-1].setText(option)
            self.checkBoxes[-1].setChecked(True)
            
            if option == 'Polymer Type (mandatory)':
                self.checkBoxes[-1].setEnabled(False)           #is mandatory!!!
            
JosefBrandt's avatar
JosefBrandt committed
64 65 66 67
#            if option == 'Additives':
#                if self.additives is None:
#                    self.checkBoxes[-1].setEnabled(False)
#                    self.checkBoxes[-1].setChecked(False)
68 69 70 71
                    
            excelvbox.addWidget(self.checkBoxes[-1])
        
        self.xlsFileName = QtWidgets.QLineEdit()
JosefBrandt's avatar
 
JosefBrandt committed
72
        self.xlsFileName.setText('{}_Particle_List'.format(self.dataset.name))
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
        excelvbox.addWidget(QtWidgets.QLabel('Filename:'))
        excelvbox.addWidget(self.xlsFileName)
        
        self.exlbtn = QtWidgets.QPushButton('Export to Excel')
        self.exlbtn.resize(self.exlbtn.sizeHint())
        self.exlbtn.clicked.connect(self.toExcel)
        
        excelvbox.addWidget(self.exlbtn)
        excelgroup.setLayout(excelvbox)
        
        self.layout.addWidget(excelgroup)

        self.show()
    
    def toExcel(self):
        requiredcolumns = []        
JosefBrandt's avatar
 
JosefBrandt committed
89 90
        self.sizes = self.particleContainer.getSizesOfAllParticles()

91 92 93 94 95 96 97
        for box in self.checkBoxes:
            if box.isChecked() == True:
                if box.text() != 'Size Classes':
                    requiredcolumns.append(box.text())
                    if box.text() == 'Long Size (µm)':
                        longSize = self.sizes
                    elif box.text() == 'Short Size (µm)':
JosefBrandt's avatar
 
JosefBrandt committed
98
                        self.shortSizes = self.particleContainer.getShortSizesOfAllParticles()
99 100
                    elif box.text() == 'Area (µm²)':
                        area = np.array([np.round(float(entry[4]), 1) for entry in self.particles])
JosefBrandt's avatar
 
JosefBrandt committed
101
                    
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
                else:
                    requiredcolumns.append('0 - 5 µm')
                    requiredcolumns.append('5 - 10 µm')
                    requiredcolumns.append('10 - 20 µm')
                    requiredcolumns.append('20 - 50 µm')
                    requiredcolumns.append('50 - 100 µm')
                    requiredcolumns.append('> 100 µm')
        
        finalData = np.zeros((self.polymers.shape[0],len(requiredcolumns)-1))
        polymertypes = [""]*self.polymers.shape[0]
        rowindex = 0
        for polymer in np.unique(self.polymers):
            indices = self.polymers == polymer
            numentries = int(np.sum(indices))
            print("Num:", numentries)
            sys.stdout.flush()
            
            for colindex, column in enumerate(requiredcolumns):
                if column == 'Polymer Type (mandatory)':
                    polymertypes[rowindex:rowindex+numentries] = self.polymers[indices]    
JosefBrandt's avatar
 
JosefBrandt committed
122 123
#                if column == 'Additives':
#                    finalData[rowindex:rowindex+numentries, colindex-1] = self.additives[indices]                
124 125 126
                if column == 'Long Size (µm)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = longSize[indices]
                if column == 'Short Size (µm)':
JosefBrandt's avatar
 
JosefBrandt committed
127
                    finalData[rowindex:rowindex+numentries, colindex-1] = self.shortSizes[indices]
128 129
                if column == 'Area (µm²)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = area[indices]
JosefBrandt's avatar
 
JosefBrandt committed
130 131
                if column == 'HQI':
                    finalData[rowindex:rowindex+numentries, colindex-1] = self.hqis[indices]
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
            
            if '> 100 µm' in requiredcolumns:
                ##append size classes
                numPrevCols = len(requiredcolumns) - 1 - len(self.sizeClasses)      #number of previous columns
                for tableindex, dataindex in enumerate(np.arange(len(indices))[indices]):    
                    for classindex in range(len(self.sizeClasses)):
                        upLimit = self.sizeClasses[classindex]
                        if classindex == 0: lowLimit = 0
                        else: lowLimit = self.sizeClasses[classindex-1]
                        curSize = self.sizes[dataindex]
                        
                        if  curSize > lowLimit and curSize <= upLimit:
                            finalData[rowindex+tableindex, numPrevCols + classindex] = np.int(1)
                        else:
                            finalData[rowindex+tableindex, numPrevCols + classindex] = np.int(0)               
            
            rowindex = rowindex + numentries
            
        #dump into excel file
        xlsname = self.directory + '//' + self.xlsFileName.text() + '.xlsx'
        print('exporting excel to:\n file name:  {} in directory: {}'.format(self.xlsFileName.text(), self.directory))
        validFileName = False
        incr = 1
        while not validFileName:
            if not os.path.exists(xlsname):
                validFileName = True
            else:
159
                xlsname = self.directory + '//' + self.xlsFileName.text() + ' {}.xlsx'.format(incr)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
                incr += 1
        
        writer = pd.ExcelWriter(xlsname, engine = 'xlsxwriter')
        
        df = pd.DataFrame(finalData, columns=requiredcolumns[1:])
        df.insert(0, 'Polymer Type', polymertypes)
        df.to_excel(writer, sheet_name = 'Individual Particles', index = False)
        if  '> 100 µm' in requiredcolumns:
            #generate particle statistics report
            header = ['0 - 5 µm', '5 - 10 µm', '10 - 20 µm', '20 - 50 µm', '50 - 100 µm', '> 100 µm']
            index = np.unique(self.polymers)
            particleclasses = []
            
            for polymer in index:
                indices = np.where(self.polymers == polymer)[0]
                sortind = np.searchsorted([5,10,20,50,100], self.sizes[indices], 'right')
                classes = np.bincount(sortind, minlength=6)
                particleclasses.append(classes)
            
            particleclasses = np.array(particleclasses)
            report = pd.DataFrame(np.array(particleclasses), columns=header,
                                  dtype=int)
            report.insert(0, 'Polymer Type', index)
            report.insert(len(report.columns), 'Sum total', particleclasses.sum(axis=1))
            report.to_excel(writer, sheet_name = 'Particle Statistics', index=False)
        writer.save()
        self.accept()


class AdditiveViewer(QtWidgets.QWidget):
    def __init__(self, polymername, sortedAdditives):
        super(AdditiveViewer, self).__init__()
        self.setGeometry(200,200, 800, 600)
        self.setWindowTitle('Additives of {}'.format(polymername))
        
        self.layout = QtWidgets.QGridLayout()
        self.setLayout(self.layout)
        
        self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
        self.ax = self.canvas.figure.subplots()
        
        self.layout.addWidget(self.canvas, 0, 0)
        
        self.ax.hist(sortedAdditives)
        self.ax.set_ylabel('Number', fontsize = 15)
205
        self.ax.tick_params(axis='both', which='both', labelsize=15)
JosefBrandt's avatar
 
JosefBrandt committed
206

207