excelexport.py 7.94 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/>.
"""

JosefBrandt's avatar
JosefBrandt committed
22
from PyQt5 import QtWidgets
23 24 25 26 27 28
import numpy as np
import pandas as pd
import os
import sys

class ExpExcelDialog(QtWidgets.QDialog):
JosefBrandt's avatar
JosefBrandt committed
29
    def __init__(self, dataset):
JosefBrandt's avatar
JosefBrandt committed
30
        super(ExpExcelDialog, self).__init__()
31
        self.setWindowTitle('Export Options')
32
        self.setGeometry(200, 200, 300, 300)
33
        
JosefBrandt's avatar
 
JosefBrandt committed
34
        self.dataset = dataset
JosefBrandt's avatar
JosefBrandt committed
35 36
        self.particleContainer = dataset.particleContainer
        
37 38 39 40 41 42 43 44
        
        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)
        
JosefBrandt's avatar
JosefBrandt committed
45
        self.exportOptions = ['Polymer Type (mandatory)', 'Long Size (µm)', 'Short Size (µm)', 'Area (µm²)', 'HQI', 'Size Classes']
46 47 48 49 50 51 52 53 54 55 56 57 58 59
        self.checkBoxes = []
        self.sizeClasses = [5, 10, 20, 50, 100, 1e6]
        
        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!!!
                    
            excelvbox.addWidget(self.checkBoxes[-1])
        
        self.xlsFileName = QtWidgets.QLineEdit()
JosefBrandt's avatar
 
JosefBrandt committed
60
        self.xlsFileName.setText('{}_Particle_List'.format(self.dataset.name))
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
        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):
JosefBrandt's avatar
JosefBrandt committed
76 77
        requiredcolumns = []       
        uniquePolymers = self.particleContainer.getUniquePolymers()
78 79
        polymers = np.array(self.particleContainer.getListOfParticleAssignments())
        sizes = np.array(self.particleContainer.getSizesOfAllParticles())
JosefBrandt's avatar
JosefBrandt committed
80
        
JosefBrandt's avatar
 
JosefBrandt committed
81

82 83 84 85 86
        for box in self.checkBoxes:
            if box.isChecked() == True:
                if box.text() != 'Size Classes':
                    requiredcolumns.append(box.text())
                    if box.text() == 'Long Size (µm)':
87
                        longSizes = np.round(sizes)
88
                    elif box.text() == 'Short Size (µm)':
89
                        shortSizes = np.round(np.array(self.particleContainer.getShortSizesOfAllParticles()))
JosefBrandt's avatar
JosefBrandt committed
90
                    elif box.text() == 'HQI':
91
                        hqis = np.array(self.particleContainer.getListOfHighestHQIs())
92
                    elif box.text() == 'Area (µm²)':
93
                        areas = np.array(self.particleContainer.getAreasOfAllParticles())
JosefBrandt's avatar
 
JosefBrandt committed
94
                    
95 96 97 98 99 100 101 102
                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')
        
103 104
        finalData = np.zeros((len(polymers),len(requiredcolumns)-1))
        polymertypes = [""]*len(polymers)
105
        rowindex = 0
JosefBrandt's avatar
JosefBrandt committed
106
        for polymer in uniquePolymers:
107
            indices = polymers == polymer
108 109 110 111 112
            numentries = int(np.sum(indices))
            sys.stdout.flush()
            
            for colindex, column in enumerate(requiredcolumns):
                if column == 'Polymer Type (mandatory)':
JosefBrandt's avatar
JosefBrandt committed
113
                    polymertypes[rowindex:rowindex+numentries] = polymers[indices]              
114
                if column == 'Long Size (µm)':
JosefBrandt's avatar
JosefBrandt committed
115
                    finalData[rowindex:rowindex+numentries, colindex-1] = longSizes[indices]
116
                if column == 'Short Size (µm)':
JosefBrandt's avatar
JosefBrandt committed
117
                    finalData[rowindex:rowindex+numentries, colindex-1] = shortSizes[indices]
118
                if column == 'Area (µm²)':
JosefBrandt's avatar
JosefBrandt committed
119
                    finalData[rowindex:rowindex+numentries, colindex-1] = areas[indices]
JosefBrandt's avatar
 
JosefBrandt committed
120
                if column == 'HQI':
JosefBrandt's avatar
JosefBrandt committed
121
                    finalData[rowindex:rowindex+numentries, colindex-1] = hqis[indices]
122 123 124 125 126 127 128 129 130
            
            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]
131
                        curSize = sizes[dataindex]
132 133 134 135 136 137 138 139 140
                        
                        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
141 142
        xlsname = os.path.join(self.dataset.path, f'{self.xlsFileName.text()}.xlsx')
        print('exporting excel to:\n file name:  {} in directory: {}'.format(self.xlsFileName.text(), self.dataset.path))
143
        incr = 1
144 145 146 147
        while os.path.exists(xlsname):
            xlsname = os.path.join(self.dataset.path, f'{self.xlsFileName.text()} {incr}.xlsx')
            incr += 1
    
148 149 150 151 152 153 154 155 156 157
        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']
            particleclasses = []
            
158 159 160
            for polymer in uniquePolymers:
                indices = self.particleContainer.getIndicesOfParticleType(polymer)
                sortind = np.searchsorted([5,10,20,50,100], sizes[indices], 'right')
161 162 163 164 165 166
                classes = np.bincount(sortind, minlength=6)
                particleclasses.append(classes)
            
            particleclasses = np.array(particleclasses)
            report = pd.DataFrame(np.array(particleclasses), columns=header,
                                  dtype=int)
167
            report.insert(0, 'Polymer Type', uniquePolymers)
168 169 170
            report.insert(len(report.columns), 'Sum total', particleclasses.sum(axis=1))
            report.to_excel(writer, sheet_name = 'Particle Statistics', index=False)
        writer.save()
171 172
        self.accept()
        QtWidgets.QMessageBox.about(self, 'Particles succesfully exported', 'List saved to\n' + str(xlsname))