Commit 6b9fc03c authored by Lars Bittrich's avatar Lars Bittrich
Browse files

analysisview.py: moved ExpExcelDialog and AdditiveViewer to new analysiswidgets.py

parent 3ca5cc5e
Loading
Loading
Loading
Loading
+2 −177
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ If not, see <https://www.gnu.org/licenses/>.

from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np
import pandas as pd
import sys
import operator
import os
@@ -33,11 +32,12 @@ 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 .editParticles import ParticleEditor
from .database import DataBaseWindow
try:
    from analysis.sqlexport import SQLExport
    from .sqlexport import SQLExport
    sqlEnabled = True
except:
    sqlEnabled = False
@@ -857,181 +857,6 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
        event.accept()


class ExpExcelDialog(QtWidgets.QDialog):
    def __init__(self, parent):
        super(ExpExcelDialog, self).__init__()
        self.setWindowTitle('Export Options')
        self.setGeometry(200,200, 300, 300)
        
        self.parent = parent
        self.particles = self.parent.particlestats
        self.polymers = self.parent.particleResults
        self.additives = self.parent.currentAdditives
        self.hqis = self.parent.hqis
        
        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]
        self.directory = self.parent.parent.dataset.path
        
        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!!!
            
            if option == 'Additives':
                if self.additives is None:
                    self.checkBoxes[-1].setEnabled(False)
                    self.checkBoxes[-1].setChecked(False)
                    
            excelvbox.addWidget(self.checkBoxes[-1])
        
        self.xlsFileName = QtWidgets.QLineEdit()
        self.xlsFileName.setText('{}_Particle_List'.format(self.parent.parent.dataset.name))
        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 = []        
        self.sizes = np.round(np.array([i[0] if np.isnan(i[2]) else i[2] for i in self.particles]), 1)
        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)':
                        shortSize = np.round(np.array([i[1] if np.isnan(i[3]) else i[3] for i in self.particles]), 1)
                    elif box.text() == 'Area (µm²)':
                        area = np.array([np.round(float(entry[4]), 1) for entry in self.particles])
                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]    
                if column == 'Additives':
                    finalData[rowindex:rowindex+numentries, colindex-1] = self.additives[indices]                
                if column == 'Long Size (µm)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = longSize[indices]
                if column == 'Short Size (µm)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = shortSize[indices]
                if column == 'Area (µm²)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = area[indices]
                # hit quality index array does not match the data size if particles have been combined
                #if column == 'HQI':
                #    finalData[rowindex:rowindex+numentries, colindex-1] = self.hqis[indices]
            
            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:
                xlsname = self.directory + self.xlsFileName.text() + ' {}.xlsx'.format(incr)
                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)
        self.ax.tick_params(axis='both', which='both', labelsize=15)


if __name__ == '__main__':
    def run():
        app = QtWidgets.QApplication(sys.argv)
+204 −0
Original line number Diff line number Diff line
# -*- 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/>.
"""

from PyQt5 import QtWidgets
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):
    def __init__(self, parent):
        super(ExpExcelDialog, self).__init__()
        self.setWindowTitle('Export Options')
        self.setGeometry(200,200, 300, 300)
        
        self.parent = parent
        self.particles = self.parent.particlestats
        self.polymers = self.parent.particleResults
        self.additives = self.parent.currentAdditives
        self.hqis = self.parent.hqis
        
        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]
        self.directory = self.parent.parent.dataset.path
        
        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!!!
            
            if option == 'Additives':
                if self.additives is None:
                    self.checkBoxes[-1].setEnabled(False)
                    self.checkBoxes[-1].setChecked(False)
                    
            excelvbox.addWidget(self.checkBoxes[-1])
        
        self.xlsFileName = QtWidgets.QLineEdit()
        self.xlsFileName.setText('{}_Particle_List'.format(self.parent.parent.dataset.name))
        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 = []        
        self.sizes = np.round(np.array([i[0] if np.isnan(i[2]) else i[2] for i in self.particles]), 1)
        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)':
                        shortSize = np.round(np.array([i[1] if np.isnan(i[3]) else i[3] for i in self.particles]), 1)
                    elif box.text() == 'Area (µm²)':
                        area = np.array([np.round(float(entry[4]), 1) for entry in self.particles])
                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]    
                if column == 'Additives':
                    finalData[rowindex:rowindex+numentries, colindex-1] = self.additives[indices]                
                if column == 'Long Size (µm)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = longSize[indices]
                if column == 'Short Size (µm)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = shortSize[indices]
                if column == 'Area (µm²)':
                    finalData[rowindex:rowindex+numentries, colindex-1] = area[indices]
                # hit quality index array does not match the data size if particles have been combined
                #if column == 'HQI':
                #    finalData[rowindex:rowindex+numentries, colindex-1] = self.hqis[indices]
            
            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:
                xlsname = self.directory + self.xlsFileName.text() + ' {}.xlsx'.format(incr)
                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)
        self.ax.tick_params(axis='both', which='both', labelsize=15)
 No newline at end of file